How to Make SCCM Properly Detect Exit Codes from PowerShell Scripts in Application Deployments


2 views

When deploying applications through SCCM 2012 using PowerShell scripts as installers, administrators frequently encounter a frustrating scenario: while the script executes successfully and installs the target software, SCCM consistently reports a return code of 0 in the AppEnforce.log, regardless of the actual exit status the PowerShell script attempts to communicate.

Common PowerShell output methods like Write-Host, Write-Output, or simply returning a value don't properly communicate with SCCM because:

  • PowerShell's output streams aren't the same as process exit codes
  • SCCM's script interpreter looks specifically at the process termination status
  • The PowerShell host process itself returns 0 unless explicitly terminated

To make SCCM correctly detect your script's status, you need to explicitly set the process exit code. Here's the definitive approach:


# Sample PowerShell installation script with proper exit code handling
try {
    # Your installation logic here
    $installResult = Start-Process -FilePath "setup.exe" -ArgumentList "/silent" -Wait -PassThru
    
    if ($installResult.ExitCode -eq 0) {
        # Success case
        [Environment]::Exit(0)
    }
    elseif ($installResult.ExitCode -eq 3010) {
        # Soft reboot required
        [Environment]::Exit(3010)
    }
    else {
        # Failure case
        Write-Error "Installation failed with code $($installResult.ExitCode)"
        [Environment]::Exit($installResult.ExitCode)
    }
}
catch {
    Write-Error $_.Exception.Message
    [Environment]::Exit(1)
}

Several critical aspects ensure this works with SCCM:

  • Use [Environment]::Exit() instead of return statements
  • Always wrap installation logic in try/catch blocks
  • Preserve the original installer's exit codes when possible
  • Document all expected return codes in your SCCM application

For installations requiring reboots (common exit code 3010), enhance your script with proper detection:


$rebootCodes = @(3010, 1641, 3011)
if ($rebootCodes -contains $installResult.ExitCode) {
    # Set pending file rename operations flag if needed
    if (Test-Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager") {
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name "PendingFileRenameOperations" -Value $null
    }
    [Environment]::Exit(3010)
}

After implementation, check these log locations to verify proper exit code handling:

  • C:\Windows\CCM\Logs\AppEnforce.log - Look for "Installation completed with exit code"
  • C:\Windows\CCM\Logs\execmgr.log - Check "Process completed with exit code" entries

If exit codes still aren't detected:

  • Ensure your deployment type uses "PowerShell" as the script host
  • Verify the account running the script has proper permissions
  • Check for uncaught exceptions in PowerShell transcript logs
  • Test with simple scripts first to isolate the issue

When deploying applications through SCCM 2012 using PowerShell scripts, many administrators encounter a frustrating scenario where SCCM consistently reports exit code 0 (success) regardless of the actual script execution outcome. This occurs because SCCM isn't properly capturing the exit codes PowerShell intends to communicate.

The issue stems from how SCCM interacts with PowerShell's execution host. By default, PowerShell exits with code 0 unless explicitly told otherwise, and SCCM doesn't properly parse Write-Host, Write-Output, or Return statements for deployment status.

Here are three reliable methods to ensure SCCM correctly interprets your PowerShell script's exit status:


# Method 1: Explicit exit code
try {
    # Installation logic
    Start-Process -FilePath "setup.exe" -ArgumentList "/silent" -Wait
    exit 0 # Success
}
catch {
    exit 1 # Generic failure
}

# Method 2: Using $LASTEXITCODE
& "setup.exe" /silent
exit $LASTEXITCODE

# Method 3: Custom error levels
$installResult = & "setup.exe" /silent
if ($installResult -eq 3010) {
    exit 3010 # Reboot required
} else {
    exit $installResult
}

1. Always use explicit exit codes rather than relying on implicit returns
2. Document your exit codes in the script header
3. Test with simple scripts first to validate SCCM interpretation
4. Consider wrapping your installation in a try-catch block

To troubleshoot exit code problems:
- Check SCCM's AppEnforce.log for detailed execution records
- Add verbose logging to your PowerShell script:


Start-Transcript -Path "C:\Logs\Install.log"
# Your installation code here
Stop-Transcript

For applications requiring reboots (exit code 3010), use this pattern:


$exitCode = (Start-Process -FilePath "setup.exe" -ArgumentList "/silent" -Wait -PassThru).ExitCode

if ($exitCode -eq 3010) {
    # Set custom registry value for post-reboot continuation
    New-ItemProperty -Path "HKLM:\SOFTWARE\YourApp" -Name "PendingReboot" -Value 1 -Force
}
exit $exitCode