-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathInstall-Exchange15.ps1
2655 lines (2399 loc) · 132 KB
/
Install-Exchange15.ps1
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
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<#
.SYNOPSIS
Install-Exchange15
Michel de Rooij
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE
RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Version 4.0, December 30th, 2024
Thanks to Maarten Piederiet, Thomas Stensitzki, Brian Reid, Martin Sieber, Sebastiaan Brozius, Bobby West,
Pavel Andreev, Rob Whaley, Simon Poirier, Brenle, Eric Vegter and everyone else who provided feedback
or contributed in other ways.
.DESCRIPTION
This script can install Exchange 2016/2019 prerequisites, optionally create the Exchange
organization (prepares Active Directory) and installs Exchange Server. When the AutoPilot switch is
specified, it will do all the required rebooting and automatic logging on using provided credentials.
To keep track of provided parameters and state, it uses an XML file; if this file is
present, this information will be used to resume the process. Note that you can use a central
location for Install (UNC path with proper permissions) to re-use additional downloads.
.LINK
http://eightwone.com
.NOTES
Requirements:
- Supported Operating Systems
- Windows Server 2016 (Exchange 2016 CU23)
- Windows Server 2019 (Desktop or Core, Exchange 2019 only)
- Windows Server 2022 (Exchange 2019 only)
- Windows Server 2025 (Exchange 2019 CU15+ only)
- Domain-joined system, except for Edge Server Role
- "AutoPilot" mode requires account with elevated administrator privileges
- When you let the script prepare AD, the account needs proper permissions
.REVISIONS
1.0 Initial community release
1.01 Added logic to prepare AD when organization present
Fixed checks and logic to prepare AD
Added testing for domain mixed/native mode
Added testing for forest functional level
1.02 Fixed small typo in post-prepare AD function
1.03 Replaced installing most OS features in favor of /InstallWindowsComponents
Removed installation of Office Filtering Pack
1.1 When used for AD preparation, RSAT-ADDS-Tools won't be uninstalled
Pending reboot detection. In AutoPilot, script will reboot and restart phase.
Installs Server-Media-Foundation feature (UCMA 4.0 requirement)
Validates provided credentials for AutoPilot
Check OS version as string (should accomodate non-US OS)
1.5 Added support for WS2008R2 (i.e. added prereqs NET45, WMF3), IEESC toggling,
KB974405, KB2619234, KB2758857 (supersedes KB2533623). Inserted phase for
WS2008R2 to install hotfixes (+reboot); this phase is skipped for WS2012.
Added InstallPath to AutoPilot set (or default won't be set).
1.51 Rewrote Test-Credentials due to missing .NET 3.5 Out of the Box in WS2008R2.
Testing for proper loading of servermanager module in WS2008R2.
1.52 Fix .NET / PrepareAD order for WS2008R2, relocated RebootPending check
1.53 Fix phase of Forest/Domain Level check
1.54 Added Parameter InstallBoth to install CAS and Mailbox, workaround as PoSHv2
can discriminate overlapping ParameterSets (resulting in AmbigiousParameterSet)
1.55 Feature installation bug fix on WS2012
1.56 Changed logic of final cleanup
1.6 Code cleanup (merged KB/QFE/package functions)
Fixed Verbose setting not being restored when script continues after reboot
Renamed InstallBoth to InstallMultiRole
Added 'Yes to All' option to extract function to prevent overwrite popup
Added detection of setup file version
Added switch IncludeFixes, which will install recommended hotfixes
(2008R2:KB2803754,KB2862063 2012:KB2803755,KB2862064) and KB2880833 for CU2 & CU3.
1.61 Fixed XML not found issue when specifying different InstallPath (Cory Wood)
1.7 Added Exchange 2013 SP1 & WS2012R2 support
Added installing .NET Framework 4.51 (2008 R2 & 2012 - 2012R2 has 4.51)
Added DisableRetStructPinning for Mailbox roles
Added KB2938053 (SP1 Transport Agent Fix)
Added switch InstallFilterPack to install Office Filter Pack (OneNote & Publisher support)
Fixed Exchange failed setup exit code anomaly
1.71 Uncommented RunOnce line - AutoPilot should work again
Using strings for OS version comparisons (should fix issue w/localized OS)
Fixed issue installing .NET 4.51 on WS2012 ('all in one' kb2858728 contains/reports
WS2008R2/kb958488 versus WS2012/kb2881468
Fixed inconsistency with .NET detection in WS2012
1.72 Added CU5 support
Added KB2971467 (CU5 Disable Shared Cache Service Managed Availability probes)
1.73 Added CU6 support
Added KB2997355 (Exchange Online mailboxes cannot be managed by using EAC)
Added .NET Framework 4.52
Removed DisableRetStructPinning (not required for .NET 4.52 or later)
1.8 Added CU7 support
1.9 Added CU8 support
Fixed CU6/CU7 detection
Added (temporary) clearing of Execution Policy GPO value
Added Forest Level check to throw warning when it can't read value
Added KB2985459 for WS2012
Using different service to detect installed version
Installs WMF4/NET452 for supported Exchange versions
Added UseWMF3 switch to use WMF3 on WS2008R2
2.0 Renamed script to Install-Exchange15
Added CU9 support
Added Exchange Server 2016 Preview support
Fixed registry checks for GPO error messages
Added ClearSCP switch to clear Autodiscover SCP record post-setup
Added Import-ExchangeModule() for post-configuration using EMS
Bug fix .NET installation
Modified AD checks to support multi-forest deployments
Added access checks for Installation, MDB and Log locations
Added checks for Exchange organization/Organization parameter
2.03 Bug & typo fix
2.1 Replaced ClearSCP with SCP param
Added Lock switch to lock computer during installation
Configures High Performance Power plan
Added installing feature RSAT-Clustering-CmdInterface
Added pagefile configuration when it's set to 'system managed'
2.11 Added Exchange 2016 RTM support
Removed Exchange 2016 Preview support
2.12 Fixed pre-CU7 .NET installation logic
2.2 Added (temporary) blocking unsupported .NET Framework 4.6.1 (KB3133990)
Added recommended updates KB2884597 & KB2894875 for WS2012
Changes to output so all output/verbose/warning/error get logged
Added check to Organization for invalid characters
Fixed specifying an Organization name containing spaces
2.3 Added support up to Exchange 2013 CU12 / Exchange 2016 CU1
Switched version detection to ExSetup, now follows Build
2.31 Fixed output error messages
2.4 Added support up to Exchange 2013 CU13 / Exchange 2016 CU2
Added support for .NET 4.6.1 (Exchange 2013 CU13+ / Exchange 2016 CU2+)
Added NONET461 switch, to use .NET 4.5.2, and block .NET 4.6.1
Added installation of .NET 4.6.1 OS-dependent required hotfixes:
* KB2919442 and KB2919355 (~700MB!) for WS2012R2 (prerequisites).
* KB3146716 for WS2008/WS2008R2, KB3146714 for WS2012, and KB3146715 for WS2012R2.
Added recommended Keep-Alive and RPC timeout settings
Added DisableSSL3 to disable SSL3 (KB187498)
2.41 Bug fix - Setup version of Exchange 2013 CU13 is .000, not .003
2.42 Bug fix - Installation of KB2919442 only detectable after reboot; adjusted logic
Added /f (forceAppsClose) for .MSU installations
2.5 Added recommended hotfixes:
* KB3146717 (=offline version of 3146718)
* KB2985459 (WS2012)
* KB3041832 (WS2012R2)
* KB3004383 (WS2008R2)
Added logging of AD Site
Added computername to filename of state file and log
Changed credential prompting, will use current account
Changed Power Plan setting to use InstanceID instead of textual match
Fixed KeepAlive timeout setting
Added checks for running as Enterpise & Schema admin
Fixed NoSetup bug (would abort)
Added check to see if Exchange server object already exists
Added Recover switch for RecoverServer mode
2.51 Script will abort when ExSetup has non-0 exitcode
Script will ignore package exit codes -2145124329 (SUS_E_NOT_APPLICABLE)
2.52 Script will abort when AD site can not be determined
Fixed SCP parameter handling, use '-' to remove the SCP
2.53 Fixed NoSetup logic skipping NET 4.6.1 installation
Added .NET framework optimization post-config (7318.DrainNGenQueue)
2.54 Fixed failing TargetPath check
2.6 Added support for Exchange 2013 CU14 and Exchange 2016 CU3
Fixed 7318.DrainNGenQueue routine
Some minor cosmetics
2.7 Added support for Windows Server 2016 (Exchange Server 2016 CU3+ only)
2.8 Added DisableRC4 to disable RC4 (kb2868725)
Fixed DisableSSL3, removed disabling SSL3 as client
Disables NIC Power Management during post config
2.9 Added support for Exchange 2016 CU4
Added support for Exchange 2013 CU15
Added KB3206632 to Exchange 2016 @ WS2016 requirements
2.91 Added support for Exchange 2016 CU5
Added support for Exchange 2013 CU16
2.92 Cosmetics and code cleanup when installing on WS2016
Output cosmetics when disabling RC4
2.93 Added blocking .NET Framework 4.7
2.95 Added support for Exchange 2016 CU6
Added support for Exchange 2013 CU17
2.96 Added support for Exchange 2016 CU7
Added support for Exchange 2013 CU18
Added FFL 2008R2 checks for Exchange 2016 CU7
Added blocking of .NET Framework 4.7.1
Consolidated .NET Framework blocking routines
Modified version comparison routine
2.97 Added support for Exchange 2016 CU8
Added support for Exchange 2013 CU19
Added NONET471 switch
2.98 Added support for Exchange 2016 CU9
Added support for Exchange 2013 CU20
Added blocking of .NET Framework 4.7.2 (Preview)
Added upgrade mode detection
Added TargetPath usage for Recover mode
2.99 Added Windows Defender exclusions (Ex2016 on WS2016)
2.991 Fixed .NET blockade removal
Fixed upgrade detection
Minor bugs and cosmetics fixes
2.99.2 Fixed Recover Mode Phase
Fixed InstallMDBDBPath location check
Added support for Exchange 2016 CU10
Added support for Exchange 2013 CU21
Added Visual C++ 2013 Redistributable prereq (Ex2016CU10+/Ex2013CU21+)
Fixed Exchange setup result detection
Changed code to determine AD Configuration container
Changed script to abort on non-static IP presence
Removed InstallFilterPack switch (obsolete)
Code cleanup and cosmetics
2.99.3 Fixed TargetPath-Recover parameter mutual exclusion
2.99.4 Fixed Recover mode not adding /InstallWindowsComponents
Added SkipRolesCheck switch
Added Exchange 2019 Public Preview support on Windows Server 2016
2.99.5 Added setting desktop background during setup
Some code cleanup
2.99.6 Added Exchange 2019 Preview on Windows Server 2019 support (desktop & core)
2.99.7 Updated location where hotfix are being published
2.99.8 Updated to Support Edge (Simon Poirier)
2.99.81 Fixed phase sequencing with reboot pending
2.99.82 Added reapplying KB2565063 (MS11-025) to IncludeFixes
Changed downloading VC++ Package to filename indicating version
Added post-setup Healthcheck / IIS Warmup
2.99.9 Added support for Exchange 2016 CU11
Updated SourcePath parameter usage (ISO)
Added .NET Framework 4.7.2 support
Added Windows Defender presence check
3.0.0 Added Exchange 2019 support
Rewritten VC++ detection
3.0.1 Integrated Exchange 2019 RTM Cipher correction
3.0.2 Replaced filename constructs with Join-Path
Fixed typo in installing KB4054530
3.0.3 Fixed typos in Join-Path constructs
3.0.4 Fixed bug in Install-MyPackage
3.1.0 Added support for Exchange 2019 CU1
Added support for Exchange 2016 CU12
Added support for Exchange 2013 CU22
Fixed Hotfix KB3041832 url
Fixed NoSetup Mode/EmptyRoles problem
Added skip Health Monitor checks for InstallEdge
Fixed potential Exchange version misreporting
3.1.1 Fixed detection of Defender
3.2.0 Added support for Exchange 2019 CU2
Added support for Exchange 2016 CU13
Added support for Exchange 2013 CU23
Added support for NET Framework 4.8
Added NoNET48 switch
Added disabling of Server Manager during installation
Removed support for Windows Server 2008R2
Removed support for Windows Server 2012
Removed Switch UseWMF3
3.2.1 Updated Pagefile config for Exchange 2019 (25% mem.size)
3.2.2 Added support for Exchange 2019 CU3
Added support for Exchange 2016 CU14
3.2.3 Fixed typo for Ex2019CU3 detection
3.2.4 Added support for Exchange 2019 CU4+CU5
Added support for Exchange 2016 CU15+CU16
3.2.5 Fixed typo in enumeration of Exchange build to report
Fixed specified vs used MDBLogPath (would add unspecified <DBNAME>\Log)
3.2.6 Added support for Exchange 2019 CU6
Added support for Exchange 2016 CU17
Added VC++ Runtime 2012 for Exchange 2019
3.3 Added support for Exchange 2019 CU7
Added support for Exchange 2016 CU18
3.4 Added support for Exchange 2019 CU8
Added support for Exchange 2016 CU19
Script allows non-static IP config with service Windows Azure Guest Agent, Network Agent or Telemetry Service present
3.5 Added support for Exchange 2019 CU8
Added support for Exchange 2016 CU19
Added support for KB5003435 for 2019CU8+9,2016CU19+20 and 2013CU23
Added support for KB5000871 for 2019RTM-CU7, 2016CU8-CU18 and 2013CU21+22
Added support for Interim Update installation & detection
Updated .NET 4.8 download link
Updated Visual C++ 2012 download link (latest release)
Updated Visual C++ 2013 download link (latest release)
Corrected not installing KB3206632 on WS2019
Corrected disabling of Server Manager during setup
Fixed setting High Performance Plan for recent Windows builds
Textual corrections
3.6 Added support for Exchange 2019 CU11
Added support for Exchange 2016 CU22
Added support for Exchange 2019 CU10
Added support for Exchange 2019 CU9
Added support for Exchange 2016 CU21
Added support for Exchange 2016 CU20
Added IIS URL Rewrite prereq for Ex2019CU11+ & Ex2016 CU22+
Added support for KB2999226 on for WS2012R2
Added DiagnosticData switch to set initial DataCollectionEnabled mode
3.61 Added mention of Exchange 2019
3.62 Added support for Exchange 2019 CU12
Added support for Exchange 2016 CU23
3.7 Added support for Windows Server 2022
Fixed logic for installing the IIS Rewrite module for Ex2016CU22+/Ex2019CU11+
Fixed logic when to use the new /IAcceptExchangeServerLicenseTerms_DiagnosticData* switch
3.71 Updated recommended Defender AV inclusions/exclusions
3.8 Added support for Exchange 2019 CU13
3.9 Added support for Exchange 2019 CU14
Added support for .NET Framework 4.8.1
Added NONET481 switch to use .NET 4.8 instead of 4.8.1 for Exchange 2019 CU14+
Added DoNotEnableEP and DoNotEnableEP_FEEWS switches for Exchange 2019 CU14+
Added deploying AUG2023 SUs for Ex2019CU13/Ex2019CU12/Ex2016CU23 when IncludeFixes specified
Changed example to show usage of iso as source
Added descriptive message when specifying invalid SourcePath
Fixed detection source path when iso already mounted without drive letter assignment
4.0 Added support for Exchange 2019 CU15
Added support for Windows Server 2025 (Exchange 2019 CU15+)
Removed Exchange 2013 support
Removed Exchange 2016 CU1-22 support
Removed Exchange 2019 RTM-CU9
Removed Windows Server 2012 R2 support
Added removal of obsolete MSMQ feature when installed
Added EnableECC switch to configure Elliptic Curve Crypto support
Added NoCBC switch to prevent configuring AES256-CBC-encrypted content support
Added EnableAMSI switch to configure AMSI body scanning for ECP, EWS, OWA and PowerShell
Added EnableTLS12 switch to configure TLS12
Added EnableTLS13 switch to configure TLS13 on WS2022/WS2025 with EX2019CU15+
Removed InstallMailbox, InstallCAS, InstallMultiRole switches
Removed NoNet461, NoNet471, NoNet472 and NoNet48 switches
Removed UseWMF3 switch
Added Ex2013 detection as it cannot coexist with Ex2019CU15+
Enabled loading Exchange module in postconf needed for possible override cmdlets
Removed setup phase shown on wallpaper
Set minimal required PS version to 5.1
Code cleanup
Functions now use approved verbs
4.01 Removed obsolete TLS13 setup detection
.PARAMETER Organization
Specifies name of the Exchange organization to create. When omitted, the step
to prepare Active Directory (PrepareAD) will be skipped.
.PARAMETER InstallEdge
Specifies you want to install the Edge server role (Exchange 2013/2016/2019).
.PARAMETER EdgeDNSSuffix
Specifies the DNS suffix you want to use on your EDGE
.PARAMETER MDBName (optional)
Specifies name of the initially created database.
.PARAMETER MDBDBPath (optional)
Specifies database path of the initially created database. Requires MDBName.
.PARAMETER MDBLogPath (optional)
Specifies log path of the initially created database. Requires MDBName.
.PARAMETER InstallPath (optional)
Specifies (temporary) location of where to store prerequisites files, log
files, etc. Default location is C:\Install.
.PARAMETER NoSetup (optional)
Specifies you don't want to setup Exchange (prepare/prerequisites only). Note that you
still need to specify the location of Exchange setup, which is used to determine
its version and which prerequisites should be installed.
.PARAMETER SourcePath
Specifies location of the Exchange installation files (setup.exe) or the location of
the Exchange installation ISO. This ISO will be mounted during installation.
.PARAMETER TargetPath
Specifies the location where to install the Exchange binaries.
.PARAMETER AutoPilot (switch)
Specifies you want to automatically restart and logon using Account specified. When
not specified, you will need to restart, logon and start the script again manually.
You also need to use the InstallPath parameter when used before, so the script knows where
to pick up the state file.
.PARAMETER Credentials
Specifies credentials to use for automatic logon. Use DOMAIN\User or user@domain. When
not specified, you will be prompted to enter credentials.
.PARAMETER IncludeFixes (optional)
Depending on operating system and detected Exchange version to install, will download
and install additional recommended Exchange hotfixes.
.PARAMETER SkipRolesCheck (optional)
Instructs script not to check for Schema Admin and Enterprise Admin roles.
.PARAMETER NONET481 (optional)
Prevents installing .NET Framework 4.8.1 and uses 4.8 when deploying Exchange 2019 CU14+
on supported Operating Systems (WS2016, WS2019). WS2022 only supports .NET Framework 4.8.1
.PARAMETER DoNotEnableEP (optional)
Do not enable Extended Protection on Exchange 2019 CU14+
.PARAMETER DoNotEnableEP_FEEWS (optional)
Do not enable Extended Protection on the Front-End EWS virtual directory on Exchange 2019 CU14+
.PARAMETER DisableSSL3 (optional)
Disables SSL3 after setup.
.PARAMETER DisableRC4 (optional)
Disables RC4 after setup.
.PARAMETER EnableECC (optional)
Configures Elliptic Curve Cryptography support after setup.
.PARAMETER NoCBC (optional)
Prevents configuring AES256-CBC-encrypted content support after setup.
.PARAMETER EnableAMSI (optional)
Configure AMSI body scanning for ECP, EWS, OWA and PowerShell (adjust as necessary in-code)
.PARAMETER EnableTLS12 (optional)
Enable or disable TLS12
.PARAMETER EnableTLS13 (optional)
Enable or disable TLS13 on WS2022/WS2025 for Exchange 2019 CU15+ (default: enable)
.PARAMETER Recover
Runs Exchange setup in RecoverServer mode.
.PARAMETER SCP (optional)
Reconfigures Autodiscover Service Connection Point record for this server post-setup, i.e.
https://autodiscover.contoso.com/autodiscover/autodiscover.xml. If you want to remove
the record, set it to '-'.
.PARAMETER Lock (optional)
Locks system when running script.
.PARAMETER DiagnosticData (optional)
Switch determines initial Data Collection mode for deploying Exchange 2019 CU11+ or Exchange 2016.
.PARAMETER Phase
Internal Use Only :)
.EXAMPLE
$Cred=Get-Credential
.\Install-Exchange15.ps1 -Organization Fabrikam -InstallMailbox -MDBDBPath C:\MailboxData\MDB1\DB -MDBLogPath C:\MailboxData\MDB1\Log -MDBName MDB1 -InstallPath C:\Install -AutoPilot -Credentials $Cred -SourcePath '\\server\share\Exchange 2019\ExchangeServer2019-x64-cu14' -SCP https://autodiscover.fabrikam.com/autodiscover/autodiscover.xml -Verbose
.EXAMPLE
.\Install-Exchange15.ps1 -InstallMailbox -MDBName MDB3 -MDBDBPath C:\MailboxData\MDB3\DB\MDB3.edb -MDBLogPath C:\MailboxData\MDB3\Log -AutoPilot -SourcePath D:\Install\ExchangeServer2019-x64-CU14.ISO -Verbose
.EXAMPLE
$Cred=Get-Credential
.\Install-Exchange15.ps1 -AutoPilot -Credentials $Cred
.EXAMPLE
.\Install-Exchange15.ps1 -Recover -Autopilot -Install -AutoPilot -SourcePath \\server1\sources\ex2016cu23
.EXAMPLE
.\Install-Exchange15.ps1 -NoSetup -Autopilot -InstallPath \\server1\exfiles\\server1\sources\ex2019cu14
#>
[cmdletbinding(DefaultParameterSetName='AutoPilot')]
param(
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[ValidatePattern(('(?# Organization Name can only consist of upper or lowercase A-Z, 0-9, spaces - not at beginning or end, hyphen or dash characters, up to 64 characters in length, and cannot be empty)^[a-zA-Z0-9\-\–\—][a-zA-Z0-9\-\–\—\ ]{1,62}[a-zA-Z0-9\-\–\—]$'))]
[string]$Organization,
[parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[switch]$InstallEdge,
[parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[string]$EdgeDNSSuffix,
[parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[switch]$Recover,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[string]$MDBName,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[string]$MDBDBPath,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[string]$MDBLogPath,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='AutoPilot')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[string]$InstallPath= 'C:\Install',
[parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[ValidateScript({ If((Test-Path -Path $_ -PathType Container) -or (Get-DiskImage -ImagePath $_)) { $true } Else { Throw ('Specified source path or image {0} not found or inaccessible' -f $_)} })]
[string]$SourcePath,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[string]$TargetPath,
[parameter( Mandatory=$true, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[switch]$NoSetup= $false,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[switch]$AutoPilot,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[System.Management.Automation.PsCredential]$Credentials,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$IncludeFixes,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$NoNet481,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$DoNotEnableEP,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$DoNotEnableEP_FEEWS,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$DisableSSL3,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$DisableRC4,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$EnableECC,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$NoCBC,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$EnableAMSI,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$EnableTLS12,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$EnableTLS13,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[ValidateScript({ ($_ -eq '') -or ($_ -eq '-') -or (([System.URI]$_).AbsoluteUri -ne $null)})]
[String]$SCP='',
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$DiagnosticData,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$Lock,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[Switch]$SkipRolesCheck,
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='M')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='E')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='NoSetup')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='AutoPilot')]
[parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName='Recover')]
[ValidateRange(0,6)]
[int]$Phase
)
process {
$ScriptVersion = '4.0'
$ERR_OK = 0
$ERR_PROBLEMADPREPARE = 1001
$ERR_UNEXPECTEDOS = 1002
$ERR_UNEXPTECTEDPHASE = 1003
$ERR_PROBLEMADDINGFEATURE = 1004
$ERR_NOTDOMAINJOINED = 1005
$ERR_NOFIXEDIPADDRESS = 1006
$ERR_CANTCREATETEMPFOLDER = 1007
$ERR_UNKNOWNROLESSPECIFIED = 1008
$ERR_NOACCOUNTSPECIFIED = 1009
$ERR_RUNNINGNONADMINMODE = 1010
$ERR_AUTOPILOTNOSTATEFILE = 1011
$ERR_ADMIXEDMODE = 1012
$ERR_ADFORESTLEVEL = 1013
$ERR_INVALIDCREDENTIALS = 1014
$ERR_MDBDBLOGPATH = 1016
$ERR_MISSINGORGANIZATIONNAME = 1017
$ERR_ORGANIZATIONNAMEMISMATCH = 1018
$ERR_RUNNINGNONENTERPRISEADMIN = 1019
$ERR_RUNNINGNONSCHEMAADMIN = 1020
$ERR_COULDNOTDETERMINEADSITE = 1021
$ERR_PROBLEMPACKAGEDL = 1120
$ERR_PROBLEMPACKAGESETUP = 1121
$ERR_PROBLEMPACKAGEEXTRACT = 1122
$ERR_BADFORESTLEVEL = 1151
$ERR_BADDOMAINLEVEL = 1152
$ERR_MISSINGEXCHANGESETUP = 1201
$ERR_PROBLEMEXCHANGESETUP = 1202
$ERR_PROBLEMEXCHANGESERVEREXISTS= 1203
$ERR_EX19EX2013COEXIST = 1204
$ERR_UNSUPPORTEDEX = 1205
$COUNTDOWN_TIMER = 10
$DOMAIN_MIXEDMODE = 0
$FOREST_LEVEL2012 = 5
$FOREST_LEVEL2012R2 = 6
# Minimum FFL/DFL levels
$EX2016_MINFORESTLEVEL = 15317
$EX2016_MINDOMAINLEVEL = 13236
$EX2019_MINFORESTLEVEL = 17000
$EX2019_MINDOMAINLEVEL = 13236
# Exchange Versions
$EX2016_MAJOR = '15.1'
$EX2019_MAJOR = '15.2'
# Exchange Install registry key
$EXCHANGEINSTALLKEY = "HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup"
# Supported Exchange versions (setup.exe)
$EX2016SETUPEXE_CU23 = '15.01.2507.006'
$EX2019SETUPEXE_CU10 = '15.02.0922.007'
$EX2019SETUPEXE_CU11 = '15.02.0986.005'
$EX2019SETUPEXE_CU12 = '15.02.1118.007'
$EX2019SETUPEXE_CU13 = '15.02.1258.012'
$EX2019SETUPEXE_CU14 = '15.02.1544.004'
$EX2019SETUPEXE_CU15 = '15.02.1748.008'
# Supported Operating Systems
$WS2016_MAJOR = '10.0'
$WS2019_PREFULL = '10.0.17709'
$WS2022_PREFULL = '10.0.20348'
$WS2025_PREFULL = '10.0.20348'
# .NET Framework Versions
$NETVERSION_48 = 528040
$NETVERSION_481 = 533320
# FFL
$FFL_2003 = 2
$FFL_2008 = 3
$FFL_2008R2 = 4
$FFL_2012 = 5
$FFL_2012R2 = 6
$FFL_2016 = 7
$FFL_2025 = 10
Function Save-State( $State) {
Write-MyVerbose "Saving state information to $StateFile"
Export-Clixml -InputObject $State -Path $StateFile
}
Function Restore-State() {
$State= @{}
If(Test-Path $StateFile) {
$State= Import-Clixml -Path $StateFile -ErrorAction SilentlyContinue
Write-Verbose "State information loaded from $StateFile"
}
Else {
Write-Verbose "No state file found at $StateFile"
}
Return $State
}
Function Get-SetupTextVersion( $FileVersion) {
$Versions= @{
$EX2016SETUPEXE_CU23= 'Exchange Server 2016 Cumulative Update 23';
$EX2019SETUPEXE_CU10= 'Exchange Server 2019 CU10';
$EX2019SETUPEXE_CU11= 'Exchange Server 2019 CU11';
$EX2019SETUPEXE_CU12= 'Exchange Server 2019 CU12';
$EX2019SETUPEXE_CU13= 'Exchange Server 2019 CU13';
$EX2019SETUPEXE_CU14= 'Exchange Server 2019 CU14';
$EX2019SETUPEXE_CU15= 'Exchange Server 2019 CU15';
}
$res= "Unsupported version (build $FileVersion)"
$Versions.GetEnumerator() | Sort-Object -Property {[System.Version]$_.Name} | ForEach-Object {
If( [System.Version]$FileVersion -ge [System.Version]$_.Name) {
$res= '{0} (build {1})' -f $_.Value, $FileVersion
}
}
return $res
}
Function Get-DetectedFileVersion( $File) {
$res= 0
If( Test-Path $File) {
$res= (Get-Command $File).FileVersionInfo.ProductVersion
}
Else {
$res= 0
}
return $res
}
Function Write-MyOutput( $Text) {
Write-Output $Text
$Location= Split-Path $State['TranscriptFile'] -Parent
If( Test-Path $Location) {
Write-Output "$(Get-Date -Format u): $Text" | Out-File $State['TranscriptFile'] -Append -ErrorAction SilentlyContinue
}
}
Function Write-MyWarning( $Text) {
Write-Warning $Text
$Location= Split-Path $State['TranscriptFile'] -Parent
If( Test-Path $Location) {
Write-Output "$(Get-Date -Format u): [WARNING] $Text" | Out-File $State['TranscriptFile'] -Append -ErrorAction SilentlyContinue
}
}
Function Write-MyError( $Text) {
Write-Error $Text
$Location= Split-Path $State['TranscriptFile'] -Parent
If( Test-Path $Location) {
Write-Output "$(Get-Date -Format u): [ERROR] $Text" | Out-File $State['TranscriptFile'] -Append -ErrorAction SilentlyContinue
}
}
Function Write-MyVerbose( $Text) {
Write-Verbose $Text
$Location= Split-Path $State['TranscriptFile'] -Parent
If( Test-Path $Location) {
Write-Output "$(Get-Date -Format u): [VERBOSE] $Text" | Out-File $State['TranscriptFile'] -Append -ErrorAction SilentlyContinue
}
}
Function Get-PSExecutionPolicy {
$PSPolicyKey= Get-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell' -Name ExecutionPolicy -ErrorAction SilentlyContinue
If( $PSPolicyKey) {
Write-MyWarning "PowerShell Execution Policy is set to $($PSPolicyKey.ExecutionPolicy) through GPO"
}
Else {
Write-MyVerbose 'PowerShell Execution Policy not configured through GPO'
}
return $PSPolicyKey
}
Function Get-MyPackage () {
Param ( [String]$Package, [String]$URL, [String]$FileName, [String]$InstallPath)
$res= $true
If( !( Test-Path $(Join-Path $InstallPath $Filename))) {
If( $URL) {
Write-MyOutput "Package $Package not found, downloading to $FileName"
Try{
Write-MyVerbose "Source: $URL"
Start-BitsTransfer -Source $URL -Destination $(Join-Path $InstallPath $Filename)
}
Catch{
Write-MyError 'Problem downloading package from URL'
$res= $false
}
}
Else {
Write-MyWarning "$FileName not present, skipping"
$res= $false
}
}
Else {
Write-MyVerbose "Located $Package ($InstallPath\$FileName)"
}
Return $res
}
Function Get-CurrentUserName {
return [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
}
Function Test-Admin {
$currentPrincipal = New-Object System.Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent() )
return $currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )
}
Function Test-SchemaAdmin {
$FRNC= Get-ForestRootNC
$ADRootSID= ([ADSI]"LDAP://$FRNC").ObjectSID[0]
$SID= (New-object System.Security.Principal.SecurityIdentifier ($ADRootSID, 0)).Value.toString()
return [Security.Principal.WindowsIdentity]::GetCurrent().Groups | Where-Object {$_.Value -eq "$SID-518"}
}
Function Test-EnterpriseAdmin {
$FRNC= Get-ForestRootNC
$ADRootSID= ([ADSI]"LDAP://$FRNC").ObjectSID[0]
$SID= (New-object System.Security.Principal.SecurityIdentifier ($ADRootSID, 0)).Value.toString()
return [Security.Principal.WindowsIdentity]::GetCurrent().Groups | Where-Object {$_.Value -eq "$SID-519"}
}
Function Test-ServerCore {
(Get-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion' -Name 'InstallationType' -ErrorAction SilentlyContinue).InstallationType -eq 'Server Core'
}
Function Test-RebootPending {
$Pending= $False
If( Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager' -Name 'PendingFileRenameOperations' -ErrorAction SilentlyContinue) {
$Pending= $True
}
If( Test-Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending' -ErrorAction SilentlyContinue) {
$Pending= $True
}
Return $Pending
}
Function Enable-RunOnce {
Write-MyOutput 'Set script to run once after reboot'
$RunOnce= "$PSHome\powershell.exe -NoProfile -ExecutionPolicy Unrestricted -Command `"& `'$ScriptFullName`' -InstallPath `'$InstallPath`'`""
Write-MyVerbose "RunOnce: $RunOnce"
New-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name "$ScriptName" -Value "$RunOnce" -ErrorAction SilentlyContinue| out-null
}
Function Disable-UAC {
Write-MyVerbose 'Disabling User Account Control'
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name EnableLUA -Value 0 -ErrorAction SilentlyContinue| out-null
}
Function Enable-UAC {
Write-MyVerbose 'Enabling User Account Control'
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name EnableLUA -Value 1 -ErrorAction SilentlyContinue| out-null
}
Function Disable-IEESC {
Write-MyOutput 'Disabling IE Enhanced Security Configuration'
$AdminKey = 'HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}'
$UserKey = 'HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}'
New-Item -Path (Split-Path $AdminKey -Parent) -Name (Split-Path $AdminKey -Leaf) -ErrorAction SilentlyContinue | out-null
Set-ItemProperty -Path $AdminKey -Name 'IsInstalled' -Value 0 -Force | Out-Null
New-Item -Path (Split-Path $UserKey -Parent) -Name (Split-Path $UserKey -Leaf) -ErrorAction SilentlyContinue | out-null
Set-ItemProperty -Path $UserKey -Name 'IsInstalled' -Value 0 -Force | Out-Null
If( Get-Process -Name explorer.exe -ErrorAction SilentlyContinue) {
Stop-Process -Name Explorer
}
}
Function Enable-IEESC {
Write-MyVerbose 'Enabling IE Enhanced Security Configuration'
$AdminKey = 'HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}'
$UserKey = 'HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}'
New-Item -Path (Split-Path $AdminKey -Parent) -Name (Split-Path $AdminKey -Leaf) -ErrorAction SilentlyContinue | out-null
Set-ItemProperty -Path $AdminKey -Name 'IsInstalled' -Value 1 -Force | Out-Null
New-Item -Path (Split-Path $UserKey -Parent) -Name (Split-Path $UserKey -Leaf) -ErrorAction SilentlyContinue | out-null
Set-ItemProperty -Path $UserKey -Name 'IsInstalled' -Value 1 -Force | Out-Null
If( Get-Process -Name explorer.exe -ErrorAction SilentlyContinue) {
Stop-Process -Name Explorer
}
}
Function get-FullDomainAccount {
$PlainTextAccount= $State['AdminAccount']
If( $PlainTextAccount.indexOf('\') -gt 0) {
$Parts= $PlainTextAccount.split('\')
$Domain = $Parts[0]
$UserName= $Parts[1]
Return "$Domain\$UserName"
} Else {
If( $PlainTextAccount.indexOf('@') -gt 0) {
Return $PlainTextAccount
}
Else {
$Domain = $env:USERDOMAIN
$UserName= $PlainTextAccount
Return "$Domain\$UserName"
}
}
}
#From https://gallery.technet.microsoft.com/scriptcenter/Verify-the-Local-User-1e365545
function Test-LocalCredential {
[CmdletBinding()]
Param
(
[string]$UserName,
[string]$ComputerName = $env:COMPUTERNAME,
[string]$Password
)
if (!($UserName) -or !($Password)) {
Write-Warning 'Test-LocalCredential: Please specify both user name and password'
} else {
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('machine',$ComputerName)
$DS.ValidateCredentials($UserName, $Password)
}
}
Function Test-Credentials {
$PlainTextPassword= [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR( (ConvertTo-SecureString $State['AdminPassword']) ))
$FullPlainTextAccount= get-FullDomainAccount
Try {
If( $State['InstallEdge']) {
$Username = $FullPlainTextAccount.split("\")[-1]
Return $( Test-LocalCredential -UserName $Username -Password $PlainTextPassword)
}else{
$dc= New-Object DirectoryServices.DirectoryEntry( $Null, $FullPlainTextAccount, $PlainTextPassword)
If($dc.Name) {
return $true
}
Else {
Return $false
}
}
}
Catch {
Return $false
}
Return $false
}
Function Enable-AutoLogon {
Write-MyVerbose 'Enabling Automatic Logon'
$PlainTextPassword= [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR( (ConvertTo-SecureString $State['AdminPassword']) ))
$PlainTextAccount= $State['AdminAccount']
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name AutoAdminLogon -Value 1 -ErrorAction SilentlyContinue| out-null
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name DefaultUserName -Value $PlainTextAccount -ErrorAction SilentlyContinue| out-null
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name DefaultPassword -Value $PlainTextPassword -ErrorAction SilentlyContinue| out-null
}
Function Disable-AutoLogon {
Write-MyVerbose 'Disabling Automatic Logon'
Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name AutoAdminLogon -ErrorAction SilentlyContinue| out-null
Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name DefaultUserName -ErrorAction SilentlyContinue| out-null
Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name DefaultPassword -ErrorAction SilentlyContinue| out-null
}
Function Disable-OpenFileSecurityWarning {
Write-MyVerbose 'Disabling File Security Warning dialog'
New-Item -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Associations' -ErrorAction SilentlyContinue |out-null
New-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Associations' -name 'LowRiskFileTypes' -value '.exe;.msp;.msu;.msi' -ErrorAction SilentlyContinue |out-null
New-Item -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments' -ErrorAction SilentlyContinue |out-null
New-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments' -name 'SaveZoneInformation' -value 1 -ErrorAction SilentlyContinue |out-null
Remove-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Associations' -Name 'LowRiskFileTypes' -ErrorAction SilentlyContinue
Remove-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments' -Name 'SaveZoneInformation' -ErrorAction SilentlyContinue
}
Function Enable-OpenFileSecurityWarning {
Write-MyVerbose 'Enabling File Security Warning dialog'
Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Associations' -Name 'LowRiskFileTypes' -ErrorAction SilentlyContinue
Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments' -Name 'SaveZoneInformation' -ErrorAction SilentlyContinue
Remove-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Associations' -Name 'LowRiskFileTypes' -ErrorAction SilentlyContinue
Remove-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments' -Name 'SaveZoneInformation' -ErrorAction SilentlyContinue
}
Function Invoke-Extract ( $FilePath, $FileName) {
Write-MyVerbose "Extracting $FilePath\$FileName to $FilePath"
If( Test-Path $(Join-Path $FilePath $Filename)) {
$TempNam= "$(Join-Path $FilePath $Filename).zip"
Copy-Item $(Join-Path $FilePath $Filename) "$TempNam" -Force
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace( $TempNam)
$destFolder = $shellApplication.NameSpace( $FilePath)
$destFolder.CopyHere( $zipPackage.Items(), 0x10)
Remove-Item $TempNam
}
Else {
Write-MyWarning "$FilePath\$FileName not found"
}
}
Function Invoke-Process ( $FilePath, $FileName, $ArgumentList) {
$rval= 0
$FullName= Join-Path $FilePath $FileName
If( Test-Path $FullName) {
Switch( ([io.fileinfo]$Filename).extension.ToUpper()) {
'.MSU' {
$ArgumentList+= @( $FullName)
$ArgumentList+= @( '/f')
$Cmd= "$env:SystemRoot\System32\WUSA.EXE"
}
'.MSI' {
$ArgumentList+= @( '/i')
$ArgumentList+= @( $FullName)
$Cmd= "MSIEXEC.EXE"
}
'.MSP' {
$ArgumentList+= @( '/update')
$ArgumentList+= @( $FullName)
$Cmd= 'MSIEXEC.EXE'
}
default {
$Cmd= $FullName
}
}
Write-MyVerbose "Executing $Cmd $($ArgumentList -Join ' ')"
$rval=( Start-Process -FilePath $Cmd -ArgumentList $ArgumentList -NoNewWindow -PassThru -Wait).Exitcode
Write-MyVerbose "Process exited with code $rval"
}
Else {
Write-MyWarning "$FullName not found"
$rval= -1
}
return $rval
}
Function Get-ForestRootNC {
return ([ADSI]'LDAP://RootDSE').rootDomainNamingContext.toString()
}
Function Get-RootNC {
return ([ADSI]'').distinguishedName.toString()
}
Function Get-ForestConfigurationNC {