Public/Set-PatchDeferral.ps1
|
function Get-DeferralState { <# .SYNOPSIS Gets the deferral state for an application .DESCRIPTION Retrieves the current deferral state including count, deadline, and phase .PARAMETER AppId The application ID to get state for .EXAMPLE Get-DeferralState -AppId 'Google.Chrome' #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$AppId ) return Get-StateFromRegistry -AppId $AppId } function Set-PatchDeferral { <# .SYNOPSIS Records a deferral for an application update .DESCRIPTION Updates the deferral state when a user defers an update .PARAMETER AppId The application ID being deferred .PARAMETER DeferUntil When to next prompt for the update .PARAMETER Reason Optional reason for deferral .EXAMPLE Set-PatchDeferral -AppId 'Google.Chrome' -DeferUntil (Get-Date).AddHours(4) .EXAMPLE Set-PatchDeferral -AppId 'Mozilla.Firefox' -DeferUntil 'Tomorrow' #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$AppId, [Parameter(Mandatory)] [object]$DeferUntil, [Parameter()] [string]$Reason ) try { # Get current state $state = Get-StateFromRegistry -AppId $AppId if ($state.TargetVersion -eq $null) { Write-PatchLog "No update pending for $AppId" -Type Warning return $false } # Check if deferral is allowed if (-not $state.CanDefer()) { Write-PatchLog "Deferral not allowed for $AppId (count: $($state.DeferralCount), phase: $($state.Phase))" -Type Warning return $false } # Parse DeferUntil $nextPrompt = switch ($DeferUntil) { '1 Hour' { [datetime]::UtcNow.AddHours(1) } '4 Hours' { [datetime]::UtcNow.AddHours(4) } 'Tomorrow' { [datetime]::UtcNow.AddDays(1) } default { if ($DeferUntil -is [datetime]) { $DeferUntil } else { [datetime]::Parse($DeferUntil) } } } # Update state $state.DeferralCount++ $state.LastDeferral = [datetime]::UtcNow # Save state Set-StateToRegistry -State $state # Log $message = "Deferred $AppId until $nextPrompt" if ($Reason) { $message += " (Reason: $Reason)" } Write-PatchLog $message -Type Info return $true } catch { Write-PatchLog "Failed to set deferral for $AppId : $_" -Type Error return $false } } function Reset-DeferralState { <# .SYNOPSIS Resets deferral state for an application .DESCRIPTION Clears the deferral count and state, typically after successful update .PARAMETER AppId The application ID to reset .EXAMPLE Reset-DeferralState -AppId 'Google.Chrome' #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$AppId ) Remove-StateFromRegistry -AppId $AppId Write-PatchLog "Reset deferral state for $AppId" -Type Info } function Test-DeferralAllowed { <# .SYNOPSIS Tests if an application can be deferred .DESCRIPTION Checks deferral count and phase to determine if deferral is allowed .PARAMETER AppId The application ID to check .EXAMPLE if (Test-DeferralAllowed -AppId 'Google.Chrome') { Show-DeferralDialog } #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory)] [string]$AppId ) $state = Get-StateFromRegistry -AppId $AppId return $state.CanDefer() } function Get-DeferralPhase { <# .SYNOPSIS Gets the current deferral phase for an application .DESCRIPTION Returns the phase (Initial, Approaching, Imminent, Elapsed) based on deadline .PARAMETER AppId The application ID to check .EXAMPLE Get-DeferralPhase -AppId 'Google.Chrome' #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$AppId ) $state = Get-StateFromRegistry -AppId $AppId if ($state.DeadlineDate -eq [datetime]::MinValue) { return [DeferralPhase]::Initial } $config = Get-PatchMyPCConfig return Get-DeferralPhaseInternal -Deadline $state.DeadlineDate -Config $config } function Get-DeferralRefreshInterval { <# .SYNOPSIS Gets the refresh interval based on deferral phase .DESCRIPTION Returns how often to re-prompt the user based on current phase .PARAMETER Phase The current deferral phase .EXAMPLE $interval = Get-DeferralRefreshInterval -Phase ([DeferralPhase]::Approaching) #> [CmdletBinding()] param( [Parameter(Mandatory)] [DeferralPhase]$Phase ) $config = Get-PatchMyPCConfig $seconds = switch ($Phase) { 'Initial' { $config.Deferrals.InitialRefreshSeconds } 'Approaching' { $config.Deferrals.ApproachingRefreshSeconds } 'Imminent' { $config.Deferrals.ImminentRefreshSeconds } 'Elapsed' { $config.Deferrals.ElapsedRefreshSeconds } default { 18000 } # 5 hours default } return [timespan]::FromSeconds($seconds) } |