Michael Niehaus' Windows and Office deployment ramblings
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:
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 Stop-Transcript
# 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 Stop-Transcript
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 Stop-Transcript
# Write all the variables and their values $tsenv.GetVariables() | % { Write-Host "$_ = $($tsenv.Value($_))" }
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 Stop-Transcript
# 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:
(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:
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.
execution policy set to 'unrestricted'
run PS script from %SCRIPTROOT%\Folder\script.ps1
Script hangs
check from local with the task sequence still active/hung
get-executionpolicy reports unrestricted
run script from %SCRIPTROOT%\folder\script.pst
script prompts for approval (which is why it hung in the task sequence I expect)
moved script to %SYSTEMROOT%\Folder\script.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.
Shawn, try setting it to -bypass vs -unrestricted and give it a shot.
T-
PowerShell - SCCM 2007 R3 - PowerShell in OSD, running in OS.
PowerShell script can't load COMObject "Microsoft.SMS.TSEnvironment"
Any thoughts would be great.