Private/NC-Hlp.ModuleUpdates.ps1
|
#Requires -Version 5.0 using namespace System.Management.Automation # Nebula.Core: Module update checks ================================================================================================================= function Test-NebulaModuleUpdates { <# .SYNOPSIS Checks PowerShell Gallery for Nebula module updates. .DESCRIPTION Compares locally installed Nebula.* modules with the latest versions on PSGallery. Returns $true when updates are found, otherwise $false. Logs results via Write-NCMessage. .PARAMETER Force Forces a new check even if one was already performed in this session. #> [CmdletBinding()] param( [switch]$Force ) if (-not $Force.IsPresent -and $script:NC_ModuleUpdateChecked) { return $false } $defaultIntervalHours = 168 $licenseCacheDays = $NCVars.LicenseCacheDays if ($licenseCacheDays -is [string]) { $parsedLicenseCacheDays = 0 if ([int]::TryParse($licenseCacheDays, [ref]$parsedLicenseCacheDays)) { $licenseCacheDays = $parsedLicenseCacheDays } } if ($licenseCacheDays -is [int] -and $licenseCacheDays -gt 0) { $defaultIntervalHours = ($licenseCacheDays * 24) } $intervalHours = $NCVars.CheckUpdatesIntervalHours if ($intervalHours -is [string]) { $parsed = 0 if ([int]::TryParse($intervalHours, [ref]$parsed)) { $intervalHours = $parsed } } if (-not ($intervalHours -is [int]) -or $intervalHours -lt 1) { $intervalHours = $defaultIntervalHours } if (-not $Force.IsPresent -and $intervalHours -gt 0) { $lastCheckUtc = Get-NCModuleUpdateLastCheck if ($lastCheckUtc) { $elapsedHours = ((Get-Date).ToUniversalTime() - $lastCheckUtc).TotalHours if ($elapsedHours -lt $intervalHours) { $script:NC_ModuleUpdateChecked = $true return $false } } } Write-NCMessage "Checking PowerShell Gallery for module updates, please wait ..." -Level INFO $script:NC_ModuleUpdateChecked = $true if (-not (Get-Command -Name Get-InstalledModule -ErrorAction SilentlyContinue)) { Write-NCMessage "PowerShellGet is required to check for Nebula updates. Install it with Install-Module PowerShellGet." -Level WARNING return $false } $installedModules = @() try { $installedModules = Get-InstalledModule -Name 'Nebula.*' -ErrorAction Stop } catch { Write-NCMessage "Unable to read installed Nebula modules. $($_.Exception.Message)" -Level WARNING return $false } $extraModules = @() try { $extraModules = Get-InstalledModule -Name @('ExchangeOnlineManagement', 'Microsoft.Graph') -ErrorAction SilentlyContinue } catch { $extraModules = @() } if ($extraModules) { $installedModules = @($installedModules + $extraModules | Where-Object { $_ }) | Group-Object Name | ForEach-Object { $_.Group | Select-Object -First 1 } } if (-not $installedModules -or $installedModules.Count -eq 0) { return $false } $updates = @() foreach ($module in $installedModules) { $galleryModule = $null try { $galleryModule = Find-Module -Name $module.Name -Repository PSGallery -ErrorAction Stop } catch { Write-NCMessage "Unable to reach PowerShell Gallery to check updates. $($_.Exception.Message)" -Level WARNING return $false } if (-not $galleryModule) { continue } $installedVersion = [version]$module.Version $latestVersion = [version]$galleryModule.Version if ($latestVersion -gt $installedVersion) { $updates += [pscustomobject]@{ Name = $module.Name InstalledVersion = $installedVersion LatestVersion = $latestVersion } } } if (-not $updates -or $updates.Count -eq 0) { Save-NCModuleUpdateLastCheck return $false } foreach ($update in $updates) { Write-NCMessage ("Update available for {0}: {1} -> {2}" -f $update.Name, $update.InstalledVersion, $update.LatestVersion) -Level WARNING } Save-NCModuleUpdateLastCheck return $true } function Get-NCModuleUpdateLastCheck { [CmdletBinding()] param() $path = Get-NCModuleUpdateCheckPath if (-not (Test-Path -LiteralPath $path)) { return $null } try { $raw = Get-Content -LiteralPath $path -Raw -ErrorAction Stop $data = $raw | ConvertFrom-Json -ErrorAction Stop if ($data -and $data.LastCheckUtc) { return [datetime]::Parse($data.LastCheckUtc, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::AssumeUniversal) } } catch { return $null } return $null } function Save-NCModuleUpdateLastCheck { [CmdletBinding()] param() $path = Get-NCModuleUpdateCheckPath $directory = Split-Path -Parent $path if (-not (Test-Path -LiteralPath $directory)) { New-Item -Path $directory -ItemType Directory -Force | Out-Null } $payload = @{ LastCheckUtc = (Get-Date).ToUniversalTime().ToString('o') } $payload | ConvertTo-Json | Set-Content -LiteralPath $path -Encoding UTF8 } function Get-NCModuleUpdateCheckPath { [CmdletBinding()] param() return (Join-Path -Path $NCVars.UserConfigRoot -ChildPath 'update-check.json') } |