In what context do SCCM Powershell detection scripts run in?

34

Empirical Results

I wrote some PowerShell that, when run as a detection script, dumps the environment variables that the detection script sees to a log file. That script is at the end of this answer.

I then cause this script to be run by the SCCM client by deploying a Deployment Type with different "Installation Behavior" and "Logon requirement" parameters. The results are in the table below:

Test InstallationBehavior LogonRequirement                   DeployedTo LoggedOnUser ScriptRunAs
---- -------------------- ----------------                   ---------- ------------ -----------     
1.1a Install for user     Only when a user is logged on      un2        un2          un2        
1.1b Install for user     Only when a user is logged on      cn1        un2          un2        
1.1c Install for user     Only when a user is logged on      cn1        un1          un1        
1.2a Install for system   Only when a user is logged on      un2        un2          un2        
1.2b Install for system   Only when a user is logged on      cn1        un2          cn1        
1.2c Install for system   Only when a user is logged on      cn1        un1          cn1        
1.3a Install for system   Whether or not a user is logged on un2        un2          un2        
1.3b Install for system   Whether or not a user is logged on cn1        un2          cn1        
1.3c Install for system   Whether or not a user is logged on cn1        un1          cn1        

   
  • unX are usernames
  • cnX are computer names

Analysis

The above results are surprising because the context that a detection script runs in seems to depend in part upon whether the Application was deployed to a user or a system. This was enough of a surprise that I ran the tests a second time. The results were consistent.

We can tentatively draw the following hypotheses from the table above:

  1. When an Application is deployed to a user, a PowerShell detection script for that Application is run as that user.
  2. When an Application is deployed to a system and the Deployment Type is installed for the system, a PowerShell detection script for that Application is run as the system.
  3. When an Application is deployed to a system and the Deployment Type is installed for the user, a PowerShell detection script for that Application is run as the logged-in user.

The above three hypotheses are supported by the test results. There may well be some other variables that weren't tested where these hypotheses do not hold. They are, at least, a good set of initial assumptions when using PowerShell detection scripts.

Mismatched Contexts (Beware!)

Jason Sandys documented a similar test of the rules for installation context. If you read that post carefully, you might notice that the rules for installation context and detection script context are not quite the same. Here are the offending rules:

When an Application's installation behavior is set to "Install as System" the installer is run as system [regardless of deployment to user].

When an Application is deployed to a user, a PowerShell detection script for that Application is run as that user [regardless of whether installation behavior is set to "Install as System"].

This means that an Application that has installation behavior “Install as system” and is deployed to a user collection will use the system context for installation, but the user context for detection.

Someone writing detection scripts for Applications where installation behavior is "Install as System" should be careful to avoid relying on any part of the environment that changes between the system and user contexts. Otherwise, detection of an Application deployed to a system collection may succeed while detection of the exact same Application deployed to a user collection fails.

Script

function Write-EnvToLog
{
    $appName = 'script-detect-test'

    $logFolderPath = "c:\$appName-$([System.Environment]::UserName)"

    if ( -not (Test-Path $logFolderPath -PathType Container) )
    {
        New-Item -Path $logFolderPath -ItemType Directory | Out-Null
    }

    if ( -not (Test-Path $logFolderPath -PathType Container ) )
    {
        return
    }

    $logFileName = "$appName`__$((Get-Date).ToString("yyyy-MM-dd__HH-mm-ss")).txt"

    $fp = "$logFolderPath\$logFileName"

    Get-ChildItem Env: | Out-File $fp | Out-Null

    return $true
}

try
{
    if ( Write-EnvToLog ) { "Detected!" }
    [System.Environment]::Exit(0)
}
catch
{
    [System.Environment]::Exit(0)
}
Share:
34

Related videos on Youtube

BumberAZ
Author by

BumberAZ

Updated on September 18, 2022

Comments

  • BumberAZ
    BumberAZ over 1 year

    This is the situation, I will write the example code:

    user = 'Boby'
    a = ['hana', 'dul', 'se']
    b = method.prepareSentence(a, user)
    
    first_sentence = method.prepareSpeech('short_speech', user, b)
    second_sentence = method.prepareDebates('quick_debates', user, b) 
    

    but here I want a to have one more element in the list, so

    a = ['hana', 'dul', 'se', 'sou']
    

    Is it possible to do this without duplicating variables and making two versions of a?

    I found this solution but this is very primitive and will make the script bigger and I want to make changes to many other similar scripts:

    a1 = ['hana', 'dul', 'se']
    b1 = method.prepareSentence(a, user)
    a2 = ['hana', 'dul', 'se', 'sou']
    b2 = method.prepareSentence(a, user)
    

    first_sentence = method.prepareSpeech('short_speech', user, b1) second_sentence = method.prepareDebates('quick_debates', user, b2)

    • Selcuk
      Selcuk over 2 years
      That's not a dictionary; it's a set. You can do a2 = a1 | {"sou"} with sets.
    • BumberAZ
      BumberAZ over 2 years
      You are right @Selcuk I am still mixing up the terms, I am a beginner. What you suggest is of course better and shorter way but, doesn't it still mean that I have to use two different variables?
    • Blckknght
      Blckknght over 2 years
      Are you looking for a.append('sou')? Lists (which you're using now) also support the + operator, if you want to create a new list with the extra element (a + ['sou']).
    • Selcuk
      Selcuk over 2 years
      This sounds like an XY problem. Maybe you should first explain why you think you need to do this in the first place. Are there too many variables that need to be created? If yes, it smells bad design.
  • MDMoore313
    MDMoore313 almost 9 years
    +1 for a solid SCCM question and answer. I do hope the SCCM community here grows as it's really the only thing I keep a look out for (email subscription for the tags.) Here, have some extra rep as a motivation to keep 'em comin.
  • alx9r
    alx9r almost 9 years
    Thanks @BigHomie. I'm filtering for SCCM too...but I miss a bunch because there's no practical way to get that filtered stream on mobile.
  • Admin
    Admin almost 9 years
    Excellent SCCM question! Come join @BigHomie and I - custodians of the [sccm] tag. There are literally a couple of us.
  • MDMoore313
    MDMoore313 almost 9 years
    Darn Skippy, @kce has the best questions this side of the Windows tag too.
  • BumberAZ
    BumberAZ over 2 years
    I am embarrassed for calling it a dictionary instead of a set. That operator is very helpful but I was thinking if there is another way to do it without creating new variables, but I guess that's impossible
  • Matiiss
    Matiiss over 2 years
    @BumberAZ you can use a list or an actual dictionary and add the new values there, that way you can access them by their keys or indexes and it wouldn't take up the namespace