Correctly Filtering with SCSM, PowerShell and SMLets

There are many examples out there on the internet for PowerShell scripts using the SMLets commandlets for Service Manager which require you to filter results. For example, you may want a script that will automatically close your resolved incidents after 5 days or to list change requests that have been created within the last 24 hours. Often you will find that these scripts use the |Where {$_.Status -eq ‘Resolved’} for example:

$Date = (get-date).adddays(-5)
$Class = Get-SCSMClass -Name “System.WorkItem.Incident$”
$Closed = Get-SCSMEnumeration IncidentStatusEnum.Closed$
$Resolved = Get-SCSMEnumeration IncidentStatusEnum.Resolved$

Get-SCSMObject -Class | Where-Object{$_.Status -ne $Closed -and $_.Status -ne $Resolved -and $_.ResolvedDate -lt $Date}

This is a very inefficient method of returning SCSM objects based on criteria and should not be used. The reason for this is that it will filter the objects client side so for example if you have 1000 incidents in your service manager environment PowerShell would have to fetch all 1000 incidents before completing the filter.

A far better method is to use the ‘-filter’ switch as this will filter server side allowing PowerShell to only return the results that are relevant – this will offer a far more efficient result. This too however does have its drawbacks. It’s not possible to use a -AND or -OR statement which means we would not be able to achieve the above example as we are wanting to get incidents that are ‘Resolved’ but also specify they should have been resolved for more than 5 days.

There is a third option however, which again will use server side filtering but also allow for specifying multiple criteria. The only drawback of this method it that it’s a little more completed to implement with a few additional lines of code but it’s more than worth the effort for an efficient Service Manager environment.

Firstly we will create a variable for the class of object we are wanting to filter on. In this example we want to filter incidents:

$Class = Get-SCSMClass -Name “System.WorkItem.Incident$”

Next we need to crate a type of object criteria:

$Type = “Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria”

Next we specify the criteria we are wanting to filter on – again we can specify multiple pieces of criteria here incvlding using AND & OR.

$Criteria = “Status != ‘$Resolved’ and Status !=’$Closed’ and ScheduledEndDate < ‘$Date'”

Finally we put this together into a new PowerShell object:

$Filter = New-Object -Type $cType $cString,$Class

We can now use the usual Get-SCSMObject to get the results we need using the -Criteria switch instead of the -Filter Switch:

$Incident = Get-SCSMObject -Criteria $Filter

 

Putting this all together in an example to return all incidents that have been resolved within the last 5 days:

Import-Module SMLets

$Class = Get-SCSMClass -Name “System.WorkItem.Incident$”
$Resolved = (Get-SCSMEnumeration -Name “IncidentStatusEnum.Resolved”).ID
$Closed = (Get-SCSMEnumeration -Name “IncidentStatusEnum.Closed”).ID

$Date = (Get-Date).AddDays(-1)

$Type = “Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria”
$Criteria = “Status = ‘$Resolved’ and ResolvedDate < ‘$Date'”
$Filter = New-Object -Type $Type $Criteria,$Class
$incident = Get-SCSMObject -Criteria $Crit

If ($incident -ne $Null){
Foreach ($x in $incident){
Set-SCSMObject -SMObject $x -Property Status -Value $Closed
}
}

Happy filtering 🙂

About the author