实验结果
我编写了一些PowerShell,这些PowerShell作为检测脚本运行时,会将检测脚本看到的环境变量转储到日志文件中。该脚本位于此答案的结尾。
然后,我通过部署具有不同“安装行为”和“登录要求”参数的部署类型,使该脚本由SCCM客户端运行。结果在下表中:
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
分析
上述结果令人惊讶,因为运行检测脚本的上下文似乎部分取决于将应用程序部署到用户还是系统。我第二次进行测试,这真是令人惊讶。结果是一致的。
我们可以从上表中暂时得出以下假设:
- 将应用程序部署到用户后,该应用程序的PowerShell检测脚本将以该用户身份运行。
- 将应用程序部署到系统并为系统安装部署类型后,该应用程序的PowerShell检测脚本将作为系统运行。
- 将应用程序部署到系统并为用户安装了部署类型后,该应用程序的PowerShell检测脚本将以登录用户身份运行。
测试结果支持以上三个假设。在这些假设不成立的地方,可能还有其他一些未经检验的变量。使用PowerShell检测脚本时,至少它们是一组很好的初始假设。
上下文不匹配(当心!)
Jason Sandys记录了对安装上下文规则的类似测试。 如果仔细阅读该文章,您可能会注意到安装上下文和检测脚本上下文的规则不太相同。以下是违规规则:
当应用程序的安装行为设置为“作为系统安装”时,安装程序将作为系统运行(无论是否部署到用户)。
将应用程序部署到用户时,将以该用户身份运行该应用程序的PowerShell检测脚本[无论是否将安装行为设置为“作为系统安装”]。
这意味着具有安装行为“作为系统安装” 并部署到用户集合的应用程序将使用系统上下文进行安装,而使用用户上下文进行检测。
有人为安装行为为“作为系统安装”的应用程序编写检测脚本时,应小心避免避免依赖环境在系统和用户上下文之间发生变化的任何部分。否则,检测到部署到系统集合的应用程序可能会成功,而检测到部署到用户集合的相同应用程序可能会失败。
脚本
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)
}