Private/PsModules/Assert-PsModuleLoaded.ps1
|
# --------------------------------------------------------------------------- # Assert-PsModuleLoaded # Shared "ensure a PowerShell module is in scope, or throw with an install # hint" primitive. Used by per-prerequisite guards (e.g. SSH, Hyper-V) so # the loaded -> available -> install cascade lives in one place and every # guard surfaces the same diagnostic shape. # # Three-step cascade, in order: # 1. Already loaded? Get-Module -Name <Name> -> return # 2. Installed but not in? Get-Module -Name <Name> -ListAvailable -> import # 3. Not installed. throw with the caller-supplied InstallHint # # Why not Get-Command <cmdletName>: false negative when # $PSModuleAutoloadingPreference = 'None' (cmdlet not discovered until # imported), and false positive when an unrelated module exports a function # of the same name (e.g. VMware PowerCLI's Get-VM colliding with the # Hyper-V cmdlet). Asking the module system about the module by name # avoids both failure modes. # # The InstallHint is mandatory and inlined verbatim into the error so each # consumer supplies its own SKU-appropriate wording (e.g. server vs client # feature names) instead of this helper trying to know them all. # --------------------------------------------------------------------------- function Assert-PsModuleLoaded { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $InstallHint ) # Step 1: already loaded. No -ListAvailable so we only see imported # modules; this is the no-side-effect happy path. if (Get-Module -Name $Name) { return } # Step 2: installed on disk but not in scope. Import it so the caller # can use the cmdlets immediately afterwards. Stop on import failure so # we can wrap it with a distinct, actionable message rather than letting # the operator chase the wrong fix for a half-installed feature. if (Get-Module -Name $Name -ListAvailable) { try { Import-Module -Name $Name -ErrorAction Stop } catch { throw [System.Management.Automation.RuntimeException]::new( "PowerShell module '$Name' is present but failed to load. $InstallHint", $_.Exception ) } return } # Step 3: not installed anywhere PowerShell can find it. throw "Required PowerShell module '$Name' is not installed. $InstallHint" } |