Public/Set-RpEventHandlers.ps1
function Set-RpEventHandlers { <# .SYNOPSIS Initializes and populates the EventHandlers property of the RemotePro object with predefined event handler scripts. .DESCRIPTION The Set-RpEventHandlers cmdlet sets up predefined event handlers for various operations in the RemotePro environment. These handlers are stored in the EventHandlers property, which is a hashtable that allows quick lookup and execution of event-specific scripts. Each handler is linked to an event (such as button clicks, text changes, or UI interactions) and defines the actions to be triggered when the event occurs. If the EventHandlers property does not exist or is not a hashtable, it is initialized as an empty hashtable. Each event handler is added to this hashtable as a key-value pair, where the key is the event name and the value is the scriptblock. Additionally, the EventHandlers hashtable is assigned a custom type 'RemotePro.EventHandlers' for easy identification and future use. .COMPONENT EventHandlers .PARAMETER None This cmdlet does not accept parameters. It simply initializes and populates the EventHandlers property with predefined event handlers. .EXAMPLE Set-RpEventHandlers This example initializes the EventHandlers hashtable and populates it with predefined event handlers. Each event is associated with a specific scriptblock to handle UI actions. .EXAMPLE Set-RpEventHandlers $handlers = $script:RemotePro.EventHandlers $handlers["OpenFile_Click"] This example sets up the EventHandlers property, retrieves all event handlers, and fetches the handler for the "OpenFile_Click" event. .EXAMPLE Set-RpEventHandlers $handler = $script:RemotePro.EventHandlers["NewConnectionFile_Click"] & $handler This example sets up the event handlers, retrieves the scriptblock for "NewConnectionFile_Click", and executes the scriptblock. .NOTES - The EventHandlers property is part of the RemotePro object and should be initialized with New-RpControllerObject before running this cmdlet. - This cmdlet does not return output unless errors occur during initialization or event handler assignment. - Event handlers are stored as scriptblocks in the EventHandlers hashtable and can be invoked based on user interactions. - See **New-RpControllerObject** and **Get-RpEventHandlers** .LINK https://www.remotepro.dev/en-US/Set-RpEventHandlers #> # Ensure RemotePro object is initialized if (-not $script:RemotePro) { Write-Error "RemotePro object is not initialized. Run New-RpControllerObject first." return } # If EventHandlers is null or not a hashtable, initialize it as an empty hashtable if ($null -eq $script:RemotePro.EventHandlers -or -not ($script:RemotePro.EventHandlers -is [hashtable])) { $script:RemotePro.EventHandlers = @{} Write-Verbose "Initialized EventHandlers as a hashtable." } # Define event handlers # ToDo: 02/09/2025 Cleanup output to console. Consider Wite-Verbose. $handlers = @{ #region Manage Connections NewConnectionFile_Click = { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { $templatePath = Join-Path -Path (New-RpAppDataPath) -ChildPath 'ConnectionFileTemplate.xlsx' if (Test-Path -Path $templatePath) { $confirmationResult = [System.Windows.MessageBox]::Show( "The file 'ConnectionFileTemplate.xlsx' already exists. Do you want to overwrite it?", "Confirm Overwrite", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Warning ) if ($confirmationResult -ne [System.Windows.MessageBoxResult]::Yes) { Write-Verbose "Operation canceled by user." return } } # Create a new connection file template Set-RpConnectionProfile -CreateTemplate -ExcelFilePath $templatePath $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog $openFileDialog.InitialDirectory = New-RpAppDataPath $openFileDialog.Filter = "Excel Sheet (*.xlsx)|*.xlsx|All files (*.*)|*.*" $openFileDialog.ShowDialog() $openFileDialog = $null } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } OpenFile_Click = { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog $openFileDialog.InitialDirectory = New-RpAppDataPath $openFileDialog.Filter = "Excel Sheet (*.xlsx)|*.xlsx|All files (*.*)|*.*" $result = $openFileDialog.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { $selectedFile = $openFileDialog.FileName [System.Windows.MessageBox]::Show("Selected file: $selectedFile") Get-RemoteProConnections -ConnectionFilePath $selectedFile } $openFileDialog = $null $selectedFile = $null } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } ConnectionsComboBox_SelectionChanged = { param($sender, $e) # Get the current selected item $script:selectedProfileName = $sender.SelectedItem } ExecuteCommand_Click = { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { $command = $CommandInput.Text try { # Execute the command entered in the TextBox $output = Invoke-Expression $command # Optionally, display the output or handle it as needed [System.Windows.MessageBox]::Show("Command executed. Output: `n$output") } catch { # Error handling [System.Windows.MessageBox]::Show("Error executing command: `n$($_.Exception.Message)") } } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } Connect_Click = { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { $queuedConnection = Get-RpConnectionProfile -name $script:selectedProfileName Connect-Vms -ServerAddress $queuedConnection.ServerAddress -Name $queuedConnection.Name -Credential $queuedConnection.Credential Clear-VmsCache $queuedConnection = $null # Helper function for updating textbox Set-RpLoadingMessageTextBox } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } Terminate_Click = { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Clear-VmsCache $script:Connection_Status_Box.Clear() #$Connection_Status_Box.Text = Get-Site | Format-List Disconnect-Vms Disconnect-ManagementServer Set-RpDefaultConnectionBox } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } CSB_TextChanged = { $textBox = $args[0] if ($textBox.Text -eq "Loading connection properties...") { $serverInfo = Get-RpConnectionsOverview # Update the TextBox content $script:Connection_Status_Box.Text = $serverInfo.Trim() } } ConnectionProfileListBox_SelectionChanged = { param($sender, $e) # Ensure that the event is only processed when there are selected profiles $selectedProfiles = $script:ConnectionProfileListBox.SelectedItems if ($selectedProfiles -and $selectedProfiles.Count -gt 0) { Write-Verbose "Selected profiles:" $script:selectedProfileDetails = @() # Clear the existing array foreach ($profile in $selectedProfiles) { $script:selectedProfileDetails += $profile # Add each selected profile to the array Write-Verbose " - $($profile.Name)" Write-Verbose "Full Details: `n$($profile.FullDetails)" } } else { # Only show "No profiles selected" if there was a previous selection and now there is none if ($script:selectedProfileDetails.Count -gt 0) { Write-Verbose "No profiles selected." } # Clear the selected profiles array $script:selectedProfileDetails = @() } } PopOutButton_Click = { if ($script:selectedProfileDetails.Count -gt 0) { foreach ($profile in $script:selectedProfileDetails) { Write-Verbose "Attempting to show profile details..." if ($profile.FullDetails) { Write-Verbose "FullDetails found, showing details..." [System.Windows.MessageBox]::Show($profile.FullDetails, "Profile Details", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information) } else { Write-Verbose "FullDetails is null or empty." } } # Refresh drop down connections. Get-RemoteProConnections } else { Write-Verbose "No profile selected." } } Connection_Profile_Refresh_Button_Click = { # Handle the Refresh button click Get-RpConnectionProfileRefresh } DeleteProfileButton_Click = { if ($script:selectedProfileDetails.Count -gt 0) { $confirmationResult = [System.Windows.MessageBox]::Show( "Are you sure you want to delete the selected profiles?", "Confirm Deletion", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Warning ) if ($confirmationResult -eq [System.Windows.MessageBoxResult]::Yes) { # Get the current collection bound to the ListBox $profilesCollection = [System.Collections.ObjectModel.ObservableCollection[object]]$script:ConnectionProfileListBox.ItemsSource # Remove selected profiles from the collection foreach ($profile in $script:selectedProfileDetails) { Write-Verbose "Deleting profile: $($profile.Name)" # Remove the profile using the appropriate command Remove-VmsConnectionProfile -Name $profile.Name # Remove the profile from the collection $profilesCollection.Remove($profile) } # Clear the selected profiles after deletion $script:selectedProfileDetails = @() # Refresh the ListBox ItemsSource $script:ConnectionProfileListBox.ItemsSource = $profilesCollection # Refresh drop down connections. Get-RemoteProConnections } else { Write-Verbose "Deletion canceled by user." } } else { Write-Verbose "No profile selected." } } AddProfileButton_Click = { # Logic to add a new profile Write-Verbose "Add Profile button clicked." # Clear existing items from the ComboBox $script:Connections_Combo_Box.Items.Clear() # Open dialog box to add connection profile Show-RpProfileEntryDialog [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { # Refresh connections box and connection profile list Get-RemoteProConnections } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } EditProfileButton_Click = { # Ensure that the event is only processed when there are selected profiles $selectedProfiles = $script:ConnectionProfileListBox.SelectedItems if ($selectedProfiles -and $selectedProfiles.Count -gt 0) { # Logic to add a new profile Write-Verbose "Edit Profile button clicked." # Open dialog box to add connection profile Show-RpProfileEntryDialog -Edit -SelectedProfile $script:selectedProfileDetails [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { # Refresh connections box and connection profile list Get-RemoteProConnections } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } else { Write-Verbose "No profiles selected." } } #endregion Manage Connections TAB #region Runspace TAB RunspaceMutexLog_TextChanged = { # Subscribe to Log tab TextChanged event (for logs) $script:runspace_mutex_log.ScrollToEnd() } #endregion Runspace TAB #region Configuration TAB # Configuration TAB > Main Settings RefreshSettings_Click = { Write-Verbose "Refreshing settings from disk file..." [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { # Logic to refresh settings from disk file Set-RpSettingsJson Write-Verbose "Settings refreshed from disk." # Refresh the ListBox ItemsSource Set-RpDefaultSettingsListView Write-Verbose "ListBox ItemsSource refreshed." } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } ResetSettings_Click = { Write-Verbose "Resetting settings to default values..." $confirmationResult = [System.Windows.MessageBox]::Show( "Are you sure you want to reset all settings to their default values?", "Confirm Reset", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Warning ) if ($confirmationResult -eq [System.Windows.MessageBoxResult]::Yes) { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Reset-RpSettingsJson Set-RpSettingsJson Set-RpDefaultSettingsListView Write-Verbose "Settings have been reset to default values." } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } else { Write-Verbose "Reset operation canceled by user." } } DeleteSetting_Click = { Write-Verbose "Deleting selected setting..." # Get the selected item $selectedSetting = $script:Settings.SelectedItem if ($selectedSetting) { $confirmationResult = [System.Windows.MessageBox]::Show( "Are you sure you want to delete '$($selectedSetting.Name)'?", "Confirm Deletion", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Warning ) if ($confirmationResult -eq [System.Windows.MessageBoxResult]::Yes) { Remove-RpSettingFromJson -Name $selectedSetting.Name Set-RpDefaultSettingsListView # Refresh UI Write-Verbose "Setting deleted: $($selectedSetting.Name)" } else { Write-Verbose "Deletion canceled." } } else { Write-Verbose "No setting selected." } } AddSetting_Click = { Write-Verbose "Adding a new setting..." Add-RpSettingToJson -ShowDialog [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Set-RpDefaultSettingsListView } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } EditSetting_Click = { Write-Verbose "Opening edit dialog..." Update-RpSettingsJson -ShowDialog [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Set-RpDefaultSettingsListView # Refresh UI after edit } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null } } # Configuration TAB > RemotePro Paths TAB ConfigurationTabs_SelectionChanged = { param($sender, $e) # Ensure the event is only processed when a tab is selected if ($e.Source -is [System.Windows.Controls.TabControl]) { $selectedTab = $sender.SelectedItem if ($selectedTab.Name -eq "RemoteProPaths") { try { Write-Verbose "Loading RemotePro module paths..." [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait $paths = @( [pscustomobject]@{ Command = "New-RpAppDataPath"; Path = New-RpAppDataPath }, [pscustomobject]@{ Command = "Get-RpSettingsJsonPath"; Path = Get-RpSettingsJsonPath }, [pscustomobject]@{ Command = "Get-RpIconPath"; Path = Get-RpIconPath }, [pscustomobject]@{ Command = "Get-RpLogPath"; Path = Get-RpLogPath }, [pscustomobject]@{ Command = "Get-RpConfigPath"; Path = Get-RpConfigPath }, [pscustomobject]@{ Command = "Get-RpConfigPath -DefaultIds"; Path = Get-RpConfigPath -DefaultIds } ) # Clear existing items from the ListBox $script:RemoteProPathsListBox.Items.Clear() # Add each path to the ListBox foreach ($path in $paths) { $script:RemoteProPathsListBox.Items.Add($path) } Write-Verbose "RemotePro module paths loaded successfully." } catch { Write-Verbose "Error loading RemotePro module paths: $_" } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } } } # Configuration TAB > ConfigCommands TAB RefreshConfigCommands_Click = { Write-Verbose "Refreshing ConfigCommands from disk file..." [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { # Refresh the ConfigCommands from the disk file Set-RpConfigCommands Write-Verbose "ConfigCommands refreshed from disk." # Refresh the DataGrid ItemsSource Set-RpDefaultConfigCommandsDataGrid Write-Verbose "DataGrid ItemsSource refreshed." } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } ResetConfigCommands_Click = { Write-Verbose "Resetting config commands to default settings..." $confirmationResult = [System.Windows.MessageBox]::Show( "Are you sure you want to reset the config commands to their default settings?", "Confirm Reset", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Warning ) if ($confirmationResult -eq [System.Windows.MessageBoxResult]::Yes) { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Reset-RpConfigCommandDefaults Set-RpDefaultConfigCommandsDataGrid Write-Verbose "Config commands have been reset to default settings." } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } else { Write-Verbose "Reset operation canceled by user." } } DeleteConfigCommands_Click = { Write-Verbose "Deleting selected ConfigCommand..." $selectedCommands = @($script:Commands | Where-Object { $_.CheckboxSelect -eq $true }) Write-Verbose "DEBUG: Found $($selectedCommands.Count) selected commands." foreach ($command in $selectedCommands) { Write-Verbose " - Command: $($command.CommandName), ID: $($command.Id), CheckboxSelect: $($command.CheckboxSelect)" } if ($selectedCommands.Count -gt 0) { $confirmationResult = [System.Windows.MessageBox]::Show( "Are you sure you want to delete the selected ConfigCommands?", "Confirm Deletion", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Warning ) if ($confirmationResult -eq [System.Windows.MessageBoxResult]::Yes) { foreach ($command in $selectedCommands) { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Remove-RpConfigCommand -CommandName $command.CommandName -Id $command.Id -Scope "ConfigCommand" } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } # Refresh config commands from disk to controller Set-RpDefaultConfigCommandsDataGrid Write-Verbose "ConfigCommands deleted successfully." } else { Write-Verbose "Deletion canceled by user." } } else { Write-Verbose "No ConfigCommand selected." } } AddConfigCommand_Click = { Write-Verbose "Adding a new ConfigCommand..." [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { # Logic to add a new ConfigCommand Add-RpConfigCommand Set-RpDefaultConfigCommandsDataGrid } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } EditConfigCommand_Click = { Write-Verbose "Editing selected ConfigCommand(s)..." $selectedCommands = @($script:Commands | Where-Object { $_.CheckboxSelect -eq $true }) if ($selectedCommands.Count -gt 0) { [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { foreach ($selectedCommand in $selectedCommands) { Update-RpConfigCommand -CommandName $selectedCommand.CommandName -Id $selectedCommand.Id -ShowDialog -ModuleName $selectedCommand.ModuleName } } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } # Refresh the DataGrid ItemsSource and UI [System.Windows.Input.Mouse]::OverrideCursor = [System.Windows.Input.Cursors]::Wait try { Set-RpDefaultConfigCommandsDataGrid } finally { [System.Windows.Input.Mouse]::OverrideCursor = $null # Reset the cursor } } else { Write-Verbose "Please select at least one ConfigCommand to edit." } } Commands_ScrollViewer_PreviewMouseWheel = { # Event handler for scrolling horizontally with Shift + Mouse Wheel param($sender, $e) # Check if Shift key is pressed if ([System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::LeftShift) -or [System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::RightShift)) { # Shift is pressed → Scroll Horizontally $scrollViewer = $sender if ($scrollViewer.HorizontalScrollBarVisibility -ne "Disabled") { $scrollViewer.ScrollToHorizontalOffset($scrollViewer.HorizontalOffset - $e.Delta) $e.Handled = $true # Prevent default vertical scrolling } } } TxtBox_FilterByName_TextChanged = { # Event handler for filtering commands by name param($sender, $e) $filterText = $sender.Text # DEBUG: Print filter text to verify filtering works Write-Verbose "DEBUG: Filtering with text: $filterText" # Apply filter to the Commands collection $script:FilteredCommands = @($script:Commands | Where-Object { $_.CommandName -like "*$filterText*" }) # DEBUG: Print the number of filtered commands Write-Verbose "DEBUG: Filtered commands count: $($script:FilteredCommands.Count)" # Update ItemsSource instead of modifying .Items $script:Commands_DataGrid.ItemsSource = $script:FilteredCommands } # Event Handler for Header Checkbox Click Commands_HeaderChkBox_Click = { param($chkBoxSender, $e) # Check if the header checkbox is checked or unchecked $isChecked = $chkBoxSender.IsChecked # Iterate through all rows in the DataGrid and set the checkbox state foreach ($item in $script:Commands) { if ($item.PSObject.Properties.Match('CheckboxSelect').Count -gt 0) { $item.CheckboxSelect = $isChecked Write-Verbose "Item: $($item.CommandName), CheckboxSelect: $isChecked" } } # Refresh DataGrid to reflect changes $script:Commands_DataGrid.Items.Refresh() Write-Verbose "Header checkbox state changed to: $isChecked" } Commands_DataGrid_CheckBox_Click = { param($clickedItem) # DEBUG: Print what was received as $clickedItem Write-Verbose "DEBUG: Clicked item type: $($clickedItem.GetType().FullName)" # Ensure clickedItem is valid if ($null -eq $clickedItem) { Write-Verbose "ERROR: Clicked item's DataContext is null!" return } # Ensure 'CheckboxSelect' property exists if ($clickedItem.PSObject.Properties.Match('CheckboxSelect').Count -eq 0) { Write-Verbose "WARNING: Adding missing 'CheckboxSelect' property to item: $clickedItem" $clickedItem | Add-Member -MemberType NoteProperty -Name 'CheckboxSelect' -Value $false -Force } # Toggle checkbox state $clickedItem.CheckboxSelect = -not $clickedItem.CheckboxSelect # DEBUG: Print state of clicked item Write-Verbose "DEBUG: Item Updated -> Command: $($clickedItem.CommandName), CheckboxSelect: $($clickedItem.CheckboxSelect)" # DEBUG: Verify that $script:Commands contains the expected objects Write-Verbose "DEBUG: Checking state of all commands:" foreach ($item in $script:Commands) { Write-Verbose " - Command: $($item.CommandName), CheckboxSelect: $($item.CheckboxSelect)" } # Check if all checkboxes are checked $script:AllItemsChecked = ($script:Commands | Where-Object { -not $_.CheckboxSelect }).Count -eq 0 $script:Commands_HeaderChkBox.IsChecked = $script:AllItemsChecked # DEBUG: Print final state of header checkbox Write-Verbose "DEBUG: Header checkbox updated to: $script:AllItemsChecked" } #endregion Configuration TAB #region Help, About, and Toolbar GithubRepositoryButton_Click = { Write-Verbose "Opening Remotepro GitHub repository webpage..." Start-Process "https://github.com/codypaternostro/RemotePro" } PowerShellGalleryButton_Click = { Write-Verbose "Opening RemotePro package PowerShell Gallery webpage." Start-Process "https://www.powershellgallery.com/packages/RemotePro" } DocsSiteButton_Click = { Write-Verbose "Opening DocsSite home webpage." Start-Process "https://www.remotepro.dev" } FlowDirectionToggleButton_Click = { Write-Verbose "Toggling flow direction..." if ($Window.FlowDirection -eq [System.Windows.FlowDirection]::LeftToRight) { $Window.FlowDirection = [System.Windows.FlowDirection]::RightToLeft Write-Verbose "Switched to Right-To-Left layout." } else { $Window.FlowDirection = [System.Windows.FlowDirection]::LeftToRight Write-Verbose "Switched to Left-To-Right layout." } } ReportIssueButton_Click = { Write-Verbose "Opening GitHub Issues webpage." Start-Process "https://github.com/codypaternostro/RemotePro/issues" } LicenseInformationButton_Click = { Write-Verbose "Opening GitHub License webpage." Start-Process "https://github.com/codypaternostro/RemotePro/blob/main/LICENSE" } AboutButton_Click = { Write-Verbose "Opening About webpage." Start-Process "https://www.remotepro.dev/getting-started/usageguide/" } #endregion Help, About, and Toolbar #region Main Window Window_AddClosed_Click = { try { #[System.Windows.Application]::Current.Shutdown() # Ensure the application is shut down properly # Dispose and close runspaces that are closed by monitor-runspaces (intentional) $script:RpOpenRunspaces | % { $runspaceId = $script:RpOpenRunspaces.Jobs.RunspaceId $runspace = Get-Runspace -InstanceId $runspaceId $runspace.Dispose() $runspace.Close() } $script:RpOpenRunspaces = $null # Dispose and close runspaces that may have been hung up (thorough cleanup) Get-Runspace | ? Id -NotLike 1 | % { $_.Dispose() $_.Close() } # Generate a log entry for job removal $logAddJobText = "Runspace timer stopped and additional runspaces removed successfully." $timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") $logAddJobMessage = "$timestamp - INFO - $logAddJobText." # UI and Log message update Set-RpMutexLogAndUI -logPath $logPath -message $logAddJobMessage -uiElement $script:Runspace_Mutex_Log Write-Verbose "$logAddJobMessage" } catch { # Generate a log entry for job removal $logAddJobErrorText = "Error closing main window: $_" $timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") $logAddJobMessage = "$timestamp - ERROR - $logAddJobErrorText." # UI and Log message update Set-RpMutexLogAndUI -logPath $logPath -message $logAddJobMessage -uiElement $script:Runspace_Mutex_Log Write-Verbose "$logAddJobErrorMessage" } finally { $script:xmlreader = $null $script:window.Close() $script:window = $null #Start-Sleep 5 -Seconds # wait for last tick # Stop and discard timer using Monitor-Runspace if ($script:RunspaceCleanupTimer -and $script:RunspaceCleanupTimer.Enabled) { $script:RunspaceCleanupTimer.Stop() $script:RunspaceCleanupTimer.Dispose() } if ($script:KillRemoteProOnExit) { [System.Environment]::Exit(0) } } } #endregion Main Window } # Add the event handler to the EventHandlers hashtable foreach ($key in $handlers.Keys) { # Add each handler to the hashtable, overwriting if it already exists $script:RemotePro.EventHandlers[$key] = $handlers[$key] } # Attach a custom type to EventHandlers $script:RemotePro.EventHandlers.PSTypeNames.Insert(0, 'RemotePro.EventHandlers') Write-Verbose "Event Handlers have been successfully added to RemotePro.EventHandlers." } |