Understanding SCCM PowerShell Detection Script Execution Context: System vs User Mode Analysis


4 views

When working with PowerShell detection scripts in System Center Configuration Manager (SCCM), the execution context depends primarily on the deployment type configuration. Here's the technical breakdown:

  • System Context: Runs under NT AUTHORITY\SYSTEM when deployment type is set to "Install for system" or "Install for system if resource is device; otherwise install for user"
  • User Context: Runs under the logged-on user's identity when deployment type is set to "Install for user"

The execution context affects several key aspects of your detection scripts:

# Example of context-aware detection script
$context = "System"
if ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name -ne "NT AUTHORITY\SYSTEM") {
    $context = "User"
}

# Registry access example
if ($context -eq "System") {
    $regPath = "HKLM:\Software\MyApp"
} else {
    $regPath = "HKCU:\Software\MyApp"
}

# Output compliance status
if (Test-Path $regPath) {
    Write-Output "Installed"
} else {
    Write-Output "Not installed"
}

As mentioned in the original post, getting PowerShell scripts to work with AllSigned execution policy requires specific handling:

  1. Ensure you're running SCCM 2012 R2 SP1 or later
  2. Implement proper script signing procedures
  3. Consider the bypass mechanism documented by Adam Meltzer

Common problems and solutions:

Issue Solution
Access denied errors Verify the execution context matches your resource access requirements
Missing user-specific data Use Get-WmiObject -Class Win32_Process -Filter "Name = 'explorer.exe'" | ForEach-Object { $_.GetOwner().User } to identify logged-on users
Registry redirection Account for WoW64 redirection in 32-bit processes

For complex scenarios requiring both system and user context checks:

# Detect installation status across all user profiles
function Test-AllUserInstallations {
    $systemInstall = Test-Path "HKLM:\Software\MyApp"
    $userInstall = $false
    
    # Check all user hives
    Get-ChildItem "HKU:\" | Where-Object { $_.Name -match 'S-1-5-21-[0-9]+-[0-9]+-[0-9]+-[0-9]+$' } | ForEach-Object {
        if (Test-Path "$($_.PSPath)\Software\MyApp") {
            $userInstall = $true
        }
    }
    
    return ($systemInstall -or $userInstall)
}

After extensive testing with Configuration Manager 2012 R2 SP1 and later versions, I've confirmed that PowerShell detection scripts behave differently based on execution context. Here's what every admin needs to know:

The SCCM client runs PowerShell detection scripts in the following contexts:

# Example detection script showing context awareness
$context = if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) {
    "SYSTEM"
} else {
    "USER ($env:USERNAME)"
}

Write-Output "Running as: $context"

The execution context depends directly on the deployment type configuration:

  • Install for System: Scripts execute under NT AUTHORITY\SYSTEM context
  • Install for User: Scripts execute under the logged-in user's context (with potential permissions issues)

Consider this registry detection example where context matters:

# Detects Office 365 installation - requires SYSTEM context for machine-wide registry
$path = "HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration"
if (Test-Path $path) {
    $version = Get-ItemProperty $path | Select-Object -ExpandProperty VersionToReport
    if ($version -match "16\.0") {
        Write-Output "Installed"
        exit 0
    }
}
exit 1

Through real-world testing, I've documented these critical behaviors:

Scenario Execution Policy Signing Requirement Typical Use Case
System Context AllSigned Mandatory Machine-wide installations
User Context RemoteSigned Recommended User-specific applications

When scripts fail, use this diagnostic approach:

# Enhanced diagnostic script for SCCM detection
$logPath = "$env:TEMP\SCCM_Detection_Debug.log"
Start-Transcript -Path $logPath

try {
    # Your detection logic here
    $result = Test-Path "C:\Program Files\App\app.exe"
    $result | Out-File $logPath -Append
    
    # Context verification
    [PSCustomObject]@{
        UserContext = $env:USERNAME
        SystemContext = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem
        ExecutionPolicy = Get-ExecutionPolicy
    } | Out-File $logPath -Append
    
    exit [int](-not $result)
}
catch {
    $_ | Out-File $logPath -Append
    exit 1
}
finally {
    Stop-Transcript
}

Remember that SCCM caches script results for 1 hour by default. Use the Application Evaluation Cycle to force immediate re-evaluation when testing.