Launch-ExchangeServerComponentStateChecker.ps1
<#PSScriptInfo
.VERSION 1.6.4 .GUID 97217c9e-9c65-471c-9c2f-18a839603eb2 .AUTHOR SammyKrosoft .COMPANYNAME #> <# .SYNOPSIS This is a WPF GUI that helps to check and bring Exchange Server components to active state. .DESCRIPTION This is a WPF GUI that helps to check and bring Exchange Server components to active state. You can list components and filter to view only inactive components, and choose the requester with which you wish to start one or more inactive components. More information here: https://github.com/SammyKrosoft/Start-E2016ServerComponentsCheck .NOTES See https://github.com/SammyKrosoft for Readme.md and screenshots... .LINK https://github.com/SammyKrosoft #> $language = "EN" $Version = "v1.6.4" <#Change history - v1.6.4 - added Github link in description - v1.6.3 - added PSScriptInfo and update Description for PSGallery publishing - v1.6.2 added | out-null after test-ExchTools Exchange tool checker call - v1.6.1 added GUI error message when Exchange tools not present - v1.6 Excluded Edge servers for cases when Edge are installed on the AD forest instead of the recommended DMZ (??) Added HealthAPI requester - v1.5.4 Add maple leaf as icon - v1.5.3 Add about (hidden) - v1.5.2 Added version number in Title - v1.5.1 Deactivate the form while running Reactivate the form while running - v1.5: Added ability to filter by server or display for all servers (# Servers...) Added basic stats (# active components / # inactive components) - v1: First published version #> Function IsPSV3 { <# .DESCRIPTION Just printing Powershell version and returning "true" if powershell version is Powershell v3 or more recent, and "false" if it's version 2. .OUTPUTS Returns $true or $false .EXAMPLE IsPSVersionV3 #> $PowerShellMajorVersion = $PSVersionTable.PSVersion.Major $msgPowershellMajorVersion = "You're running Powershell v$PowerShellMajorVersion" Write-Host $msgPowershellMajorVersion -BackgroundColor blue -ForegroundColor yellow If($PowerShellMajorVersion -le 2){ Write-Host "Sorry, PowerShell v3 or more is required. Exiting." Return $false Exit } Else { Write-Host "You have PowerShell v3 or later, great !" -BackgroundColor blue -ForegroundColor yellow Return $true } } Function Update-ListView { if ($Global:GlobalResult -ne $null){ if ($wpf.chkInactiveOnly.isChecked){ if ($wpf.comboBoxServers.selectedValue -eq $Global:FirstComboBoxServersValue){ $wpf.ListView.ItemsSource = $Global:GlobalResult | ? {$_.State -eq "Inactive"} } Else { $wpf.ListView.ItemsSource = $Global:GlobalResult | ? {$_.State -eq "Inactive" -and $_.Server -eq $($wpf.comboBoxServers.SelectedValue)} } } Else { if ($wpf.comboBoxServers.selectedValue -ne $Global:FirstComboBoxServersValue){ $wpf.ListView.ItemsSource = $Global:GlobalResult | ? {$_.Server -eq $($wpf.comboBoxServers.SelectedValue)} } Else { $wpf.ListView.ItemsSource = $Global:GlobalResult} } $TotalNbActiveComponents = ($wpf.ListView.ItemsSource | ? {$_.State -eq "Active"}).count $TotalNbInactiveComponents = ($wpf.ListView.ItemsSource | ? {$_.State -eq "Inactive"}).count $wpf.txtNbActiveComponents.text = $TotalNbActiveComponents $wpf.txtNbInactiveComponents.text = $TotalNbInactiveComponents } } Function Test-ExchTools(){ <# .SYNOPSIS This small function will just check if you have Exchange tools installed or available on the current PowerShell session. .DESCRIPTION The presence of Exchange tools are checked by trying to execute "Get-ExBanner", one of the basic Exchange cmdlets that runs when the Exchange Management Shell is called. Just use Test-ExchTools in your script to make the script exit if not launched from an Exchange tools PowerShell session... .EXAMPLE Test-ExchTools => will exit the script/program si Exchange tools are not installed #> Try { Get-command Get-MAilbox -ErrorAction Stop $ExchInstalledStatus = $true $Message = "Exchange tools are present !" Write-Host $Message -ForegroundColor Blue -BackgroundColor Red } Catch [System.SystemException] { $ExchInstalledStatus = $false $Message = "Exchange Tools are not present ! This script/tool need these. Exiting..." Write-Host $Message -ForegroundColor red -BackgroundColor Blue # Add-Type -AssemblyName presentationframework, presentationcore # Option #4 - a message, a title, buttons, and an icon # More info : https://msdn.microsoft.com/en-us/library/system.windows.messageboximage.aspx $msg = "You must run this tool from an Exchange-enabled PowerShell console like Exchange Management Console or a PowerShell session where you imported an Exchange session." $Title = "Error - No Exchange Tools available !" $Button = "Ok" $Icon = "Error" [System.Windows.MessageBox]::Show($msg,$Title, $Button, $icon) Exit } Return $ExchInstalledStatus } Function Title1 ([string]$title, $TotalLength = 100, $Back = "Yellow", $Fore = "Black") { $TitleLength = $Title.Length [string]$StarsBeforeAndAfter = "" $RemainingLength = $TotalLength - $TitleLength If ($($RemainingLength % 2) -ne 0) { $Title = $Title + " " } $Counter = 0 For ($i=1;$i -le $(($RemainingLength)/2);$i++) { $StarsBeforeAndAfter += "*" $counter++ } $Title = $StarsBeforeAndAfter + $Title + $StarsBeforeAndAfter Write-host Write-Host $Title -BackgroundColor $Back -foregroundcolor $Fore Write-Host } Function StatusLabel { [CmdletBinding()] Param( [parameter(Position = 1)][string]$msg, [parameter(Position = 2)][string]$LabelObjectName = "lblStatus" ) # Trick to enable a Label to update during work : # Follow with "Dispatcher.Invoke("Render",[action][scriptblobk]{})" or [action][scriptblock]::create({}) $wpf.$LabelObjectName.Content = $Msg $wpf.$FormName.Dispatcher.Invoke("Render",[action][scriptblock]{}) } Function Update-WPFProgressBarAndStatus { Param( [parameter(Position = 1)][string]$msg="Message", [parameter(Position=2)][int]$p=50, [parameter(Position = 3)][string]$status="Working...", [parameter(position = 4)][string]$color = "#FFC310BB", [parameter(position = 5)][string]$ProgressBarName = "ProgressBar") $wpf.$ProgressBarName.Foreground = $Color $wpf.$ProgressBarName.Value = $p Title1 $msg; StatusLabel $msg If ($p -eq 100){ $status = "Done!" } Write-progress -Activity $msg -Status $status -PercentComplete $p } Function Check-E2016ComponentStateToActive { <# .NOTES Based on V1.1 08.06.2014 by Adnan Rafique @ExchangeITPro Modified by Samuel Drey @Microsoft V1 10.OCT.2018 .SYNOPSIS Bring Exchange components to active state. .DESCRIPTION Bring Exchange components to active state. .PARAMETER HybridServer Indicates to check 2 additional Server Components that are important for Office 365 synchronization between the On-premises environment and the Exchange Online environment : "ForwardSyncDaemon" and "ProvisioningRps". .PARAMETER CheckOnly Indicated the script to only check which Components are inactive before attempting anything. .EXAMPLE .\Start-E2016ServerComponentStateToActive.ps1 -HybridServer -CheckOnly Will check all Server Components, including ForwardSyncDaemon and ProvisioningRps components, but won't attempt to start these. .EXAMPLE .\Start-E2016ServerComponentStateToActive.ps1 Will check all Server Components, excluding the ForwardSyncDaemon and ProvisioningRps, and attempt to start these. The script will tell you if the operation was successful or not. .EXAMPLE .\Start-E2016ServerComponentStateToActive.ps1 -HybridServer Will check and try to start all Server Components, including ForwardSyncDaemon and ProvisioningRps .EXAMPLE .\Start-E2016ServerComponentStateToActive.ps1 -CheckOnly Will check all Server Components, excluding ForwardSyncDaemon and ProvisioningRps components, but won't attept to start these. .LINK https://blogs.technet.microsoft.com/exchange/2012/09/21/lessons-from-the-datacenter-managed-availability/ #> #Requires -version 3.0 [CmdletBinding()] Param( [Parameter(Mandatory = $false)][switch]$HybridServer, [Parameter(Mandatory = $false)][switch]$CheckOnly ) If ($CheckOnly) { Title1 "Check only specified - will just list inactive components without trying to activate ..." } Else { Title1 "CheckOnly NOT specified ... will try to activate everything if more than 2 components are inactive..." } $msg = "Getting Exchange servers in the current organization ..." $p = 0 Update-WPFProgressBarAndStatus $msg $p $ExchangeNamesList = @() if ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2016"){ $ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15.1" -and -not ($_.ServerRole -match "Edge")} } Else { $ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15.0" -and -not ($_.ServerRole -match "Edge")} } If ($ExchangeServers -eq $null) { # Option #4 - a message, a title, buttons, and an icon # More info : https://msdn.microsoft.com/en-us/library/system.windows.messageboximage.aspx $msg = "No $($wpf.comboSelectExchangeVersion.Text) servers found ... Try another Exchange version..." $Title = "Error - No servers found !" $Button = "Ok" $Icon = "Error" [System.Windows.MessageBox]::Show($msg,$Title, $Button, $icon) Return } Else { $ServerCount = $ExchangeServers.Count $Global:FirstComboBoxServersValue = "$ServerCount Servers..." $wpf.comboBoxServers.Items.Clear() $wpf.comboBoxServers.AddChild($Global:FirstComboBoxServersValue) Foreach ($Server in $ExchangeServers){ $wpf.comboBoxServers.AddChild($($Server.Name)) } $wpf.comboBoxServers.SelectedVAlue = $Global:FirstComboBoxServersValue } Foreach ($item in $ExchangeServers){$ExchangeNamesList += $($item.Name)} $msg = "$($ExchangeServers.count) servers found ... parsing each Exchange server ..." $p = 20 Update-WPFProgressBarAndStatus $msg $p $ServerComponentsCollection = @() $counter = 0 $Counter2 = 0 Foreach ($Server in $ExchangeServers){ Title1 $Server write-progress -id 1 -Activity "Activating all components" -Status "Server $Server" -PercentComplete $($Counter/$($ExchangeServers.Count)*100) $msg = "Parsing $($Server.name) server ..." $p = 20 + $Counter2 Update-WPFProgressBarAndStatus $msg $p $Counter++ $Counter2+=((100-20)/$($ExchangeServers.count)) #Get the status of components If (!($HybridServer)){ Write-Host "You didn't specify the -HybridServer switch, meaning that this is an On-Premises only environment (aka not Hybrid, not synchronizing with the cloud). We don't need ForwardSyncDaemon and ProvisioningRPS Components - leaving these as-is" $ComponentStateStatus = Get-ServerComponentState ($Server.Name) | ? {$_.Component -ne "ForwardSyncDaemon" -and $_.Component -ne "ProvisioningRps"} } Else { Write-Host "You specified the -HybridServer parameter, indicating that this is an On-Premises environment syncinc with O365. All Server Components need to be active..." $ComponentStateStatus = Get-ServerComponentState ($Server.Name) } #$ComponentStateStatus | ft Component,State -Autosize $InactiveComponents = $ComponentStateStatus | ? {$_.State -eq "Inactive"} $ACtiveComponents = $ComponentStateStatus | ? {$_.State -eq "Active"} $NbActiveComponents = $ACtiveComponents.Count If ($NbActiveComponents -eq $null){$NbActiveComponents = 0} $NbInactiveComponents = $InactiveComponents.Count If ($NbInactiveComponents -eq $null){$NbInactiveComponents = 0} Write-Host "There are $NbActiveComponents active components, and $NbInactiveComponents inactive components on server $($Server.Name)" -BackgroundColor yellow -ForegroundColor red If ($NbInactiveComponents -eq 0){ Write-Host "There are no inactive components, everything looks good ... " $ServerComponentsCollection += $ComponentStateStatus Continue } Else { Write-host "Some components are not active - we have $NbInactiveComponents inactive components..." $InactiveComponents | ft Component If (!($CheckOnly)){ Write-host "... trying to re-activate all inactive components..." $Counter1 = 0 Foreach ($Component in $InactiveComponents) { Write-progress -id 2 -ParentId 1 -Activity "Setting component states" -Status "setting $($Component.Component)..." -PercentComplete ($Counter1/$NbInactiveComponents*100) $Requester = $wpf.comboBoxRequester.Text $Command = "Set-ServerComponentState $($Server.Name) -Component $($Component.Component) -State Active -Requester $Requester" Write-host "Running the following command: `n$Command" -BackgroundColor Blue -ForegroundColor White Invoke-Expression $Command $Counter1++ } #Get the new status of components If (!($HybridServer)){ Write-Host "You didn't specify the -HybridServer switch, meaning that this is an On-Premises only environment (aka not Hybrid, not synchronizing with the cloud). We don't need ForwardSyncDaemon and ProvisioningRPS Components - leaving these as-is" $ComponentStateStatus = Get-ServerComponentState ($Server.Name) | ? {$_.Component -ne "ForwardSyncDaemon" -and $_.Component -ne "ProvisioningRps"} } Else { Write-Host "You specified the -HybridServer parameter, indicating that this is an On-Premises environment syncinc with O365. All Server Components need to be active..." $ComponentStateStatus = Get-ServerComponentState ($Server.Name) } #$ComponentStateStatus | ft Component,State -Autosize $InactiveComponents = $ComponentStateStatus | ? {$_.State -eq "Inactive"} $ACtiveComponents = $ComponentStateStatus | ? {$_.State -eq "Active"} $NbActiveComponents = $ACtiveComponents.Count If ($NbActiveComponents -eq $null){$NbActiveComponents = 0} $NbInactiveComponents = $InactiveComponents.Count If ($NbInactiveComponents -eq $null){$NbInactiveComponents = 0} Write-Host "There are now $NbActiveComponents active components, and $NbInactiveComponents inactive components" If ($NbInactiveComponents -eq 0) {Write-Host "$Server is now completely out of maintenance mode and component are active and functional." -ForegroundColor Yellow} Else {Write-host "There are still some inactive components ... please troubleshoot !" -BackgroundColor Red -ForegroundColor Yellow} } Else { Write-Host "Checking only... here's your list of inactive components:" $InactiveComponents | ft Component } $ServerComponentsCollection += $ComponentStateStatus } } $msg = "All servers done ..." $p = 100 Update-WPFProgressBarAndStatus $msg $p write-progress -id 1 -Activity "Activating all components" -Status "All done !" -PercentComplete $($Counter/$($ExchangeServers.Count)*100) #sleep 1 $PSObjectServerComponentsColl = @() $ServerComponentsCollection | Foreach { $PSObjectSrvComp = [PSCustomObject]@{ Server = $_.Identity Component = $_.Component State = $_.State } $PSObjectServerComponentsColl += $PSObjectSrvComp } $wpf.ListView.ItemsSource = $PSObjectServerComponentsColl $TotalNbActiveComponents = ($wpf.ListView.ItemsSource | ? {$_.State -eq "Active"}).count $TotalNbInactiveComponents = ($wpf.ListView.ItemsSource | ? {$_.State -eq "Inactive"}).count $wpf.txtNbActiveComponents.text = $TotalNbActiveComponents $wpf.txtNbInactiveComponents.text = $TotalNbInactiveComponents $Global:GlobalResult = $PSObjectServerComponentsColl return $PSObjectServerComponentsColl } $lblabout_Click = { switch ($Language) { "EN" { $systemst = "QXV0aG9yOiBTYW0gRHJleQ0Kc2FtZHJleUBtaWNyb3NvZnQuY29tDQpzYW1teUBob3RtYWlsLmZyDQpNaWNyb3NvZnQgRW` 5naW5lZXIgc2luY2UgT2N0IDE5OTkNCjE5OTktMjAwMDogUHJlc2FsZXMgRW5naW5lZXIgKEZyYW5jZSkNCjIwMDAtMjAwMzogU3VwcG9yd` CBFbmdpbmVlciAoRnJhbmNlKQ0KMjAwMy0yMDA2OiB2ZXJ5IGZpcnN0IFBGRSBpbiBGcmFuY2UNCjIwMDYtMjAwOTogTUNTIENvbnN1bHRhb` nQgKEZyYW5jZSkNCjIwMDktMjAxMDogVEFNIChGcmFuY2UpDQoyMDEwLW5vdyA6IENvbnN1bHRhbnQgKENhbmFkYSkNCk11c2ljaWFuLCBjb` 21wb3NlciAoS2V5Ym9hcmQsIEd1aXRhcikNClBsYW5lIHBpbG90IHNpbmNlIDE5OTUNCkZvciBTaGFyZWQgU2VydmljZXMgQ2FuYWRh" } "FR" { $systemst = "QXV0ZXVyOiBTYW0gRHJleQ0Kc2FtZHJleUBtaWNyb3NvZnQuY29tDQpzYW1teUBob3RtYWlsLmZyDQpJbmfDqW5pZXVyIGNo` ZXogTWljcm9zb2Z0IGRlcHVpcyBPY3QgMTk5OQ0KMTk5OS0yMDAwOiBJbmfDqW5pZXVyIEF2YW50LVZlbnRlIChGcmFuY2UpDQoyMDAwLTIwMD` M6IFNww6ljaWFsaXN0ZSBUZWNobmlxdWUgKEZyYW5jZSkNCjIwMDMtMjAwNjogUHJlbWllciBQRkUgZW4gRnJhbmNlDQoyMDA2LTIwMDk6IENv` bnN1bHRhbnQgTUNTIChGcmFuY2UpDQoyMDA5LTIwMTA6IFJlc3BvbnNhYmxlIFRlY2huaXF1ZSBkZSBDb21wdGUgKEZyYW5jZSkNCjIwMTAtMjA` xNiA6IENvbnN1bHRhbnQgKENhbmFkYSkNCk11c2ljaWVuLCBjb21wb3NpdGV1ciAoQ2xhdmllciwgR3VpdGFyZSkNCkJyZXZldCBkZSBQaWxvdGU` gUHJpdsOpIGRlcHVpcyAxOTk1DQpQb3VyIFNlcnZpY2VzIFBhcnRhZ8OpcyBDYW5hZGE=" } } $systemst = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($systemst)) # Option #4 - a message, a title, buttons, and an icon # More info : https://msdn.microsoft.com/en-us/library/system.windows.messageboximage.aspx $msg = $systemst $Title = $wpf.$FormName.Title $Button = "Ok" $Icon = "Information" [System.Windows.MessageBox]::Show($msg,$Title, $Button, $icon) } Function Run-Command { $Command = "Check-E2016ComponentStateToActive" if ($wpf.chkCheckOnly.IsChecked -eq $true) { $Command += " -CheckOnly" } if ($wpf.chkHybridServer.IsChecked -eq $true){ $Command += " -HybridServer" } Invoke-Expression $Command $msg = "Ready !" $p = 0 Update-WPFProgressBarAndStatus $msg $p } #First check for PowerShell version ... if PowerShell <v3, exit IsPSV3 | out-null # Load a WPF GUI from a XAML file build with Visual Studio Add-Type -AssemblyName presentationframework, presentationcore #Immediately test for Exchange tools => if not loaded, exit script Test-ExchTools | out-null $wpf = @{ } # NOTE: Either load from a XAML file or paste the XAML file content in a "Here String" #$inputXML = Get-Content -Path ".\WPFGUIinTenLines\MainWindow.xaml" $inputXML = @" <Window x:Name="frmCheckServerComponents" x:Class="Check_E2016ServerComponents.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Check_E2016ServerComponents" mc:Ignorable="d" Title="Exchange Server Components Checker" Height="513.689" Width="800" ResizeMode="NoResize"> <Grid> <ComboBox x:Name="comboSelectExchangeVersion" HorizontalAlignment="Left" Margin="10,124,0,0" VerticalAlignment="Top" Width="120" SelectedIndex="1" IsReadOnly="True"> <ComboBoxItem Content="Exchange 2013"/> <ComboBoxItem Content="Exchange 2016"/> </ComboBox> <CheckBox x:Name="chkCheckOnly" Content="CheckOnly" HorizontalAlignment="Left" Margin="10,151,0,0" VerticalAlignment="Top" IsChecked="True"/> <TextBox HorizontalAlignment="Left" Height="79" Margin="144,10,0,0" TextWrapping="Wrap" Text="Exchange 2013/2016 Server Component Checker" VerticalAlignment="Top" Width="518" TextAlignment="Center" VerticalContentAlignment="Center" FontSize="20" FontWeight="Bold" IsReadOnly="True"> <TextBox.Effect> <DropShadowEffect ShadowDepth="10" Color="#FFACD151"/> </TextBox.Effect> </TextBox> <Button x:Name="btnRun" Content="Run" HorizontalAlignment="Left" Margin="12,357,0,0" VerticalAlignment="Top" Width="74"/> <Button x:Name="btnQuit" Content="Quit" HorizontalAlignment="Left" Margin="681,380,0,0" VerticalAlignment="Top" Width="75"/> <Label Content="List of Exchange components and their state" HorizontalAlignment="Left" Margin="251,168,0,0" VerticalAlignment="Top" Width="246"/> <CheckBox x:Name="chkHybridServer" Content="HybridServer" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,171,0,0"/> <ProgressBar x:Name="ProgressBar" HorizontalAlignment="Left" Height="28" Margin="10,441,0,0" VerticalAlignment="Top" Width="762"/> <Label x:Name="lblStatus" Content="Ready !" HorizontalAlignment="Left" Margin="12,409,0,0" VerticalAlignment="Top" Width="760"/> <CheckBox x:Name="chkInactiveOnly" Content="Show Inactive Only" HorizontalAlignment="Left" Margin="612,174,0,0" VerticalAlignment="Top"/> <DataGrid x:Name="ListView" HorizontalAlignment="Left" Height="144" Margin="10,200,0,0" VerticalAlignment="Top" Width="746" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Server}" Header="Server"/> <DataGridTextColumn Binding="{Binding Component}" Header="Component"/> <DataGridTextColumn Binding="{Binding State}" Header="State"/> </DataGrid.Columns> </DataGrid> <ComboBox x:Name="comboBoxRequester" HorizontalAlignment="Left" Margin="198,357,0,0" VerticalAlignment="Top" Width="120" SelectedIndex="2" IsEnabled="False"> <ComboBoxItem Content="Maintenance"/> <ComboBoxItem Content="Sidelined"/> <ComboBoxItem Content="Functional"/> <ComboBoxItem Content="Deployment"/> <ComboBoxItem Content="HealthAPI"/> </ComboBox> <Label x:Name="lblRequester" Content="Requester:" HorizontalAlignment="Left" Margin="121,357,0,0" VerticalAlignment="Top" Width="72"/> <ComboBox x:Name="comboBoxServers" HorizontalAlignment="Left" Margin="612,124,0,0" VerticalAlignment="Top" Width="120"/> <TextBlock x:Name="txtNbActiveComponents" HorizontalAlignment="Left" Margin="564,357,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top" Width="62"/> <TextBlock x:Name="txtNbInactiveComponents" HorizontalAlignment="Left" Margin="564,378,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top" Width="62"/> <Label Content="Nb of active componnents:" HorizontalAlignment="Left" Margin="396,352,0,0" VerticalAlignment="Top"/> <Label Content="Nb of inactive componnents:" HorizontalAlignment="Left" Margin="396,373,0,0" VerticalAlignment="Top"/> <Rectangle HorizontalAlignment="Left" Height="47" Margin="396,352,0,0" VerticalAlignment="Top" Width="230"> <Rectangle.Stroke> <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ActiveBorderColorKey}}"/> </Rectangle.Stroke> </Rectangle> <Label Content="Servers found ->" HorizontalAlignment="Left" Margin="507,122,0,0" VerticalAlignment="Top" Width="100"/> <Rectangle HorizontalAlignment="Left" Height="29" Margin="245,167,0,0" VerticalAlignment="Top" Width="255"> <Rectangle.Stroke> <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ActiveBorderColorKey}}"/> </Rectangle.Stroke> </Rectangle> <Label x:Name="lblabout" Content="." HorizontalAlignment="Center" Margin="774,0,0,0" VerticalAlignment="Top" Width="20" Height="24" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/> </Grid> </Window> "@ $inputXMLClean = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace 'x:Class=".*?"','' -replace 'd:DesignHeight="\d*?"','' -replace 'd:DesignWidth="\d*?"','' [xml]$xaml = $inputXMLClean $reader = New-Object System.Xml.XmlNodeReader $xaml $tempform = [Windows.Markup.XamlReader]::Load($reader) $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") $namedNodes | ForEach-Object {$wpf.Add($_.Name, $tempform.FindName($_.Name))} #Get the form name to be used as parameter in functions external to form... $FormName = $NamedNodes[0].Name #extra added on v1.5.4 - maple leaf encoding $base64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYYAAB2GAV2iE4EAAAIOSURBVFhHvZfBTsJAEIZ/DG/gE4iJ0RAPJvIAkHD0ATzrA8gD4AUvJN6MMR54BB/AizfPPXgxMehVoyRgCKAhWWfcabq2pd3uIl/yl9nZ2ZntlJZSUgRcubsDSiWgXhdHcfw2wMUZjxRr8lmciwsxCNMuiHsHwrMPcUxj14HHR6DZlAFxeCiGgenjWF5jA3fACn2OSm1tRXZc5pwl9pHb21HyPHGsJfZfwiK3WoHYxRt4exNDaDTEsCAeG89lIp1IUi4rdX0tA+LjI73daeLYEM7BuRYA1e/rRQcHSp2fKxUESr2+RslubiSUCH15CuG1oY9zcm6uwbXYR7V1dBi0SLe3v2GqVkufN7W/r2N5Tdq8KUIfj4+Tk3FdXSm1vp4+Z4pjODZtzhTXJMgi7u+TAf8trklEj+L4o/W/kbJrGI+Bk5PfwUrhmlxbtdt/W7NKUW06EuGtuEpxTYIsg2o1GbhscQ0D8sTodJKLlqWzMykSQd4Unp6Si33FOVOgmQx2dpKJiopzZJD/Sub7fMhJn/0+kPUzaktOjuwOtNtArwfs7QEbG0ClorW5CezuAt0u8PUFnJ4CDw9Avw88P2u9vABBABwdAZ2OJEzi/lbMXF4C399AqyWO4rj/L2De34HPTxm44beB0QiYTmXght8GJhN9CTzw28BgAMznMnDDvwOzmQzc8NvAcKg34QzwAxxYrwxNP4cjAAAAAElFTkSuQmCC" # Create a streaming image by streaming the base64 string to a bitmap streamsource $bitmap = New-Object System.Windows.Media.Imaging.BitmapImage $bitmap.BeginInit() $bitmap.StreamSource = [System.IO.MemoryStream][System.Convert]::FromBase64String($base64) $bitmap.EndInit() $bitmap.Freeze() # This is the icon in the upper left hand corner of the app $wpf.$FormName.Icon = $bitmap #Define events functions #region Load, Draw (render) and closing form events #Things to load when the WPF form is loaded aka in memory $wpf.$FormName.Add_Loaded({ #Update-Cmd if ($wpf.chkCheckOnly.IsChecked -eq $true){ $wpf.comboBoxRequester.IsEnabled = $false } Else { $wpf.comboBoxRequester.IsEnabled = $True } $wpf.$FormName.Title += " - $Version" }) #Things to load when the WPF form is rendered aka drawn on screen $wpf.$FormName.Add_ContentRendered({ #Update-Cmd }) $wpf.$FormName.add_Closing({ $msg = "bye bye !" write-host $msg }) #endregion Load, Draw and closing form events #End of load, draw and closing form events #region Buttons $wpf.btnRun.add_Click({ $wpf.$FormName.IsEnabled = $false $wpf.ListView.ItemsSource= $null Run-Command Update-ListView $wpf.$FormName.IsEnabled = $true }) $wpf.btnQuit.add_Click({ $wpf.$FormName.Close() }) $wpf.lblAbout.Add_MouseLeftButtonDown($lblabout_Click) #endregion #End Buttons region #region Checkboxes $wpf.chkInactiveOnly.add_Click({ Update-ListView }) $wpf.chkCheckOnly.add_Click({ if ($wpf.chkCheckOnly.IsChecked){ $wpf.comboBoxRequester.IsEnabled = $false } Else { $wpf.comboBoxRequester.IsEnabled = $true } }) #endregion #End Checkboxes region $wpf.comboBoxServers.add_DropDownClosed({ Update-ListView }) #HINT: to update progress bar and/or label during WPF Form treatment, add the following: # ... to re-draw the form and then show updated controls in realtime ... $wpf.$FormName.Dispatcher.Invoke("Render",[action][scriptblock]{}) # Load the form: # Older way >>>>> $wpf.MyFormName.ShowDialog() | Out-Null >>>>> generates crash if run multiple times # Newer way >>>>> avoiding crashes after a couple of launches in PowerShell... # USing method from https://gist.github.com/altrive/6227237 to avoid crashing Powershell after we re-run the script after some inactivity time or if we run it several times consecutively... $async = $wpf.$FormName.Dispatcher.InvokeAsync({ $wpf.$FormName.ShowDialog() | Out-Null }) $async.Wait() | Out-Null |