Select Page

If you are new to PowerShell and have searched through the “google-verse” you’ll likely find millions of examples with most if not all filtering the results via “WHERE” cmdlet. One thing I noticed today while conducting research on Get-WmiObject vs Get-Service was a serious performance difference. I wanted to understand the reason why Get-Service was lighting fast in contrast to Get-WmiObject. I mean literally 10 to 1 in regards to performance (measured in seconds in my particular case).

After reviewing a few sites and articles and growing increasingly impatient I found no resource that would answer my question. So instead of continuing the search I turned to tinkering and I tell you I am glad I did. The best 10 mins that would completely change my life!

I was able to tune my process and speed up performance by 62%. From the previous 2 mins down to 46 seconds. Here’s what I did. Below is merely an example for illustration purposes.

Get-Service (fast)

function GetServices ($server) {
    $StartDate = (Get-Date)
    $services = @(Get-Service -ComputerName $server | Where-Object {$_.name -like '*sql*' -or $_.name -like '*MsDTS*' -or $_.name -like '*ReportServer*'} | Select-Object MachineName, Status, Name, DisplayName | Sort-Object Status -Descending)
    $services | ft -AutoSize
    # DISPLAY DURATION    
    $EndDate = (Get-Date)
    $r = New-TimeSpan -Start $StartDate -End $EndDate | select Seconds, Minutes, Hours
    Write-Output ''
    Write-Output "Elapsed Time: $($r.Hours) Hrs $($r.Minutes) Mins $($r.Seconds) Secs"
}

Get-WmiObject using the WHERE cmdlet (slow)

function GetServicesWMI ($server) {
    $StartDate = (Get-Date)   
    $services = @(Get-WmiObject -computername $server -Class win32_service | Where-Object {$_.name -like '*sql*' -or $_.name -like '*MsDTS*' -or $_.name -like '*ReportServer*'} | SELECT-Object SystemName, state, name, startmode, startname | Sort-Object state)
    $services | ft -AutoSize
    # DISPLAY DURATION    
    $EndDate = (Get-Date)
    $r = New-TimeSpan -Start $StartDate -End $EndDate | select Seconds, Minutes, Hours
    Write-Output ''
    Write-Output "Elapsed Time: $($r.Hours) Hrs $($r.Minutes) Mins $($r.Seconds) Secs"
}   

Get-WmiObject using the switch -Filter (fast)

function GetServicesWMI2 ($server) {
    $StartDate = (Get-Date)
    $services = @(Get-WmiObject -computername $server -Class win32_service -filter "(name like '%sql%' or name like '%MsDts%' or name like '%ReportServer%')" | SELECT-Object SystemName, state, name, startmode, startname | Sort-Object state)
    $services | ft -AutoSize
    # DISPLAY DURATION    
    $EndDate = (Get-Date)
    $r = New-TimeSpan -Start $StartDate -End $EndDate | select Seconds, Minutes, Hours
    Write-Output ''
    Write-Output "Elapsed Time: $($r.Hours) Hrs $($r.Minutes) Mins $($r.Seconds) Secs"
}  
Clear-Host    
GetServices Server01 
GetServicesWMI Server01 
GetServicesWMI2 Server01 

Results: Get-Services (fast)

Get-ServiceResults

Results: Get-WmiObject using WHERE cmdlet (slow)

Get-WmiObjectWhereResults

Results: Get-WmiObject using -Filter (fast)

Get-WmiObject-FilterResults

As you can see by the results above I was able to achieve the same performance as Get-Service simply by switching the filtering from using WHERE to -Filter with a little WQL syntax.

Share This