Running PowerShell scripts as part of a task sequence

Both MDT 2010 Lite Touch and ConfigMgr 2007 run the same task sequencer.  This task sequencer can run any command that you want, just specify the command line to use.  That’s the simple part – the harder part is figuring out what this command line should do.  Often the command, a VBScript or PowerShell script, needs to get information from the task sequence itself, accessing variables in the task sequence environment.  Remember, these task sequence variables aren’t environment variables – they are distinctly separate, so you can’t use the PowerShell “Env:” drive.

If you are using MDT, building a VBScript that includes the ZTIUtility.vbs script makes accessing task sequence variables pretty simple, as you can then reference something like this in your script:

sValue = oEnvironment.Item("MYVAR")

But PowerShell is now the rage – what if you wanted to do the same thing using PowerShell?  Fortunately that’s not too difficult either.  Here’s a simple example that gets the value of a particular variable:

$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
Write-Host $tsenv.Value("_SMSTSLogPath")

You would then need to set up a task sequence step that ran that PowerShell script.  In the Lite Touch case, I would suggest saving the file in the “Scripts” directory on the deployment share, for example as “Test.ps1”.  You could then create a “Run command line” step in the task sequence that executes this command:

PowerShell.exe -File "%SCRIPTROOT%\Test.ps1"

If you were using MDT 2010 integrated with ConfigMgr, the same thing would work, but you would need to add the file to the “Scripts” directory of the MDT toolkit package.  Alternatively, you could create a new software distribution package containing the PowerShell script, specify to use that package on the “Run command line” step of the ConfigMgr task sequence, and then specify a command line that assumes the script is in the working directory:

PowerShell.exe -File "%SCRIPTROOT%\Test.ps1"

If you want to change a task sequence variable (or set a new one), you use the same “Value” method:

$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$tsenv.Value("MyVar") = "My Value"

Maybe you want to do something a little more involved, like create an transcript (log) of the execution of your script.  You can use the _SMSTSLogPath variable to determine where to place the file:

# Determine where to do the logging
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$logPath = $tsenv.Value("_SMSTSLogPath")
$logFile = "$logPath\$($myInvocation.MyCommand).log"

# Start the logging
Start-Transcript $logFile

# Insert your real logic here
Write-Host "We are logging to $logFile"

# Stop logging

Another useful example is a script that logs the values of all task sequence variables:

# Determine where to do the logging
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$logPath = $tsenv.Value("_SMSTSLogPath")
$logFile = "$logPath\$($myInvocation.MyCommand).log"

# Start the logging
Start-Transcript $logFile

# Write all the variables and their values
$tsenv.GetVariables() | % { Write-Host "$_ = $($tsenv.Value($_))" }

# Stop logging

Or you could use the same technique to turn all the task sequence variables into PowerShell variables:

# Determine where to do the logging
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$logPath = $tsenv.Value("_SMSTSLogPath")
$logFile = "$logPath\$($myInvocation.MyCommand).log"

# Start the logging
Start-Transcript $logFile

# Convert the task sequence variables into PowerShell variables
$tsenv.GetVariables() | % { Set-Variable -Name "$_" -Value "$($tsenv.Value($_))" }

# Write out a specific variable value
Write-Host $_SMSTSMDataPath

# Get all the variables
Dir Variable:

# Stop logging

(Take out all the extra stuff and this could be reduced to two lines, the one that creates the COM object and the one that calls GetVariables.)

A few other notes worth mentioning:

  • You need to make sure scripts are enabled before trying to run these via a task sequence.  In the case of MDT Lite Touch, the scripts will typically be run from a network UNC path.  For ConfigMgr, a local path (for download-on-demand or download-and-execute) or a network path (for “run from DP”) will be used.  You can include a step in the task sequence to set the needed execution policy, e.g. “powershell.exe -Command { Set-ExecutionPolicy Unrestricted }”, or configure the same via Group Policy.
  • You may want to add the “-noprofile” parameter to the PowerShell.exe command line as the profile commands may cause issues with your script.
  • The Microsoft.SMS.TSEnvironment COM object is only available while the task sequence is running, so you need to test your script inside of a task sequence.  (This can be a case where the “convert task sequence environment to PowerShell variables could come in handy: do you testing with hard-coded variables, remove the values before deploying the script.)
  • The task sequencer only registers the matching platform of Microsoft.SMS.TSEnvironment.  For example, when the x86 task sequencer is running the x86 Microsoft.SMS.TSEnvironment will be available but the x64 version will not.  For an x64 task sequence, only the x64 Microsoft.SMS.TSEnvironment will be available.
  • ConfigMgr will run the x86 version of the task sequencer even on x64 operating systems, so the x86 version of PowerShell will normally be run in this case.  (For MDT Lite Touch, the x86 version of the task sequencer is used on x86 OSes and the x64 version is used on x64 OSes.)  Make sure you are aware of which platform is running, as that might affect your PowerShell script execution.  (Note that x64 processes run via a ConfigMgr task sequence, done by disabling file system redirection for the task sequence step or by specifying “sysnative” in the path, won’t be able to create the Microsoft.SMS.TSEnvironment object because of the previous note.)
  • If you want to return an error, you should insert an “exit” statement in your PowerShell script, e.g. “exit 1234”.  This will cause PowerShell.exe to return that return code to the task sequencer.

Comments (9)
  1. MDT runs all commands elevated, so you don't need to explicitly elevate any single command.

    You do need to be careful though that the command you specify is an executable.  In your case "copy" is not, so you need to prefix the command with "cmd.exe /c", e.g. "cmd.exe /c copy …".

  2. Eric says:

    Is there any difference between running this in Windows 7 and running this in Windows XP? We have completed our Windows 7 task sequence and successfully utilized a PowerShell script to rename the machine based on location. However, when I run the exact same steps in our XP task sequence, I get an error indicating the file is not a recognized cmdlet, function, operable program or script file. I don't know enough about this stuff to make an educated guess as to how to begin remediating.

  3. shawn says:

    execution policy set to 'unrestricted'

    run PS script from %SCRIPTROOT%Folderscript.ps1

    Script hangs

    check from local with the task sequence still active/hung

    get-executionpolicy reports unrestricted

    run script from %SCRIPTROOT%folderscript.pst

    script prompts for approval (which is why it hung in the task sequence I expect)

    moved script to %SYSTEMROOT%Folderscript.ps1 in the deployment

    everything runs successfully

    Question is… why?

    Obviously I'm not understanding something about what 'unrestricted' means when executing ps1 scripts from the deployment share.

  4. Theron says:

    Shawn, try setting it to -bypass vs -unrestricted and give it a shot.


  5. Tim Knapp says:

    PowerShell – SCCM 2007 R3 – PowerShell in OSD, running in OS.

    PowerShell script can't load COMObject "Microsoft.SMS.TSEnvironment"

    Any thoughts would be great.

  6. Paul Ireland says:

    I'd like to run a powershell script as an application in MDT 2012, and in the script, I'd like to elevate permissions and copy a file from one location into another that requires elevated permissions.

    I've tried using a batch file with the following command, but it's failing:

    copy WinZip.wzmul C:ProgramDataWinZip /q

    Any help you could offer would be appreciated greatly.

  7. LvilleSystemsJockey says:

    I knew this was doable and just needed syntax. This was perfect. Saving for reference.

  8. showbox says:

    Thanks for the great info. I really loved this. I would like to apprentice at the same time as you amend your web site, how could i subscribe for a blog site?
    For more info on showbox please refer below sites:
    Latest version of Showbox App download for all android smart phones and tablets. – It’s just 2 MB file you can easily get it on your android device without much trouble. Showbox app was well designed application for android to watch movies and TV shows, Cartoons and many more such things on your smartphone.
    For showbox on iOS (iPhone/iPad), please read below articles:
    Showbox for PC articles:
    There are countless for PC clients as it is essentially easy to understand, simple to introduce, gives continuous administration, effectively reasonable. it is accessible at completely free of expense i.e., there will be no establishment charges and after establishment
    it doesn’t charge cash for watching films and recordings. Not simply watching, it likewise offers alternative to download recordings and motion pictures. The accompanying are the strides that are to be taken after to introduce Showbox application on Android.
    The above all else thing to be done is, go to the Security Settings on your Android telephone, Scroll down and tap on ‘Obscure sources’.

  9. aw says:

    hai, I just want to tell you that I am just very new to blogs and seriously loved this website. More than likely I’m planning to bookmark your blog post .
    You amazingly come with really good posts. Thanks a lot for sharing your blog Microsoft.

Comments are closed.