Private/UI/Show-PIMActivationDialog.ps1
function Show-PIMActivationDialog { <# .SYNOPSIS Displays a dialog for PIM role activation requirements. .DESCRIPTION Shows a Windows Forms dialog to collect justification and/or ticket information required for PIM role activation. Returns user input or cancellation status. .PARAMETER RequiresJustification Specifies that justification text is mandatory for activation. .PARAMETER RequiresTicket Specifies that a ticket number is mandatory for activation. .PARAMETER OptionalJustification Displays justification field as optional with recommended usage note. .EXAMPLE Show-PIMActivationDialog -RequiresJustification Shows dialog with required justification field. .EXAMPLE Show-PIMActivationDialog -RequiresTicket -OptionalJustification Shows dialog with required ticket field and optional justification. .OUTPUTS PSCustomObject Returns object with Justification, TicketNumber, and Cancelled properties. .NOTES Requires System.Windows.Forms assembly for GUI display. #> [CmdletBinding()] param( [switch]$RequiresJustification, [switch]$RequiresTicket, [switch]$OptionalJustification ) # Initialize result object $result = [PSCustomObject]@{ Justification = "" TicketNumber = "" TicketSystem = "ServiceNow" Cancelled = $true } # Create main form $form = New-Object System.Windows.Forms.Form -Property @{ Text = "Role Activation Requirements" Size = [System.Drawing.Size]::new(500, 350) StartPosition = 'CenterScreen' FormBorderStyle = 'FixedDialog' MaximizeBox = $false MinimizeBox = $false BackColor = [System.Drawing.Color]::White TopMost = $true ShowInTaskbar = $true } $y = 10 # Add justification field if required or optional if ($RequiresJustification -or $OptionalJustification) { $labelText = if ($RequiresJustification) { "Justification (required):" } else { "Justification (optional - recommended):" } $lblJust = New-Object System.Windows.Forms.Label -Property @{ Text = $labelText Location = [System.Drawing.Point]::new(10, $y) Size = [System.Drawing.Size]::new(460, 20) Font = [System.Drawing.Font]::new("Segoe UI", 9) ForeColor = [System.Drawing.Color]::FromArgb(32, 31, 30) } $y += 25 $txtJust = New-Object System.Windows.Forms.TextBox -Property @{ Name = "txtJustification" Location = [System.Drawing.Point]::new(10, $y) Size = [System.Drawing.Size]::new(460, 80) Multiline = $true AcceptsReturn = $true ScrollBars = 'Vertical' Text = "PowerShell activation" } $y += 90 $form.Controls.AddRange(@($lblJust, $txtJust)) # Store the justification textbox in a variable for later use $justificationControl = $txtJust } # Add ticket field if required if ($RequiresTicket) { $lblTicket = New-Object System.Windows.Forms.Label -Property @{ Text = "Ticket Number *" Location = [System.Drawing.Point]::new(10, $y) Size = [System.Drawing.Size]::new(120, 23) Font = [System.Drawing.Font]::new("Segoe UI", 9) } $form.Controls.Add($lblTicket) $txtTicket = New-Object System.Windows.Forms.TextBox -Property @{ Name = "txtTicket" Location = [System.Drawing.Point]::new(130, $y) Size = [System.Drawing.Size]::new(280, 23) Font = [System.Drawing.Font]::new("Segoe UI", 9) } $form.Controls.Add($txtTicket) $y += 30 # Add ticket system dropdown $lblTicketSystem = New-Object System.Windows.Forms.Label -Property @{ Text = "Ticket System" Location = [System.Drawing.Point]::new(10, $y) Size = [System.Drawing.Size]::new(120, 23) Font = [System.Drawing.Font]::new("Segoe UI", 9) } $form.Controls.Add($lblTicketSystem) $cmbTicketSystem = New-Object System.Windows.Forms.ComboBox -Property @{ Name = "cmbTicketSystem" Location = [System.Drawing.Point]::new(130, $y) Size = [System.Drawing.Size]::new(280, 23) Font = [System.Drawing.Font]::new("Segoe UI", 9) DropDownStyle = 'DropDownList' } # Add common ticket systems $ticketSystems = @('ServiceNow', 'Jira', 'Azure DevOps', 'ServiceDesk Plus', 'BMC Remedy', 'Cherwell', 'Other') $cmbTicketSystem.Items.AddRange($ticketSystems) # Try to use saved preference or default to ServiceNow $savedSystem = Get-SavedTicketSystem if ($savedSystem -and $ticketSystems -contains $savedSystem) { $cmbTicketSystem.SelectedItem = $savedSystem } else { $cmbTicketSystem.SelectedIndex = 0 # Default to ServiceNow } $form.Controls.Add($cmbTicketSystem) $y += 35 } # Add optional justification note if ($OptionalJustification -and -not $RequiresJustification) { $lblNote = New-Object System.Windows.Forms.Label -Property @{ Text = "Note: While justification is optional, providing a clear reason helps with audit trails." Location = [System.Drawing.Point]::new(10, $y) Size = [System.Drawing.Size]::new(460, 40) ForeColor = [System.Drawing.Color]::FromArgb(96, 94, 92) Font = [System.Drawing.Font]::new("Segoe UI", 8) } $y += 45 $form.Controls.Add($lblNote) } # Create OK button with styling and validation $okButton = New-Object System.Windows.Forms.Button -Property @{ Text = "OK" DialogResult = [System.Windows.Forms.DialogResult]::OK Location = [System.Drawing.Point]::new(290, ($y + 20)) Size = [System.Drawing.Size]::new(80, 30) BackColor = [System.Drawing.Color]::FromArgb(0, 103, 184) ForeColor = [System.Drawing.Color]::White FlatStyle = [System.Windows.Forms.FlatStyle]::Flat Font = [System.Drawing.Font]::new("Segoe UI", 9) Cursor = [System.Windows.Forms.Cursors]::Hand } $okButton.FlatAppearance.BorderSize = 0 # Add button hover effects $okButton.Add_MouseEnter({ $this.BackColor = [System.Drawing.Color]::FromArgb(0, 90, 158) }) $okButton.Add_MouseLeave({ $this.BackColor = [System.Drawing.Color]::FromArgb(0, 103, 184) }) # Validate required fields on OK click $okButton.Add_Click({ $isValid = $true $validationMessage = "" # Validate ticket if required if ($RequiresTicket) { $ticketText = $form.Controls["txtTicket"].Text.Trim() if ([string]::IsNullOrWhiteSpace($ticketText)) { $isValid = $false $validationMessage += "Ticket number is required.`n" } } # Validate justification if required if ($RequiresJustification -and $justificationControl -and [string]::IsNullOrWhiteSpace($justificationControl.Text)) { Show-TopMostMessageBox -Message "Justification is required for these roles." -Title "Validation Error" -Icon Warning $_.Cancel = $true return } if ($RequiresTicket -and $txtTicket -and [string]::IsNullOrWhiteSpace($txtTicket.Text)) { Show-TopMostMessageBox -Message "Ticket number is required for these roles." -Title "Validation Error" -Icon Warning $_.Cancel = $true return } if ($isValid) { # Set result values $result.Justification = if ($justificationControl) { $justificationControl.Text.Trim() } else { "" } if ($RequiresTicket) { $result.TicketNumber = $form.Controls["txtTicket"].Text.Trim() $result.TicketSystem = $cmbTicketSystem.SelectedItem.ToString() # Save ticket system preference Save-TicketSystemPreference -System $result.TicketSystem } $result.Cancelled = $false $form.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.Close() } else { Show-TopMostMessageBox -Message $validationMessage.TrimEnd() -Title "Validation Error" -Icon Warning } }) # Create Cancel button with styling $cancelButton = New-Object System.Windows.Forms.Button -Property @{ Text = "Cancel" DialogResult = [System.Windows.Forms.DialogResult]::Cancel Location = [System.Drawing.Point]::new(390, ($y + 20)) Size = [System.Drawing.Size]::new(80, 30) BackColor = [System.Drawing.Color]::White ForeColor = [System.Drawing.Color]::FromArgb(32, 31, 30) FlatStyle = [System.Windows.Forms.FlatStyle]::Flat Font = [System.Drawing.Font]::new("Segoe UI", 9) Cursor = [System.Windows.Forms.Cursors]::Hand } $cancelButton.FlatAppearance.BorderSize = 1 $cancelButton.FlatAppearance.BorderColor = [System.Drawing.Color]::FromArgb(200, 198, 196) $cancelButton.Add_MouseEnter({ $this.BackColor = [System.Drawing.Color]::FromArgb(245, 245, 245) }) $cancelButton.Add_MouseLeave({ $this.BackColor = [System.Drawing.Color]::White }) # Add controls and set form properties $form.Controls.AddRange(@($okButton, $cancelButton)) $form.AcceptButton = $okButton $form.CancelButton = $cancelButton # Ensure the form is brought to front and activated $form.Add_Shown({ $this.Activate() $this.BringToFront() $this.TopMost = $true $this.Focus() }) # Show dialog and process result $dialogResult = $form.ShowDialog() if ($dialogResult -eq [System.Windows.Forms.DialogResult]::OK) { if (($RequiresJustification -or $OptionalJustification) -and $justificationControl) { $result.Justification = if ([string]::IsNullOrWhiteSpace($justificationControl.Text)) { "PowerShell activation" } else { $justificationControl.Text } } if ($RequiresTicket -and $txtTicket -and -not [string]::IsNullOrWhiteSpace($txtTicket.Text)) { $result.TicketNumber = $txtTicket.Text } } else { $result.Cancelled = $true } $form.Dispose() return $result } function Get-SavedTicketSystem { <# .SYNOPSIS Retrieves the last used ticket system preference. .DESCRIPTION Gets the saved ticket system preference from the user's local profile. .OUTPUTS String - The saved ticket system name, or $null if not found. #> [CmdletBinding()] param() $prefsPath = Join-Path $env:LOCALAPPDATA "PIMActivation\preferences.json" if (Test-Path $prefsPath) { try { $prefs = Get-Content $prefsPath -Raw | ConvertFrom-Json return $prefs.TicketSystem } catch { Write-Verbose "Failed to load ticket system preference: $_" } } return $null } function Save-TicketSystemPreference { <# .SYNOPSIS Saves the user's ticket system preference. .PARAMETER System The ticket system name to save. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$System ) $prefsDir = Join-Path $env:LOCALAPPDATA "PIMActivation" $prefsPath = Join-Path $prefsDir "preferences.json" # Ensure directory exists if (-not (Test-Path $prefsDir)) { New-Item -ItemType Directory -Path $prefsDir -Force | Out-Null } try { # Load existing preferences or create new $prefs = if (Test-Path $prefsPath) { Get-Content $prefsPath -Raw | ConvertFrom-Json } else { [PSCustomObject]@{} } # Update ticket system $prefs | Add-Member -NotePropertyName TicketSystem -NotePropertyValue $System -Force # Save $prefs | ConvertTo-Json | Set-Content $prefsPath -Force Write-Verbose "Saved ticket system preference: $System" } catch { Write-Warning "Failed to save ticket system preference: $_" } } |