NTS.Tools.MSExchange.psm1
function Get-ExchangeCU { <# .Description downloads exchange cu from microsoft .Parameter Version version of the cu .Parameter Outpath path where the cu is stored .Example # stores the cu to $Outpath Get-ExchangeCU -Version 2019_CU12 -Outpath $Outpath .NOTES https://learn.microsoft.com/en-us/exchange/new-features/build-numbers-and-release-dates?view=exchserver-2019 #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateSet("2019_CU12", "2016_CU23")] [string] $Version, [Parameter(Mandatory = $true)] [string] $Outpath ) $ErrorActionPreference = 'Stop' if ($Outpath[-1] -eq "\") { $Outpath = $Outpath.Substring(0, $Outpath.Length - 1) } if ((Test-Path -Path $Outpath) -eq $false) { New-Item -Path $Outpath -Force -ItemType Directory | Out-Null } $ExchangeCUFilePath = "$($Outpath)\Exchange-$($Version).iso" switch ($Version) { "2019_CU12" { $DownloadURL = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=104131" } "2016_CU23" { $DownloadURL = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=104132" } Default { throw "no version was selected or not supported" } } try { $Content = Invoke-WebRequest -UseBasicParsing -Uri $DownloadURL $UpdateLink = ($Content.Links | Where-Object -FilterScript { $PSItem.href -like "*download.microsoft.com*" -and $PSItem.outerHTML -like "*download manually*" }).href Start-FileDownload -DownloadURL $UpdateLink -FileOutPath $ExchangeCUFilePath } catch { throw "$($env:COMPUTERNAME): error getting exchange cu files - $($PSItem.Exception.Message)" } Write-Output "$($env:COMPUTERNAME): finished download - check folder $($Outpath)" } function Install-ExchangePrerequisites { <# .Description use this function to install exchange windows feature prerequesits .Example # install exchange windows feature prerequesits Install-ExchangePrerequisites .NOTES https://learn.microsoft.com/en-us/exchange/plan-and-deploy/prerequisites?view=exchserver-2019 #> $Features = @( "Server-Media-Foundation" "NET-Framework-45-Features" "RPC-over-HTTP-proxy" "RSAT-Clustering" "RSAT-Clustering-CmdInterface" "RSAT-Clustering-Mgmt" "RSAT-Clustering-PowerShell" "WAS-Process-Model" "Web-Asp-Net45" "Web-Basic-Auth" "Web-Client-Auth" "Web-Digest-Auth" "Web-Dir-Browsing" "Web-Dyn-Compression" "Web-Http-Errors" "Web-Http-Logging" "Web-Http-Redirect" "Web-Http-Tracing" "Web-ISAPI-Ext" "Web-ISAPI-Filter" "Web-Lgcy-Mgmt-Console" "Web-Metabase" "Web-Mgmt-Console" "Web-Mgmt-Service" "Web-Net-Ext45" "Web-Request-Monitor" "Web-Server" "Web-Stat-Compression" "Web-Static-Content" "Web-Windows-Auth" "Web-WMI" "Windows-Identity-Foundation" "RSAT-ADDS" ) try { Write-Output "$($env:COMPUTERNAME): installing required features for exchange" Install-WindowsFeature -Name $Features | Out-Null } catch { throw $PSItem.Exception.Message } } function Initialize-ADForExchange { <# .Description used the exchange setup.exe to prepare ad for exchange installation or upgrade .Parameter SetupPath path to the exchange setup.exe .Parameter OrganizationName name of the exchange organization .Example # prepares active directory for the organization mw corp org Initialize-ADForExchange -SetupPath "$($Volume.DriveLetter):\Setup.exe" -OrganizationName "mw corp org" .NOTES #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $SetupPath, [Parameter(Mandatory = $true)] [string] $OrganizationName ) if (Test-Path -Path $SetupPath) { try { Write-Output "$($env:COMPUTERNAME): preparing ad - check logs at $($env:SystemDrive)\ExchangeSetupLogs for more details" if ($OrganizationName -eq "") { $Process = Start-Process -FilePath $SetupPath -ArgumentList "/PrepareAD /IAcceptExchangeServerLicenseTerms_DiagnosticDataOFF" -Wait -NoNewWindow -PassThru } else { $Process = Start-Process -FilePath $SetupPath -ArgumentList "/PrepareAD /IAcceptExchangeServerLicenseTerms_DiagnosticDataOFF /OrganizationName:`"$($OrganizationName)`"" -Wait -NoNewWindow -PassThru } if ($Process.ExitCode -ne 0) { $MessageCount = 5 $Content = Get-Content -Path "$($env:SystemDrive)\ExchangeSetupLogs\ExchangeSetup.log" $Message = ($Content | Select-String -Pattern "FAILED") | Select-Object -Last $MessageCount | ForEach-Object { $PSItem.ToString() } Write-Output "---" Write-Output "error preparing ad - last $($MessageCount) messages with 'failed':" Write-Output $Message throw "check logs at $($env:SystemDrive)\ExchangeSetupLogs for more details" } Write-Output "$($env:COMPUTERNAME): finished preparing ad" } catch { throw $PSItem.Exception.Message } } else { throw "cannot find $($SetupPath)" } } function Initialize-SchemaForExchange { <# .Description used the exchange setup.exe to prepare schema of ad for exchange installation or upgrade .Parameter SetupPath path to the exchange setup.exe .Example # prepares active directory schema for exchange install Initialize-SchemaForExchange -SetupPath "$($Volume.DriveLetter):\Setup.exe" .NOTES #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $SetupPath ) if (Test-Path -Path $SetupPath) { try { Write-Output "$($env:COMPUTERNAME): preparing schema - check logs at $($env:SystemDrive)\ExchangeSetupLogs for more details" $Process = Start-Process -FilePath $SetupPath -ArgumentList "/PrepareSchema /IAcceptExchangeServerLicenseTerms_DiagnosticDataOFF" -Wait -NoNewWindow -PassThru if ($Process.ExitCode -ne 0) { $MessageCount = 5 $Content = Get-Content -Path "$($env:SystemDrive)\ExchangeSetupLogs\ExchangeSetup.log" $Message = ($Content | Select-String -Pattern "FAILED") | Select-Object -Last $MessageCount | ForEach-Object { $PSItem.ToString() } Write-Output "---" Write-Output "error schema - last $($MessageCount) messages with 'failed':" Write-Output $Message throw "check logs at $($env:SystemDrive)\ExchangeSetupLogs for more details" } Write-Output "$($env:COMPUTERNAME): finished preparing schema" } catch { throw $PSItem.Exception.Message } } else { throw "cannot find $($SetupPath)" } } function Install-Exchange { <# .Description used the exchange setup.exe install exchange on the local server .Parameter SetupPath path to the exchange setup.exe .Example # installs exchange on the local server Install-Exchange -SetupPath "$($Volume.DriveLetter):\Setup.exe" .NOTES #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $SetupPath ) if (Test-Path -Path $SetupPath) { Write-Output "$($env:COMPUTERNAME): installing exchange - check logs at $($env:SystemDrive)\ExchangeSetupLogs for more details" Write-Output "$($env:COMPUTERNAME): this can take a while" $Process = Start-Process -FilePath $SetupPath -ArgumentList "/m:install /roles:mb /IAcceptExchangeServerLicenseTerms_DiagnosticDataOFF /InstallWindowsComponents" -Wait -NoNewWindow -PassThru if ($Process.ExitCode -ne 0) { $Content = Get-Content -Path "$($env:SystemDrive)\ExchangeSetupLogs\ExchangeSetup.log" $Message = ($Content | Select-String -Pattern "ERROR")[-1].ToString() throw "error installing exchange - $($Message)" } Write-Output "$($env:COMPUTERNAME): finished installing exchange" } else { throw "cannot find $($SetupPath)" } } |