Being able to read and write Task Sequence variables on the fly is one of the most powerful techniques in the ConfigMgr toolkit — whether you are debugging a failing OSD deployment, dynamically adjusting TS behaviour based on hardware detection, or passing values between custom scripts and built-in steps. This updated guide expands the original single-command approach into a complete practical reference, including the critical x64/x32 COM object caveat that breaks many scripts silently.

Detail
Last UpdatedMarch 2026
Applies ToSCCM/ConfigMgr 2303+, Windows PE, Windows 10/11
COM ObjectMicrosoft.SMS.TSEnvironment
RequiresRunning inside an active Task Sequence
DifficultyIntermediate

How Task Sequence Variables Work

Task Sequence variables are key-value pairs stored in the Task Sequence environment — a runtime memory space managed by the SMS Task Sequence Manager (TSManager.exe). They are accessible to any step running within the task sequence via the Microsoft.SMS.TSEnvironment COM automation object.

Variables come in two types:

  • Built-in variables — prefixed with _SMSTS or OSD, set and read by ConfigMgr itself. Examples: _SMSTSLogPath, OSDComputerName, _SMSTSMachineName
  • Custom variables — created by you in the TS editor or via script. No naming restrictions other than avoiding the reserved _SMSTS prefix. Values persist for the remainder of the running task sequence.

Critical: The x64 PowerShell COM Object Problem

This is the most common reason scripts that access TSEnvironment work in testing but silently fail in production. The Microsoft.SMS.TSEnvironment COM object only works in 32-bit (x86) PowerShell — even on 64-bit systems. If your Run PowerShell Script step is configured to run in 64-bit PowerShell, the COM object will either return empty values or fail to instantiate entirely.

The fix depends on your step configuration:

  • In the Run PowerShell Script step properties, set PowerShell execution policy and ensure Run script in 64 bit PowerShell Host is unchecked — or
  • Call your script explicitly via %SYSTEMROOT%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe in a Run Command Line step — or
  • Pass TS variables as script parameters rather than reading them inside the script via COM (see the parameters approach in the examples below)

Basic Usage — Read, Write, and List Variables

The foundation — instantiate the COM object and use it to read or write any variable:

# Instantiate the TSEnvironment COM object
# Must run inside an active Task Sequence — fails outside of a TS context
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

# Read a built-in variable
$logPath = $TSEnv.Value("_SMSTSLogPath")
Write-Host "TS Log Path: $logPath"

# Read another common built-in variable
$computerName = $TSEnv.Value("OSDComputerName")
Write-Host "OSD Computer Name: $computerName"

# Write / create a custom variable
$TSEnv.Value("MyCustomVariable") = "Hello from PowerShell"

# Read it back to verify
Write-Host "Custom var: $($TSEnv.Value('MyCustomVariable'))"

List all currently loaded variables — useful for debugging:

# List all TS variables currently in the environment
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$TSEnv.GetVariables() | Sort-Object | ForEach-Object {
    Write-Host "$_ = $($TSEnv.Value($_))"
}

Convert all TS variables into native PowerShell variables for easy use within the script:

# Import all TS variables as PowerShell variables
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$TSEnv.GetVariables() | ForEach-Object {
    Set-Variable -Name $_ -Value $TSEnv.Value($_)
}

# Now use them directly — e.g. $OSDComputerName, $_SMSTSLogPath
Write-Host "Computer Name: $OSDComputerName"
Write-Host "Log Path: $_SMSTSLogPath"

Practical Use Case: Set Variable Based on Hardware Detection

A very common pattern — detect hardware properties during the TS and set a variable that subsequent steps use as a condition. For example, detecting chassis type to decide whether to apply a laptop or desktop configuration:

# Detect chassis type and set a TS variable accordingly
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

$chassis = (Get-CimInstance -ClassName Win32_SystemEnclosure).ChassisTypes[0]

# ChassisType values: 8,9,10,11,12,14 = laptop/portable; 3,4,5,6,7,15,16 = desktop
$chassisTypeMap = @{
    3 = "Desktop"; 4 = "Desktop"; 5 = "Desktop"; 6 = "Desktop"
    8 = "Laptop"; 9 = "Laptop"; 10 = "Laptop"; 11 = "Laptop"
    12 = "Laptop"; 14 = "Laptop"; 30 = "Tablet"
}

$formFactor = $chassisTypeMap[[int]$chassis]
if (-not $formFactor) { $formFactor = "Unknown" }

$TSEnv.Value("HWFormFactor") = $formFactor
Write-Host "HWFormFactor set to: $formFactor"

In the TS editor, add a condition to subsequent steps: Task Sequence Variable → HWFormFactor → equals → Laptop. The step only runs on laptops — no separate task sequences needed for different form factors.

Practical Use Case: Set OSDComputerName Dynamically

One of the most common custom TS variable use cases — automatically naming the machine based on serial number, asset tag, or a naming convention without requiring technician input:

# Automatically set OSDComputerName from BIOS serial number
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

$serial = (Get-CimInstance -ClassName Win32_BIOS).SerialNumber.Trim()

# Apply a naming convention — e.g. prefix + first 10 chars of serial
$prefix = "CORP"
$computerName = "$prefix-$($serial.Substring(0, [Math]::Min(10, $serial.Length)))"
$computerName = $computerName.ToUpper() -replace '[^A-Z0-9\-]', ''  # Remove invalid chars

$TSEnv.Value("OSDComputerName") = $computerName
Write-Host "OSDComputerName set to: $computerName"

Practical Use Case: Track Step Outcomes Across the TS

Set a variable after a risky step (e.g. BIOS update or driver injection) to track whether it succeeded. Use the variable as a condition on a subsequent restart step — only restart if the BIOS was actually updated:

# At the end of a BIOS update script — record outcome in a TS variable
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

# One-liner version — useful as an inline command in a Run Command Line step
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command `
    "& {`$ts = New-Object -COMObject Microsoft.SMS.TSEnvironment; `$ts.Value('BIOSUpdated') = 'True'}"

# Then in the TS editor, condition the restart step:
# Task Sequence Variable → BIOSUpdated → equals → True

Passing TS Variables as Script Parameters (x64 Safe)

When the 32-bit COM object limitation is a problem — or when you want a cleaner script architecture — pass TS variables as parameters in the Run PowerShell Script step rather than reading them from inside the script:

In the Run PowerShell Script step, set the Parameters field to:

-ComputerName %OSDComputerName% -LogPath %_SMSTSLogPath% -PackageID %SMSTSPackageID%

In your script, declare matching parameters:

param (
    [string]$ComputerName,
    [string]$LogPath,
    [string]$PackageID
)

# TS variables are now available as standard PS parameters
# No COM object needed — works reliably in both 32 and 64-bit PS
Write-Host "Deploying to: $ComputerName"
Write-Host "Log path: $LogPath"
"$(Get-Date) — Script ran for $ComputerName" | Out-File "$LogPath\custom.log" -Append

Debugging TS Variables Interactively During a Running TS

Sometimes you need to inspect or edit TS variables live — while the TS is paused at a breakpoint or waiting at a prompt. The approach differs depending on whether you are in WinPE or the full OS phase.

In Windows PE

Open a command prompt via the debug step or F8 (if enabled in boot media), then launch PowerShell and access TSEnvironment directly:

# In WinPE command prompt — first enable PowerShell if not already running
X:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

# Then access TSEnvironment
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$TSEnv.GetVariables() | Sort-Object | ForEach-Object { "$_ = $($TSEnv.Value($_))" }

# Edit a variable on the fly
$TSEnv.Value("OSDComputerName") = "TESTMACHINE01"

In Full OS Phase

TSEnvironment is only accessible from the SYSTEM account context in the full OS. Use PsExec from Sysinternals to launch an interactive SYSTEM PowerShell session:

# From an elevated command prompt — launch PowerShell as SYSTEM interactively
# Download PsExec from Sysinternals first
PsExec.exe -i -s PowerShell.exe

# Now in the SYSTEM PowerShell session — access TSEnvironment normally
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$TSEnv.Value("OSDComputerName")

Using the Built-in TS Debugger (ConfigMgr 2002+)

Since ConfigMgr 2002, the Task Sequence Debugger provides a proper GUI debugger — set breakpoints on any step and inspect/edit variables without needing PsExec or debug command lines:

  1. In the ConfigMgr console, right-click the task sequence → Debug
  2. Deploy the TS to a test device in Debug mode
  3. The debugger GUI launches on the device — use Set Variable to edit any variable interactively while the TS is paused

This is the recommended approach for modern ConfigMgr environments — far cleaner than the PsExec workaround.

Commonly Used Built-in Variables Reference

VariableDescriptionRead/Write
_SMSTSLogPathPath where TS log files are writtenRead
_SMSTSMachineNameCurrent machine name during TSRead
_SMSTSPackageNameName of the running TSRead
OSDComputerNameComputer name to apply during deploymentRead/Write
OSDDomainNameDomain to joinRead/Write
SMSTSRebootDelaySeconds before restart (set to 0 for immediate)Read/Write
SMSTSPersistContentKeeps downloaded content in TS cache after completionRead/Write
OSDPreserveDriveLetterWhether to preserve existing drive letter during Apply OSRead/Write
_SMSTSInWinPETrue if TS is running in Windows PERead
_SMSTSCurrentActionNameName of the currently running stepRead

Common Gotchas

  • COM object only works inside a running TS — if you test your script outside of a TS, New-Object -COMObject Microsoft.SMS.TSEnvironment will throw an error. Add a try/catch for testing outside the TS
  • x64 PowerShell returns empty variables — the COM object runs in 32-bit mode. Uncheck “Run in 64-bit PowerShell” in the step, or pass variables as parameters
  • Run as alternate credentials breaks COM access — TSEnvironment is only accessible from the SYSTEM account. If the step is configured to run as a named account, the COM object returns E_ACCESSDENIED (0x80070005)
  • Variable names are case-sensitiveOSDComputerName and osdcomputername are treated as different variables
  • Sensitive variables are masked in smsts.log — variables marked as sensitive in the TS editor do not appear in plain text in the log file, even when read via GetVariables()

Summary

The Microsoft.SMS.TSEnvironment COM object remains the standard mechanism for reading and writing Task Sequence variables from scripts in 2026 — nothing has changed architecturally, but the practical gotchas have become better understood. The x64 PowerShell limitation and the SYSTEM context requirement are the two issues that catch most people. The TS Debugger (available since ConfigMgr 2002) has made interactive debugging significantly cleaner and is worth adopting if you are still using PsExec workarounds.

  • Always instantiate: $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
  • Read: $TSEnv.Value("VariableName") — Write: $TSEnv.Value("VariableName") = "value"
  • List all: $TSEnv.GetVariables() | Sort-Object | ForEach-Object { "$_ = $($TSEnv.Value($_))" }
  • Uncheck “Run in 64-bit PowerShell” or pass variables as parameters to avoid the COM x64 issue
  • Use the built-in TS Debugger for interactive variable inspection — available since ConfigMgr 2002