From 3e6bc934f307ca38d7e18c76e5232c2504be36f2 Mon Sep 17 00:00:00 2001 From: fadwen <110697945+fadwen@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:18:15 -0700 Subject: [PATCH] fix(repair): Repair-IntuneScript takes -Context, -Architecture and -EnforceSignatureCheck Repair-IntuneScript ran its analysis with Test-IntuneScript's defaults for the context, the architecture and the signature check, because it had no parameter to pass on for any of them. A script deployed to the 64-bit host in system context was repaired as the inferred 32-bit user-or-system script, so its findings, its fixes and the Remaining count could disagree with Test-IntuneScript run for the deployment. The command takes the three parameters now, with the same values and defaults as Test-IntuneScript, and hands them to both analyses: the one that finds the fixes and the one that counts what is left after the write. Help and README updated; MAML rebuilt. --- CHANGELOG.md | 4 + Public/Repair-IntuneScript.ps1 | 16 +++- README.md | 3 +- .../Unit/Public/Repair-IntuneScript.Tests.ps1 | 31 +++++++ docs/IntuneScriptLab/Repair-IntuneScript.md | 88 ++++++++++++++++++- en-US/IntuneScriptLab-Help.xml | 72 +++++++++++++++ 6 files changed, 208 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c39608..e409aca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ release notes. ### Fixed +- **`Repair-IntuneScript` analyzed every script under the inferred context and architecture**, whatever the + caller deployed to, because it had no `-Context`, `-Architecture` or `-EnforceSignatureCheck` to pass on. + It takes the three now and hands them to both analyses, so its findings, fixes and `Remaining` count are + the ones `Test-IntuneScript` gives for the same options. - **`-Credential` found no session on Windows Home editions, and matched by name.** The session list came from parsing `query user`, which Home editions do not ship (every run there fell back to the stored-password task) and which prints localized text. Sessions now come from the owners diff --git a/Public/Repair-IntuneScript.ps1 b/Public/Repair-IntuneScript.ps1 index c3a789a..d199cc9 100644 --- a/Public/Repair-IntuneScript.ps1 +++ b/Public/Repair-IntuneScript.ps1 @@ -15,10 +15,18 @@ function Repair-IntuneScript { [ValidateSet('Auto', 'Detection', 'Remediation', 'PlatformScript', 'Win32Detection', 'Win32Requirement')] [string]$ScriptType = 'Auto', + [ValidateSet('Auto', 'System', 'User')] + [string]$Context = 'Auto', + + [ValidateSet('Auto', 'x86', 'x64', 'arm64')] + [string]$Architecture = 'Auto', + [string[]]$IncludeRule, [string[]]$ExcludeRule, + [switch]$EnforceSignatureCheck, + $Settings ) @@ -34,7 +42,13 @@ function Repair-IntuneScript { } foreach ($file in $files) { - $testSplat = @{ Path = $file; ScriptType = $ScriptType } + # The analysis sees the script the way the caller deploys it, so the findings, their + # fixes and the Remaining count are the ones Test-IntuneScript would give for the same + # options + $testSplat = @{ + Path = $file; ScriptType = $ScriptType; Context = $Context; Architecture = $Architecture + } + if ($EnforceSignatureCheck) { $testSplat.EnforceSignatureCheck = $true } if ($IncludeRule) { $testSplat.IncludeRule = $IncludeRule } if ($ExcludeRule) { $testSplat.ExcludeRule = $ExcludeRule } if ($PSBoundParameters.ContainsKey('Settings')) { $testSplat.Settings = $Settings } diff --git a/README.md b/README.md index ebf792f..c3bdf6a 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,8 @@ Three findings come with an edit the tool can make for you, each behaviour-prese script-scope `return` becomes the `exit 0` it already produced, with any returned value written first (`return 'ok'` to `'ok'; exit 0`); a UTF-16 or BOM-less non-ASCII file is rewritten as UTF-8 with a BOM; a padded requirement value (`' ok '`) is trimmed. `Repair-IntuneScript` applies them -per script, reports what it changed and how many findings remain, and previews with `-WhatIf`. +per script, reports what it changed and how many findings remain, previews with `-WhatIf`, and +takes `-ScriptType`, `-Context`, `-Architecture` and `-EnforceSignatureCheck` the way `Test-IntuneScript` does. Whether that `exit 0` should have been an `exit 1` is still the author's call, which is why the finding stays an error until the intent is made explicit. Where the script already says which exit was meant, a `return` with an exit other than 0 after it in the same block (`return 1; exit 1`), diff --git a/Tests/Unit/Public/Repair-IntuneScript.Tests.ps1 b/Tests/Unit/Public/Repair-IntuneScript.Tests.ps1 index a7cd066..6329953 100644 --- a/Tests/Unit/Public/Repair-IntuneScript.Tests.ps1 +++ b/Tests/Unit/Public/Repair-IntuneScript.Tests.ps1 @@ -128,6 +128,37 @@ Describe 'Repair-IntuneScript' -Tag 'Unit', 'Public' { $fixed.Applied | Should-Be 1 } + It 'hands -Context and -EnforceSignatureCheck to the analysis, on both runs' { + # Without them the repair analyzed every script under the inferred context whatever the + # caller deployed to, so Remaining could disagree with Test-IntuneScript run with the + # same options. HKCU: and USERPROFILE are two errors under System (REM-PROBE-SYS64) and + # under User the rule gives one note; an unsigned Win32 detection is an error only with + # the signature check enforced + $body = "Get-ItemProperty HKCU:\Software\Contoso`nTest-Path `$env:USERPROFILE\x`nexit 1" + $path = New-TestScript 'Remediations\F\Detect.ps1' $body -Bom + $asUser = Repair-IntuneScript -Path $path -Context User -IncludeRule IslContextIssue + $asSystem = Repair-IntuneScript -Path $path -Context System -IncludeRule IslContextIssue + $asUser.Remaining | Should-Be 1 + $asSystem.Remaining | Should-Be 2 + + $unsigned = New-TestScript 'Win32\F\Detect-App.ps1' "if (Test-Path C:\x) { exit 0 }`nexit 1" -Bom + $enforced = Repair-IntuneScript -Path $unsigned -ScriptType Win32Detection -EnforceSignatureCheck + $plain = Repair-IntuneScript -Path $unsigned -ScriptType Win32Detection + $enforced.Remaining | Should-Be ($plain.Remaining + 1) + } + + It 'counts the architecture the caller names, not the inferred one, in Remaining' { + # x86 is the portal default for a remediation, so the 32-bit System32 finding is there + # under Auto and gone under -Architecture x64 (REM-PROBE-SYS32) + $body = "Start-Process C:\Windows\System32\msiexec.exe -Wait`nexit 0" + $folder = New-TestScript 'Remediations\G\Detect.ps1' $body -Bom + $inferred = Repair-IntuneScript -Path $folder + $native = Repair-IntuneScript -Path $folder -Architecture x64 + $inferred.Remaining | Should-Be (@(Test-IntuneScript -Path $folder).Count) + $native.Remaining | Should-Be (@(Test-IntuneScript -Path $folder -Architecture x64).Count) + $native.Remaining | Should-BeLessThan $inferred.Remaining + } + It 'expands a folder and reports one object per script' { $folder = Join-Path $TestDrive 'Tree' New-TestScript 'Tree\Remediations\One\Detect.ps1' "if (`$a) { return 'a' }`nexit 1" -Bom | Out-Null diff --git a/docs/IntuneScriptLab/Repair-IntuneScript.md b/docs/IntuneScriptLab/Repair-IntuneScript.md index a2cecee..17636b0 100644 --- a/docs/IntuneScriptLab/Repair-IntuneScript.md +++ b/docs/IntuneScriptLab/Repair-IntuneScript.md @@ -1,10 +1,10 @@ ---- +--- document type: cmdlet external help file: IntuneScriptLab-Help.xml HelpUri: https://github.com/fadwen/IntuneScriptLab/blob/main/docs/IntuneScriptLab/Repair-IntuneScript.md Locale: en-US Module Name: IntuneScriptLab -ms.date: 10/05/2026 +ms.date: 10/06/2026 PlatyPS schema version: 2024-05-01 title: Repair-IntuneScript --- @@ -20,8 +20,9 @@ Applies the mechanical fixes for findings that have one, and reports what is lef ### __AllParameterSets ``` -Repair-IntuneScript [-Path] [-ScriptType ] [-IncludeRule ] - [-ExcludeRule ] [-Settings ] [-WhatIf] [-Confirm] [] +Repair-IntuneScript [-Path] [-ScriptType ] [-Context ] + [-Architecture ] [-IncludeRule ] [-ExcludeRule ] + [-EnforceSignatureCheck] [-Settings ] [-WhatIf] [-Confirm] ``` ## ALIASES @@ -71,8 +72,40 @@ Get-ChildItem .\Win32 -Recurse -Filter Requirement*.ps1 | Repair-IntuneScript -I Trims padded requirement values only, in every requirement script under Win32. +### EXAMPLE 4 + +Repair-IntuneScript -Path .\Remediations -Architecture x64 -Context System + +Repairs the scripts as deployed to the 64-bit host in system context, so the findings that depend +on either, and the Remaining count, match Test-IntuneScript run with the same options. + ## PARAMETERS +### -Architecture + +The host the script runs in, passed to the analysis: x86 (portal default for scripts and +remediations), x64 (Win32 detection default) or arm64. Auto (default) infers per script as +Test-IntuneScript does. The findings an architecture decides, System32 against Sysnative among +them, and the fixes and Remaining count that follow from them, are then the ones +Test-IntuneScript gives for the same value. + +```yaml +Type: System.String +DefaultValue: '' +SupportsWildcards: false +Aliases: [] +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### -Confirm Prompts you for confirmation before running the cmdlet. @@ -95,6 +128,53 @@ AcceptedValues: [] HelpMessage: '' ``` +### -Context + +System or User, passed to the analysis. Auto (default) uses the directive or the type's portal +default, as Test-IntuneScript does. HKCU: and the profile variables are errors under System and +not under User, so Remaining follows the context the script is deployed in. + +```yaml +Type: System.String +DefaultValue: '' +SupportsWildcards: false +Aliases: [] +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + +### -EnforceSignatureCheck + +Analyze Win32 detection and requirement scripts as if the rule's "Enforce script signature +check" were on: an unsigned script gets an IslSignatureIssue error, which has no fix and is +counted in Remaining. The directive comment "# IntuneScriptLab: EnforceSignatureCheck=true" +does the same for one script, and the settings key EnforceSignatureCheck = $true for a folder. + +```yaml +Type: System.Management.Automation.SwitchParameter +DefaultValue: '' +SupportsWildcards: false +Aliases: [] +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### -ExcludeRule Rule names (wildcards allowed) whose findings are not fixed. diff --git a/en-US/IntuneScriptLab-Help.xml b/en-US/IntuneScriptLab-Help.xml index fcf7138..bd04a69 100644 --- a/en-US/IntuneScriptLab-Help.xml +++ b/en-US/IntuneScriptLab-Help.xml @@ -4197,6 +4197,22 @@ The command supports System.String + + Context + + string + + System.String + + + + Architecture + + string + + System.String + + IncludeRule @@ -4213,6 +4229,13 @@ The command supports System.String[] + + EnforceSignatureCheck + + + System.Management.Automation.SwitchParameter + + Settings @@ -4238,6 +4261,20 @@ The command supports + + Architecture + + The host the script runs in, passed to the analysis: x86 (portal default for scripts and +remediations), x64 (Win32 detection default) or arm64. Auto (default) infers per script as +Test-IntuneScript does. The findings an architecture decides, System32 against Sysnative among +them, and the fixes and Remaining count that follow from them, are then the ones +Test-IntuneScript gives for the same value. + + System.String + + System.String + + Confirm @@ -4247,6 +4284,30 @@ The command supports System.Management.Automation.SwitchParameter + + Context + + System or User, passed to the analysis. Auto (default) uses the directive or the type's portal +default, as Test-IntuneScript does. HKCU: and the profile variables are errors under System and +not under User, so Remaining follows the context the script is deployed in. + + System.String + + System.String + + + + EnforceSignatureCheck + + Analyze Win32 detection and requirement scripts as if the rule's "Enforce script signature +check" were on: an unsigned script gets an IslSignatureIssue error, which has no fix and is +counted in Remaining. The directive comment "# IntuneScriptLab: EnforceSignatureCheck=true" +does the same for one script, and the settings key EnforceSignatureCheck = $true for a folder. + + + System.Management.Automation.SwitchParameter + + ExcludeRule @@ -4365,6 +4426,17 @@ script already did, or changes the file's encoding, never what the script decide + + --------- EXAMPLE 4 --------- + + Repair-IntuneScript -Path .\Remediations -Architecture x64 -Context System + € + Repairs the scripts as deployed to the 64-bit host in system context, so the findings that depend +on either, and the Remaining count, match Test-IntuneScript run with the same options. + + + +