When we work with getting data out of SCOM via PowerShell, or building automations, something that can really help speed things up are Hashtables.
I was recently working with a customer to build a discovery for a new class, and get properties from other existing classes. I had to build an array of these class objects (Windows Computers) and loop through them each time I wanted to use one. As I found out – this became VERY time consuming.
In this case, I was doing something basic like this:
$WCarr = Get-SCOMClass -Name “Microsoft.Windows.Computer” | Get-SCOMClassInstance
That creates an array ($WCarr) and fills it with all the Windows Computer objects in the management group.
The customer has about 10,000 Windows Computers in this SCOM Management group, so this operation takes about 85 seconds to complete. Not a big deal for my script.
However, in a subsequent part of the script, I needed to loop through about 600 objects, and on each one I needed to get properties from the Windows Computer object. Here is an example:
FOREACH ($WC in $WCarr)
{
IF ($NameImLookingFor -eq $WC.DisplayName)
{
$MatchingComputerObject = $WC
}
}
A cleaner way to write this same thing would be:
$MatchingComputerObject = $WCarr | where {$_.DisplayName -eq $NameImLookingFor}
I am basically just going through all 10,000 records in memory, until I find the one I am looking for. At the customer, this process takes about 25 seconds.
25 seconds isn’t a big deal, right?
However, remember, I am doing this same thing 600 times! Because I need to find the matching object FOR EACH of my 600 objects that I am adding discovery data for.
(600 * 25 seconds) = 15,000 seconds. 15000 seconds / 3600 seconds = 4.17 HOURS!!!! This is no bueno! I need to run this on a regular basis, and I cannot have it hammering my management servers like this.
So I take a different approach – what if I just go back to the SDK, and look up the Windows Computer object each time?
$MatchingComputerObject = Get-SCOMClass -Name “Microsoft.Windows.Computer” | Get-SCOMClassInstance | Where-Object -Property DisplayName -eq $NameImLookingFor
That takes 70 seconds and hits the SDK service and the SQL database every time. Much worse! Now my script will take 12 hours and hammer the SDK while it is running. Ugh.
Enter in, the Hash Table
A Hash Table is defined as an associative array, with a compact data structure that stores key/value pairs. Here is a simple example:
Create a new empty hashtable:
$HashTable = @{}
Add stuff to it:
$HashTable.Add(‘Kevin’,’Rocks’)
Kevin is the “Key” in the Hashtable. Rocks is the value. In this case it is a simple string, but it could also be an object, which is powerful!
If I want to retrieve the Value for the Key “Kevin” I would:
$HashTable.’Kevin’
Which returns the value, “Rocks”.
Similarly – we can input an object:
$HashTable.Add(‘DC1.opsmgr.net’,(Get-SCOMClass -Name “Microsoft.Windows.Computer” | Get-SCOMClassInstance | Where-Object -Property DisplayName -eq “DC1.opsmgr.net”))
In the above example, I am using the string FQDN as the Key, and inputting the Windows Computer object as the Value for the hashtable.
Now I can quickly retrieve the object without needing to go to the SDK, or loop through an array to find that object.
Here is a real world example:
# Get all the Windows Computers into my Array $WCarr = Get-SCOMClass -Name "Microsoft.Windows.Computer" | Get-SCOMClassInstance # Create an empty Hashtable $HashTable = @{} # Fill the hashtable from the array using the unique FQDN as the Key FOREACH($WC in $WCarr) { $HashTable.Add("$($WC.DisplayName)",$WC) } # Loop through each instance of my custom array and get properties from the Windows Computer as needed FOREACH ($MyObject in $MyObjects) { # Retrieve the individual matching object from the Hashtable $WC = $HashTable.($MyObject.DisplayName) # Get some property from the Windows Computer Object $IPAddress = $WC.'[Microsoft.Windows.Computer].IPAddress'.Value }
Now – when I need to retrieve a matching object – I don’t need to parse through all 10,000 objects each time, I simply request the specific object by the indexed Key from the hashtable.
How long does this take?
Well I am glad you asked!
The following line from above:
$WC = $HashTable.($MyObject.DisplayName)
takes exactly 0.4 MILLISECONDS.
That’s right. Milliseconds.
What took 21 SECONDS before, now takes four tenths of a millisecond.
The script section, which took 4.17 HOURS before, now completes in 0.24 SECONDS.
Script time matters. Make sure yours aren’t running any longer than they have to.
I really do recommend placing a start time and end time, and total runtime in all your SCOM scripts – to help you monitor these kinds of things closely:
https://kevinholman.com/2017/09/10/demo-scom-script-template/