Refactor module functions to use begin/process/end with safer error handling - #32
Conversation
Agent-Logs-Url: https://github.com/rwidmark/WinSoftwareUpdate/sessions/f981789e-3b64-4df8-bd97-5d7a4ed428ea Co-authored-by: rwidmark <76907327+rwidmark@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rwidmark/WinSoftwareUpdate/sessions/f981789e-3b64-4df8-bd97-5d7a4ed428ea Co-authored-by: rwidmark <76907327+rwidmark@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rwidmark/WinSoftwareUpdate/sessions/f981789e-3b64-4df8-bd97-5d7a4ed428ea Co-authored-by: rwidmark <76907327+rwidmark@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rwidmark/WinSoftwareUpdate/sessions/f981789e-3b64-4df8-bd97-5d7a4ed428ea Co-authored-by: rwidmark <76907327+rwidmark@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rwidmark/WinSoftwareUpdate/sessions/f981789e-3b64-4df8-bd97-5d7a4ed428ea Co-authored-by: rwidmark <76907327+rwidmark@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rwidmark/WinSoftwareUpdate/sessions/f981789e-3b64-4df8-bd97-5d7a4ed428ea Co-authored-by: rwidmark <76907327+rwidmark@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors key functions in the WinSoftwareUpdate PowerShell module to use a consistent advanced-function structure (begin/process/end) and adds more targeted error handling around web requests, installs, and external process execution.
Changes:
- Converted several functions to advanced functions with explicit
begin/process/endblocks. - Tightened error handling for GitHub API calls, downloads,
Add-AppxPackage, andStart-Processexit-code validation. - Added
SupportsShouldProcesstoUpdate-rsWinSoftwareand refactored WinGet upgrade argument construction.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ErrorAction = "Stop" | ||
| } | ||
|
|
||
| if (-not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { |
There was a problem hiding this comment.
Same issue as above: this adds HttpVersion unconditionally based on a non-empty string, which will break on Windows PowerShell 5.1 because Invoke-RestMethod there doesn’t accept -HttpVersion. Gate adding this parameter on $PSVersionTable.PSVersion.Major -ge 7 (or parameter availability) to keep the module compatible with the manifest’s PowerShellVersion = 5.1.
| if (-not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { | |
| if ( | |
| $PSVersionTable.PSVersion.Major -ge 7 -and | |
| -not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion) | |
| ) { |
| if ($null -ne $SysInfo -and -not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { | ||
| $MetadataParameters.HttpVersion = $SysInfo.HTTPVersion | ||
| } | ||
| elseif ($CurrentVersion -ge $MinimumPwsh7Version) { | ||
| $MetadataParameters.HttpVersion = "3.0" | ||
| } |
There was a problem hiding this comment.
Invoke-RestMethod on Windows PowerShell 5.1 doesn’t support -HttpVersion, but this block can still set HttpVersion (e.g., from $SysInfo.HTTPVersion or hard-coded "3.0") even when running under 5.1, leading to a runtime parameter binding failure. Only add HttpVersion when the current session supports it (PS 7+), otherwise omit it entirely.
| if ($null -ne $SysInfo -and -not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { | |
| $MetadataParameters.HttpVersion = $SysInfo.HTTPVersion | |
| } | |
| elseif ($CurrentVersion -ge $MinimumPwsh7Version) { | |
| $MetadataParameters.HttpVersion = "3.0" | |
| } | |
| if ($PSVersionTable.PSVersion.Major -ge 7) { | |
| if ($null -ne $SysInfo -and -not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { | |
| $MetadataParameters.HttpVersion = $SysInfo.HTTPVersion | |
| } | |
| elseif ($CurrentVersion -ge $MinimumPwsh7Version) { | |
| $MetadataParameters.HttpVersion = "3.0" | |
| } | |
| } |
| if (-not $IsAdministrator) { | ||
| Write-Error ("{0} needs admin privileges, exiting now...." -f $MyInvocation.MyCommand) | ||
| return | ||
| } | ||
|
|
||
| # Register WinGet | ||
| # Add-AppxPackage -RegisterByFamilyName -MainPackage "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe" | ||
| if (-not $PSCmdlet.ShouldProcess("Local computer", "Update installed software with WinGet")) { | ||
| return | ||
| } |
There was a problem hiding this comment.
With SupportsShouldProcess, -WhatIf should ideally be able to run without requiring elevation, but the admin check happens before ShouldProcess, so non-admin users can’t even preview actions. Consider calling ShouldProcess first (and returning early on -WhatIf), and only enforcing the admin check when actually performing the update.
| Function Confirm-rsDependency { | ||
| # Collecting systeminformation | ||
| $SysInfo = Get-rsSystemInfo | ||
|
|
||
| # If any dependencies are missing it will install them | ||
| foreach ($_info in $SysInfo.Software.keys) { | ||
| if ($_info -notlike "WinGet") { | ||
| $Software = $SysInfo.Software.$_info | ||
| if ($null -eq $Software.version -or $Software.version -eq "0.0.0.0") { | ||
| [CmdletBinding()] | ||
| Param() | ||
|
|
||
| begin { | ||
| } | ||
|
|
||
| process { | ||
| $SysInfo = Get-rsSystemInfo | ||
|
|
||
| foreach ($DependencyName in $SysInfo.Software.Keys | Where-Object { $_ -ne "WinGet" }) { | ||
| $Software = $SysInfo.Software[$DependencyName] | ||
| if ($null -eq $Software.Version -or $Software.Version -eq "0.0.0.0") { |
There was a problem hiding this comment.
Confirm-rsDependency is exported (per module manifest) and performs state-changing installs/downloads, but it doesn’t declare SupportsShouldProcess or honor ShouldProcess internally. Either add SupportsShouldProcess + ShouldProcess guards around the install/download operations, or make this a private helper (remove from FunctionsToExport) so callers don’t invoke side effects unexpectedly.
| @@ -281,73 +357,92 @@ Function Confirm-rsPowerShell7 { | |||
| .EXAMPLE | |||
| #> | |||
|
|
|||
| $MissingPWSH7 = $false | |||
|
|
|||
| [version]$CurrentVersion = if ($PSVersionTable.PSVersion.Major -lt 7) { | |||
| $CheckpwshVersion = Test-Path -Path "C:\Program Files\PowerShell\7\pwsh.exe" | |||
| [CmdletBinding()] | |||
| Param( | |||
| [Parameter(Mandatory = $false)] | |||
| $SysInfo | |||
| ) | |||
There was a problem hiding this comment.
The module manifest exports Get-rsPowerShell7, but this file defines Confirm-rsPowerShell7 (and there is no Get-rsPowerShell7 function). This makes the public API inconsistent and can prevent consumers from calling the intended function. Align the function name and the manifest’s FunctionsToExport list (rename the function or update the manifest).
| Write-Output "PowerShell 7 was not installed on your system, PowerShell 7 have been installed and you need to restart PowerShell to use the new version" | ||
| } | ||
| else { | ||
| Write-Output "PowerShell 7 have been updated from $CurrentVersion to $Release, you need to restart PowerShell to use the new version" |
There was a problem hiding this comment.
Grammar in user-facing output: use singular verb forms ("has") with "PowerShell 7". This improves professionalism and clarity of console output.
| Write-Output "PowerShell 7 was not installed on your system, PowerShell 7 have been installed and you need to restart PowerShell to use the new version" | |
| } | |
| else { | |
| Write-Output "PowerShell 7 have been updated from $CurrentVersion to $Release, you need to restart PowerShell to use the new version" | |
| Write-Output "PowerShell 7 was not installed on your system, PowerShell 7 has been installed and you need to restart PowerShell to use the new version" | |
| } | |
| else { | |
| Write-Output "PowerShell 7 has been updated from $CurrentVersion to $Release, you need to restart PowerShell to use the new version" |
| ErrorAction = "Stop" | ||
| } | ||
|
|
||
| if (-not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { |
There was a problem hiding this comment.
$SysInfo.HTTPVersion is always set to a non-empty value ("2.0" on Windows PowerShell 5.1), so this code will add an HttpVersion parameter even when running on PowerShell 5.1 where Invoke-RestMethod does not support -HttpVersion, causing a parameter binding error. Only include HttpVersion when the current PowerShell supports it (e.g., $PSVersionTable.PSVersion.Major -ge 7 or by checking the cmdlet’s parameter set), or set SysInfo.HTTPVersion to $null for PS < 7.
| if (-not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion)) { | |
| if ( | |
| -not [string]::IsNullOrWhiteSpace([string]$SysInfo.HTTPVersion) -and | |
| (Get-Command -Name Invoke-RestMethod).Parameters.ContainsKey('HttpVersion') | |
| ) { |
The module functions were missing a consistent advanced-function structure and had several failure paths without targeted exception handling. This change standardizes function flow with
begin/process/end, tightens error handling around downloads/installations/process execution, and removes a few brittle code paths.Function structure
begin/process/endblocksSupportsShouldProcesstoUpdate-rsWinSoftwareso state-changing behavior is declared explicitlyError handling
try/catchmsiexecandwingetfinallyblocks for temp file cleanup after WinGet, dependency, and PowerShell installer downloadsCode-path hardening
HttpVersionusage so requests do not fail on unset valuesSmall optimizations
Example of the updated pattern: