SCSM PowerShell: Get Work Item Information | Quisitive
SCSM PowerShell: Get Work Item Information
June 22, 2015
Matthew Dowst
Read our blog.

This post is part of a series on Service Manager PowerShell. Be sure to check out the Overview Page for all posts in this series.

If you look at the Service Manager cmdlets, you will notice that there are no cmdlets along the lines of Get-Incident or Get-ServiceRequest. So you may ask yourself, how do I find this information? And the answer is, by using the Get-SCSMClassInstance cmdlet. The Get-SCSMClassInstance cmdlet can be used to return any work item or configuration using either the item’s ID or Class. The ID parameter is not referring the ID you see in the console, like SR1234 or IR429. It is referring to the internal GUID of the item. Since I don’t commonly make a habit of memorizing 128-bit integers, I tend to find the Class parameter much easier to use. You can use the Class parameter to query against all items in a specific class. Then you can use filters to get the items you want. In our examples here we will mainly be using the Class parameter.

Before diving into the Get-SCSMClassInstance cmdlet I want to give a quick recap on how Service Manager classifies things. All work items and configuration items inside of Service Manager are members of a class. Incident is a class, Service Request is a class, Computers is a class, and on. Also, many classes inherit from parent classes. For example, Incident and Service Request are sub-classes under the Work Items class. Configuration items work the same way, but we will cover those in a later section.

Finding the Class

In order to return a class instance, you must first take a step back and find what class you want. When dealing with Work Items this is usually pretty easy to do. They will typically fall into one of the major ITIL roles; Incident, Service Request, Change Request, Problem, Release Records, and Activities. To get the class we’ll use the Get-SCSMClass cmdlet. For example to get the Incident class we use the command.

Get-SCSMClass -Name System.WorkItem.Incident

So how did I know to use the name “System.WorkItem.Incident”? To tell you the truth, I’ve been working with these enough, that I have it memorized. However, there are hundreds of different classes, and I admit I don’t have all of them committed to memory. To find the class you want, you could enter Get-SCSMClass, without any parameters, and dig through all of the results until you find the one you want. Another option is, since you must likely know the name of the class you want, you can use the DisplayName parameter with wildcards. This will greatly reduce the number of results. For example to find the Incident class I used the command:

Get-SCSMClass -DisplayName *incident* | FT DisplayName, Name

This returned a short list of all classes with the word “incident” in the display name. From here I can easily find the incident work item class’s name and use that in my command. You may have noticed that I used the Name parameter with System.WorkItem.Incident instead of the DisplayName parameter with just Incident. This is because the display name is not a unique field. You can have two classes with the same display name. For this reason, always use the Name parameter in your final scripts.

Querying Work Items

Now that you have your class you can use the Get-SCSMClassInstance cmdlet. When using the Class parameter you cannot just enter the class name. You must use the class object returned from the Get-SCSMClass cmdlet. You can either do this directly in the command line by using parenthesis, or by saving the class to a variable. I suggest the latter when you will be using the same class multiple times in a script.

Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) 

$class = Get-SCSMClass -Name System.WorkItem.Incident 
Get-SCSMClassInstance -Class $class

When you run this command it will return every incident in your Service Manager environment. You can narrow down your results by using filters. There are two ways that you can filter the results. You can use the Filter parameter, or you can use the where-object cmdlet. Which one you choose is really up to your preference and the requirements of your script. There are a few things to consider when choosing between Filter and Where-Object. When you use the Filter parameter it will only return results that make the filter. When using the Where-Object all objects are returned, but those matching the where-object are displayed. The filter parameter will typically run quicker and use less memory, but it is very finicky. It requires very specific formatting and is case sensitive with the properties. The where-clause is much more powerful than the filter. With the where-clause you can string together multiple criteria much easier, and work with sub properties and arrays. As I stated previously it is up to you which you choose to use. My personal preference is to use the where-object, unless I’m returning so many objects the filter causes a significant performance improvement. Below are examples using both methods to return incident ID IR3570.

Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | Where-Object {$_.ID -eq "IR3570"} 

Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) -Filter "Id -eq IR3570"

*PowerShell Tip

You can use a simple question mark “?” in place of the Where-Object command. Be aware if you see a ? in future examples it is the same as typing Where-Object. This is known as an alias. When PowerShell was first created, they included aliases for well know commands. For example if you type “dir” into a PowerShell window, it will actually run the “Get-ChildItem” cmdlet. Over the years this has been expanded upon, and you can even create your own if you like.

Formatting Your Output

PowerShell allows you to control the output to the screen in multiple ways. The two we will work with here are Format-List and Format-Table, or FL and FT respectively. Format-List displays all results in a list form, with each property displayed on a separate line. Format-Table displays the properties across the top and the values below. Each of these can be run with or without the names of the properties you want to display.

Format-List

Format-Table

To find a list of all properties a cmdlet will return, you can use the Get-Member cmdlet. By adding a pipe and Get-Member to the end of a command, it will display all of the properties and methods associated with that command, but not their actual value.

When you run the command you’ll notice multiple member types. I will not go into detail here on what all the different member types are, but there are a few I would like to cover. You see there are multiple different type of properties (NoteProperty, Property, ScriptProperty). For now all you need to know is these properties are used to return values. For example, ID is a ScriptProperty and it returns the actual ID of the item. The other type we will be working with later on are the Methods. Methods allow you to examine, compare, and format many properties of a PowerShell object. We will cover methods more in later sections. For more information in the different MemberTypes refer to MSDN.

Saving Your Results

Often when you are using PowerShell you want to perform multiple things with the items you returned. To do this you can save your output into a variable. In the example below, I am writing the results to the variable $IR. Now, anytime I want to reference these results I just need to enter $IR.

$IR = Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | ?{$_.ID -eq "IR3570"}

Once you have your results loaded into the variable you can work with individual properties by using the variable name dot the property name.

$IR = Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | ?{$_.ID -eq "IR3570"} 
Write-Host "ID: " $IR.ID 
Write-Host "Title: " $IR.Title

Filtering Your Results

As you saw in the examples above I filtered the results on the ID of the Incident, using the logic ID –eq “IR3570”. So what if I want to return all incidents with a status of Active? I could try Status –eq “Active”. However, if I ran that I would receive zero results. This is because Active is a display name, and not the internal property name. A good rule of thumb to help you remember this is, if it is a list item (e.g. a dropdown on the form in console), then it will have an internal name and a display name. This is similar to what was covered earlier with classes. So in order to return Active incidents, you need to query off of the sub properties. Examples of these are shown below.

Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | ?{$_.Status.Name -eq "IncidentStatusEnum.Active"} | FT ID, Status 

Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | ?{$_.Status.DisplayName -eq "Active"} | FT ID, Status

The same logic here applies to all list items like category, urgency, impact, etc. We will cover ways to determine the name values of list items in a later post, but a quick way to find the internal name is to run the command against an item you know has the property set, and find the internal name in the output.

Working with Results

One of the best things you can learn to work with in PowerShell is the Foreach-Object cmdlet. It allows you to step through, and perform actions on each item individually. It can be run straight from the command line using a pipe or on its own. For simplicity we will be running it as a stand alone in the examples below.

Let’s go back to returning all Active incidents. I’m going to save the results to the variable $IR and I want to output the ID, Status, and Classification Category for each of these. If I simply did a FT and listed the properties out, it would return them, but it would return the internal names of the status and classification categories. To get the display name property we need to specify the sub property of display name. This can be done with the $IR.Status.DisplayName.

$IR = Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | ?{$_.Status.Name -eq "IncidentStatusEnum.Active"} 
Foreach($item in $IR) 
{
     Write-Host $item.ID "`t" $item.Classification.DisplayName "`t" $item.Status.DisplayName 
}

*PowerShell Tip

PowerShell ISE has a horrible habit of crashing the first time you try to enter information inside of the foreach brackets. It appears to be an issue with the auto-complete feature. To prevent this I always create the foreach with nothing inside the brackets, then execute the script. After doing this the auto-complete works, and ISE does not crash.

In this post you have seen how to determine the class of a work item and use that to return information about specific work items. The next few sections are going to cover creating and updating work items, and working with relationships. And also be sure to check the Overview Post for more content in this series.