Modules/Private/16-ModuleValidation.ps1
|
function Invoke-RangerModuleValidation { <# .SYNOPSIS v2.0.0 (#231): validate and optionally install/update required PowerShell modules on startup. .DESCRIPTION Iterates a list of required and optional modules, checks installed version via Get-Module -ListAvailable, and attempts Install-Module / Update-Module when below the minimum. Failures log a warning but do not abort the run. Skipped entirely when -SkipModuleUpdate is set on the outer command. #> [CmdletBinding()] param( [switch]$Quiet ) $required = @( @{ Name = 'Az.Accounts'; MinVersion = '2.13.0' }, @{ Name = 'Az.Resources'; MinVersion = '6.0.0' }, @{ Name = 'Az.ConnectedMachine';MinVersion = '0.7.0' }, @{ Name = 'Az.KeyVault'; MinVersion = '4.0.0' } ) $optional = @( @{ Name = 'Az.StackHCI'; MinVersion = '2.0.0'; Reason = 'HCI cluster-level operations' }, @{ Name = 'Az.ResourceGraph'; MinVersion = '0.13.0'; Reason = 'Faster ARM discovery (#205)' }, @{ Name = 'ImportExcel'; MinVersion = '7.8.0'; Reason = 'XLSX output (#209)' } ) $results = New-Object System.Collections.ArrayList foreach ($m in $required) { $result = Invoke-RangerSingleModuleCheck -Name $m.Name -MinVersion $m.MinVersion -Category 'required' -Quiet:$Quiet [void]$results.Add($result) } foreach ($m in $optional) { $result = Invoke-RangerSingleModuleCheck -Name $m.Name -MinVersion $m.MinVersion -Category 'optional' -Reason $m.Reason -Quiet:$Quiet [void]$results.Add($result) } return @($results) } function Invoke-RangerSingleModuleCheck { param( [Parameter(Mandatory = $true)][string]$Name, [Parameter(Mandatory = $true)][string]$MinVersion, [Parameter(Mandatory = $true)][ValidateSet('required','optional')][string]$Category, [string]$Reason, [switch]$Quiet ) $available = @(Get-Module -ListAvailable -Name $Name -ErrorAction SilentlyContinue) $installedMax = if ($available.Count -gt 0) { ($available | Sort-Object Version -Descending | Select-Object -First 1).Version } else { $null } $minVer = [version]$MinVersion $action = 'none' $status = 'ok' $message = $null if (-not $installedMax) { if ($Category -eq 'required') { $action = 'install' $message = "Installing $Name (>= $MinVersion)..." try { if (-not $Quiet) { Write-Host "[ranger] $message" -ForegroundColor DarkCyan } Install-Module -Name $Name -MinimumVersion $MinVersion -Scope CurrentUser -Force -AllowClobber -ErrorAction Stop $status = 'installed' } catch { Write-Warning "Module install failed: $Name — $($_.Exception.Message). Continuing; run will be affected if $Name is needed." $status = 'install-failed' } } else { $status = 'missing-optional' $message = "Optional module '$Name' not installed ($Reason). Install with: Install-Module $Name -Scope CurrentUser" if (-not $Quiet) { Write-Verbose $message } } } elseif ($installedMax -lt $minVer) { $action = 'update' $message = "Updating $Name ($installedMax → >= $MinVersion)..." try { if (-not $Quiet) { Write-Host "[ranger] $message" -ForegroundColor DarkCyan } Update-Module -Name $Name -Force -ErrorAction Stop $status = 'updated' } catch { Write-Warning "Module update failed: $Name — $($_.Exception.Message). Installed $installedMax remains in use." $status = 'update-failed' } } else { $status = 'current' } [ordered]@{ name = $Name category = $Category minVersion = $MinVersion installedMax = if ($installedMax) { [string]$installedMax } else { $null } action = $action status = $status message = $message } } |