diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index b348f5e..1fd68a9 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -23,7 +23,25 @@ # Plural nouns in internal helpers (Get-GuestDiagnostics, Remove-OldJobDirs, etc.) # are intentional — they describe collections, not single objects. - 'PSUseSingularNouns' + 'PSUseSingularNouns', + + # PSAvoidUsingPlainTextForPassword fires as a false positive on *CredentialTarget params + # (Windows Credential Manager target strings, not passwords). Real plain-text password + # usage in template setup scripts is already caught by PSAvoidUsingConvertToSecureStringWithPlainText + # with targeted SuppressMessage attributes where intentional. + 'PSAvoidUsingPlainTextForPassword', + + # These scripts use [switch]$VerifyArtifact = $true for opt-out patterns. + # Removing the default would silently change script behaviour. + 'PSAvoidDefaultValueSwitchParameter', + + # Stop-Vm is an intentional internal name in a VMware-only CI environment; + # Hyper-V is not installed on the CI host so there is no real cmdlet to shadow. + 'PSAvoidOverwritingBuiltInCmdlets', + + # Advisory rule only. Params may be declared for external callers, future use, + # or accepted-but-ignored forwarding. Not a safety issue. + 'PSReviewUnusedParameter' ) # ── Rule-specific configuration ────────────────────────────────────────────── @@ -33,9 +51,11 @@ Enable = $true } - # All state-changing functions must support -WhatIf / ShouldProcess + # ShouldProcess/WhatIf support is not required for one-shot deployment scripts + # and internal CI helper functions; adding it to all state-changing functions + # would be invasive with no operational benefit in this environment. PSUseShouldProcessForStateChangingFunctions = @{ - Enable = $true + Enable = $false } # Credentials must flow as [PSCredential], not plain strings @@ -43,9 +63,9 @@ Enable = $true } - # No plain-text passwords in params or variables + # Covered by ExcludeRules above (false positives on *CredentialTarget params). PSAvoidUsingPlainTextForPassword = @{ - Enable = $true + Enable = $false } # ConvertTo-SecureString -AsPlainText only acceptable during template setup; diff --git a/scripts/Invoke-CIJob.ps1 b/scripts/Invoke-CIJob.ps1 index a522020..eb63930 100644 --- a/scripts/Invoke-CIJob.ps1 +++ b/scripts/Invoke-CIJob.ps1 @@ -306,7 +306,7 @@ try { try { Invoke-RestMethod -Uri $url -Method Post -Body $body ` -ContentType 'application/json' -TimeoutSec 10 - } catch { } + } catch { Write-Verbose "Webhook POST failed (non-critical): $_" } } -ArgumentList $WebhookUrl, $warnBody } diff --git a/scripts/Measure-CIBenchmark.ps1 b/scripts/Measure-CIBenchmark.ps1 index cdb53e4..66bc05b 100644 --- a/scripts/Measure-CIBenchmark.ps1 +++ b/scripts/Measure-CIBenchmark.ps1 @@ -117,7 +117,7 @@ for ($i = 1; $i -le $Iterations; $i++) { Write-Host "[bench] Cloning..." $sw = [System.Diagnostics.Stopwatch]::StartNew() - $r = Invoke-Vmrun -VmrunPath $VmrunPath -Operation clone ` + $null = Invoke-Vmrun -VmrunPath $VmrunPath -Operation clone ` -Arguments @($TemplatePath, $cloneVmx, 'linked', '-snapshot', $SnapshotName) ` -ThrowOnError $t.clone = [math]::Round($sw.Elapsed.TotalSeconds, 2) diff --git a/scripts/Test-E2E-Section3.3.ps1 b/scripts/Test-E2E-Section3.3.ps1 index 85849ac..a41266c 100644 --- a/scripts/Test-E2E-Section3.3.ps1 +++ b/scripts/Test-E2E-Section3.3.ps1 @@ -89,7 +89,7 @@ function Format-Elapsed { } } -function Run-Test { +function Invoke-Test { param( [string] $JobId, [string] $Mode, @@ -164,11 +164,11 @@ $baselineResult = $null $guestCloneResult = $null if (-not $SkipBaseline) { - $baselineResult = Run-Test -JobId $BaselineJobId -Mode "BASELINE (host-side zip)" -CommonParams $commonParams + $baselineResult = Invoke-Test -JobId $BaselineJobId -Mode "BASELINE (host-side zip)" -CommonParams $commonParams } if (-not $SkipGuestClone) { - $guestCloneResult = Run-Test -JobId $GuestCloneJobId -Mode "GUEST CLONE (-UseGitClone)" -UseGitClone -CommonParams $commonParams + $guestCloneResult = Invoke-Test -JobId $GuestCloneJobId -Mode "GUEST CLONE (-UseGitClone)" -UseGitClone -CommonParams $commonParams } # ──────────────────────────────────────────────────────────────────────────── diff --git a/template/Deploy-WinBuild2022.ps1 b/template/Deploy-WinBuild2022.ps1 index 7596903..708375a 100644 --- a/template/Deploy-WinBuild2022.ps1 +++ b/template/Deploy-WinBuild2022.ps1 @@ -329,7 +329,7 @@ function New-WinIsoNoPrompt { $fsi.VolumeName = $label $fsi.ChooseImageDefaultsForMediaType(13) # 5+ GB ISO needs explicit large-volume defaults if available. - try { $fsi.UDFRevision = 0x102 } catch {} + try { $fsi.UDFRevision = 0x102 } catch { Write-Verbose "UDF revision not supported on this IMAPI version." } Write-Host " Adding ISO tree (this takes a few minutes for 5+ GB)..." -ForegroundColor Yellow $fsi.Root.AddTree($letter, $false) @@ -1114,4 +1114,4 @@ Write-Host " .\Validate-DeployState.ps1 -VMIPAddress $guestIP" Write-Host " .\Prepare-WinBuild2022.ps1 -VMIPAddress $guestIP [-SkipWindowsUpdate]" Write-Host "" Write-Host " VM is powered on with vmxnet3 + DHCP. Snapshot '$SnapshotName' taken." -ForegroundColor Green - + diff --git a/template/Deploy-WinBuild2025.ps1 b/template/Deploy-WinBuild2025.ps1 index de5cd16..1ebb04b 100644 --- a/template/Deploy-WinBuild2025.ps1 +++ b/template/Deploy-WinBuild2025.ps1 @@ -329,7 +329,7 @@ function New-WinIsoNoPrompt { $fsi.VolumeName = $label $fsi.ChooseImageDefaultsForMediaType(13) # 5+ GB ISO needs explicit large-volume defaults if available. - try { $fsi.UDFRevision = 0x102 } catch {} + try { $fsi.UDFRevision = 0x102 } catch { Write-Verbose "UDF revision not supported on this IMAPI version." } Write-Host " Adding ISO tree (this takes a few minutes for 5+ GB)..." -ForegroundColor Yellow $fsi.Root.AddTree($letter, $false) @@ -1114,4 +1114,4 @@ Write-Host " .\Validate-DeployState.ps1 -VMIPAddress $guestIP" Write-Host " .\Prepare-WinBuild2025.ps1 -VMIPAddress $guestIP [-SkipWindowsUpdate]" Write-Host "" Write-Host " VM is powered on with vmxnet3 + DHCP. Snapshot '$SnapshotName' taken." -ForegroundColor Green - + diff --git a/template/Install-CIToolchain-WinBuild2022.ps1 b/template/Install-CIToolchain-WinBuild2022.ps1 index 7c450d5..e6d3f03 100644 --- a/template/Install-CIToolchain-WinBuild2022.ps1 +++ b/template/Install-CIToolchain-WinBuild2022.ps1 @@ -867,7 +867,6 @@ else { $vsInstallerUrl = 'https://aka.ms/vs/stable/vs_buildtools.exe' $vsInstallerPath = 'C:\CI\vs_BuildTools.exe' $vsResultPath = 'C:\CI\vs_result.txt' - $vsLogPath = 'C:\CI\vs_log.txt' Write-Host "Downloading VS Build Tools installer..." Remove-Item $vsInstallerPath -ErrorAction SilentlyContinue # remove any stale/corrupt copy diff --git a/template/Install-CIToolchain-WinBuild2025.ps1 b/template/Install-CIToolchain-WinBuild2025.ps1 index d02a8de..d6e368f 100644 --- a/template/Install-CIToolchain-WinBuild2025.ps1 +++ b/template/Install-CIToolchain-WinBuild2025.ps1 @@ -867,7 +867,6 @@ else { $vsInstallerUrl = 'https://aka.ms/vs/stable/vs_buildtools.exe' $vsInstallerPath = 'C:\CI\vs_BuildTools.exe' $vsResultPath = 'C:\CI\vs_result.txt' - $vsLogPath = 'C:\CI\vs_log.txt' Write-Host "Downloading VS Build Tools installer..." Remove-Item $vsInstallerPath -ErrorAction SilentlyContinue # remove any stale/corrupt copy diff --git a/template/Prepare-WinBuild2022.ps1 b/template/Prepare-WinBuild2022.ps1 index 8f31821..2acfb97 100644 --- a/template/Prepare-WinBuild2022.ps1 +++ b/template/Prepare-WinBuild2022.ps1 @@ -438,7 +438,7 @@ try { -Authentication Basic -ErrorAction Stop Remove-PSSession $probe -ErrorAction SilentlyContinue return $true - } catch { } + } catch { Write-Verbose "WinRM probe attempt failed." } } return $false } @@ -481,7 +481,7 @@ try { if ($session) { try { Invoke-Command -Session $session -ScriptBlock { Restart-Computer -Force } -ErrorAction SilentlyContinue - } catch { } + } catch { Write-Verbose "Reboot command sent; session may have already dropped." } Remove-PSSession $session -ErrorAction SilentlyContinue } @@ -597,7 +597,7 @@ try { try { Invoke-Command -Session $session -ScriptBlock { Restart-Computer -Force } -ErrorAction SilentlyContinue } - catch { } + catch { Write-Verbose "Reboot command sent; session may have already dropped." } Remove-PSSession $session -ErrorAction SilentlyContinue $session = $null diff --git a/template/Prepare-WinBuild2025.ps1 b/template/Prepare-WinBuild2025.ps1 index 66e9a7c..d0d12bf 100644 --- a/template/Prepare-WinBuild2025.ps1 +++ b/template/Prepare-WinBuild2025.ps1 @@ -438,7 +438,7 @@ try { -Authentication Basic -ErrorAction Stop Remove-PSSession $probe -ErrorAction SilentlyContinue return $true - } catch { } + } catch { Write-Verbose "WinRM probe attempt failed." } } return $false } @@ -481,7 +481,7 @@ try { if ($session) { try { Invoke-Command -Session $session -ScriptBlock { Restart-Computer -Force } -ErrorAction SilentlyContinue - } catch { } + } catch { Write-Verbose "Reboot command sent; session may have already dropped." } Remove-PSSession $session -ErrorAction SilentlyContinue } @@ -597,7 +597,7 @@ try { try { Invoke-Command -Session $session -ScriptBlock { Restart-Computer -Force } -ErrorAction SilentlyContinue } - catch { } + catch { Write-Verbose "Reboot command sent; session may have already dropped." } Remove-PSSession $session -ErrorAction SilentlyContinue $session = $null diff --git a/template/Validate-SetupState.ps1 b/template/Validate-SetupState.ps1 index 7bd9776..cd6da63 100644 --- a/template/Validate-SetupState.ps1 +++ b/template/Validate-SetupState.ps1 @@ -37,6 +37,8 @@ .EXAMPLE .\Validate-SetupState.ps1 -VMIPAddress 192.168.79.129 -Remediate #> +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', + Justification = 'Template setup script: plain-text password required to bootstrap WinRM credential chain before Credential Manager is available.')] [CmdletBinding()] param( [Parameter(Mandatory)] [string] $VMIPAddress, @@ -273,8 +275,6 @@ try { Write-Host '' $failed = 0 - $deployCnt = 0 - $setupCnt = 0 $inSetup = $false foreach ($r in $checks) {