Exchange v15 Unattended Setup

Ex2013 Logo

Latest version: 3.9, February 15th, 2024

I’m pleased to announce the availability of Install-Exchange15.ps1, a PowerShell script to perform a fully automated unattended setup of Exchange Server 2013, Exchange Server 2016, or Exchange Server 2019 (Desktop and Core) is supported).

The script takes care of:

  • Installing requires Windows Server features
  • Install Exchange Server prerequisites, e.g., .NET Framework 4.5.2/4.6.1/4.6.2/4.7.1/4.7.2/4.8/4.8.1 and Visual C++ Runtime 2012 or 2013, depending on roles, OS, and Exchange version to install.
  • Install additional prerequisites and prepare Active Directory.
  • Optionally install Exchange Server 2013 / 2016 / 2019.
  • Optionally, install required fixes and perform post configuration, like setting your Power Plan to High Performance, reconfiguring the pagefile to best practices (memory + 10MB with a maximum of 32GB+10MB) if it is system managed, and performing .NET framework optimizations. Custom post-configuration is possible by modifying the script.
  • On Windows Server 2016 and later, it will configure Windows Defender exclusions when present.
  • For Exchange 2016 CU22 and Exchange 2019 CU11 and later, will install the required URL Rewrite 2 module.
  • Finally, the script will clean things up, like removing the state file and setting the startup of Transport Service back to Automatic.

Usage
This script version requires a domain-joined Windows Server, an account to perform the installation (and optionally prepare Active Directory), and the location where the Exchange Server 2013/2016/2019 installation files are stored (e.g., a UNC path).

The syntax is as follows:

Install-Exchange15.ps1 -[InstallMultiRole|InstallMailbox|InstallEdge|InstallCAS|NoSetup|Recover] [-Organization <string>] [-MDBName <string>] [-MDBDBPath <string>] [-MDBLogPath <string>] [-InstallPath <string>] [-SourcePath <string>] [-TargetPath <string>] [-Credentials <pscredential>] [-IncludeFixes] [-NoNet461] [-NoNet471] [-NoNet472] [-NoNet48] [-NoNet481] [-DoNotEnableEP] [-DoNotEnableEP_FEEWS] [-UseWMF3] [-DisableSSL3] [-DisableRC4] [-DiagnosticData] [-SCP <string>] [-EdgeDNSSuffix <string>] [-Lock] [-SkipRolesCheck] [-AutoPilot] [<CommonParameters>]
Install-Exchange15.ps1 -InstallMultiRole -SourcePath <string> [-Organization <string>] [-InstallPath <string>] [-TargetPath <string>] [-AutoPilot] [-Credentials <pscredential>] [-IncludeFixes] [-NoNet461] [-NoNet471] [-NoNet472] [-NoNet48] [-NoNet481] [-DoNotEnableEP] [-DoNotEnableEP_FEEWS] [-UseWMF3] [-DisableSSL3] [-DisableRC4] [-DiagnosticData] [-Lock] [-SkipRolesCheck] [-Phase <int>] [<CommonParameters>]

A short description of the parameters:

  • Organization (optional): Specifies the name of the Exchange organization to create. When omitted, the step to prepare Active Directory (PrepareAD) will be skipped.
  • InstallMailbox: Specifies you want to install the Mailbox server role. This applies to Exchange 2013 as well as Exchange 2016.
  • InstallCAS: Specifies you want to install the CAS role. This applies to Exchange 2013 only, ignored when installing Exchange 2016.
  • InstallMultiRole: Specifies you want to install both Mailbox server and CAS roles. Applies to Exchange 2013 only.
  • InstallEdge: Specifies to install the Edge Transport rule (Exchange 2013/2016).
  • MDBName (optional): Specifies the name of the initially created database.
  • MDBDBPath (optional): Specifies the database path of the initially created database (requires MDBName).
  • MDBLogPath (optional): Specifies the log path of the initially created database (requires MDBName).
  • InstallPath (optional): Specifies (temporary) location of where to locate – and when downloaded store – prerequisite files, the state file, and log files. The default location is C:\Install. You can also use a UNC path to use a central location, given the credentials have sufficient permissions to write at this location. This is ideal when you want the script to use previously downloaded hotfix files, for example, as some required hotfixes are quite large (e.g. KB3206632 for WS2016 ~ 1GB, KB2919355 for WS2012R2 ~ 700MB).
  • NoSetup (optional): Specifies you only want to install prerequisites (and optionally prepare the Exchange organization), Exchange setup and post-configuration steps are not performed. You still need to specify SourcePath because the Exchange version will determine the prerequisites to install.
  • Recover: Specifies you want to install this server in Recovery mode. The script will check if an Exchange server object is already defined.
  • SourcePath: Specifies the location of the Exchange 2013 installation files. This can point to the location of setup.exe, or you can specify the Exchange ISO file.
  • TargetPath: Specifies the location where to install the Exchange 2013.
  • AutoPilot (switch): Specifies you want to automatically restart, log on using the credentials specified, and continue the installation. When not specified, you will need to restart, log on, and start the script manually each time (without parameters).
  • Credentials (optional): Specifies credentials to use for automatic logon. Use DOMAIN\User or user@domain. When not specified, you will be prompted to enter credentials.
  • IncludeFixes (optional): Depending on the operating system and detected Exchange version to install, will download and install recommended hotfixes.
  • DiagnosticData (optional): This switch determines the initial Data Collection mode for deploying Exchange 2019 CU11, Exchange 2016 CU22, or later builds.
  • DoNotEnableEP Do not enable Extended Protection on Exchange 2019 CU14+
  • DoNotEnableEP_FEEWS Do not enable Extended Protection on the Front-End EWS virtual directory on Exchange 2019 CU14+
  • SCP (optional) allows you to reconfigure the Service Connection Point record for Autodiscover after the Exchange setup has finished. Specify the full URI, e.g. https://autodiscover.contoso.com/autodiscover/autodiscover.xml. Use ‘-‘ to clear the SCP entries of the server.
  • Lock (optional) locks the system when running script.
  • NoNet481 (optional) prevents installing .NET Framework 4.8.1 and uses 4.8 when deploying Exchange 2019 CU14+
  • NoNet48 (optional) to use .NET Framework 4.7.2, even when installing an Exchange version that is supported with .NET Framework 4.8.
  • NoNET471 (optional) to use .NET Framework 4.6.2, even when installing an Exchange version which is supported with .NET Framework 4.7.1.
  • NoNET472 (optional) to use .NET Framework 4.7.1, even when installing an Exchange version which is supported with .NET Framework 4.7.2.
  • NoNET461 (optional) to use .NET Framework 4.5.2, even when installing an Exchange version which is supported with .NET Framework 4.6.1 or higher.
  • DisableSSL3 (optional) to disable SSL3 protocol as per KB187498.
  • DisableRC4 (optional) to disable RC4 cipher as per KB2868725.
  • SkipRolesCheck (optional) to bypass membership checks for Schema Admin and Enterprise Admin roles.
  • EdgeDNSSuffix specifies the DNS suffix to configure on the primary NIC.

Note that the script uses an XML file to store the (original) parameters used to start the script but also to keep track of the the process. Of course, if required, you can use predefined XML files to run the script without parameters.

Note that when not present, the script will try to download the prerequisites from the internet. When that isn’t possible or to save bandwidth, you can put them in the location defined by InstallPath and the script will detect and use them.

The post-configuration is currently adding IFilters for OneNote and Publisher (Mailbox) only. There are comments in the script where to add your own additional post-configuration steps.

For example, assume we want to start a fully unattended install of an Exchange Server 2013 Client Access server, using a network location for the Exchange Server 2013 source files. After setting the Execution Policy to Unrestricted and storing the script locally, we start the script using:

 .\Install-Exchange15.ps1 –InstallCAS –SourcePath
'\\server\share\isos\Microsoft\Exchange2013\mu_exchange_server_2013_x64_dvd_1112105'
–AutoPilot –Verbose

The script will perform some checks and since AutoPilot was specified without using the Credentials parameter, the script will ask for credentials.

Capture1

After entering the credentials, the required features will be installed. Since OrganizationName wasn’t specified, Active Directory preparation will be skipped.

Capture2

After rebooting, the system will automatically log on using the credentials specified earlier and start the script (RunOnce registry key is utilized for this purpose). It will read the last known state from the XML file and will continue with the next phase, which is downloading (when not present) and installing the Exchange prerequisites.

Capture3

Next, after rebooting and the automatic logon, Exchange will be installed from the source location.

Capture4

When done, the system will perform post-configuration and finalization steps.

When running in AutoPilot mode, the system will automatically perform reboots and logons between the steps. Note that it may seem like a lot of reboots, but rebooting after installing Windows features and Exchange prerequisites is required anyway, so I also put reboots after the other milestones.

Customization
If you want to perform post-setup configuration of Exchange running Exchange cmdlets from the script, you need to tailor it to your needs. Locate the line which reads:

#Load-ExchangeModule

Uncomment this line so a proper Exchange Management Shell session will be set up to the local Exchange server. You can insert Exchange-related cmdlets after the Load-ExchangeModule line to configure your server. Be advised that you need to port modifications to new versions of the installation script.

Recovery
The script also supports recovery mode (/mode:RecoverServer). After checking the Exchange server object is present in Active Directory, installation will proceed as normal, with the exception of running setup in recovery mode. For example:

.\Install-Exchange15.ps1 -Recover -Autopilot -SourcePath \server1\sources\ex2019cu13.iso

Update
The script also supports update mode (/mode:Update). After checking the Exchange server object is present in Active Directory, and checking for presence of Exchange installation, installation will proceed as normal, with the exception of running setup in Update mode.

Feedback
Feedback is welcomed through the comments. If you have scripting suggestions or questions, do not hesitate to use the contact form.

Download
You can download Install-Exchange15.ps1 from TechNet or GitHub.

Revision History
See Technet Gallery page.

224 thoughts on “Exchange v15 Unattended Setup

  1. Pingback: Microsoft Exchange Server 2013 Unattended Installation Script - Mark Fugatt - Exchange and OCS Blog - Site Home - TechNet Blogs

  2. Pingback: NeWay Technologies – Weekly Newsletter #31 – February 21, 2013NeWay | NeWay

  3. Hi Michael
    filter office pack and sp1 aren’t required for 2013
    you can remove them from the script(its a TechNet error for basic office filtering not required)

    Like

  4. Pingback: The UC Architects » Episode 18: Get Us Drunk, and We’re Yours!

  5. Pingback: Spr33 » Microsoft Exchange Server 2013 Unattended Instal Script

  6. Pingback: Exchange 2013 Unattended Installation Script (Updated) | EighTwOne (821) | JC's Blog-O-Gibberish

  7. Hi.. Great Job and thank you for sharing this.
    I´m getting following error…
    C:\Install\Install-Exchange2013.ps1 : Unexpected OS Version (6.2)
    In Zeile:1 Zeichen:1
    + .\Install-Exchange2013 -Organization ‘EXLAB’ -InstallMailbox -MDBDBPath ‘D:\DB1’ …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-Exchange2013.ps1

    Like

  8. Pingback: Installing Exchange 2013 prerequisites | Andy Heywood Online

  9. I am having problems with the script when installing from a newly built 2012 server it fails to install the UCMA 4.0 runtime as the windows feature Server-Media-Foundation is not getting installed before UCMA 4.0 and it seems to be a prerequisite for this even though its not published. Have you seen this before?

    Like

  10. Thanks for the script! I ran into a couple snags. One being the UCMA issue that you appear to be aware of. The other was that the Exchange installation was failing due to the ‘ol DiscoverySearchMailbox problems. The problem is the script wasn’t providing any visibility into the fact that the installation wasn’t completing successfully. As far as it knew everything went through fine, but the ClientAccess role wasn’t being installed (and I think the mailbox role was only partially installed).

    I was able to launch setup through the GUI and it gave me the errors which I could then troubleshoot.

    On an unrelated note – would it be possible to provide an option to NOT uninstall RSAT-ADDS-Tools after completion? 🙂

    Like

  11. Pingback: Exchange 2013 Unattended Installation Script v1.1 | EighTwOne (821)

  12. Pingback: Exchange 2013 Unattended Installation Script v1.5 | EighTwOne (821)

  13. Greetings! I know this is somewhat off topic but I was wondering if
    you knew where I could get a captcha plugin for my comment form?
    I’m using the same blog platform as yours and I’m having problems finding one?

    Thanks a lot!

    Like

  14. Note: There looks to be a PowerShell v2 bug (as it works as expected in PSv3, ie WS2012). Cause is that on WS2008R2, you can’t either specify InstallCAS or InstallMailbox, only both. Apparantly, PSv2 can’t figure out what parameter set to use (should use “CM” variant) so it ends in AmbigiousParameterset. Note that when running help .\Install-Exchange2013.ps1 is shows that only specifying InstallMailbox or InstallCAS is a valid syntax. Standby while I look for a suited workaround.

    Like

  15. Hi
    To day I found this link and downloaded the script.
    Im testing the script with server2012 but get stuck with this error, how do I get around it
    Checking Forest Functional Level
    The following exception occurred while retrieving member “get”: “Unknown error (0x80005000)”
    At C:\install\Install-Exchange2013.ps1:411 char:15
    + return( ([ADSI]”LDAP://cn=partitions,cn=configuration,$RootDSE”).get(“ms …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
    + FullyQualifiedErrorId : CatchFromBaseGetMember

    Check-Sanity : Forest is not Functional Level 2003 or later
    At C:\install\Install-Exchange2013.ps1:906 char:5
    + Check-Sanity
    + ~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Check-Sanity

    Like

  16. Regarding “KB2758857: Insecure library loading could allow remote code execution (supersedes KB2533623)” – it supersedes KB2533623 for W2008 only, not for W2008R2.
    And the Exchange prerequisites page still says KB2533623 is required.

    Like

  17. To check if this feature is installed, you should use
    If( ! (Get-WindowsFeature $Feat).Installed )
    instead of
    If( !( Get-WindowsFeature ($Feat)))

    Also, (at least for some features) reboot was required before they showed up as installed.

    Great script, thanks!

    Like

  18. Great script!

    I installed a Exchange 2013 server with this script today and after the install i wanted to apply CU2
    i got the following 3 errors

    RSAT-Clustering-CmdInterface
    FilterPack64bit
    filterpack2010sp1-kb2460041-x64-fullfile-en-us

    are not installed.

    Can you please fix this
    thnx

    Like

      • Michel,

        I installed RTM and then tried to upgrade to CU2 (yes i know next time install CU right away, but i forgot that CU2 was released) and de setup from CU2 gave me the error that i need to istall the 3 components above

        Like

        • If I recall correctly, the filter packs will only result in a warning. They aren’t required. That issue with RSAT-Clustering-CmdInterface is a bit of quirk (it’s not required with fresh CU2 installs, just confirmed as I’m reinstalling some of my lab servers atm)

          Like

  19. Pingback: Exchange Server 2013 CU2 Service Templates for Virtual Machine Manager - Building Clouds Blog - Site Home - TechNet Blogs

  20. This is a great script. As FYI, it fails if there are spaces in the arguments, such as in the MDB path or the Exchange setup path. Once I removed them, it worked fine.

    Like

  21. Pingback: Exchange 2013 Unattended Installation Script (Updated) | EighTwOne (821) | JC's Blog-O-Gibberish

  22. Great script Michel.

    Can you please check the spaces?

    TargetPath ‘D:\Program Files\Microsoft\Exchange Server\V15’
    but installed in: D:\Program,Files\Microsoft\Exchange,Server\V15

    Like

      • Hi Michel, see below log details. Please note the LogFolderPath is also incorrect: Command Line:./Install-Exchange2013.ps1 -InstallMultiRole -MDBName DAG01_DB01 -MDBDBPath D:\DAG_01\DB -MDBLogPath D:\DAG_01\Log -SourcePath D:\Install\E2K13CU3 -TargetPath ‘D:\Program Files\Microsoft\Exchange Server\V15’ -AutoPilot -Credentials $Cred -IncludeFixes -Verbose Transcript started, output file is C:\Install\Install-Exchange2013.ps1_20140215102622.logVERBOSE: Disabling File Security Warning dialogVERBOSE: Disabling Automatic LogonChecking for pending reboot ..VERBOSE: Current phase is 4 of 6Installing Exchange 2013Installing Microsoft Exchange Server 2013VERBOSE: Executing D:\Install\E2K13CU3\setup.exe /mode:install /roles:Mailbox,ClientAccess /IAcceptExchangeServerLicenseTerms /InstallWindowsComponents /MdbName:DAG01_DB01 /DBFilePath:”D:\DAG_01\DB\DAG01_DB01.edb” /LogFolderPath:”D:\DAG_01\Log\DAG01_DB01\Log” /TargetDir:D:\Program Files\Microsoft\Exchange Server\V15 /DoNotStartTransportInstall-Exchange2013_ : Problem installing At D:\Install\Install-Exchange2013.ps1:943 char:13+ Install-Exchange2013_+ ~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-Exchange2013_ **********************Windows PowerShell transcript endEnd time: 20140215103102********************** Regards,Franck Date: Sat, 15 Feb 2014 09:37:26 +0000To: franckwolf@hotmail.comFrom: comment-reply@wordpress.comSubject: [New comment] Exchange 2013 Unattended Installation Script (Updated)

        WordPress.com

        Michel de Rooij commented: “Thanks for the heads-up!”

        Like

  23. Sadly unable to make this work at all. Brand new 2012 R2 server with Exchange 2013 SP1, doesn’t have access to the Internet so have saved UCMA locally.

    Running as Autopilot, runs once, reboots machine, runs through script again, then reboots … Nothing happens.

    Re-run script manually, reboots machine … Nothing happens.

    Re-run script manually, actually installs UCMA, reboots … Nothing happens.

    Would appear that the pre-requisites in particular the Windows Features never install, as a result of not being connected to the Internet.

    Like

    • When doing an “offline” install, make sure you put the requirement components in the folder you specified with InstallPath (default C:\Install) – it will pick them up from there. The “Windows Features” come with the Operating System, and should be able to install regardless. Currently, for WS2012R2 the required files are (you could distill them from the script as well):
      * NDP451-KB2858728-x86-x64-AllOS-ENU.exe
      * UcmaRuntimeSetup.exe
      * FilterPack64bit.exe
      * filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe
      Note: The Filter Pack files need only to be present when you specify InstallFilterPack.

      I’ll make a note of perhaps checking for the existence of these files upfront, as it will now – as you found out- abort halfway when it can’t download or find the file/patch. Note that the log file contains information on the reason of prematurely ending the installation. When the script has aborted and you want to continue running it, just kick it off from an elevated PowerShell prompt; no need to include any parameters except for InstallPath if you selected a different path than the default one.

      Like

      • Thanks Michel, didn’t think NDP451-KB2858728-x86-x64-AllOS-ENU.exe was required for WS2012R2.

        Also possible that due to being an offline installation that the windows features being called by the exchange setup is failing as well as they don’t have a source specified.

        Like

        • Not required, but highly recommended (alternative is 4.5 with a set of hotfixes only available through support).
          Installing Windows features does not require original source files (like in early versions of Windows)

          Like

  24. Still having issue here whereby the autopilot function doesn’t rerun after reboot the server … and I have to re-run the script at every single stage. Win2013R2SP1.

    Like

    • Check if the credentials provided are working (used to automatically log on) in the event log. Otherwise, when the XML is still there (in the InstallPath), it will re-use it so throw it away when you want to have another ‘fresh’ go.

      Like

        • When you run it with the Verbose option, the log will contain a line starting with “RunOnce: $RunOnce”
          Now either that reg. key doesn’t get set (policies, permissions?) or the cmd won’t go on your system for some reason ..
          If you want me to have a look please provide the log file (michel [at] eightwone.com )

          Like

            • Hi squiggleh,
              i ran into the same issue. Are you running an englisch OS? I used a german one. I had to put some values in quotes.
              Search for $MajorOSVersion…
              Switch ($State[“InstallPhase”]) {
              1 {
              Write-Output “Installing Operating System prerequisites”
              Install-WindowsFeatures $MajorOSVersion

              If( $MajorOSVersion -ne “6.1”) {
              # Skip phase 2 for WS2012
              $State[“InstallPhase”]++

              Hope that helps.

              Like

          • @flex: I’m having a deja-vu 😦 I have a hunch where it goes bad .. I think it has to do with the US using “.” for decimal seperator and DE (amonst other countries) not. I’ll fetch a German WS2012R2 to check my theory.

            Like

          • Rebuilt my farm … The log file never contains anything related to Run/RunOnce even with the Verbose switch. I have to continually re-run the command again and again.

            Like

  25. great script.
    On windows 2008 R2 SP1, I keep getting this error
    Installing Exchange 2013 prerequisites
    Processing Windows Management Framework 3.0 (KB2506143)
    Package-Install : Problem installing Windows Management Framework 3.0
    At C:\Users\Administrator\Desktop\Install-Exchange2013.ps1:996 char:32
    + Package-Install <<<< "KB2506143" "Windows Management Framework 3.0" "Windows6.1-KB2506143-x64.msu" "
    http://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-x64.msu&quot; ("/quie
    t", "/norestart")
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Package-Install

    Despite the fact that I have the following files in the c:\Install directory.

    437878_intl_i386_zip.exe
    filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe
    FilterPack32bit.exe
    FilterPack64bit.exe
    Install-Exchange2013.ps1_20140504222556.log
    Install-Exchange2013.ps1_state.xml
    NDP451-KB2858728-x86-x64-AllOS-ENU.exe
    UcmaRuntimeSetup.exe
    Windows6.1-KB2506143-x64.msu
    Windows6.1-KB2533623-x64.msu
    Windows6.1-KB974405-x64.msu

    Can you please list out the files needed in the c:\install for offline installer?
    Thanks

    Like

      • Thank you. I am able re-start the installation using elevated powershell privileges.
        I have a quick followup question. What do I need to change in the code to make sure the pre-reqs are picked from the c:\install if already present?

        Installation works fine in WS2012 R2. But on WS2012 I keep seeing this.
        Processing Microsoft .NET Framework 4.51 ({7DEBE4EB-6B40-3766-BB35-5CBBC385DA37})
        Package-Install : Problem installing Microsoft .NET Framework 4.51
        At C:\Users\Administrator\Desktop\Install-Exchange2013.ps1:988 char:21
        + Package-Install “{7DEBE4EB-6B40-3766-BB35-5CBBC385DA37}” “Mi …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Package-Install

        Like

  26. Hello, This is why on Windows 2012 R2 the autologin does not work. If you see the log, it tells you if you use the -verbose switch. Any idea how to get the autologin to work, I am not sure how many times to run the script because it is not autologin and running the script. Thanks for your help Michael.

    Transcript started, output file is C:\Install\Install-Exchange2013.ps1_20140509092028.log
    VERBOSE: Disabling File Security Warning dialog
    VERBOSE: Disabling Automatic Logon
    Checking for pending reboot ..
    VERBOSE: Current phase is 1 of 6
    Installing Operating System prerequisites

    Like

    • This is as designed. The script disables autologin right after starting to prevent situations where the script will automatically start (again) should the server restart in unforeseen ways (i.e. before it ends) to prevent ending up in a loop. Before the scripts configures RunOnce etc. and initiating a reboot, it will enable AutoLogin again (except for the last phase) – that’s also logged.

      Like

      • Michael you’re absolutely right. I hadn’t noticed that the autologin is re-enabled towards the end of the script. For me, it never continued after reboot but knowing what phase had completed was good enough. Kept running the script until I got to phase 6. Have production environment up and running and currently testing backups and Lync 2013 OWA IM and Presence integration. Although I am having an issue with OWA IM and Presence integration…IM sign-in is failing. Do you have any good points you can pass on or links to helpful articles…my problem from seeing the Lync logs is that for some reason, my Mailbox server is trying to make the connection to Lync although the CAS service is on a totally different server. Thanks Michael.

        Like

  27. Your script is truly a work of art!!! Such A joy to read. There’s so much to take away from this one script!!! Thank you for this!!! Keep up the good work!!!

    Like

  28. Pingback: Exchange 2013 Unattended Installation Script (Updated) | EighTwOne (821) | JC's Blog-O-Gibberish

  29. Pingback: Script Updates | EighTwOne (821)

  30. Hey Michael,

    So i can see this working for my initial server for a brand new organization, but can you advise how i would use your script for installing other multi roles servers? For instance should i simply omit one of the peramters, and if so which one? so far i’m reading if you define organization then it creates the organization name, which is my scenario is i seperately implemented schema already, but if not then it attempts a AD schema prep. i would imagine i wouldn’t want either for the additional multirole servers?

    Edgar

    Like

    • Preparing Active Directory seperately is not uncommon. If you omit the Organization parameter, it will skip the preparation (e.g. PrepareAD), for example:
      $Cred=Get-Credentials
      .\Install-Exchange2013 -InstallMultiRole -AutoPilot -Credentials $Cred

      Like

  31. Hi,
    Fantastic Script – saves a lot of time and messing around. Seems to work very well for what I need.
    One thing to note however, if I choose to set my own database name during the build such as “LAB Database 7” it will actually show as LAB,Database,7 on the ECP… Is this something that can be ironed out at all?

    Thanks,
    Dave

    Like

  32. I can’t seem to get this to run regardless of the switches I use. Here’s my latest attempt:

    .\Install-Exchange2013.ps1 -InstallMultiRole -SourcePath C:\ExchangeCu5 -IncludeFixes
    -InstallFilterPack

    Installing Microsoft Exchange Server 2013
    WARNING: \setup.exe not found

    PS C:\ExchangeCu5> dir setup.exe

    Directory: C:\ExchangeCu5

    Mode LastWriteTime Length Name
    —- ————- —— —-
    -a— 10/05/2014 5:14 PM 27824 setup.exe

    Help?

    Like

    • When you run it with the -Verbose parameter, what is it trying to execute? Just checked with a local path (C:\ExchangeSetup) as I usually run it directory off an UNC path, and see no issues. Could it be blocked from running?

      Like

  33. Michel,

    First off, thank you for this script. Excellent work!

    Next, I am curious why when I run “.\Install-Exchange2013 -NoSetup -Autopilot” multiple times (to prep the OS), the server restarts regardless of what roles, features or other prerequisites have been previously installed.

    I know one wouldn’t not normally run this command multiple times but it leads me to believe that: 1) Something isn’t installing correctly; or 2) The script does not have a built-in check to stop if all prereqs are found to be installed.

    The server I am testing on is a domain-joined Windows Server 2012 R2 Standard with all available updates installed.

    Can you help me to understand what I perceive to be a bug?

    Lastly, I received an error during the install. Below is the message from the log. Please help.

    Install-Exchange2013_ : Problem installing Exchange
    At C:\Tools\Scripts\Install-Exchange2013.ps1:1108 char:13
    + Install-Exchange2013_
    + ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Install-Exchange2013_

    **********************

    Thanks again.
    Todd

    Like

    • The script is based on certain phases (i.e. prereqs, prep, install, etc). I currently do not have shortcuts built-in when things. Also, you should not need to fire the script manually when specifying AutoPilot, unless there is something no in order with automatic logon. This is also the reason why you are not left with a prompt when install fails for some reason – I don’t want to end up with an unlocked desktop with logged on credentials.
      The error looks like an unsuccesfull install. I just do a basic check – for any setup issues, Exchange setup logs should provide more information.

      Like

      • Michel,

        The AutoPilot “auto login” piece worked fine. It seems as though when the prereqs were found to be installed that script ended. But there is no indication why it did not proceed. The log only states “WARNING: Unified Communications Managed API 4.0 Runtime already installed” and the transcript ends. No XML created, no other indication that the script will continue or needs to continue. Therefore, I perceive it to be a bug. I ran AutoPilot several times and never received a different result or output, so I stopped using the AutoPilot switch. That’s when I actually started seeing progress with script and received the installation error that I provided in my original comment.

        Regarding that error, I checked the Exchange setup logs and found the issue … missing organization name.

        I think I supposed too much when I thought that installing Exchange in a new domain with this script that the default organization name of “First Organization” would be used.

        Suggestion: Document this a bit more and/or make the Organization switch required for your script when no organization is present (i.e. prompt for org name if one is needed).

        Next, apparently, if we do not run in AutoPilot mode, we have to run the same command over and over and over until all of the “phases” are completed.

        Suggestion: When not using AutoPilot, create a pause instead of having the script stop altogether; or make this very clear in your documentation that we need to run the script several times (and how many times that may be based on the number of phases there are). There isn’t anything currently that I could find in the script that states the commands needs to be run several times.

        Lastly, if the install fails, for whatever reason, the next time I run the script (no matter what new switches I add), the XML file seems to take precedence because it contains information (switch values) from the previous run(s). This caused me some frustration when trying to run the script after I found the cause of the install failure and tried to add the Organization switch. The value I added for Organization did not get updated in the XML file, therefore, the install continued to fail. I had to remove/rename the XML file and start all over with phase 1 by running the script again.

        Thankfully, I have a lab to test out how to run this script through trial and error. The script isn’t perfect but what is (we always seem to be chasing our tail on one thing or another). I can see that it will save me A LOT of time (and potential mistakes) once I have it figured.

        Michel, this is a great script! I appreciate it very much and your contributions to the community.

        Thank you.
        Todd

        Like

        • Hi Todd,

          Thanks for your feedback. Checking if AD is already prepared or not in relation to the Organization parameter was already on the ‘to do’ list 🙂
          On not using AutoPilot .. “When not specified, you will need to restart, logon and start the script manually each time (without parameters).” Agreed that that could use some rephrasing, thanks. Regarding success/failure, I was thinking
          Lastly, if the install fails, for whatever reason, I was more thinking on opening up setup logs (cause that is what most people do), leaving the system locked.
          On the XML parameter precedence, duly noted 🙂

          Cheers!

          Like

  34. Found a minor bug. In line 1151 or thereabouts script checks the version of the MSExchangeIS service’s exe to determine installed Exchange version. Problem is that the IS service is not present for dedicated CAS servers so the script fails to install recommended hotfixes.

    Line: $ImagePathVersion= File-DetectVersion ( (Get-WMIObject -Query ‘select * from win32_service where name=”MSExchangeIS”‘).PathName.Trim(‘”‘) )

    Switching to a common service like MSExchangeServiceHost should resolve. Will confirm once I’ve installed my mailbox servers.

    Nice script, thanks for making it available by the way.

    Like

  35. Great Script !!! It successfully install Exchange 2013 when ran under Administrator account. Does this support System ( “NTAuthority”) account?

    Like

  36. Pingback: Thoughts on Exchange and comparisons | Dave Stork's IMHO

  37. Hi Michel,

    If I don’t specify MDBDB and MDBDBPath and Logs, does this mean that script will not create databases?

    Or in other words, how can I use the screenshot without creating databases?

    Cheers!

    Like

  38. Hi Michel,

    Bumping into an issue, where forest functional level can’t get verified.
    I’m trying to install Exchange 2013 CU6 on Windows Server 2012.
    There is already one Exchange 2010 and Exchange 2013 CU6 server installed in the same domain.
    Servers are installed in CHILD domain of this greenfield AD forest deployment.

    Below the cmdlet and output:
    PS D:\Software> .\Install-Exchange2013.ps1 -InstallMultiRole -SourcePath “D:\Software\Exchange2013_Extracted” -TargetPat
    h “D:\ExchSrvr” -AutoPilot -IncludeFixes -InstallFilterPack -Verbose
    VERBOSE: Script D:\Software\Install-Exchange2013.ps1 called using [InstallMultiRole, True] [SourcePath,
    D:\Software\Exchange2013_Extracted] [TargetPath, D:\ExchSrvr] [AutoPilot, True] [IncludeFixes, True]
    [InstallFilterPack, True] [Verbose, True]
    VERBOSE: Using parameterSet CM
    VERBOSE: Running on OS build 6.2.9200
    VERBOSE: No state file found at C:\Install\Install-Exchange2013.ps1_state.xml
    Performing sanity checks ..
    VERBOSE: Checking Operating System .. 6.2.9200
    Checking running mode ..
    Checking if we can access Exchange setup ..
    Exchange setup version: 15.00.0995.028 (Unknown Version)
    Checking roles to install
    Checking domain membership status ..
    Checking NIC configuration ..
    Checking temporary installation folder ..
    Checking Exchange Forest Schema Version
    Exchange Forest Schema Version is
    Checking Exchange Domain Version
    Exchange Domain version is 13236
    Checking domain mode
    Domain is in native mode
    Checking Forest Functional Level
    The following exception occurred while retrieving member “get”: “There is no such object on the server.

    At D:\Software\Install-Exchange2013.ps1:496 char:15
    + return( ($ForestRoot.get(“msDS-Behavior-Version”) ))
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
    + FullyQualifiedErrorId : CatchFromBaseGetMember

    Check-Sanity : Forest is not Functional Level 2003 or later
    At D:\Software\Install-Exchange2013.ps1:1031 char:5
    + Check-Sanity
    + ~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Check-Sanity

    When I run the functions separately, I get result for domain level, but not for Forest level

    PS D:\Software> Function Get-ExchangeForestLevel {
    $RootDSE= ([ADSI]””).distinguishedName
    return ( ([ADSI]”LDAP://CN=ms-Exch-Schema-Version-Pt,CN=Schema,CN=Configuration,$RootDSE”).rangeUpper )
    }

    Function Get-ExchangeDomainLevel {
    $RootDSE= ([ADSI]””).distinguishedName
    return( ([ADSI]”LDAP://CN=Microsoft Exchange System Objects,$RootDSE”).objectVersion )
    }

    PS D:\Software> Get-ExchangeDomainLevel
    13236

    PS D:\Software> Get-ExchangeForestLevel

    PS D:\Software>

    I’m able to connect to Configuration partition using ADSIEDIT with the same credentials.

    Like

  39. Hi,

    I am having problems with the script crashing out after the 1st reboot with:

    Exchange Domain version is
    Checking domain mode
    Domain is in native mode
    Checking Forest Functional Level
    Forest Functional Level is 2003 or later
    Checking provided credentials
    Check-Sanity : Provided credentials don’t seem to be valid
    At C:\MSX2K13\Install-Exchange2013.ps1:1030 char:5
    + Check-Sanity
    + ~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Check-Sanity

    I have moved all the files into new folders and allowed full access to them. Also run the powershell as domain admin (with ent admin etc) and still same – any ideas?

    Like

  40. Michel Hi,

    It looks like the script was originally designed and tested only with “single forest / single domain” scenario.

    That’s why a number of folks are having issues especially with the Forest level functions.

    I took the liberty to change the script as follows, this way the forest level checks in “single forest / multiple domain” scenario, especially if the Exchange is to be installed on one of the child domains.
    Lines 493 down:
    ### Begin Changes
    Function Get-ForestFunctionalLevel {
    #$RootDSE= ([ADSI]””).distinguishedName
    $RootDSE= (Get-ADRootDSE).rootDomainNamingContext
    write-host $RootDSE
    return( ([ADSI]”LDAP://cn=partitions,cn=configuration,$RootDSE”).get(“msDS-Behavior-Version”) )
    }

    Function Test-DomainNativeMode {
    $RootDSE= ([ADSI]””).distinguishedName
    return( ([ADSI]”LDAP://$RootDSE”).ntMixedDomain )
    }

    Function Test-ExchangeOrganization( $Organization) {
    #$RootDSE= ([ADSI]””).distinguishedName
    $RootDSE= (Get-ADRootDSE).rootDomainNamingContext
    return( [ADSI]”LDAP://CN=$Organization,CN=Microsoft Exchange,CN=Services,CN=Configuration,$RootDSE”)
    }

    Function Get-ExchangeForestLevel {
    #$RootDSE= ([ADSI]””).distinguishedName
    $RootDSE= (Get-ADRootDSE).rootDomainNamingContext
    return ( ([ADSI]”LDAP://CN=ms-Exch-Schema-Version-Pt,CN=Schema,CN=Configuration,$RootDSE”).rangeUpper )
    }
    ### End Changes
    This works well on a Windows 2013 R2 server. If you need to run this on an older version of Windows you may need to also import the ActiveDirectory module at the beginning of the script. The “Get-RootDSE” function requires the AD module.

    By the way, it is a great script and saved us a lot of time already.

    Regards,

    -Ilker

    Like

  41. I installed Exchange with this successfully. However I wonder why the BITS feature is removed, isn’t that necessary for succesful Windows updates?

    Also, the event log is filled with endless records about performance counters that have failed to update.

    Some events:
    – Event 2, Session “FastDocTracingSession” failed to start with the following error: 0xC0000035
    – Event 106, numerous times, e.g.:
    Performance counter updating error. Counter name is Per-Tenant KeyToRemoveBudgets Cache Size, category name is MSExchangeRemotePowershell. Optional code: 3. Exception: The exception thrown is : System.InvalidOperationException: The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.

    Performance Counters Layout information: FileMappingNotFoundException for category MSExchangeRemotePowershell : Microsoft.Exchange.Diagnostics.FileMappingNotFoundException: Cound not open File mapping for name Global\netfxcustomperfcounters.1.0msexchangeremotepowershell. Error Details: 2

    Could this be related to the removal of BITS or is it something else?

    Like

  42. Pingback: PowerShell Scripts for your Exchange and Office 365 Toolkit

  43. Pingback: IT/DEV Connections 2015 Wrap-Up | EighTwOne (821)

  44. Does the /DoNotStartTransport persist? I want to install some servers BUT not have them route mail etc. i was planning on also adding some sections to net stop some other services. Have you looked into this, or have any pointers?

    Thanks

    Like

  45. Hi! Nice script!
    Trying to install using the Exchange 2013 CU10-installer and I get this error in the ExchangeSetup.log: [ERROR] Exchange organization name is required for this mode. To specify an organization name, use the /OrganizationName parameter.

    The name I entered as organization didn’t validate and as such wasn’t processed.
    I added the following line at line-position 200 (between the [paramater-definition and the [string]-line for $Organization):
    [ValidatePattern(‘(?# Organization Name cannot contain special characters, only upper- or lowercase letters from A to Z, numbers 0 to 9, spaces but not at the beginning or end, a hyphen or a dash, and can be up to 64 characters, but not blank.)^[a-zA-Z0-9\-\–\—][a-zA-Z0-9\-\–\—\ ]{1,62}[a-zA-Z0-9\-\–\—]$’)]
    It now looks like this:
    [parameter( Mandatory=$false, ValueFromPipelineByPropertyName=$false, ParameterSetName=”NoSetup”)]
    [ValidatePattern(‘(?# Organization Name cannot contain special characters, only upper- or lowercase letters from A to Z, numbers 0 to 9, spaces but not at the beginning or end, a hyphen or a dash, and can be up to 64 characters, but not blank.)^[a-zA-Z0-9\-\–\—][a-zA-Z0-9\-\–\—\ ]{1,62}[a-zA-Z0-9\-\–\—]$’)]
    [string]$Organization,

    After that, passing an invalid organization-name will trigger this error:
    C:\Install\Install-Exchange15.ps1 : Cannot validate argument on parameter ‘Organization’. The argument “This is a very long name with more than 64 characters to show that it triggers an error onvalidation” does not match the “(?# Organization Name cannot caontain special characters, only upper- or lowercase letters from A to Z, numbers 0 to 9, spaces but not at the beginning or end, a hyphen or a dash, and can be up to 64 characters, but not blank.)^[a-zA-Z0-9\-\–\—][a-zA-Z0-9\-\–\—\ ]{1,62}[a-zA-Z0-9\-\–\—]$” pattern. Supply an argument that matches “(?# Organization Name cannot caontain special characters, only upper- or lowercase letters from A to Z, numbers 0 to 9, spaces but not at the beginning or end, a hyphen or a dash, and can be up to 64 characters, but not
    blank.)^[a-zA-Z0-9\-\–\—][a-zA-Z0-9\-\–\—\ ]{1,62}[a-zA-Z0-9\-\–\—]$” and try the command again.
    At line:1 char:58
    + .\Install-Exchange15.ps1 -InstallMultiRole -Organization $org -MDBName MDB01 -MD …
    + ~~~~
    + CategoryInfo : InvalidData: (:) [Install-Exchange15.ps1], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Install-Exchange15.ps1

    Like

  46. Pingback: Installing Exchange 2013 prerequisites – Unified Communications Technologist

  47. Tried to install Exchange on the drive which was formatted as ReSFS.
    Setup just failed, found that in an Exchange setup log.
    Something that the script is missing for the requirements check.

    Like

    • Thanks for the feedback. I can’t mimic all of Exchange setup’s prerequisite checks, but it tries to do the obvious ones. I’ll put this on the wish list. And as you found out, ReFS is not supported to store the binaries.

      Like

  48. Hi Michel,
    thx for this wonderful script!

    I tried to install only pre-reqs in a New Lab for Exchange 2013 CU12 on a newly fresh server (WS2012R2), but it fails.

    I looked at your code, and you give this example:
    .EXAMPLE
    .\Install-Exchange15.ps1 -NoSetup -Autopilot

    But this is not working, and gives the following:

    PS C:\ex2013lab> .\Install-Exchange15.ps1 -NoSetup -Autopilot
    Script C:\ex2013lab\Install-Exchange15.ps1 called using [NoSetup, True] [AutoPilot, True]
    Using parameterSet NoSetup
    Running on OS build 6.3.9600
    Performing sanity checks ..
    Checking temporary installation folder ..
    Checking running mode ..
    Write-MyError : OrganizationName not specified and no Exchange Organization discovered

    Also, that’s inside the install log:
    2016-05-30 16:49:36Z: Performing sanity checks ..
    2016-05-30 16:49:36Z: Checking temporary installation folder ..
    2016-05-30 16:49:36Z: [VERBOSE] Checking Operating System .. 6.3.9600
    2016-05-30 16:49:36Z: Checking running mode ..
    2016-05-30 16:49:36Z: [VERBOSE] Can’t find Exchange Organization object
    2016-05-30 16:49:36Z: [ERROR] OrganizationName not specified and no Exchange Organization discovered

    Maybe the NoSetup mode is broken with your 2.31 script version ?

    PS: I tried to add the Orginasation but then it asks for roles… and it seems roles parameter is not compatible with NoSetup parameter.

    thx in advance.

    Like

  49. Hello,
    I made a fork of this script with the following additions:
    – Add validation for initial AutoPilot credentials
    – Checks user for Enterprise-Admins and Schema-Admins group (starting at phase 3), because is user is not in Schema, then Exchange setup will fail, but script will start phase 4 anyway and re-fail…

    Let me know if you want it.

    Like

  50. Thanks for your script.
    It is working fine when executed locally from Exchange box itself but is there any way to execute the same script along with all Arguments from remote machine.

    Trying to execute below command but it is failing with error,
    Invoke-Command -ComputerName autoex1 -ScriptBlock { C:\Utils\Install-Exchange15.ps1 -Organization DemoLab -InstallMultirole -MDBDBPath E:\Databases\MDB01 -MDBLogPath E:\Logs\MDB01 -MDBName MDB01 -InstallPath C:\Utils\ -AutoPilot -Credentials $Cred -SourcePath E:\Install\ -IncludeFixes -InstallFilterPack -Verbose}

    PS C:\Users\Administrator>
    Invoke-Command -ComputerName -ScriptBlock { C:\Utils\Install-Exchange15.ps1 -Organization DemoLab -InstallMultirole -MDBDBPath E:\Databases\MDB01 -MDBLogPath E:\Logs\MDB01 -MDBName MDB01 -InstallPath C:\Utils\ -AutoPilot -Credentials $Cred -SourcePath E:\Install\ -IncludeFixes -InstallFilterPack -Verbose} -credential donmainame\administrator
    VERBOSE: No state file found at C:\Utils\\Install-Exchange15.ps1_state.xml
    Script C:\Utils\Install-Exchange15.ps1 called using [Organization, DemoLab] [InstallMultiRole, True] [MDBDBPath, E:\Databases\MDB01] [MDBLogPath, E:\Logs\MDB01] [MDBName, MDB01] [In
    stallPath, C:\Utils\] [AutoPilot, True] [Credentials, ] [SourcePath, E:\Install\] [IncludeFixes, True] [InstallFilterPack, True] [Verbose, True]
    Using parameterSet CM
    Running on OS build 6.3.9600
    Performing sanity checks ..
    Checking temporary installation folder ..
    VERBOSE: Checking Operating System .. 6.3.9600
    Checking running mode ..
    VERBOSE: Can’t find Exchange Organization object
    Exchange Organization will be: DemoLab
    Checking if we can access Exchange setup ..
    Exchange setup located at E:\Install\\setup.exe
    ExSetup version: 15.00.0847.032 (Exchange Server 2013 Service Pack 1)
    Checking roles to install
    Checking domain membership status ..
    Checking NIC configuration ..
    Checking MDB log path ..
    Checking MDB database path ..
    Checking Exchange Forest Schema Version
    Active Directory is not prepared
    Checking Exchange Domain Version
    Checking domain mode
    Domain is in native mode
    Checking Forest Functional Level
    Can’t read Forest schema version, operator possible not member of Schema admin group
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError
    + PSComputerName :

    Forest is not Functional Level 2003 or later
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError
    + PSComputerName :

    Like

  51. Hi Michel
    I needed to create your script as an function.
    So i just wrapped the script from before the cmdletbindings to the end like this.

    Function Install-Exchange15{
    Script code….
    }

    I ran this command:
    Install-Exchange15 -InstallMultiRole -SourcePath $CDRomPath -Organization “Tenant03” -MDBName “MDB1” -MDBDBPath “C:\MailboxData\MDB1\DB” -MDBLogPath “C:\MailboxData\MDB1\Log” -InstallPath “C:\Install” -AutoPilot -IncludeFixes -InstallFilterPack -Credentials $DomainCred -SCP “https://autodiscover.tenant03.com/autodiscover/autodiscover.xml”

    But when i am using it, i get this error.
    Install-Exchange15 : You cannot call a method on a null-valued expression.
    At line:12 char:1
    + Install-Exchange15 -InstallMultiRole -SourcePath $CDRomPath -Organization “Tenan …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [Install-Exchange15], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull,Install-Exchange15

    After debugging further, i got this error output.
    Exception : System.Management.Automation.RuntimeException: You cannot call a method on a null-valued expression.
    at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Excep
    tion exception)
    at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
    at System.Management.Automation.PSScriptCmdlet.RunClause(Action`1 clause, Object dollarUnderbar, Object input
    ToProcess)
    at System.Management.Automation.PSScriptCmdlet.DoProcessRecord()
    at System.Management.Automation.CommandProcessor.ProcessRecord()
    TargetObject :
    FullyQualifiedErrorId : InvokeMethodOnNull,Install-Exchange15
    InvocationInfo : System.Management.Automation.InvocationInfo
    ErrorCategory_Category : 7
    ErrorCategory_Activity : Install-Exchange15
    ErrorCategory_Reason : RuntimeException
    ErrorCategory_TargetName :
    ErrorCategory_TargetType :
    ErrorCategory_Message : InvalidOperation: (:) [Install-Exchange15], RuntimeException
    SerializeExtendedInfo : False
    CategoryInfo : InvalidOperation: (:) [Install-Exchange15], RuntimeException
    ErrorDetails :
    ScriptStackTrace : at Install-Exchange15, : line 1519
    at , : line 12
    PipelineIterationInfo : {}
    PSMessageDetails :

    Like

        • Hi Michel

          I think Powershell is having a bug.
          I know says line 1520.
          But find i do a search for the line in the function its really line 1631.

          It is bugging in this line which make sense, duo to it is a function.
          $ScriptName = $ScriptFullName.Split(“\”)[-1]

          Like

          • Nevermind this thread.

            I did not think this through.
            I cant make it as an functions, because i can see in the function Enable-RunOnce you are reusing the script. I cant do that with a function 🙂

            In my office my coworkers would like to say “Buy us an screw up cake!”.

            My plan is to use your perfect script for automatically deploying Exchange 2013 via Invoke commands with a remote PSSession.

            I think I programatically needs to copy “Install-Exchange15.ps1” to the remote computer, and then script an invoke command, with the correct parameters.

            How are you using this script in scripted rutines?

            \Simon

            Like

  52. Hi Michel

    I succeded copying the script to the remote server and it is up and running.
    Is they anyway i can get a status to know when the installation is completed?

    \Simon

    Like

    • You could use a (writable) UNC path location for InstallPath – there, logging and the status file will be stored. You can monitor / follow the log file – being it on that UNC share location or locally (systemdrive c$ share) using a tool like tail or baretail.

      Like

  53. Hi Michel

    I’m in trouble again. I actually downloaded the latest available version of the script.
    Script and parameters working fine when running the script manually on my other server.
    But when running with an Invoke-Command i get this error.

    C:\Scripts\Install-Exchange15.ps1 : Cannot index into a null array.
    At line:22 char:21
    + . “C:\$ScriptsPathName\Install-Exchange15.ps1” -InstallMulti …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [Install-Exchange15.ps1], RuntimeException
    + FullyQualifiedErrorId : NullArray,Install-Exchange15.ps1

    Exception : System.Management.Automation.RuntimeException: Cannot index into a null array.
    at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext f
    uncContext, Exception exception)
    at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame fra
    me)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedF
    rame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedF
    rame frame)
    at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
    at System.Management.Automation.PSScriptCmdlet.RunClause(Action`1 clause, Object dollarUnder
    bar, Object inputToProcess)
    at System.Management.Automation.PSScriptCmdlet.DoProcessRecord()
    at System.Management.Automation.CommandProcessor.ProcessRecord()
    TargetObject :
    CategoryInfo : InvalidOperation: (:) [Install-Exchange15.ps1], RuntimeException
    FullyQualifiedErrorId : NullArray,Install-Exchange15.ps1
    ErrorDetails :
    InvocationInfo : System.Management.Automation.InvocationInfo
    ScriptStackTrace : at Test-SchemaAdmin, C:\Scripts\Install-Exchange15.ps1: line 572
    at Check-Sanity, C:\Scripts\Install-Exchange15.ps1: line 1319
    at , C:\Scripts\Install-Exchange15.ps1: line 1716
    at , : line 22
    PipelineIterationInfo : {}
    PSMessageDetails :

    Cannot index into a null array.

    Length
    ——
    190

    22

    Before this error I printed my variables in an logfile on the remote server.

    D: – Tenant03 – ExchangeInstall – tenant03.com\administrator – https://autodiscover.tenant03.com/autodiscover/autodiscover.xml

    $SourcePath = “D:”
    $Organization = “Tenant03”
    $ExchangeInstallPath = “ExchangeInstall”
    $DomainCred = tenant03\administrator #Printed credential username.
    $SCP = “https://autodiscover.tenant03.com/autodiscover/autodiscover.xml”

    Like

  54. In the log from the InstallPath this is the only output i get.

    2016-08-12 21:10:45Z: Performing sanity checks ..
    2016-08-12 21:10:45Z: Computer name is 003MS01.tenant03.com
    2016-08-12 21:10:45Z: Checking temporary installation folder ..
    2016-08-12 21:10:45Z: Operating System is 6.3.9600
    2016-08-12 21:10:46Z: .NET Framework is 379893 (4.5.2)
    2016-08-12 21:10:46Z: Script running in elevated mode
    2016-08-12 21:11:15Z: Checking provided credentials
    2016-08-12 21:11:15Z: Credentials seem valid

    Like

  55. I can see the trail….

    Via Check-Sanity -> Test-SchemaAdmin -> Get-ForestRootNC functions.
    But if i manually copy paste your code to my remote server, it works…. Jus not via Invoke-Command….

    Like

  56. Tested the Get-ForestRootNC function via Invoke-Command and the function have no trouble.
    I think my debugging skills has reached an end, regarding your script VS Invoke-Command 😦

    Like

  57. I removed my try catch and now i am getting this.

    Script C:\Scripts\Install-Exchange15.ps1 called using [InstallMultiRole, True] [SourcePath, D:\] [Organization, Tenant03
    ] [MDBName, DB01] [MDBDBPath, C:\MailboxData\DB01\DB] [MDBLogPath, C:\MailboxData\DB01\Log] [InstallPath, c:\ExchangeIns
    tall] [AutoPilot, True] [IncludeFixes, True] [InstallFilterPack, True] [Credentials, System.Management.Automation.PSCred
    ential] [SCP, https://autodiscover.tenant03.com/autodiscover/autodiscover.xml%5D
    Running on OS build 6.3.9600
    Performing sanity checks ..
    Computer name is 003MS01.tenant03.com
    Checking temporary installation folder ..
    Operating System is 6.3.9600
    .NET Framework is 379893 (4.5.2)
    Script running in elevated mode
    Checking provided credentials
    Credentials seem valid
    Cannot index into a null array.
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
    + PSComputerName : 192.168.0.131

    Exception calling “.ctor” with “2” argument(s): “Value cannot be null.
    Parameter name: binaryForm”
    + CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
    + PSComputerName : 192.168.0.131

    Current user is not member of Schema Administrators
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError
    + PSComputerName : 192.168.0.131

    Like

      • It is something about the credential i believe….

        Testet it OK locally on remote machine… Hmm….

        Script C:\Scripts\Install-Exchange15.ps1 called using [InstallMultiRole, True] [SourcePath, D:\] [Organization, Tenant03
        ] [MDBName, DB01] [MDBDBPath, C:\MailboxData\DB01\DB] [MDBLogPath, C:\MailboxData\DB01\Log] [InstallPath, c:\ExchangeIns
        tall] [AutoPilot, True] [IncludeFixes, True] [InstallFilterPack, True] [Credentials, System.Management.Automation.PSCred
        ential] [SCP, https://autodiscover.tenant03.com/autodiscover/autodiscover.xml%5D
        Running on OS build 6.3.9600
        The requested operation cannot be completed. The computer must be trusted for delegation and the current user account m
        ust be configured to allow delegation.
        + CategoryInfo : NotSpecified: (:) [ConvertFrom-SecureString], CryptographicException
        + FullyQualifiedErrorId : System.Security.Cryptography.CryptographicException,Microsoft.PowerShell.Commands.Conver
        tFromSecureStringCommand
        + PSComputerName : 192.168.0.131

        Performing sanity checks ..
        Computer name is 003MS01.tenant03.com
        Checking temporary installation folder ..
        Operating System is 6.3.9600
        .NET Framework is 379893 (4.5.2)
        Script running in elevated mode
        AutoPilot specified but no or improper credentials provided
        + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError
        + PSComputerName : 192.168.0.131

        Like

  58. First off, awesome work! I really appreciate the contributions to the community. I think i may have come across a bug or possibly expected behavior. I am \launching the script with NoSetup option in which i am expecting to only install the prerequisites.

    It appears that all prerequisites install with the exception of the .NET prerequisites for 4.6.1. it seems that the logic skips the .NET identification due to the MajorSetupVersion not being enumerated if NoSetup is run. this causes Install461 not to be set and the script follows the 4.5.2 branch which doesnt require the hotfixes, and it also adds the 4.6.1 blockade to a server that already has 4.6.1 installed 🙂

    My notes:

    Excerpt From Log (that apply to my testing)
    .NET Framework is 394271 (4.6.1)
    Exchange setup version (15.01.0466.034) doesn’t support .NET Framework 4.6.1
    .NET Framework 4.5.2 or later detected
    Set installation blockade for .NET Framework 4.6.1 (KB3133990)

    *******************************************************************************
    The last entry from above is inaccurate evaluation because EX2016_CU2 does support 4.6.1. with appropriate hotfixes

    To debug this i first looked at where the 461 code for installing the updates was in the script:

    If( @($WS2008R2_MAJOR, $WS2012_MAJOR, $WS2012R2_MAJOR) -contains $MajorOSVersion) {

    $TempInstall461= $False
    If( ($State[“MajorSetupVersion”] -ge $EX2016_MAJOR -and (is-MinimalBuild $State[“SetupVersion”] $EX2016SETUPEXE_CU2)) -or
    ($State[“MajorSetupVersion”] -eq $EX2013_MAJOR -and (is-MinimalBuild $State[“SetupVersion”] $EX2013SETUPEXE_CU13))) {
    If( $State[“NoNet461”]) {
    Write-MyOutput “.NET Framework 4.6.1 supported, but NoNet461 specified – will use .NET Framework 4.5.2”
    }
    **** Else {
    Write-MyOutput “Exchange setup version ($($State[“SetupVersion”])) found, will use .NET Framework 4.6.1″
    $State[“Install461”]= $True
    }
    }
    Else {
    If( $State[“NoNet461”]) {
    Write-MyWarning “Ignoring NoNet461 switch: Exchange setup version ($($State[“SetupVersion”])) doesn’t support .NET Framework 4.6.1″
    }
    Else {
    Write-MyOutput “Exchange setup version ($($State[“SetupVersion”])) doesn’t support .NET Framework 4.6.1″
    }

    My run should have followed the Else branch above (denoted with ****) and set $State[“Install461”]= $True, but it failed the condition because $State[“MajorSetupVersion” are only set when “NoSetup” is not being run and you are actually installing exchange.

    I guess i would just think that the .NET hotfixes should be included as part of the pre-req run as they are pretty large downloads and nice to get out of the way prior to the actual exchange install.

    I could be wrong as im not the greatest with powershell but thought i would forward along…

    Like

  59. Hi Michel,

    Nice script but having a slight problem with Phase 4 – the actual Exchange install on v2.7.
    Invalid parameter.

    Installer Log
    2016-11-15 14:52:57Z: Installing Exchange
    2016-11-15 14:52:57Z: Installing Microsoft Exchange Server (15.0)
    2016-11-15 14:52:57Z: [VERBOSE] Executing C:\xch\xchbinaries\setup.exe /mode:install /roles:Mailbox,ClientAccess /IAcceptExchangeServerLicenseTerms /InstallWindowsComponents /MdbName:AC01DAGDB2 /DBFilePath:”M:\ExDB\AC01DAGDB2\AC01DAGDB2.edb” /LogFolderPath:”M:\EXDB\AC01DAGDB2\Log” /TargetDir:”e:\program files\Microsoft Exchange Server\” /DoNotStartTransport
    2016-11-15 14:53:07Z: [VERBOSE] Process exited with code 1
    2016-11-15 14:53:07Z: [ERROR] Problem installing Exchange. Please consult the Exchange setup log, i.e. C:\ExchangeSetupLogs\ExchangeSetup.log

    Exchange Log
    [11/15/2016 14:53:06.0147] [0] The registry key, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\V15\Setup, wasn’t found.
    [11/15/2016 14:53:06.0407] [0] RuntimeAssembly was started with the following command: ‘/mode:install /roles:Mailbox,ClientAccess /IAcceptExchangeServerLicenseTerms /InstallWindowsComponents /MdbName:AC01DAGDB2 /DBFilePath:M:\ExDB\AC01DAGDB2\AC01DAGDB2.edb /LogFolderPath:M:\EXDB\AC01DAGDB2\Log /TargetDir:e:\program files\Microsoft Exchange Server /DoNotStartTransport /sourcedir:C:\xch\xchbinaries’.
    [11/15/2016 14:53:06.0422] [0] [ERROR] The parameter ‘donotstarttransport’ cannot have a value.
    [11/15/2016 14:53:06.0422] [0] The registry key, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\v8.0, wasn’t found.
    [11/15/2016 14:53:06.0422] [0] The registry key, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v14, wasn’t found.
    [11/15/2016 14:53:06.0422] [0] Setup checks failed: Invalid command line arguments.

    I can see /DoNotStartTransport in the script but not where it adds the /sourcedir:C:\xch\xchbinaries at the end. And I can’t find anything from MS that states that /donotstarttransport has to be in a particular place.
    Also I would have thought that the /TargetDir should have quotes since there are spaces. The installer log suggests that it has them but it doesn’t carry across to the setup command line according to the Exchange log. Maybe the log just doesn’t log them of course. 🙂

    Like

  60. Pingback: Results Install-Exchange15 survey | EighTwOne (821)

  61. Great effort Michel, Thanks a lot.
    but according to my read, found somewhere written filter pack is not at all recquired in exchange 2016 CU5. then why its considering installing and that too mandatory. my setup failed on filterpack…

    exchange got inbuilt features now so advise is to do not install filterpack additonally because you always have to care of filter pack updated and new versions releases too .. its like a dependency.

    thaughts?

    Like

    • Thanks for the feedback. It was originally added to add and register OneNote and Publisher filter drivers for older versions of Exchange 2013.
      Since then, support for those types was added in the product and installing the driver was deprecated (check supported file types using Get-SearchDocumentFormat).
      Might be time to get rid of the switch 🙂

      Like

  62. Seems that it is downloading cumulative update (KB3206632) to Server 2016 that is already updated with the latest CU (to date). After that the script just exits.

    Like

  63. It doesn’t install or check for .Net 4.6.2 (required) when installing version 2013 CU17. Install just stops with no messages.

    Like

  64. Pingback: Building an Ultra Secure Microsoft Exchange Server | Jonathan Hassell

  65. Hi Michel, first of all: Nice script! You added targetpath support for recover mode but using targetpath with recover is not valid: “Parameter set cannot be resolved using the specified named parameters.”. It seems that the parameterset is missing for the targetpath switch in script version 2.99.2. Could you please check that?

    Like

  66. Hi Michael,
    Would it be possible to add a switch to NOT check for membership of Enterprise Admins and Schema Admins?
    e.g. An AD team will do any schema updates etc. beforehand and won’t add the install account to those groups.

    Like

  67. Thanks for this great script!! I used it without issue on an Exchange 2016 deplyment and the result was excellent. Getting ready to try the newly updated on another 2016 ddployment.

    Like

  68. Hey, getting FilePath-Error for EX-Setup with EX19 preview on Server2016 Core. Did not had this error with older setups/script versions.

    Write-MyError : Can’t find Exchange setup at C:\install\EX
    At C:\install\Install-Exchange15.ps1:1766 char:13
    + Write-MyError “Can’t find Exchange setup at $($State[‘Sou …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError

    regards

    Like

  69. hey,

    UCMA 4 Setup from download does not work for Server core. so you have to use the setup included in the install media.
    Can you build up a check for this an install from the apropriate source?

    regards

    Like

  70. There is a typo in line 2616 as “{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}” appears twice in this statement…

    If ( $State[“VCRedist2013”] ) {
    Package-Install “{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}|{5740BD44-B58D-321A-AFC0-6D3D4556DD6C}|{CB0836EC-B072-368D-82B2-D3470BF95707}|{929FBD26-9020-399B-9A7A-751D61F0B942}|{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}” “Visual C++ 2013 Redistributable” “vcredist_x64_2013.exe” “https://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe” (“/install”, “/quiet”, “/norestart”)
    }

    Also I’m having an issue as the install of vcredist_x64_2013 on my Windows 2016 Datacenter server. The install seems to work without errors but these two registry keys “{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}” and {929FBD26-9020-399B-9A7A-751D61F0B942} are not created. Your script is looking for these keys and tries to reinstall this package and then fails.

    2018-10-23 01:24:04Z: [VERBOSE] Checking if package {929FBD26-9020-399B-9A7A-751D61F0B942} is installed ..
    2018-10-23 01:24:05Z: [ERROR] Problem installing Visual C++ 2013 Redistributable – For fixes, check C:\Windows\WindowsUpdate.log; For .NET Framework issues, check ‘Microsoft .NET Framework 4 Setup’ HTML document in C:\Users\username\AppData\Local\Temp

    I’m reluctant to just create the registry files which is what this URL suggests… https://zzz.buzz/notes/vc-redist-packages-and-related-registry-entries/#x64-120305010

    Please help
    Brian

    Like

    • Thanks for catching the duplicate. VC++ comes in many forms, and every package has its own GUID. Therefor, I check on these GUIDs (which I know of). Only one of these should be present to indicate VC++2013 is there; if it’s not, it’s not installed (or as said, I don’t check for that GUID). The error with VC++ could be because it’s already installed. Still looking for a better way to detect VC++2013 (and 2012 and 2010 for that matter), as this becomes a bit messy 🙂

      Like

  71. Pingback: Installing Exchange 2016 in the lab – Notes from MWhite

  72. Hi Michel,
    Hopefully just me but the Get-VCRuntime function in v3.00.3 is identifying the Visual C++ 2013 pre-req for CU21 as being already installed when it isn’t and obviously Exchange 2013 then refuses to install.

    If I run this which I used for checking whether it was present for a CU21 update I get $null
    $VisualCUpdatePresent = Get-WmiObject -Class win32_product|where-object {$_.identifyingnumber -eq “{929FBD26-9020-399B-9A7A-751D61F0B942}”}

    Registry shows only v11.0 under the HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\ path

    Regards
    NT

    Like

  73. Hi! I tried to use your script but sadly run into a error after the preparations:

    Checking for pending reboot ..
    Installing Exchange
    Installing Microsoft Exchange Server (15.1)

    Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly ‘Microsoft.Exchange.Setup.Bootstrapper.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad
    364e35’ or one of its dependencies. The system cannot find the file specified.
    Write-MyError : Exchange Setup exited with non-zero value or Install info missing from registry: Please consult the Exchange setup log, i.e. C:\ExchangeSetupLogs\ExchangeSetup.log
    At C:\install\Install-Exchange15.ps1:1186 char:17
    + … Write-MyError ‘Exchange Setup exited with non-zero value …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError

    I cant find the error. Am I missing something? Trying to install the latest 2016 cu 11 file on a patched windows server 2016.

    Like

  74. Hello Michel,

    Thanks for this great script! I am facing a small issue with the script as following:

    PS E:\> .\Install-Exchange15.ps1 -NoSetup -SourcePath ‘D:\’ -Verbose
    VERBOSE: State information loaded from C:\Install\SERVER_Install-Exchange15.ps1_state.xml
    Script E:\Install-Exchange15.ps1 v3.00.2 called using [NoSetup, True] [SourcePath, D:\] [Verbose, True]
    VERBOSE: Using parameterSet NoSetup
    Running on OS build 10.0.14393
    VERBOSE: Loaded assemblies for configuring wallpaper
    VERBOSE: Continuing from last successful phase 3
    Performing sanity checks ..
    Computer name is SERVER.NAME.COM
    Checking temporary installation folder ..
    Operating System is 10.0.14393
    Server core mode: False
    .NET Framework is 461814 (4.7.2)
    Script running in elevated mode
    User is member of Schema Administrators
    User is member of Enterprise Administrators
    Computer is located in AD site HQ
    Exchange Organization is: Organization
    Checking if we can access Exchange setup ..
    Exchange setup located at D:\setup.exe
    ExSetup version: Exchange Server 2019 RTM (build 15.01.1591.010)
    Not checking roles (NoSetup, Recover or Upgrade mode)
    Checking domain membership status ..
    Checking NIC configuration ..
    Checking Exchange Forest Schema Version
    Exchange Forest Schema Version is 15332
    Checking Exchange Domain Version
    Exchange Domain Version is 13236
    Checking domain mode
    Domain is in native mode
    Checking Forest Functional Level
    Forest Functional Level is 2012 R2 or later
    Checking for pending reboot ..
    Installing Exchange
    Installing Microsoft Exchange Server (15.1)

    Microsoft Exchange Server 2016 Cumulative Update 11 Unattended Setup

    An empty value is specified for parameter ‘roles’.
    Setup checks failed: Invalid command line arguments.

    Please type ‘setup.exe /help’ for more information.
    Write-MyError : Exchange Setup exited with non-zero value or Install info missing from registry: Please consult the Exchange setup log, i.e. C:\ExchangeSetupLogs\ExchangeSetup.log
    At E:\Install-Exchange15.ps1:1187 char:17
    + … Write-MyError ‘Exchange Setup exited with non-zero value …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError

    Like

      • Thanks Michel for the quick response!

        I just want to share my workaround that fixed my issue. So in the line # 1167

        $Params= ‘/mode:install’, “/roles:$RolesParm”, ‘/IAcceptExchangeServerLicenseTerms’, ‘/DoNotStartTransport’, ‘/InstallWindowsComponents’

        I changed the parameter /roles:$RolesParm to be /roles:Mailbox as following:

        $Params= ‘/mode:install’, “/roles:Mailbox”, ‘/IAcceptExchangeServerLicenseTerms’, ‘/DoNotStartTransport’, ‘/InstallWindowsComponents’

        Again, many thanks for this helpful tool you made.

        Regards,
        Waddah

        Like

  75. Hi Michel,
    Unless I’m mistaken you don’t seem to have updated the script for Exchange 2013 CU22 etc?

    Regards
    Neill

    Like

  76. Hi Michel,
    in the line: If( Get-Command -Cmdlet Add-MpPreference -ErrorAction SilentlyContinue) you have to check for -Name and not -CmdLet. In case a server does NOT have the Windows Defender binaries and you run Get-Command -Cmdlet Add-MpPreference you simply get a list of all cmdlets on the system and not an error so it simply assumes that Defender is present and will start to try and make exclusions.. that obviously fails.

    When I change that line into:
    If( Get-Command -Name Add-MpPreference -ErrorAction SilentlyContinue)
    it correctly handles the absence of Defender.

    Thanks for the script!
    Regards,
    Eric

    Like

  77. Pingback: Useful PowerShell scripts – ITom Blog

  78. Pingback: Dowst.Dev | PowerShell Weekly – September 20, 2019

  79. Hi Michel,

    I’m just about to upgrade my Exchange environment (which I originally set up with your script, too ;-)) and ran into an error when determining the Exchange Version (using your current version 3.2.2):

    … A null key is not allowed in a hash literal.
    At line:47 char:9…

    … You cannot call a method on a null-valued expression.
    At line:51 char:7…

    After I checked the code I noticed that though you added the new build number for Exchange 2019 CU3 but you didn’t change corresponding variable. I also know copy/paste problems :-). After changing line 613 from $EX2019SETUPEXE_CU2 to $EX2019SETUPEXE_CU3 the script runs without error. Perhaps you want to fix that.

    And again thanks for the script!
    Daniel

    Like

  80. I must be doing something wrong. The script ran through a few reboots, but then just quit. Never installed Exchange, and all I am left with is a background stating “Setup Exchange Server 2016 Cumulative Update 14, phase 4”

    Like

    • Ah. I get this…

      Write-MyError : Exchange Setup exited with non-zero value or Install info missing from registry: Please consult the
      Exchange setup log, i.e. C:\ExchangeSetupLogs\ExchangeSetup.log
      At C:\temp\Install-Exchange15.ps1:1233 char:17
      + … Write-MyError ‘Exchange Setup exited with non-zero value …
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
      + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError

      Like

  81. Hi Michel,

    I tryed your script but there is a problem with downloading a patch usin Bits.

    2020-01-26 17:44:04Z: Package CPU usage is high when you use RPC over HTTP protocol in Windows 8.1 or Windows Server 2012 R2 not found, downloading to windows8.1-kb3041832-x64_67dff11777c5aca0f86f2b20862de4a7959fa2ea.msu
    2020-01-26 17:44:04Z: [VERBOSE] Source: http://download.windowsupdate.com/c/msdownload/update/software/htfx/2015/04/windows8.1-kb3041832-x64_67dff11777c5aca0f86f2b20862de4a7959fa2ea.msu
    2020-01-26 17:44:17Z: Installing CPU usage is high when you use RPC over HTTP protocol in Windows 8.1 or Windows Server 2012 R2 from C:\Install
    2020-01-26 17:44:17Z: [WARNING] C:\Install\windows8.1-kb3041832-x64_67dff11777c5aca0f86f2b20862de4a7959fa2ea.msu not found

    I can download and install it manualy. Just wanted to inform you.

    Like

  82. Hi Michel, the Exchange 2016 versions in lines 703 and 704 are incorrect. The CU14 key is mentioned twice and CU16 in missing. This results in the error: DuplicateKeyInHashLiteral.
    Could you update those lines pls?
    Thanks!

    Like

  83. Another thing, sorry.
    Does the source path have to be local, or can it be a UNC path to a share?
    I’ve tried “\\servername\sharename\folder” and ‘\\servername\sharename\folder’ within the command but both return the same error in the ExchangeSetup.log
    “F:\TargetPath /sourcedir:\\servername\sharename\folder” is not an acceptable path. You must use an absolute, local, long file path, that does not contain ‘~’.
    Parameter name: Path

    Thanks

    Like

  84. Hi Michel, the installation of Exchange 2019 also requires VCRuntime 2012. The script v3.2.5 line 2565 now says: ‘$State[“MajorSetupVersion”] -eq $EX2016_MAJOR’. I had to change that to ‘$State[“MajorSetupVersion”] -ge $EX2016_MAJOR’ to set ‘$State[“VCRedist2012”]= $True’. Now the installation continues.
    Usually I manually install the prerequisites already before starting your script so didn’t run in to this issue before.

    Like

  85. Pingback: Exchange 2019 – Automated Install – Troublenet

  86. Hi there!
    Just posting my experience with the script so far:
    Installing Exchange 2016 CU19
    Here’s my parameter set:

    .\Install-Exchange15.ps1 –InstallMailbox –SourcePath “F:\” -AutoPilot -MDBName “MDB01” -MDBDBPath “E:\DB” -MDBLogPath “E:\Logs” -Credentials $cred -IncludeFixes -Verbose

    now to the conclusion:
    – prerequisite check didn’t recognize that vc++ 2013 was installed and was failing to download via BITS. When i pasted the file in C:\Install it continued without problems
    – The Autopilot parameter didn’t work at all. I had to reboot the server manually and had to restart the script after every phase
    – Parameters MDBName, MDBDBPath and MDBLogPath didn’t work either. It just created a default database under C:\Program Files\Microsoft\Exchange Server\V15\Mailbox

    In the end it seems there is no “finish” on the script, i’m just getting an error :

    Current phase is 7 of 3
    Write-MyError : Unknown phase (7)
    In C:\_install\Install-Exchange15.ps1:2997 Zeichen:13
    + Write-MyError “Unknown phase ($($State[“InstallPhase”]))”
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-MyError

    Other than that, the script finished the install

    Any idea what might’ve gone wrong?

    Regards,
    Chris

    Like

    • Thanks for your feedback. Made a note re VC++2013. On installation, what do the logs say; aborting at step 3 = problem with ExSetup – see Exchange Setup log.
      For AutoPilot to work, provided credentials need to be able to log on interactively, there is no GPO blocking automatic log on, source path (F) drive is available for the (domain) credentials you provided (and which are used to log on.. provided it can log on), amongst other things.

      Like

  87. Hi,

    Looks like a great script! Couple of quick questions:
    With the update mode, will the script go through and place the server into maintenance mode etc prior to completing the upgrade?

    Also, when running the script to install as a new server in existing DAG, will it mark the server as off-line/maintenance mode at end to allow post installation work e.g SSL certs receive connectors etc.
    I am assuming that these sorts of task could be added manually to the script within “Customisation”?

    Like

    • 1) No. that is actually a good point.
      2) Yes. What the script can do is set the Autodiscover SCP record post-installation; any custom code can be put in the customization section, or call an external script to run for configuration etc. Since that is often very specific, I’ll leave that up to you.

      Like

  88. Hi Michel!

    The latest script (v3.8) doesn’t recognize the exchange version correctly. For Ex2016 CU23 I’m getting “ExSetup version: Exchange Server 2019 Public Preview (build 15.01.2507.006)” and for Ex2019 CU13 its “ExSetup version: Unknown version (build 15.02.1258.012)”

    I’m using the localized DE version of Exchange Setup on localized Win2016 and Win2019, both DE as well.

    The script omits the installation of the Rewrite-Module and starts Exchange Setup with the deprecated “/IAcceptExchangeServerLicenseTerms”.

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.