Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Find Files with PowerShell 3.0

Posted on February 7, 2013February 21, 2014

My last few articles have looked at using WMI and CIM_DATAFILE class to find files, primarily using Get-WmiObject in PowerShell. But now that we have PowerShell 3.0 at our disposal, we can use the new CIM cmdlets. So I took my most recent version of Get-CIMFile and revised it specifically to use Get-CimInstance. I also took the liberty of adding a few more refinements, some of which you could integrate into previous versions. Here's the new v3 function.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!
#Requires -version 3.0

Function Get-CIMFile {
<#
.Synopsis
Get a file object using CIM.
.Description
This command uses the Get-CIMInstance and the CIM_DataFile class to find a 
file or files on a computer. The command by default searches drive C: on the 
local computer for the specified file. The wildcard character (*) is permitted 
anywhere in the filename. 

You can search one or more remote computers by computername or CIM sessions.

.Parameter Name
The name of the file to find. Wildcards (*) in the name are permitted but they
will make the search run a little longer.
.Parameter Drive
The name of the drive to search. The default is C:. You do not need to include
the trailing \.
.Parameter Computername
The name of the computer to search. The default is the local computer. 
.Parameter CimSession
Connect to remote computers via a Cimsession object.
.Example
PS C:\> Get-Cimfile hidden.txt
.Example
PS C:\> Get-Cimfile myapp.dll -comp $computers 
.Example
PS C:\> $sess = New-CimSession $computers
PS C:\> Get-Cimfile myapp.dll -cimsession $sess | Select PSComputername,Name,Filesize
.Notes
Version     : 3.0
Last Updated: 02/06/2013
Author      : Jeffery Hicks (@JeffHicks)

Read PowerShell:
Learn Windows PowerShell 3 in a Month of Lunches
Learn PowerShell Toolmaking in a Month of Lunches
PowerShell in Depth: An Administrator's Guide

  ****************************************************************
  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *
  * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
  * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *
  ****************************************************************
.Link
https://jdhitsolutions.com/blog/2013/02/find-files-with-powershell-3-0/
.Link
Get-CIMInstance
New-CimSession
.Inputs
String
.Outputs
Microsoft.Management.Infrastructure.CimInstance#root\cimv2\CIM_DataFile
#>

[cmdletbinding(DefaultParameterSetName="Computername")]

Param(
[Parameter(Position=0,Mandatory=$True,HelpMessage="What is the name of the file?")]
[ValidateNotNullorEmpty()]
[alias("file")]
[string]$Name,
[ValidatePattern("^[a-zA-Z]:$")]
[string]$Drive="C:",
[Parameter(ParameterSetName="Computername")]
[ValidateNotNullorEmpty()]
[string[]]$Computername=$env:computername,
[Parameter(ParameterSetName="CIMSession")]
[ValidateNotNullorEmpty()]
[Microsoft.Management.Infrastructure.CimSession[]]$CimSession
)

Write-Verbose "Starting $($MyInvocation.MyCommand)"
Write-Verbose "Parameter set = $($PSCmdlet.ParameterSetName)"

#create a hashtable of parameter values that can be splatted to Get-CimInstance
$paramHash=@{Classname="CIM_DATAFILE"}

Write-Verbose "Searching for $filename on drive $drive"
if ($pscmdlet.ParameterSetName -eq "Computername") {
    Write-Verbose "...on $computername"
    $paramHash.Add("Computername",$computername)
}
elseif ($pscmdlet.ParameterSetName -eq "CimSession")  {
    Write-Verbose "...on $Cimsession"
    $paramHash.Add("CimSession",$cimSession)
}
else {
    #this should never happen
    Write-Verbose "No computername or cimsession specified. Defaulting to local host"
    #bail out of the function
    Return
}

#define default operators
$fileOp="="
$extOp="="

<#
Normally you might think to simply split the name on the . character. But
you might have a filename like myfile.v2.dll so that won't work. In a case 
like this the extension would be everything after the last . and the filename
everything before.

So instead I'll use the substring method to "split" the filename string.
#>

#get the index of the last .
$index = $name.LastIndexOf(".")

#it is possible the filename doesn't have an extension
if ($index -gt 0) {
    #get the first part of the name
    $filename=$Name.Substring(0,$index)
    #get the last part of the name
    $extension=$name.Substring($index+1)
}
else {
    $filename=$Name
    #will need to use wildcard search for filename when extension is empty
    $fileop="LIKE"
    $extension=$null
}
#if there is * in the filename or extension, replace it with %
#and change the comparison operator for the WMI query
if ($filename -match "\*" ) { 
    Write-Verbose "Wildcard search on filename"
    $filename = $filename.Replace("*","%")
    $fileOp="LIKE"
}

if ($extension -match "\*") {
    Write-Verbose "Wildcard search on extension"
    $extension = $extension.Replace("*","%")
    $extOp="LIKE"
}

$filter = "Filename $fileOp '$filename' AND extension $extOp '$extension' AND Drive='$drive'"
Write-Verbose $filter

#add the filter to the hashtable
$paramHash.Add("Filter",$filter)

#invoke the command
Write-Verbose "Parameter Hash $($paramHash| out-String)"

#let's time how long it took
$start=Get-Date  

Get-CimInstance @paramhash

$end=Get-Date
Write-Verbose "Search completed in $($end-$start)"
Write-Verbose "Ending $($MyInvocation.MyCommand)"

} #end Get-CIMFile

This version let's you search remote computers by name or CIM session. Because they are mutually exclusive options, this function uses parameter sets, defaulting to using a computername. I also added a validation check on the drive name using regular expressions. The function will fail if the value is not a letter followed by a colon.

Another major change was modifying code to search for filenames without an extension. What if you are looking for a file like README? The WQL query turned out to be more complicated than I imagined. It would be easier if the extension property was NULL, but it isn't. It is a 0 length string. I found that in order to make this work, I needed to create a query like this:

SELECT * FROM CIM_DATAFILE WHERE Filename LIKE 'readme' AND extension = '' AND Drive='d:'

So I modified my code to adjust operators and variables that I use to build the filter string.

#get the index of the last .
$index = $name.LastIndexOf(".")

#it is possible the filename doesn't have an extension
if ($index -gt 0) {
    #get the first part of the name
    $filename=$Name.Substring(0,$index)
    #get the last part of the name
    $extension=$name.Substring($index+1)
}
else {
    $filename=$Name
    #will need to use wildcard search for filename when extension is empty
    $fileop="LIKE"
    $extension=$null
}
...
$filter = "Filename $fileOp '$filename' AND extension $extOp '$extension' AND Drive='$drive'"

Now I can find files without an extension, or with.

PS C:\>  get-cimfile readme -drive d:

Compressed     : False
Encrypted      : False
Size           : 
Hidden         : False
Name           : d:\readme
Readable       : True
System         : False
Version        : 
Writeable      : True
PSComputerName : SERENITY

PS C:\>  get-cimfile readme.txt -drive d:


Compressed     : False
Encrypted      : False
Size           : 
Hidden         : False
Name           : d:\readme.txt
Readable       : True
System         : False
Version        : 
Writeable      : True
PSComputerName : SERENITY

The last major change you'll notice is that I build a hash table of parameter values and then splat it.

$paramHash=@{Classname="CIM_DATAFILE"}

Write-Verbose "Searching for $filename on drive $drive"
if ($pscmdlet.ParameterSetName -eq "Computername") {
    Write-Verbose "...on $computername"
    $paramHash.Add("Computername",$computername)
}
elseif ($pscmdlet.ParameterSetName -eq "CimSession")  {
    Write-Verbose "...on $Cimsession"
    $paramHash.Add("CimSession",$cimSession)
}
...
#add the filter to the hashtable
$paramHash.Add("Filter",$filter)
...
Get-CimInstance @paramhash

This is a terrific technique when you are dynamically generating parameters.

Get-CimInstance can be used to query remote computers, assuming they are also running PowerShell 3.0. However, you can also use CIM Sessions which allow you to establish a connection to an older system using the DCOM protocol.

$sess = New-CimSession jdhit-dc01 -SessionOption (New-CimSessionOption -Protocol Dcom)

The end result is that I can still use my PowerShell 3.0 function to query a PowerShell 2.0 machine as long as I have a pre-created session.

get-cimfile3

Now I have a very powerful tool that can search just about any computer in my domain.

Oh, one more thing I realized in working on this. Initially I was only paying attention to the file name and version. Then I noticed that the Size property in the default output was always empty. That struck me as odd and not very useful. So I looked at the actual object with Get-Member and it turns out there is a FileSize property which is populated. It looks like the default property set for CIM_DATAFILE uses the Size property, when it should really be FileSize. So keep that in mind as you are working with the results.

Download Get-CIMFile3 and try it out for yourself.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

2 thoughts on “Find Files with PowerShell 3.0”

  1. Pingback: Microsoft Most Valuable Professional (MVP) – Best Posts of the Week around Windows Server, Exchange, SystemCenter and more – #15 - TechCenter - Blog - TechCenter – Dell Community
  2. Pingback: Dell Community

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d