Monday, July 28, 2008

Enumerating File Server Resources

This post provides several methods of enumerating sessions, connections and open files on a local or remote machine. Apart from the Powershell script that calls NetFileEnum there's nothing particularly new about this post, but I thought it was worth putting several different methods in one place.

This information is useful for gauging the use of file servers in particular, including the detail of which users are connected and what files they have locked.

Querying information against a single computer:

  • Run 'compmgmt.msc /computer=%server%' and look in 'Shared Folders' for Shares, Sessions and 'Open Files'
  • Run 'procexp.exe' (Process Explorer - SysInternals) on the machine and view the handles of the server service
  • psexec \\%server% net file
  • psloggedon \\server
  • psexec \\%server% -c handle.exe

Querying against one or more computers:

  • for %i in (server1 server2 server3 server4) do wmic /node:"%i" path win32_serverconnection get * /format:csv >> ServerConnections.txt
  • for %i in (server1 server2 server3 server4) do wmic /node:"%i" path win32_serversession get * /format:csv >> ServerSessions.txt
  • for %i in (server1 server2 server3 server4) do cscript //nologo listOpenFiles.vbs %i >> OpenFiles_%dateflat%.txt
  • for %i in (server1 server2 server3 server4) do psexec \\%i net file
    $servers = ("server1", "server2") foreach {. .\EnumOpenFiles.ps1 -s $_} write-host

Closing handles:

  • The compmgmt.msc GUI
  • The .remove method in the VBS below
  • net session \\%client% [/delete]
  • net file %id% [/close]

' VBScript
On Error Resume Next

If wscript.arguments.count = 1 Then
 strserver = wscript.arguments.unnamed(0)
 wscript.echo "Error, no server name provided"
End If

Set objConnection = GetObject("WinNT://" & strServer & "/LanmanServer")
Set colResources = objConnection.Resources

For Each objResource in colResources
    Wscript.Echo objResource.User & "," & objResource.LockCount & "," & objResource.Path & "," & objResource.Name

  ' Remove the session: colResources.Remove(objResource.Name)


# PowerShell
# EnumOpenFiles #
# 28/07/2008, martinwx, Initial version
# Description:
#   Call NetFileEnum() to enumerate open files on a file server
#   the computer that a user is connecting from.
# Assumptions, this script works on the assumption that:
#   The caller has administrator or server operator rights to the specified machines
# Usage
#   Enumerate open files from the specified server:
#   . .\EnumOpenFiles.ps1 -s server
# References

$server = $null

if (($args.count -eq 2) -or ($args.count -eq 4)) {
  for ($i = 0; $i -le $args.count-1; $i+=2) {
    if ($args[$i].ToLower().Contains("-s")) {
      $server = $args[$i+1]
    } elseif ($args[$i].ToLower().Contains("-v")) {
      $verbosePreference = $args[$i+1]

$info = ""
if ($server -eq $null) {
    write-output "No server specified, listing local files"

$provider = new-object Microsoft.VisualBasic.VBCodeProvider
$params = new-object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"

$txtCode = @'
Imports System
Imports System.Runtime.InteropServices
Imports System.Net

Class EnumFiles

Const ERROR_SUCCESS As Long = 0
Private Const MAX_PREFERRED_LENGTH As Long = -1

Private Const PERM_FILE_READ = &h1
Private Const PERM_FILE_WRITE = &h2
Private Const PERM_FILE_CREATE = &h4
Private Const ACCESS_EXEC = &h08  '  Execute Permission (X)
Private Const ACCESS_DELETE = &h10  '  Delete Permission (D)
Private Const ACCESS_ATRIB = &h20  '  Change Attribute Permission (A)
Private Const ACCESS_PERM = &h40  '  Change ACL Permission (P)

Private Structure FILE_INFO_3
    public fi3_id As Integer
    public fi3_permissions As Integer
    public fi3_num_locks As Integer
    public fi3_pathname As String
    public fi3_username As String

    'fi3_id  Specifies a DWORD value that contains the identification number assigned to the resource when it is opened.
    'fi3_permissions Specifies a DWORD value that contains the access permissions associated with the opening application. This member can be one or more of the following values.
    'fi3_num_locks  Specifies a DWORD value that contains the number of file locks on the file, device, or pipe.
    'fi3_pathname  Pointer to a string that specifies the path of the opened resource.
    'fi3_username Pointer to a string that specifies which user (on servers that have user-level security) or which computer (on servers that have share-level security) opened the resource. Note that Windows does not support share-level security.

End Structure

Declare Auto Function NetApiBufferFree Lib "netapi32" (ByVal Buffer As Long) As Long

Declare Function NetFileEnum Lib "netapi32.dll" ( _
    ByVal servername As String, _
    ByVal basepath As String, _
    ByVal username As String, _
    ByVal level As Integer, _
    ByRef bufptr As Integer, _
    ByVal prefmaxlen As Integer, _
    ByRef entriesread As Integer, _
    ByRef totalentries As Integer, _
    ByVal resume_handle As Integer) As Integer

Function Main(Optional ByVal servername As String = Nothing) As String()
   Dim result  As Long
   Dim ptr  As IntPtr
   Dim bufptr  As Long  'out buffer
   Dim i  As Integer
   Dim fi3  As FILE_INFO_3
   Dim finfo  As Object
   Dim dwEntriesread As Long  'out
   Dim dwTotalentries As Long  'out
   Dim dwResumehandle As Long  'out
   Dim iPermissions  As Integer
   Dim sPermissions As String = ""

    If servername = "" Then servername = Nothing

    result = NetFileEnum(servername, _
   Nothing, _
   Nothing, _
   3, _
   bufptr, _
   dwEntriesRead, _
   dwTotalEntries, _

    'Console.WriteLine("Entries: " + dwTotalentries.ToString() + ", " + dwEntriesRead.ToString())

    Dim output(dwEntriesRead-1) As String        ' Re-dim the array for the number of results
    if result = 0 then

        ptr = BufPtr          ' Convert long to pointer
        For i = 0 To dwEntriesread -1
     sPermissions = ""
            ptr = BufPtr          ' Convert long to pointer
            fi3 = CType(Marshal.PtrToStructure(ptr, GetType(FILE_INFO_3)),FILE_INFO_3)   ' Marshal this record of the output buffer to the structure
            BufPtr = BufPtr + Marshal.SizeOf(fi3)       ' Increment for the next record

     iPermissions = fi3.fi3_permissions
     If (iPermissions AND PERM_FILE_READ) Then sPermissions = sPermissions + "+Read"
     If (iPermissions AND PERM_FILE_WRITE) Then sPermissions = sPermissions + "+Write"
     If (iPermissions AND PERM_FILE_CREATE) Then sPermissions = sPermissions + "+Create"
     If (iPermissions AND ACCESS_EXEC) Then sPermissions = sPermissions + "+Execute"
     If (iPermissions AND ACCESS_DELETE) Then sPermissions = sPermissions + "+Delete"
     If (iPermissions AND ACCESS_ATRIB) Then sPermissions = sPermissions + "+Attr"
     If (iPermissions AND ACCESS_PERM) Then sPermissions = sPermissions + "+Security"

     If sPermissions.Length > 1 Then sPermissions = sPermissions.Remove(0,1)

            output(i) = serverName + "," + fi3.fi3_id.ToString() + "," + fi3.fi3_pathname + "," + _
                        fi3.fi3_username + "," + fi3.fi3_num_locks.ToString() + "," + sPermissions
        Output = Nothing
    End If

    Call NetApiBufferFree(ptr)         ' Free the memory

    return output
End Function

end class


$cr = $provider.CompileAssemblyFromSource($params, $txtCode)
if ($cr.Errors.Count) {
    $codeLines = $txtCode.Split("`n");
    foreach ($ce in $cr.Errors)
        write-output -i "Error: $($codeLines[$($ce.Line - 1)])"
        write-output -i $ce
        #$ce write-output
    Throw "INVALID DATA: Errors encountered while compiling code"
$mAssembly = $cr.CompiledAssembly
$instance = $mAssembly.CreateInstance("EnumFiles")

#write-output "Enumerating open files from $server"
$result = $instance.main($server)    # Call the VB.Net entry point
write-output -i $result


IADsResource Property Methods

IADsResource Interface

List Open Sessions and Open Files

Wayne's World of IT (WWoIT)


jv said...

In VB code block. Passed in $server (to servername) fails to pas into NetEnum API call. It only works when servername is set to Nothing. I suspect this is a misdeclaration of the parameters in the API "declare". It shule be a pointer being passed. Can't yet prove this without loading VB6.

Have you tried to fix this yet?

Wayne Martin said...


I haven't had any problems using this when passing in a remote server - which is how I originally used the script.

Please make sure you are using this syntax:
. .\EnumOpenFiles.ps1 -s server

Any compilation errors would show up when trying to run the PowerShell script (you can test this by making an error in the VB.Net code).

I've only tested this with PowerShell v1.0 by the way; it may not work correctly under 2.0?

digital signatures said...

Although it covered most of code that is needed and quite helpful for those who need this solution.Querying information against a single computer is easy but when it comes to multiple then you need to pay attention

All Posts

printQueue AD objects for 2003 ClusterVirtualCenter Physical to VirtualVirtual 2003 MSCS Cluster in ESX VI3
Finding duplicate DNS recordsCommand-line automation – Echo and macrosCommand-line automation – set
Command-line automation - errorlevels and ifCommand-line automation - find and findstrBuilding blocks of command-line automation - FOR
Useful PowerShell command-line operationsMSCS 2003 Cluster Virtual Server ComponentsServer-side process for simple file access
OpsMgr 2007 performance script - VMware datastores...Enumerating URLs in Internet ExplorerNTLM Trusts between 2003 and NT4
2003 Servers with Hibernation enabledReading Shortcuts with PowerShell and VBSModifying DLL Resources
Automatically mapping printersSimple string encryption with PowerShellUseful NTFS and security command-line operations
Useful Windows Printer command-line operationsUseful Windows MSCS Cluster command-line operation...Useful VMware ESX and VC command-line operations
Useful general command-line operationsUseful DNS, DHCP and WINS command-line operationsUseful Active Directory command-line operations
Useful command-linesCreating secedit templates with PowerShellFixing Permissions with NTFS intra-volume moves
Converting filetime with vbs and PowerShellDifference between bat and cmdReplica Domain for Authentication
Troubleshooting Windows PrintingRenaming a user account in ADOpsMgr 2007 Reports - Sorting, Filtering, Charting...
WMIC XSL CSV output formattingEnumerating File Server ResourcesWMIC Custom Alias and Format
AD site discoveryPassing Parameters between OpsMgr and SSRSAnalyzing Windows Kernel Dumps
Process list with command-line argumentsOpsMgr 2007 Customized Reporting - SQL QueriesPreventing accidental NTFS data moves
FSRM and NTFS Quotas in 2003 R2PowerShell Deleting NTFS Alternate Data StreamsNTFS links - reparse, symbolic, hard, junction
IE Warnings when files are executedPowerShell Low-level keyboard hookCross-forest authentication and GP processing
Deleting Invalid SMS 2003 Distribution PointsCross-forest authentication and site synchronizati...Determining AD attribute replication
AD Security vs Distribution GroupsTroubleshooting cross-forest trust secure channels...RIS cross-domain access
Large SMS Web Reports return Error 500Troubleshooting SMS 2003 MP and SLPRemotely determine physical memory
VMware SDK with PowershellSpinning Excel Pie ChartPoke-Info PowerShell script
Reading web content with PowerShellAutomated Cluster File Security and PurgingManaging printers at the command-line
File System Filters and minifiltersOpsMgr 2007 SSRS Reports using SQL 2005 XMLAccess Based Enumeration in 2003 and MSCS
Find VM snapshots in ESX/VCComparing MSCS/VMware/DFS File & PrintModifying Exchange mailbox permissions
Nested 'for /f' catch-allPowerShell FindFirstFileW bypassing MAX_PATHRunning PowerSell Scripts from ASP.Net
Binary <-> Hex String files with PowershellOpsMgr 2007 Current Performance InstancesImpersonating a user without passwords
Running a process in the secure winlogon desktopShadow an XP Terminal Services sessionFind where a user is logged on from
Active Directory _msdcs DNS zonesUnlocking XP/2003 without passwords2003 Cluster-enabled scheduled tasks
Purging aged files from the filesystemFinding customised ADM templates in ADDomain local security groups for cross-forest secu...
Account Management eventlog auditingVMware cluster/Virtual Center StatisticsRunning scheduled tasks as a non-administrator
Audit Windows 2003 print server usageActive Directory DiagnosticsViewing NTFS information with nfi and diskedit
Performance Tuning for 2003 File ServersChecking ESX/VC VMs for snapshotsShowing non-persistent devices in device manager
Implementing an MSCS 2003 server clusterFinding users on a subnetWMI filter for subnet filtered Group Policy
Testing DNS records for scavengingRefreshing Computer Account AD Group MembershipTesting Network Ports from Windows
Using Recovery Console with RISPAE Boot.ini Switch for DEP or 4GB+ memoryUsing 32-bit COM objects on x64 platforms
Active Directory Organizational Unit (OU) DesignTroubleshooting computer accounts in an Active Dir...260+ character MAX_PATH limitations in filenames
Create or modify a security template for NTFS perm...Find where a user is connecting from through WMISDDL syntax in secedit security templates

About Me

I’ve worked in IT for over 13 years, and I know just about enough to realise that I don’t know very much.