-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLaunch-ExchangeServerComponentStateChecker.ps1
More file actions
641 lines (557 loc) · 30.3 KB
/
Launch-ExchangeServerComponentStateChecker.ps1
File metadata and controls
641 lines (557 loc) · 30.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
<#PSScriptInfo
.VERSION 1.7.1
.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.8.1"
<#Change history
- v1.8.1 - merged changes 1.7.1 with 1.8.0
- v1.7.1 - updated for component in "Draining" state (Transport component), starting all component NOT in "Active" State instead of all components in "Inactive" state
- v1.8.0 - added support for Exchange 2019
- v1.7.0 - added "Edge" checkbox to check Edge servers only, and fixed Requester information to see which requester stopped or
started the component for the last time.
- v1.6.5 - changed ExchToolsCheck to test on "Get-ExchangeServer" instead of "Get-Mailbox" to be usable on Edge servers
- 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 -ne "Active"})
} Else {
$wpf.ListView.ItemsSource = @($Global:GlobalResult | ? {$_.State -ne "Active" -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 -ne "Active"}).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-ExchangeServer -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.chkEdgeServer.Ischecked -eq $True){
if ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2016"){
$ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15\.1" -and ($_.ServerRole -match "Edge")}
} Elseif ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2013") {
$ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15\.0" -and ($_.ServerRole -match "Edge")}
} Elseif ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2019") {
$ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15\.2" -and ($_.ServerRole -match "Edge")}
}
} Else {
if ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2016"){
$ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15\.1" -and -not ($_.ServerRole -match "Edge")}
} Elseif ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2013") {
$ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15\.0" -and -not ($_.ServerRole -match "Edge")}
} Elseif ($wpf.comboSelectExchangeVersion.SelectedValue -match "Exchange 2019") {
$ExchangeServers = Get-ExchangeServer | ? {$_.AdminDisplayVersion -match "15\.2" -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 -ne "Active"}
$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 -ne "Active"}
$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-Object {
$ComponentsStateLastRequester = ($_ | Select-Object -ExpandProperty LocalStates | Sort-Object TimeStamp | Select-Object -Last 1).Requester
$PSObjectSrvComp = [PSCustomObject]@{
Server = $_.Identity
Component = $_.Component
State = $_.State
Requester = $ComponentsStateLastRequester
}
$PSObjectServerComponentsColl += $PSObjectSrvComp
}
$wpf.ListView.ItemsSource = $PSObjectServerComponentsColl
$TotalNbActiveComponents = ($wpf.ListView.ItemsSource | ? {$_.State -eq "Active"}).count
$TotalNbInactiveComponents = ($wpf.ListView.ItemsSource | ? {$_.State -ne "Active"}).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"/>
<ComboBoxItem Content="Exchange 2019"/>
</ComboBox>
<CheckBox x:Name="chkCheckOnly" Content="CheckOnly" HorizontalAlignment="Left" Margin="10,151,0,0" VerticalAlignment="Top" IsChecked="True"/>
<CheckBox x:Name="chkInactiveOnly" Content="Show Inactive Only" HorizontalAlignment="Left" Margin="612,174,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="chkEdgeServer" Content="Edge Server" HorizontalAlignment="Left" Margin="144,128,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="chkHybridServer" Content="HybridServer" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,171,0,0"/>
<TextBox HorizontalAlignment="Left" Height="79" Margin="144,10,0,0" TextWrapping="Wrap" Text="Exchange 2013/2016/2019 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"/>
<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"/>
<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"/>
<DataGridTextColumn Binding="{Binding Requester}" Header="Requester"/>
</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