Nathan Ziehnert

6 minute read

I honestly haven’t played around too much with the scripting features built into ConfigMgr - probably makes me a terrible consultant, but oh well. A fellow ConfigMgr blogger @gwblok however has had the chance to play around with them, and find the limitations inherent to any massively scalable system.

The official response from the ConfigMgr development team makes a lot of sense. When you give someone unlimited resources they will abuse them and it tends to lead to bad things happening.

So, with that said - can we creatively get around it for the time being if you need more than 10? Yeah, you can. With some minor caveats. It all comes down to a beautiful feature in PowerShell called Hashtables. For the most thorough rundown of Hashtables I think I’ve ever seen, look here at Kevin Marquette’s blog. Seriously, if you’ve got the time, read it - it’s great.

 

Hashtables - a Quick Primer

For those of you without enough time to read through the whole blog, here’s a little primer. Hashtables are sort of like an array of variables and their value all defined at one time. You create a hashtable with @{} with the key and then value defined. Multiple key and value pairs can be separated by a new line or by a semicolon.

Separated By Line:

$hashtable = @{
    "Key1" = "Value1"
    "Key2" = 2
}

Separated By Semicolon:

$hashtable = @{"Key1" = "Value1"; "Key2" = 2}

Hashtables can basically store anything in the value that could be stored in a variable. That’s strings, integers, booleans, arrays, and objects.

 

Converting a Hashtable into Multiple Variables

Here’s the rub - ConfigMgr only supports integers and strings as parameters. I’m sure that someday it will support other variable types, but for now that’s what we’re limited to. So we need a method to take a “string” representation of a hashtable and convert it to a hashtable. Then we can convert all the entries in the hashtable to new variables - this part isn’t entirely necessary, but it will make referencing your variables in the hashtable more familiar. The code looks something like this:

Param(
    [string]$variableHashTable=""
)
$cHashtable = Invoke-Expression $variableHashTable
foreach($key in $cHashtable.Keys)
{
    New-Variable -Force -Name $key -Value $cHashTable[$key]
}

So let’s break this down.

  1. We’re adding a string as a parameter to your script. This will represent the Hashtable (since we can only use strings or integers).
  2. We take the string representation of the hashtable and make a hashtable out of it. We use “Invoke-Expression” for this.
  3. Then we take all of the keys from the hashtable and create new variables for each one. We name the variable after the “key” and set the value of the variable to the “value”.

So now you can reference any of the newly created variables as you would in any other script. If you had a hashtable entry with a key of “TestVariable” you would just reference it as $TestVariable. Pretty straightforward, but if you have questions, let me know in the comments and I’ll break it down further.

Now that we have the “base” code put into our script, how do we actually create the darn hashtable string?

 

Creating Your Hashtable String

This is probably the most confusing part and honestly was the hardest part to figure out how to format in a way that the ConfigMgr client wouldn’t choke on the output. Understand this: ConfigMgr passes the parameters of the script to the client using a Base64 encoded string. The ConfigMgr client then takes the name of the locally stored script and the parameters and runs PowerShell thusly:

 "C:\Windows\system32\WindowsPowerShell\v1.0\PowerShell.exe" -NonInteractive -NoProfile -ExecutionPolicy RemoteSigned -Command "& { . 'C:\Windows\CCM\ScriptStore\%scriptname%.ps1 -parameterName '%parameterstring%' | ConvertTo-Json -Compress }"

I apologize to my mobile readers…

Anyways, since the [string] parameter is passed in with single quotes (’ ‘) we can’t have any single quotes in our hashtable. Everything needs to be double quotes.

Additionally here is one caveat - if you store a string as an entry in your Hashtable, you cannot have single quotes in it. Sorry about that, but I’m pretty sure you can get creative with what you’re putting into these variables (or maybe you reserve those strings as one of the other 9 remaining parameters that you can use).

So let’s take an example hashtable and turn it into a properly formatted string:

@{
    TString = "This is a string."
    TInteger = 12
    TObject = (Get-ChildItem C:\Windows\)
    TProperty = (Get-ChildItem C:\Windows\System32).Directory
    TBoolean = $false
    TArray = @(1,2,3,4,5,6)
}

The steps we need to take now are as follows:

  1. Encapsulate the keys in double quotes.
  2. Add escape characters for any string values.
  3. Add semi-colons and bring everything into one line.

The result looks like this:

@{"TString" = \"This is a string.\"; "TInteger" = 12; "TObject" = (Get-ChildItem C:\Windows\); "TProperty" = (Get-ChildItem C:\Windows\System32).Directory; "TBoolean" = $false; "TArray" = @(1,2,3,4,5,6)}

Again - apologies to my mobile readers.

One final caveat. The maximum string length for a parameter in ConfigMgr is 1024 characters, so if you expect to exceed that you may have to create an additional parameter and convert it similarly to how we’re converting it here. Use it, don’t abuse it :)

 

Using the Hashtable String

Now we can get it into our script in ConfigMgr. You will literally put what you’ve generated (no need to surround it with any quotes) into the parameter field like so:

Parameter in ConfigMgr

And then execute your script! Don’t forget to make sure your script has some sort of output back to the console otherwise you’ll get no results back in the console (I may or may not have learned that one the hard way).

 

Closing Thoughts

This process is a bit cumbersome, but for those of you with scripts which use more than 10 parameters, maybe it’s a good bandaid until the limit is increased to something like 25. As with everything in PowerShell and ConfigMgr, you wield a great amount of power with your tools, so use them responsibly and ALWAYS test before going into production.

With that said - I hope you found this helpful, and as always Happy Admining!

comments powered by Disqus