Using SCCM Task Sequence Variables as Scripts

The more I dig in to SCCM/ConfigMgr, the more cool things I find. Every time I read a new post blog about things people have done with their Task Sequences, I get inspired to try more things. One of those things is setting Task Sequence variable values from the output of a script. At this point, I’m sure we’ve all read and re-read Gary Blok’s Waas posts and picked up a few tricks, I know I have. Last week on Twitter,  I asked about dynamically setting variables to script output and Gary reminded me that he had several examples of this in his Waas posts using PowerShell to create a new TSEnvironment object, which I use in most of my scripts as well. While this approach works fine, I was actually looking for a shorter alternative, but it made me wonder if it would be possible to store your scripts as Task Sequence Variables then reference them in Run Command Line steps. The answer is “YES!”. Some of you may have already known this or tried it or have determined that this is a silly idea, but for me, I’m relatively new to some of what SCCM has to offer, so I’m excited about it!

The Theory

My theory was that the Task Sequence would expand any text inside a Task Sequence variable and string it all together and run it as a command just like if you had type the full command line into the text box. This would allow you to maintain a “Variable-Based Script Repository”. I find that I always have to copy an existing script/command step or go look it up to be sure I’ve got it right – why memorize if you know where to look it up when you need it? So things like the powershell.exe command line with the correct parameters or the ServiceUI command line for debug prompts or user prompts could be stored into variables for use later in Run Command Line steps. While you could save entire command blocks into the variables, you could store single PowerShell cmdlets then string them together at runtime.

The Setup

For these examples, I’m going to use Get-CimClass Win32_OperatingSystem to return Operating System version information.  Note: If I was doing this in production, I would use more shorthand code, but I want it to easy to understand the examples, so they are less than optimal, but hopefully easier to follow. Also note, I’m much more comfortable in PowerShell. If you want to see examples of doing similar things with generating batch files on the fly, check out Gary’s SetupComplete post.

To get started, run this in PowerShell ISE.

Your output should be something like this:

If we add the TSEnvironment object to the script, we get this:

If we launch a Task Sequence and add a Debug command line (See below for steps to add Debug to as Task Sequence), we can run this manually and get this:

Amazing right? It’s almost as if this worked!!

At this point, you would normally save this to a script then use the Run PowerShell Script step in the Task Sequence to launch it. But that would require you to maintain a script in a file and replicating content each time you needed to change the script (debugging or future updates). Keep reading for some cool alternatives.

Option 1 – Run Command Line

Your first option for running in-line code would be to simply take a working script block, then remove all line breaks and replace them with semicolons. Then make sure you don’t have any double quotes in the script. Then add it to a Run Command Line step and run it. Using the script above, your command line would look like this:

Option 2 – Output to Script

NOTE: The code below doesn’t work (other code I tested with did work) as written when run from a TS, but just fine in a cmd prompt. I don’t feel like working it out since this is just sample code anyway. The concept/technique still stands, just not this particular code. Sorry.

If you wanted to export a block of code into a local file then call it using a Run Powershell Script, you could use the ECHO function in the Command Prompt.

You could use ECHO and >> but if your script has any special characters like > or | you will need to escape the characters with ^ or you can use | Set /p=”” to add quoted text like this:

So your completed code would look like this and would output a file called GetOSInfo.ps1 that can now be run inside your Task Sequence or be left on the computer for later use.

Type: Run Command Line
Name: Export Script
Command Line:

Type: Run Command Line
Name: Launch Local Script
Command Line:

Option 3 – Storing scripts in Task Sequence Variables

Here’s the approach that I was hoping would work when I began down this road. I have tested several different ways and was surprised that they each worked pretty well. I’m honestly not sure to what extent you’d even use this, but I think it’s cool and at least worth experimenting with. I plan to use it so I can re-use the same embedded script, without having to update content AND so that I can change a value 1 time in a Task Sequence and know that all references to it were changed.

Type: Set Task Sequence Variable
Name: Set Variable – PowerShellCommandOpen
Task Sequence Variable: PowerShellCommandOpen

Type: Set Task Sequence Variable
Name: Set Variable – PowerShellCommandClose
Task Sequence Variable: PowerShellCommandClose

Not a typo. Just use }” This is the closing tag for the PowerShell script block.

Type: Set Task Sequence Variable
Name: Set Variable – GetOSInfo
Task Sequence Variable: GetOSInfo

Paste in the whole script. No need to remove line breaks or ; but DO remove ” or the script will break.

Type: Run Command Line
Name: Get OS Info
Command Line:

Consecutive % must include an extra % around the variable in the middle

When you launch the TS, you can check the logs and see that the script ran and see the results.


This information has been posted many times. If you want to write scripts that depend on information from your Task Sequence, you should build a Task Sequence that has a Debug step in it. The Debug step simply opens a command prompt in the user’s context then allows you to launch anything as Local System. I generally launch PowerShell_ISE.exe to open PowerShell. From there, you can interact with the Task Sequence. You also need to include ServiceUI.exe in your Task Sequence as a reference to make this work. Using Option 3, here’s how I added a Debug step to my Task Sequence.

Type: Set Task Sequence Variable
Name: Set Variable – TSDebug
Task Sequence Variable: GetOSInfo

Type: Run Command Line
Name: Debug
Command Line:


After going down this path, I feel like I know more about what we can do with ConfigMgr Task Sequence Variables and scripts. I really wanted Option 3 to be far superior to the alternatives. If you have a script that you use all the time, this could make it easier to update it and use it on the fly without updating content. I think it just depends on your use case. If you want to easily edit long scripts in the Task Sequence, you can use variables to break it into pieces them string them all back together when you want to run them. Or you can take the values of existing variable and embed them into your script variables and have an even more dynamic experience. I’d love to know what you thought. Send me a tweet or post a comment here and let me know how you would use this, or if it’s just a dumb idea.

No Comments


This site uses Akismet to reduce spam. Learn how your comment data is processed.


Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST` resulted in a `400 Invalid instrumentation key` response: {"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Invalid instrumentation key"}]} in /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113 Stack trace: #0 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/promises/src/Promise.php(156): Guzzle in /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113