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 WMI and PowerShell Revisited

Posted on February 4, 2013

computereyeLast week I posted a PowerShell function to find files using WMI. One of the comments I got was about finding files with wildcards. In WMI, we've been able to search via wildcards and the LIKE operator since the days of XP.

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!

In a WMI query we use the % as the wildcard character. Here's an example:


PS C:\scripts> get-wmiobject win32_service -filter "displayname LIKE 'Micro%'" | Select Name,Displayname,State,Startmode

Name Displayname State Startmode
---- ----------- ----- ---------
MSiSCSI Microsoft iSCSI Initi... Stopped Manual
swprv Microsoft Software Sh... Stopped Manual
wlidsvc Microsoft Account Sig... Stopped Manual

So it wasn't especially difficult to revise my original function to accept wildcards as part of the file name. Since we are used to using * as the wildcard character, I assumed it would be used here as well. So all I had to do was replace the * with % and change the operator.


#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"
}
else {
$fileOp="="
}
if ($extension -match "\*") {
Write-Verbose "Wildcard search on extension"
$extension = $extension.Replace("*","%")
$extOp="LIKE"
}
else {
$extOp="="
}
$filter = "Filename $fileOp '$filename' AND extension $extOp '$extension' AND Drive='$drive'"
Write-Verbose $filter

The reason I didn't simply make the expression use LIKE all the time is performance. When you use the LIKE operator, there is a significant performance price to pay. So I only wanted to use LIKE if I really had to.

The other change I made was to accept an alternate credential (using a technique Boe Prox turned me on to).


...
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
...

If you pass a string like mydomain\admin, you'll get prompted for the password. Or you can pass a previously created credential object. Here's the revised code, less the comment based help.


#requires -version 2.0

Function Get-CIMFile {

[cmdletbinding(DefaultParameterSetName="Default")]
Param(
[Parameter(Position=0,Mandatory=$True,HelpMessage="What is the name of the file?")]
[ValidateNotNullorEmpty()]
[alias("file")]
[string]$Name,
[ValidateNotNullorEmpty()]
[string]$Drive="C:",
[ValidateNotNullorEmpty()]
[string[]]$Computername=$env:computername,
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
[Parameter(ParameterSetName="Job")]
[switch]$AsJob,
[Parameter(ParameterSetName="Job")]
[int32]$ThrottleLimit=32
)

<# strip off any trailing characters to drive parameter that might have been passed. #>
If ($Drive.Length -gt 2) {
$Drive=$Drive.Substring(0,2)
}

Write-Verbose "Searching for $Name on Drive $Drive on computer $Computername."

<# 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(".")
#get the first part of the name
$filename=$Name.Substring(0,$index)
#get the last part of the name
$extension=$name.Substring($index+1)

#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"
}
else {
$fileOp="="
}
if ($extension -match "\*") {
Write-Verbose "Wildcard search on extension"
$extension = $extension.Replace("*","%")
$extOp="LIKE"
}
else {
$extOp="="
}
$filter = "Filename $fileOp '$filename' AND extension $extOp '$extension' AND Drive='$drive'"
Write-Verbose $filter

#build the core command
$cmd="Get-WmiObject -Class CIM_Datafile -Filter ""$filter"" -ComputerName $Computername"

if ($credential) {
write-Verbose "Adding credential for $($credential.username)"
$cmd+=" -credential `$credential"

} #if credential

#get all instances of the file and write the WMI object to the pipeline
if ($AsJob) {
Write-Verbose "Running query as a job"
$cmd+=" -Asjob -ThrottleLimit $ThrottleLimit"
}
else {
#record the start time
$start=Get-Date
}

Write-Verbose $cmd
Invoke-Expression -Command $cmd

#display how long this took if not running as a job
if ($start) {
#get the end time and report how long the search took
$end=Get-Date
Write-Verbose "Search completed in $($end-$start)"
}

} #end Get-CIMFile

The last major change is that I construct a Get-WmiObject command string based on the parameter values. I start with a core command.


#build the core command
$cmd="Get-WmiObject -Class CIM_Datafile -Filter ""$filter"" -ComputerName $Computername"

And then add other parameters based on the user's input. I use Invoke-Expression to run the final command.

You can download my revised version of Get-CIMFile

Finally, while I was working on this revision PowerShell madman Boe Prox was working up his own version which has even more bells and whistles. Many of the articles I write here are intended as tutorials and not necessarily production ready tools. Boe's version on the other hand is on PEDs (PowerShell Enhancing Drug). Check it out.


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

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