Repository navigation
fix(win32): warn about powershell.exe inside the batch file an install command names #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,11 +132,29 @@ function Invoke-IntuneWin32AppTest { | |
| # cmd.exe, as the agent's own 32-bit process does | ||
| function Invoke-ContentCommand { | ||
| param([string]$Phase, [string]$Content, [string]$CommandLine) | ||
| if ($CommandLine -match '(?i)(^|[\s"])powershell(\.exe)?([\s"]|$)') { | ||
| $source = (Resolve-Path -LiteralPath $Content).ProviderPath | ||
| $hostPattern = '(?i)(^|[\s"])powershell(\.exe)?([\s"]|$)' | ||
| if ($CommandLine -match $hostPattern) { | ||
| $warnings.Add("powershell.exe in the $Phase command runs the 32-bit host (the agent is a 32-bit " + | ||
| 'process); HKLM:\SOFTWARE and Program Files are redirected there') | ||
| } | ||
| $source = (Resolve-Path -LiteralPath $Content).ProviderPath | ||
| else { | ||
| # The same host hides inside a batch file the command line names: install.cmd calling | ||
| # powershell.exe runs it 32-bit too, from the agent's 32-bit cmd.exe, without the | ||
| # command line showing it | ||
| $first = if ($CommandLine -match '^\s*"([^"]+)"') { $Matches[1] } | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first token is taken from the command line as the portal would see it: a quoted path ( |
||
| else { ($CommandLine.Trim() -split '\s+', 2)[0] } | ||
| $batch = if ($first -match '(?i)\.(cmd|bat)$') { Join-Path -Path $source -ChildPath $first } | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only .cmd and .bat are scanned, because those are text the harness can read. A setup.exe or a .vbs wrapper that launches powershell.exe is out of reach, and |
||
| else { $null } | ||
| if ($batch -and (Test-Path -LiteralPath $batch -PathType Leaf)) { | ||
| $hit = Select-String -LiteralPath $batch -Pattern $hostPattern | Select-Object -First 1 | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First hit only: one warning per batch file, naming the first line so the reader can find it, rather than one per call. The pattern is the same one applied to the command line, so a |
||
| if ($hit) { | ||
| $warnings.Add("powershell.exe in $first (line $($hit.LineNumber)), which the $Phase " + | ||
| 'command runs through the 32-bit cmd.exe, is the 32-bit host (the agent is a 32-bit ' + | ||
| 'process); HKLM:\SOFTWARE and Program Files are redirected there') | ||
| } | ||
| } | ||
| } | ||
| $runId = [guid]::NewGuid().ToString('N') | ||
| # Another account cannot reach the caller's temp folder; its copy lives under ProgramData | ||
| $cache = if ($Credential) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -217,6 +217,35 @@ Describe 'Invoke-IntuneWin32AppTest' -Tag 'Unit', 'Public' { | |
| $result.Warnings -join ' ' | Should-BeLikeString '*powershell.exe*32-bit host*' | ||
| } | ||
|
|
||
| It 'warns about powershell.exe inside the batch file the install command names' { | ||
| Set-Content -Path (Join-Path $script:Fixture.Content 'install.cmd') -Encoding ascii -Value @( | ||
| '@echo off' | ||
| 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File install.ps1' | ||
| ) | ||
| $intuneWin32AppTestSplat = @{ | ||
| DetectionPath = $script:Fixture.Detection | ||
| ContentPath = $script:Fixture.Content | ||
| InstallCommand = 'install.cmd' | ||
| } | ||
| $result = Invoke-IntuneWin32AppTest @intuneWin32AppTestSplat | ||
| $result.Warnings -join ' ' | | ||
| Should-BeLikeString '*powershell.exe in install.cmd (line 2)*32-bit host*' | ||
| } | ||
|
|
||
| It 'does not warn when the batch file the install command names has no powershell call' { | ||
| Set-Content -Path (Join-Path $script:Fixture.Content 'install.cmd') -Encoding ascii -Value @( | ||
| '@echo off' | ||
| 'setup.exe /S' | ||
| ) | ||
| $intuneWin32AppTestSplat = @{ | ||
| DetectionPath = $script:Fixture.Detection | ||
| ContentPath = $script:Fixture.Content | ||
| InstallCommand = '"install.cmd" /quiet' | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The negative case uses the quoted-with-arguments spelling so it exercises the first-token parsing, not just the absence of a powershell line: the file must be found and scanned, and still produce nothing. |
||
| } | ||
| $result = Invoke-IntuneWin32AppTest @intuneWin32AppTestSplat | ||
| $result.Warnings -join ' ' | Should-NotBeLikeString '*32-bit host*' | ||
| } | ||
|
|
||
| It 'passes -EnforceSignatureCheck to every detection run' { | ||
| $intuneWin32AppTestSplat = @{ | ||
| DetectionPath = $script:Fixture.Detection | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An else rather than a second independent check, so a command line such as
powershell.exe -File install.ps1keeps its one warning and a batch file is only scanned when the command line itself said nothing. Two warnings for the same host would read as two problems.