From time to time I find myself writing PowerShell scripts for custom workflows: rules, monitors, tasks, etc. Often times the project at hand requires a property bag full of juicy data to be used in the workflow. There are a handful of other blogs that describe what a property bag is but here I’ll show you how to make your property bag experience just a bit easier.
When you want to harvest data with a PowerShell script and then return that data to the workflow (to be used any number of ways ) name value pairs get returned in what is called a property bag. A property bag is simply XML structure that looks like this:
<DataItem type="System.PropertyBagData" time="2018-08-30T20:33:12.2154943-06:00" sourceHealthServiceId="c0c09ff6-3834-fc37-4bb9-1633c62eda56"> <Property Name="Fingers" VariantType="3">10</Property> <Property Name=”Toes” VariantType="3">10</Property> <Property Name="Eyes" VariantType="3">2</Property> </DataItem>
The XML dataitem includes the following information:
- This is a property bag.
- A timestamp indicating when it was submitted to the management server.
- The name/value pairs contained in the property bag.
The VariantType describes the type of the value that is returned. The typical variant types are:
0 = Empty
1 = Null
2 = Short
3 = Integer
4 = Single
5 = Double
6 = Currency
7 = Date
8 = String
9 = Object
10 = Error
11 = Boolean
12 = Variant
13 = DataObject
14 = Decimal
15 = Byte
16 = Char
17 = Long
The property bag is a pretty simple animal but sometimes it can produce unexpected results. When that happens it helps to be able to see what the property bag contains when testing your script. Here’s a sample script which creates a property bag and displays the dataitem to the screen:
#Script: PBTypes.ps1 # Here we create the com object $api = new-object -comObject 'MOM.ScriptAPI' # From the com object we spawn the bag. Now we can stuff things into the bag. $bag = $api.CreatePropertyBag() # Here I've added an assortment of different type things to the bag. # They each have a name and a value. $bag.AddValue('string: My String',[string]"My String" ) $bag.AddValue('decimal: 1234567890',[decimal]123456.5) #ordinary decimal $bag.AddValue('max_decimal1: 12345678901234.2',[decimal]12345678901234.2) #max digits with decimal value $bag.AddValue('max_decimal2: 1234567890123456789.2',[decimal]1234567890123456789.2) #oversided decimal digits get replaced by zeros $bag.AddValue('max_decimal3: 12345678901234567891234567890',[decimal]12345678901234567891234567890) $bag.AddValue('double: 1234567890',[double]1234567890) #max digits without causing error $bag.AddValue('max_double: 123456789012345.5',[double]123456789012345.5) #Rounded up. #max digits without converted to E+ notation $bag.AddValue('oversize_double: 1234567890123456789123456789',[double]1234567890123456789123456789) #gets converted to E+ notation $bag.AddValue('int: 1234',[int]1234 ) #ordinary integer $bag.AddValue('max_int: 1234567890',[int]1234567890) #max digits without causing error $bag.AddValue('float: 12.66',[float]12.12) #ordinary float $bag.AddValue('max_float: 1234567.6',[float]1234567.6) #max digits without converted to E+ notation $bag.AddValue('oversize_float: 12345678901234567890.66',[float]12345678901234567890.66) #gets converted to E+ notation $bag.AddValue('long: 1234567890',[long]1234567890) #ordinary long $bag.AddValue('max_long: 1234567890123456789',[long]1234567890123456789) #max digits without causing error $bag.AddValue('byte: 12',[byte]12) #max digits without causing error $bag.AddValue('datetime: 03/04/2012',[datetime]"03/04/2012" ) $bag.AddValue('null: $null', $null ) # Here is how I would ordinarily return the bag so # that the SCOM workflow can use the contents of the bag. $bag # Here is how I can display the contents of the bag to the screen. This is # useful only when testing the script manually. $api.Return($bag)
Run the script from an ordinary PowerShell console (not ISE):
It’s pretty easy to get the data to display on the screen but it’s a messy blob of confusing text. This example is small. Imagine if you had dozens or hundreds of name/value pairs in your bag. It would be a nightmare to comb through all of it. You could copy/paste the text from the console into a text editor and try to reconstruct all of the broken lines but that’s an awful waste of time.
Solution: The easiest way to analyze a property bag is with the Show-SCOMPropertyBag function in the SCOMHelper PowerShell module. This can be used from within the PowerShell ISE as shown below. You’ll notice not only the PB item name and value, but also the VariantType code and type name.
You might find that for large values the data gets truncated on the screen. Here is how you can access the resulting PowerShell object.
Use the -Format parameter to return a hash object.
$hash = Show-SCOMPropertyBag -FilePath C:\test\PBTypes_LargeValue.ps1 -Format HashTable
Once you have the hash object you can access the keys/values of the hash table.
$hash = Show-SCOMPropertyBag -FilePath C:\test\PBTypes_LargeValue.ps1 -Format HashTable $hash #reveal the hash table $hash[1] #show the keys and values. The contents of Key[1] is an array $hash[1][3] #show the property of the 4th element in the array. The object has a "Name" and "Value" $hash[1][3].Name #show the full value of the "Name" property $hash[1][3].Value #show the full value of the "Value" property
Alternate Solution: Output that data to a text file and format it easily with Notepad++. (NPP can be found easily with a quick search of the innerwebs. Yes, innerwebs.)
Output the property bag to an .xml file. This is easy with the redirection operator:
Open the file with Notepad++. The file is still ugly. Let’s fix that.
Format the data with the XML Tools plugin:
Note: You may have to manually add the “Plugin Manager”. This is pretty easy. It involves extracting a few DLLs into the Notepad++ Plugins directory. Once Plugin Manger is available, you can add tons of plugins with a few clicks, including XML Tools. There’s a blurb about it here.
Easy!
Note: Line 1 is a result of the script statement:
$bag
Lines 2 – 12 are a result of the script statement:
$api.Return($bag)
You’ll also notice that in line 10 the variant type is “20”. It was cast as a “long” which PowerShell equates to “System.Int64″ and I would expect it to end up as VariantType=”17”. I don’t know what type “20” is and I don’t have time to research it. Anyone want to hunt it down? I’m sure it’s in some schema doc somewhere. This is an example of getting something unexpected in the property bag.