Exchange 2010 - Auto SSL Redirect Script (Also Resets Authentication, SSL)

Started by Brad G. - AdvenTech, September 07, 2011, 08:31:14 PM

Previous topic - Next topic

Brad G. - AdvenTech

Save everything below as Set-Exchange2010IISConfig.ps1



<# 
.SYNOPSIS 
    Script provides common configuration of Exchange 2010 RTM & SP1 specific IIS settings.
.DESCRIPTION 
    Redirects / to /owa recommended vdirs
    Configures rights on web.config file for OAB
    Restart IIS
    Redirect 80 to 443
    Force SSL
.PARAMETER URL
    Include this paramter to specify the FQDN of the Exchange server or array.  If ommitted the script will attempt to determine the FQDN and prompt user for confirmation.
.PARAMETER ForceSSL
   Sets Exchange specific virtual directories to require SSL.
.PARAMETER RedirectUrl
    Sets default website to redirect to /owa.
.PARAMETER RedirectProtocol
    Creates custom 403.4 error page to redirect to https://<URL>/owa
.PARAMETER AclOAB
    Adds READ permissions for NT Authority\Authenticated Users to ClientAccess\OAB\web.config file. This switch will NOT create an IIS Backup.
.PARAMETER IISReset
    Restarts IIS at the end of script execution.
.NOTES 
    Author       : Robert Durkin
    Email Addr   : rdurkin (at) ehloworld.net
    My Blog      : http://ehloworld.net
    Rights Req   : Local Server Admin (Run As Administrator)
    Exchange Ver : 2010 & 2010SP1
    Disclaimer   : THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. BE SURE TO TEST!
    Version      : 1.0 - 04/26/2010 - initial version
                 : 2.0 - 08/02/2010 - Modified to removed httpredirect from all sub sites.
                                      Added custom error message
                                      Removed manditory parameters and detect URL from ClientAccessArray.
                                      push and pop starting location
                 : 2.1 - 08/03/2010 - Added the detection of the ClientAccessArray and the ability to use that or specify your own.
                 : 2.2 - 08/03/2010 - Can detect 403.4 error page and remove to allow script to update error page redirect value.
                 : 2.3 - 03/02/2011 - Added several switch paramters to allow for modular execution of script.
                                      Checks to make sure the script is being run on an Exchange 2010 CAS server.
                 : 2.4 - 03/04/2011 - Checks for proper execution.
                 : 2.5 - 03/21/2011 - Updated redirection function to update the applicationhost.config file with the /commit:apphost parameter
.LINK
   http://ehloworld.net/?p=104
.EXAMPLE
   .\Set-Exchange2010IISConfig.ps1 -url "mail.ehloworld.net" -ForceSSL
.EXAMPLE
    .\Set-Exchange2010IISConfig.ps1 -RedirectUrl -RedirectProtocol
.INPUTS
   None. You cannot pipe objects to this script.
.OUTPUTS
    If changes are made to IIS configuration a backup of the configuration will be created in the <Windows Directory>\System32\inetsrv\backup directory.   
#>

#Requires -Version 2.0

param(
   [Parameter(Mandatory = $false,valueFromPipeline=$true)][string] $URL,
   [Parameter(Mandatory = $false,valueFromPipeline=$true)][switch] $ForceSSL,
   [Parameter(Mandatory = $false,valueFromPipeline=$true)][switch] $RedirectUrl,
   [Parameter(Mandatory = $false,valueFromPipeline=$true)][switch] $RedirectProtocol,
   [Parameter(Mandatory = $false,valueFromPipeline=$true)][switch] $AclOAB,
   [Parameter(Mandatory = $false,valueFromPipeline=$true)][switch] $IISReset
) #end param

###################
# Begin Functions #
###################

function GetExchangeInstallPath
{
    # Get the root setup entires.
    $setupRegistryPath = "HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup"
    $setupEntries = Get-ItemProperty $setupRegistryPath
    if($setupEntries -eq $null)
    {
        return $null
    }

    # Try to get the Install Path.
    $InstallPath = $setupEntries.MsiInstallPath
    return $InstallPath
} # end GetExchangeInstallPath

function UseArray
{
    #Check for a defined CAS array and give user the option to use that.  Or, specify their own root URL
    $ArrayFQDN = (Get-ClientAccessArray).FQDN
    IF ($ArrayFQDN) {
        $title = "Client Access Array detected."
        $message = "Use $ArrayFQDN for URL redirection?"
        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Configure URL redirection based on the root URL: $ArrayFQDN"
        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Do not use the detected URL and allow you to specify your own."
        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
        $result = $host.ui.PromptForChoice($title, $message, $options, 0)
        switch ($result)
            {
                0 { return $ArrayFQDN }
                1 { return Read-Host "`nPlease specify root URL for redirection.`nFor example, if your OWA site is located at `"https://owa.ehloworld.net/owa`" you would specify `"owa.ehloworld.net`"" }
            }
    } #endif
} #endfunction UseArray

function BackupIISConfig
{
    Write-Host "Backing up current IIS configuration" -ForegroundColor green
    pushd
    Set-Location "$env:windir\System32\inetsrv"
    $backup = "Exchange IIS Backup "+(get-date -format "MMddyyyy-hhmmss")
    .\appcmd.exe ADD Backup $backup
    Write-Host "Backup saved to: $env:windir\System32\inetsrv\backup\$backup" -ForegroundColor Green
    popd
} #ENDFUNCTION BackupIISConfig

##############
# Begin Main #
##############

## Check for proper command execution.
IF (!$URL -and ($RedirectUrl -or $RedirectProtocol)){  #If the URL is not specified and a switch that uses it is, try and determine.
    $URL = UseArray
} ELSEIF ($url -and (!($RedirectUrl -or $RedirectProtocol))) {
    Write-Host "URL has been specified, but no associated action specified. Include '-RedirectUrl' or '-RedirectProtocol' with the -URL switch.`n" -ForegroundColor Yellow
    Write-Host "Reference help by running Get-Help $MyInvocation.InvocationName" -ForegroundColor Yellow
    IF (!($AclOAB -or $ForceSSL -or $IISReset)) {
        Write-Host "Script execution doesn't include any needed switches. Please specify action.  Displaying Help." -ForegroundColor Yellow
        Get-Help $MyInvocation.InvocationName
        Exit 0
    }
} ELSEIF (!($AclOAB -or $ForceSSL -or $IISReset)) {
    Write-Host "Script execution doesn't include any needed switches. Please specify action.  Displaying Help." -ForegroundColor Yellow
    Get-Help $MyInvocation.InvocationName
    Exit 0
}

If (!(Get-ExchangeServer -Identity $env:computername) | %{$_.IsClientAccessServer -and $_.IsE14OrLater}) {
    Write-Host "This is not an Exchange 2010 Client Access Server, which is where it MUST be run." -ForegroundColor Red
    Exit 58
}

## Any IIS Changes made will set this to $True and prompt user for iisreset.
$StuffChanged = $False

Write-Host "Preparing execution environment: Loading ServerManager" -ForegroundColor Green
Import-Module ServerManager
if ((Get-WindowsFeature web-http-redirect).installed -eq $false){
   Write-Host "Preparing execution environment: Loading web-http-redirect feature" -ForegroundColor green
   ServerManagerCMD -i web-http-redirect
}

#Add/Update Custom Error Message
IF ($RedirectProtocol) {
    Write-Host "Configuring Protocol Redirection." -ForegroundColor Green
    pushd
    Set-Location "$env:windir\System32\inetsrv"
    IF (.\appcmd list config /section:httpErrors | where { $_ -like "*statusCode=`"403`" subStatusCode=`"4`"*" }) {
        Write-Host "Found 403.4 Error Page; REMOVING" -ForegroundColor yellow
        .\appcmd set config /section:httpErrors /-"[statusCode='403',subStatusCode='4']"
    }
    Write-Host "Creating Custom 403.4 Error Page" -ForegroundColor green
    .\appcmd set config /section:httpErrors /+"[statusCode='403',subStatusCode='4',path='https://$URL/',ResponseMode='Redirect']"
    popd
    $StuffChanged = $True
} #END RedirectProtocol

IF ($AclOAB) {
    Write-Host "Setting ACL on OAB web.config file." -ForegroundColor White -NoNewline
    $PathToFile = (GetExchangeInstallPath)+"ClientAccess\OAB\web.config"
    if (Test-Path($PathToFile)){
       icacls $PathToFile /grant:R 'NT Authority\Authenticated Users:R'
      Write-Host "  :  [Complete]" -ForegroundColor Green
    } ELSE {
      Write-Host "  :  [Missing]" -foregroundcolor Yellow
      Write-host "No web.config file does not exist." -ForegroundColor DarkYellow
   }
} #END AclOAB

## Configure URL Redirection
IF ($RedirectUrl) {
    Write-Host "Configuring redirection to $URL" -ForegroundColor Green
    BackupIISConfig
    pushd
    Set-Location "$env:windir\System32\inetsrv"
    .\appcmd set config "Default Web Site" /section:httpRedirect /exactDestination:false /childonly:true /enabled:true /destination:"https://$URL/owa" /commit:apphost
    .\appcmd set config "Default Web Site/Aspnet_Client" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/Autodiscover" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/EWS" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/ECP" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/Microsoft-Server-ActiveSync" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/OWA" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default web site/PowerShell" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default web site/OAB" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/Rpc" /section:httpRedirect /enabled:false /commit:apphost
    .\appcmd set config "Default Web Site/RpcWithCert" /section:httpRedirect /enabled:false /commit:apphost
    popd
    $StuffChanged = $True
} #End URL Redirection

#Configure SSL
IF ($ForceSSL) {
   Write-Host "Setting SSL configuration" -ForegroundColor green
    BackupIISConfig
    pushd
    Set-Location "$env:windir\System32\inetsrv"
   .\appcmd set config "Default Web Site" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/Aspnet_Client" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/Autodiscover" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/EWS" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/ECP" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/Exchange" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/Exchweb" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/Microsoft-Server-ActiveSync" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/OWA" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default web site/PowerShell" /section:access /sslFlags:"" /commit:apphost
   .\appcmd set config "Default web site/OAB" /section:access /sslFlags:"" /commit:apphost
   .\appcmd set config "Default Web Site/Public" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
   .\appcmd set config "Default Web Site/Rpc" /section:access /sslFlags:Ssl /commit:apphost
   .\appcmd set config "Default Web Site/RpcWithCert" /section:access /sslFlags:"Ssl,Ssl128" /commit:apphost
    popd
    $StuffChanged = $True
} #END ForceSSL

IF ($IISReset) {
    Write-Host "Restarting IIS." -ForegroundColor Green
    iisreset /noforce
} ELSEIF ($StuffChanged) {
        $title = "IIS Reset Required."
        $message = "Changes have been made that require an IIS reset to apply.  Would you like to reset IIS now?"
        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Reset IIS."
        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Do not reset IIS."
        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
        $result = $host.ui.PromptForChoice($title, $message, $options, 1)
        switch ($result)
            {
                0 { iisreset /noforce }
                1 { Write-Host "IIS has not been reset. Changes will not be applied until IIS is reset.  To reset IIS run: 'iisreset /noforce'". -ForegroundColor Yellow }
            }
} #END IISReset