Search for files using WMI

Retrieving information about a remote Filesystem is possible in a number of methods, in this article I will focus on accessing a remote Filesystem using the Win32_Directory class in combination with Get-CimInstance. This can be useful in scenarios where you are not permitted by firewall or by other restrictions to use the Get-ChildItem cmdlet.

For instance, if we would like to gather the files stored in the root of the C-drive, this includes the hidden and system files, the following code can be used:

1
Get-CimInstance -Query "ASSOCIATORS OF {Win32_Directory.Name='C:\'} Where ResultClass = CIM_DataFile"

This same command can also be executed using the legacy cmdlet Get-WmiObject, some of the advantages of the Get-CimInstance cmdlet is that it will convert the WMI datetime objects to human readable PowerShell datatime objects. Also Get-CimInstance utilizes PowerShell Remoting which greatly simplifies queries against multiple systems simultaneously. The following code will generate a similar result to the previous code while using Get-WmiObject:

1
Get-WmiObject -Query "ASSOCIATORS OF {Win32_Directory.Name='C:\'} Where ResultClass = CIM_DataFile"

By using the Get-Member cmdlet an overview of all properties of the objects returned by this query can be shown:

1
Get-CimInstance -Query "ASSOCIATORS OF {Win32_Directory.Name='C:\'} Where ResultClass = CIM_DataFile" | Get-Member

To get a better overview the Select-Object object can be used to select some common properties:

1
2
Get-CimInstance -Query "ASSOCIATORS OF {Win32_Directory.Name='C:\'} Where ResultClass = CIM_DataFile" |
Select-Object -Property Name,CreationDate,FileSize,FileType

Win32_Directory-C-Root

It is also possible to get a list of folders contained, in the following example I will filter out only the CIM_Directory class instead of the CIM_DataFile type which results in only the folders related to the C:\Users folders to be displayed. This includes the Root folder C:\. The code is as follows:

1
2
Get-CimInstance -Query "ASSOCIATORS OF {Win32_Directory.Name='C:\Users'} Where ResultClass = CIM_Directory" |
Select-Object Name,LastModified,Path,Caption

Win32_Directory-C-Users

It is also possible to use the CIM_DataFile class directly to search the entire Filesystem for a file or folder matching the query. For example the following Query returns all ost files found on a system:

1
Get-CimInstance -Query "Select * from CIM_DataFile Where Extension = 'ost'"

A more complicated query could be to retrieve all ntuser.dat files on the local C: drive:

1
2
Get-CimInstance -Query "Select * from CIM_DataFile Where ((Drive = 'C:') AND (FileName = 'ntuser') AND (Extension = 'dat'))" |
Select Name

I hope this article was able to highlight some of the capabilities of these WMI classes and the Get-CimInstance cmdlet. I would like to remind you that all the code in this article could also be executed using the Get-WmiObject cmdlet, as the query strings are identical.

Links to the related WMI Classes
Win32_Directory Class
CIM_DataFile Class
CIM_Directory Class
Share

One thought on “Search for files using WMI

  1. Kevin E

    Hi Jaap,

    Thanks for sharing this post. It’s very interesting. Currently I’m working on a script to run through all of our servers to search for files with a given extension. However currently the script is very limited and there are things I would like to change. Currently it takes two weeks for the script to complete so I would like to add the ability to run concurrent threads of the script. That aside I would like to include a list of exclusions, for eg. exclude c:\windows\temp.
    And lastly it would be nice the script could search for all existing drives on a given server.

    — begin script —
    # Import the AD module to the session
    Import-Module ActiveDirectory

    $computers = Get-ADComputer -Filter * -SearchBase “OU=Servers, DC=domain, DC=com” -Properties dNSHostName |Select-Object -ExpandProperty dNSHostName

    $filenames = Get-Content “C:\bin\scripts\filenamelist.txt”

    foreach ($computer in $computers) {

    foreach ($filename in $filenames) {
    Write-host $computer $filename
    Get-ChildItem -Recurse -Force \\$computer\c$, \\$computer\d$, \\$computer\e$, \\$computer\f$, \\$computer\g$, \\$computer\h$ -ErrorAction SilentlyContinue | Where-Object { ($_.PSIsContainer -eq $false) -and ( $_.Name -like “$filename”) } | Select-Object Directory,Name| Export-Csv C:\temp\FilesFound.csv -nti -append
    }
    }

    — end script —
    The script requires a file named filenamelist.txt where it lists all given extensions to search for. One extension per line.

    It would be nice if your script could be merged into mine. Unfortunately I’m not at all a programmer and already spend 2 days on my simple script. It works but it has it flaws..

    Reply

Leave a Reply