Private/Show-ADTInstallationRestartPromptClassic.ps1
#----------------------------------------------------------------------------- # # MARK: Show-ADTInstallationRestartPromptClassic # #----------------------------------------------------------------------------- function Show-ADTInstallationRestartPromptClassic { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'formRestartPromptStartLocation', Justification = "This parameter is used within delegates that PSScriptAnalyzer has no visibility of. See https://github.com/PowerShell/PSScriptAnalyzer/issues/1472 for more details.")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'CountdownNoHideSeconds', Justification = "This parameter is used within delegates that PSScriptAnalyzer has no visibility of. See https://github.com/PowerShell/PSScriptAnalyzer/issues/1472 for more details.")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'UnboundArguments', Justification = "This parameter is just to trap any superfluous input at the end of the function's call.")] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String]$Title, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.UInt32]$CountdownSeconds, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.UInt32]$CountdownNoHideSeconds, [Parameter(Mandatory = $false)] [System.Management.Automation.SwitchParameter]$NoCountdown, [Parameter(Mandatory = $false)] [System.Management.Automation.SwitchParameter]$NotTopMost, [Parameter(Mandatory = $false, ValueFromRemainingArguments = $true, DontShow = $true)] [ValidateNotNullOrEmpty()] [System.Collections.Generic.List[System.Object]]$UnboundArguments ) # Initialize variables. $adtConfig = Get-ADTConfig $adtStrings = Get-ADTStringTable # Define starting counters. $startTime = [System.DateTime]::Now $countdownTime = $startTime # Set up some default values. $controlSize = [System.Drawing.Size]::new($Script:Dialogs.Classic.Width, 0) $paddingNone = [System.Windows.Forms.Padding]::new(0, 0, 0, 0) $buttonSize = [System.Drawing.Size]::new(195, 24) # Define events for form windows. $formRestart_Load = { # Disable the X button. try { Disable-ADTWindowCloseButton -WindowHandle $formRestart.Handle } catch { # Not a terminating error if we can't disable the button. Just disable the Control Box instead Write-ADTLogEntry 'Failed to disable the Close button. Disabling the Control Box instead.' -Severity 2 $formRestart.ControlBox = $false } # Initialize the countdown timer. $currentTime = [System.DateTime]::Now $countdownTime = $startTime.AddSeconds($countdownSeconds) $timerCountdown.Start() # Set up the form. $remainingTime = $countdownTime.Subtract($currentTime) $labelCountdown.Text = [System.String]::Format('{0}:{1:d2}:{2:d2}', $remainingTime.Days * 24 + $remainingTime.Hours, $remainingTime.Minutes, $remainingTime.Seconds) if ($remainingTime.TotalSeconds -le $countdownNoHideSeconds) { $buttonRestartLater.Enabled = $false } # Correct the initial state of the form to prevent the .NET maximized form issue. $formRestart.WindowState = [System.Windows.Forms.FormWindowState]::Normal $formRestart.BringToFront() # Get the start position of the form so we can return the form to this position if PersistPrompt is enabled. $formRestartPromptStartLocation = $formRestart.Location } $restartTimerPersist_Tick = { # Show the Restart Popup. $formRestart.WindowState = [System.Windows.Forms.FormWindowState]::Normal $formRestart.TopMost = !$NotTopMost $formRestart.Location = $formRestartPromptStartLocation $formRestart.BringToFront() } $buttonRestartLater_Click = { # Minimize the form. $formRestart.WindowState = [System.Windows.Forms.FormWindowState]::Minimized if ($NoCountdown) { # Reset the persistence timer. $restartTimerPersist.Stop() $restartTimerPersist.Start() } } $buttonRestartNow_Click = { Write-ADTLogEntry -Message 'Forcefully restarting the computer...' Restart-Computer -Force } $timerCountdown_Tick = { # Get the time information. $currentTime = Get-Date $countdownTime = $startTime.AddSeconds($countdownSeconds) $remainingTime = $countdownTime.Subtract($currentTime) # If the countdown is complete, restart the machine. if ($countdownTime -le $currentTime) { $buttonRestartNow.PerformClick() } else { # Update the form. $labelCountdown.Text = [String]::Format('{0}:{1:d2}:{2:d2}', $remainingTime.Days * 24 + $remainingTime.Hours, $remainingTime.Minutes, $remainingTime.Seconds) if ($remainingTime.TotalSeconds -le $countdownNoHideSeconds) { $buttonRestartLater.Enabled = $false # If the form is hidden when we hit the "No Hide", bring it back up. If ($formRestart.WindowState.Equals([System.Windows.Forms.FormWindowState]::Minimized)) { $formRestart.WindowState = [System.Windows.Forms.FormWindowState]::Normal $formRestart.TopMost = !$NotTopMost $formRestart.Location = $formRestartPromptStartLocation $formRestart.BringToFront() } } } } $formRestart_FormClosed = { $timerCountdown.remove_Tick($timerCountdown_Tick) $restartTimerPersist.remove_Tick($restartTimerPersist_Tick) $buttonRestartNow.remove_Click($buttonRestartNow_Click) $buttonRestartLater.remove_Click($buttonRestartLater_Click) $formRestart.remove_Load($formRestart_Load) $formRestart.remove_FormClosed($formRestart_FormClosed) } $formRestart_FormClosing = { if ($_.CloseReason -eq 'UserClosing') { $_.Cancel = $true } } # Persistence Timer. $timerCountdown = [System.Windows.Forms.Timer]::new() $restartTimerPersist = [System.Windows.Forms.Timer]::new() $restartTimerPersist.Interval = $adtConfig.UI.RestartPromptPersistInterval * 1000 $restartTimerPersist.add_Tick($restartTimerPersist_Tick) if ($NoCountdown) { $restartTimerPersist.Start() } # Picture Banner. $pictureBanner = [System.Windows.Forms.PictureBox]::new() $pictureBanner.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom $pictureBanner.MinimumSize = $pictureBanner.ClientSize = $pictureBanner.MaximumSize = [System.Drawing.Size]::new($Script:Dialogs.Classic.Width, $Script:Dialogs.Classic.BannerHeight) $pictureBanner.Location = [System.Drawing.Point]::new(0, 0) $pictureBanner.Name = 'PictureBanner' $pictureBanner.Image = $Script:Dialogs.Classic.Assets.Banner $pictureBanner.Margin = $paddingNone $pictureBanner.TabStop = $false # Label Message. $labelMessage = [System.Windows.Forms.Label]::new() $labelMessage.MinimumSize = $labelMessage.ClientSize = $labelMessage.MaximumSize = $controlSize $labelMessage.Margin = [System.Windows.Forms.Padding]::new(0, 10, 0, 5) $labelMessage.Padding = [System.Windows.Forms.Padding]::new(10, 0, 10, 0) $labelMessage.Anchor = [System.Windows.Forms.AnchorStyles]::Top $labelMessage.Font = $Script:Dialogs.Classic.Font $labelMessage.Name = 'LabelMessage' $labelMessage.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter $labelMessage.TabStop = $false $labelMessage.AutoSize = $true $labelMessage.Text = if ($NoCountdown) { $adtStrings.RestartPrompt.Message } else { "$($adtStrings.RestartPrompt.Message) $($adtStrings.RestartPrompt.MessageTime)`n`n$($adtStrings.RestartPrompt.MessageRestart)" } # Label Countdown. $labelCountdown = [System.Windows.Forms.Label]::new() $labelCountdown.MinimumSize = $labelCountdown.ClientSize = $labelCountdown.MaximumSize = $controlSize $labelCountdown.Margin = $paddingNone $labelCountdown.Padding = [System.Windows.Forms.Padding]::new(10, 0, 10, 0) $labelCountdown.Font = [System.Drawing.Font]::new($Script:Dialogs.Classic.Font.Name, ($Script:Dialogs.Classic.Font.Size + 9), [System.Drawing.FontStyle]::Bold) $labelCountdown.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter $labelCountdown.Text = '00:00:00' $labelCountdown.Name = 'LabelCountdown' $labelCountdown.TabStop = $false $labelCountdown.AutoSize = $true # Panel Flow Layout. $flowLayoutPanel = [System.Windows.Forms.FlowLayoutPanel]::new() $flowLayoutPanel.SuspendLayout() $flowLayoutPanel.MinimumSize = $flowLayoutPanel.ClientSize = $flowLayoutPanel.MaximumSize = $controlSize $flowLayoutPanel.Location = [System.Drawing.Point]::new(0, $Script:Dialogs.Classic.BannerHeight) $flowLayoutPanel.Margin = $flowLayoutPanel.Padding = $paddingNone $flowLayoutPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::TopDown $flowLayoutPanel.AutoSize = $true $flowLayoutPanel.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowAndShrink $flowLayoutPanel.Anchor = [System.Windows.Forms.AnchorStyles]::Top $flowLayoutPanel.WrapContents = $true $flowLayoutPanel.Controls.Add($labelMessage) if (!$NoCountdown) { # Label Time remaining message. $labelTimeRemaining = [System.Windows.Forms.Label]::new() $labelTimeRemaining.MinimumSize = $labelTimeRemaining.ClientSize = $labelTimeRemaining.MaximumSize = $controlSize $labelTimeRemaining.Margin = $paddingNone $labelTimeRemaining.Padding = [System.Windows.Forms.Padding]::new(10, 0, 10, 0) $labelTimeRemaining.Anchor = [System.Windows.Forms.AnchorStyles]::Top $labelTimeRemaining.Font = [System.Drawing.Font]::new($Script:Dialogs.Classic.Font.Name, ($Script:Dialogs.Classic.Font.Size + 3), [System.Drawing.FontStyle]::Bold) $labelTimeRemaining.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter $labelTimeRemaining.Text = $adtStrings.RestartPrompt.TimeRemaining $labelTimeRemaining.Name = 'LabelTimeRemaining' $labelTimeRemaining.TabStop = $false $labelTimeRemaining.AutoSize = $true $flowLayoutPanel.Controls.Add($labelTimeRemaining) $flowLayoutPanel.Controls.Add($labelCountdown) } # Button Panel. $panelButtons = [System.Windows.Forms.Panel]::new() $panelButtons.SuspendLayout() $panelButtons.MinimumSize = $panelButtons.ClientSize = $panelButtons.MaximumSize = [System.Drawing.Size]::new($Script:Dialogs.Classic.Width, 39) $panelButtons.Margin = [System.Windows.Forms.Padding]::new(0, 10, 0, 0) $panelButtons.Padding = $paddingNone $panelButtons.AutoSize = $true # Button Restart Now. $buttonRestartNow = [System.Windows.Forms.Button]::new() $buttonRestartNow.MinimumSize = $buttonRestartNow.ClientSize = $buttonRestartNow.MaximumSize = $buttonSize $buttonRestartNow.Location = [System.Drawing.Point]::new(14, 4) $buttonRestartNow.Margin = $buttonRestartNow.Padding = $paddingNone $buttonRestartNow.Name = 'ButtonRestartNow' $buttonRestartNow.Font = $Script:Dialogs.Classic.Font $buttonRestartNow.Text = $adtStrings.RestartPrompt.ButtonRestartNow $buttonRestartNow.TabIndex = 1 $buttonRestartNow.AutoSize = $true $buttonRestartNow.UseVisualStyleBackColor = $true $buttonRestartNow.add_Click($buttonRestartNow_Click) $panelButtons.Controls.Add($buttonRestartNow) # Button Minimize. $buttonRestartLater = [System.Windows.Forms.Button]::new() $buttonRestartLater.MinimumSize = $buttonRestartLater.ClientSize = $buttonRestartLater.MaximumSize = $buttonSize $buttonRestartLater.Location = [System.Drawing.Point]::new(240, 4) $buttonRestartLater.Margin = $buttonRestartLater.Padding = $paddingNone $buttonRestartLater.Name = 'ButtonRestartLater' $buttonRestartLater.Font = $Script:Dialogs.Classic.Font $buttonRestartLater.Text = $adtStrings.RestartPrompt.ButtonRestartLater $buttonRestartLater.TabIndex = 0 $buttonRestartLater.AutoSize = $true $buttonRestartLater.UseVisualStyleBackColor = $true $buttonRestartLater.add_Click($buttonRestartLater_Click) $panelButtons.Controls.Add($buttonRestartLater) $panelButtons.ResumeLayout() # Add the Buttons Panel to the flowPanel. $flowLayoutPanel.Controls.Add($panelButtons) $flowLayoutPanel.ResumeLayout() # Button Default (Hidden). $buttonDefault = [System.Windows.Forms.Button]::new() $buttonDefault.MinimumSize = $buttonDefault.ClientSize = $buttonDefault.MaximumSize = [System.Drawing.Size]::new(0, 0) $buttonDefault.Margin = $buttonDefault.Padding = $paddingNone $buttonDefault.Name = 'buttonDefault' $buttonDefault.Font = $Script:Dialogs.Classic.Font $buttonDefault.BackColor = [System.Drawing.Color]::Transparent $buttonDefault.ForeColor = [System.Drawing.Color]::Transparent $buttonDefault.FlatAppearance.BorderSize = 0 $buttonDefault.FlatAppearance.MouseDownBackColor = [System.Drawing.Color]::Transparent $buttonDefault.FlatAppearance.MouseOverBackColor = [System.Drawing.Color]::Transparent $buttonDefault.FlatStyle = [System.Windows.Forms.FlatStyle]::System $buttonDefault.TabStop = $false $buttonDefault.Enabled = $false $buttonDefault.Visible = $true # Has to be set visible so we can call Click on it. $buttonDefault.UseVisualStyleBackColor = $true # Form Restart. $formRestartPromptStartLocation = $null $formRestart = [System.Windows.Forms.Form]::new() $formRestart.SuspendLayout() $formRestart.ClientSize = $controlSize $formRestart.Margin = $formRestart.Padding = $paddingNone $formRestart.Font = $Script:Dialogs.Classic.Font $formRestart.Name = 'FormRestart' $formRestart.Text = $Title $formRestart.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::Font $formRestart.AutoScaleDimensions = [System.Drawing.SizeF]::new(7, 15) $formRestart.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $formRestart.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D $formRestart.MaximizeBox = $false $formRestart.MinimizeBox = $false $formRestart.TopMost = !$NotTopMost $formRestart.TopLevel = $true $formRestart.AutoSize = $true $formRestart.Icon = $Script:Dialogs.Classic.Assets.Icon $formRestart.Controls.Add($pictureBanner) $formRestart.Controls.Add($flowLayoutPanel) $formRestart.Controls.Add($buttonDefault) $formRestart.add_Load($formRestart_Load) $formRestart.add_FormClosed($formRestart_FormClosed) $formRestart.add_FormClosing($formRestart_FormClosing) $formRestart.AcceptButton = $buttonDefault $formRestart.ActiveControl = $buttonDefault $formRestart.ResumeLayout() # Timer Countdown. if (!$NoCountdown) { $timerCountdown.add_Tick($timerCountdown_Tick) } # Show the Form. if ($NoCountdown) { Write-ADTLogEntry -Message 'Displaying restart prompt with no countdown.' } else { Write-ADTLogEntry -Message "Displaying restart prompt with a [$countDownSeconds] second countdown." } return $formRestart.ShowDialog() } |