Classes, Lists, Getting items, and Updating Items. We’ve covered some decent Service Manager ground in just 3 blog posts. In this post, we’re going to take a very slight detour from pure Service Manager and focus on fundamental PowerShell with an emphasis on SCSMHere we’ll be looking in greater detail at functionsthe pipeline, and loops so let’s get at it. 

Functions 

As you’re reading through this series, you may be noticing a pattern emerging with not just how PowerShell is written but how Service Manager operates behind the scenes. 

  • Always declaring classes to get their objects 
  • Class names look kind of similar 
  • Variable names are short and descriptive of the results we’re working with 
  • Once you’ve written a few lines, you may save it to re-use later in a slightly different scenario 

And the good news is we can do something with those observations. We can make PowerShell functions! With every PowerShell function you create, you generate not just personal time savings but also have less to memorize and keep track of as you move across the automation spectrum of PowerShell with Service Manager. Let me show you what I mean:

function Edit-ServiceIncident ($IncidentNumber, $ResolutionDescription, $Computername)
{
$irClass = Get-SCSMClass -name "System.Workitem.Incident$" -computername $Computername
$incident = Get-SCSMObject -class $irClass -filter "Name -eq '$incidentNumber'" -computername $Computername

Set-SCSMObject -SMObject $incident -PropertyHashtable @{

"ResolvedDate" = (Get-Date).ToUniversalTime();
"Status" = "IncidentStatusEnum.Resolved$";
"ResolutionCategory" = "415f9324-96bd-4d43-8f23-5eb44f045af3";
"ResolutionDescription" = "$ResolutionDescription";

   }
}

Once we’ve built and run the script that contains our function, it’s loaded into memory and exists as long as our PowerShell window remains open. So now that it’s in memory just hanging around we need to call it in order to take advantage of our hard work. Fortunately, that’s as simple as: 

Edit-ServiceIncident -IncidentNumber "IR1234" -ResolutionDescription "The Windows Service wasn't running." -Computername "mgmtserver01" 

If you were wondering what the variables were in parentheses following the function, I hope they’ve revealed their purpose. They are in fact custom parameters for our function as you can see when we call our functionWith our brand new Edit-ServiceIncident command, you can use it as much as you want! Not to mention, you can also share it with your peers and lower their learning curve with appropriately named functions. Write once. Run many. With PowerShell functions we’re able to make our own tools, but more importantly – our own shortcuts to common processes we execute within our respective organizations. 

Looping 

I can’t tell you how many times I’ve used a PowerShell loop in the last week alone. It gives you the ability to write once and run for as many items as you need to process. Speaking of which, let’s talk about the aptly named Foreach loop. 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
$incidents = Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01"

foreach ($incident in $incidents)

{
Write-Output $incident.Title
} 

The first two lines should look rather familiar to you. Declare a Class to work with, get Objects of that Class (in this case any Incident whose Title starts with “Issue with Printer”), and then we loop through them. We loop through each of them. Our foreach loop does exactly what it says! For each item in our collection (or array) of things – write their Title out to the PowerShell command line. Whether we retrieved 3, 7, or 50 Incidents; the foreach loop runs for each item in the array. 

Tip: Whether you’re working with functions, quick one and done scripts, loops, and everything else in PowerShell, another pattern that you may have noticed from an SCSM perspective is the idea of declaring everything we need to work with up front. Think of it like setting up a chess board. We’re getting all our pieces setup and then we make our moves. Just like declaring classes, getting the objects/data you need, and then performing actions against them. 

Lastly, if you’ve never worked with loops before you can easily see where $incidents (plural) came from. It’s a variable that was created before the loop that holds all of our returned objects (Incidents in this case). So where did the $incident (singular) variable come from? In a foreach loop, there is another way you can look at its initial declaration: 

  • Foreach (item in group) 
  • Foreach (employee in department) 
  • Foreach (singular in plural) 

We are wholly inventing the first variable directly with our foreach declaration and the second is the array previously declared. Since we’re inventing it, that means we could call it anything we wanted. Here’s the same exact script, but with the variable name changed. 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
$incidents = Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01"

foreach ($thing in $incidents)

{

Write-Output $thing.Title

}

The point of showing this small difference is to emphasize the readability and attention to variable naming you should take into consideration. $thing is perfectly valid here, but is it the quickest to understand if you were reading the script at 2am? What if the script was a few hundred lines long? Again there isn’t anything wrong with it per se, but it could be more appropriately named. So let’s rename it, get Set-SCSMObject involved in this example, and update several Incidents: 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
$incidents = Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01"

foreach ($incident in $incidents)

{

$newTitle = "Printer: " + $incident.Title
Set-SCSMObject -smobject $incident -property "Title" -value "$newTitle" -computername "mgmtServer01"

}

Pipeline 

If you ever searched around the internet for a PowerShell script that does a particular function. You tend to come across this topic somewhat frequently. But as far as what the pipeline is, how it functions, and how it can be used tends to be assumed with whatever script you’re looking at. Let’s re-write some of the concepts we’ve learned up until this point and throw in some PowerShell pipeline maneuvers. 

Where-Object 

In the following PowerShell, we’re going to get Incidents that start with a Title, and whose Last Modified Date is within the last 3 days: 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01" | Where-Object {$_.LastModified -gt (Get-Date).AddDays(-3)} 

As I’ve shared in previous posts. The pipeline operator in PowerShell lets the output of the command to the left of the pipeline act as the input to the right. In this case, we’re getting all Incidents that start with “Issue with Printer” and then of let’s say the 10 returned, only showing 3 that were modified in the last 3 days. We also make use of an assumed or implied variable. The often seen and seldom explained $_. When it comes to the pipeline, the $_ represents the 1, 5, or 100 objects coming down the pipe.

Tip: It’s best to use Where-Object when you are dealing with low volumes of data coming down the pipe. In short – do not use it as a substitute for the filter parameter! The –filter parameter ensures your initial call to SCSM scopes the data SCSM is going to return back to you. If you moved the “Title -like ‘Issue with Printer*’” into the Where-Object and out of the Get-SCSMObject, you would return ALL of your Incidents and then you’d be performing that qualifier client side on your local workstation. It’s important to recognize the importance of the order of operations here as it is a significant difference in performance! 

Select-Object 

This is a cmdlet seen rather frequently on the pipeline as it’s a way to distill your results down. For example, rather than return every single property an Incident has to the command line. You could just return the Created Date and Title: 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01" | Select-Object CreatedDate, Title 

But when you don’t know what properties are called, it may be easier to just see what a single Incident looks like, view its properties, and then build the command from above. Here we can actually use the –First parameter to declare how many results we want from the pipeline. 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01" | Select-Object * –First 1 

Sort-Object 

The name of this command rather quickly gives away its purpose. Using the optional –descending parameter I can control the sort order for the property I’m choosing to sort against. The best part is that PowerShell will sort on numbers, dates, or alphabetically. It intuitively knows what to do! 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01" | Select-Object CreatedDate, Title | Sort-Object CreatedDate -descending 

Group-Object 

Let’s wrap a few previous examples into this one: 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01"
Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01" | Where-Object {$_.LastModified -gt (Get-Date).AddDays(-3)} | Group-Object Priority | Sort-Object Count -descending 

Here we’re getting all of the Incidents whose Title starts with “Issue with Printer”, that have been modified in the last 3 days, grouped by their Priority, then sorted by their Priority descending. As you can see, we can chain our pipelines together for as long as we need. All without creating a single variable. Instead, we can accomplish a task in a single line! 

Foreach-Object 

Last example before we wrap this post up. We’ll make a single callback to a topic seen in Where-Object which is the $_ (i.e. the implied/assumed variable). Then we’ll re-write the previous foreach loop from above into a pipeline foreach. 

$irClass = Get-SCSMClass –name "System.WorkItem.Incident$" -computername "mgmtServer01”
Get-SCSMObject –class $irClass –filter "Title -like 'Issue with Printer*'" -computername "mgmtServer01" | Foreach-Object {$newTitle = "Printer: " + $_.Title; Set-SCSMObject –smobject $_ –property "Title" -value "$newTitle" -computername "mgmtServer01" } 

Test it Out!

The great thing about the PowerShell pipeline is that it lends itself rather well to frequent iteration. Didn’t get the results you were expecting? You can break it down and run just the first part of the pipeline, then the first + second, then the first + second + third, etc. etc. So you can quickly TEST. TEST. TEST.

And now that we’ve gotten this far, you know what time it is? It’s time for… 

Homework Assignment #3 

  • Build a function for a small process you or your peers routinely perform. Here are some ideas 
    • Resolving Incidents of a particular type 
    • Completing Manual Activities of a particular type
    • Mass shift several Hardware Assets Status to “In Stock” 
  • Change the Scheduled Start or End Date of several Manual Activities 
  • Shape several similar Incidents to begin with the same Title, but followed by their original title 
  • Get Review Activities that are In Progress and older than 10 days 
  • Get Incidents that were Resolved in the Last 4 days 
  • Use a Group-Object to group: 
    • Several Active Directory Computers or Users based on a common property (e.g. AD Site, Department, or Job Title) 
    • Active Incidents by their Classification then sort based the count 

 

Next week we’ll return to our definitive commands and how you can will Incidents, Printers, and other items into existence in just a couple lines. Until then! 


Definitive Service Manager PowerShell Blog Series: Part 1 / Part 2 / Part 3