Skip to content

Instantly share code, notes, and snippets.

@dudeitssm
Forked from kking124/configure-iis.ps1
Created April 8, 2022 19:02
Show Gist options
  • Save dudeitssm/9085984544e70e33ff77977e75b85aa5 to your computer and use it in GitHub Desktop.
Save dudeitssm/9085984544e70e33ff77977e75b85aa5 to your computer and use it in GitHub Desktop.

Revisions

  1. @kking124 kking124 revised this gist Mar 26, 2019. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion configure-iis.ps1
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,6 @@
    # * Installs FTP
    #
    # .NOTES
    # Copyright 2015 - New West Technologies, LLC a Cybergy Partners Company
    #
    # IN CODE COMMENT DESCRIPTORS
    #
  2. @kking124 kking124 created this gist Feb 24, 2017.
    513 changes: 513 additions & 0 deletions configure-iis.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,513 @@
    # configure-iis.ps1
    # Version: 1.2
    # Author: kking124 (https://github.com/kking124)
    #
    # Copyright 2016, 2017
    #
    # License: MIT
    # .SYNOPSIS
    # Tries to configure IIS as a minimal, secure installation on Windows Server 2008 and later
    #
    # .DESCRIPTION
    # IMPORTANT: Script must be run from Administrator mode.
    #
    # Available Switches:
    # * Retail
    # * Enable IIS Retail Mode
    # * MediumTrust
    # * Set Application Trust Level to Medium and block override
    # * AppPoolConfig
    # * CSP
    # * Set HTTP Header - Content-Security-Policy: default-src 'self'
    # * Set HTTP Header - X-Content-Security-Policy: default-src 'self'
    # * RequireHttpCookies
    # * Adds to HTTP Header - Set-Cookie: httpOnly
    # * SecureCookies
    # * Adds to HTTP Header - Set-Cookie: secure
    # * AppPoolConfig
    # * Install - URL Rewrite (if necessary)
    # * Change HTTP Header - Server: Apache
    # * Set HTTP Header - Cache-Control: no-cache,no-store
    # * Set HTTP Header - X-Content-Type-Options: nosniff
    # * Set HTTP Header - X-Frame-Options: SAMEORIGIN
    # * Set HTTP Header - X-XSS-Protection: 1;mode-block
    # * Remove HTTP Header - X-Powered-By
    # * Disable Directory Indexing
    # * IisCrypto
    # * Configures TLS to FIPS140
    # * IisSetup
    # * Remove WebDAV, FTP
    # * FTP - Requires IisSetup flag
    # * Installs FTP
    #
    # .NOTES
    # Copyright 2015 - New West Technologies, LLC a Cybergy Partners Company
    #
    # IN CODE COMMENT DESCRIPTORS
    #
    # SEE: => reasoning
    # TODO: => functionality to implement
    # REF: => help to implement
    # NOTE: => informative comment
    #
    # CHANGELOG
    # 1.2
    # - Fixed bug in removal of X-Powered-By header
    # - Moved installation of URL Rewrite to AppPoolConfig from IisSetup
    # - Add switch to install Web Platform Tools 5.0
    # 1.1
    # - Converted switches from exclusive to inclusive
    # 1.0
    # - Initial Release
    #

    param(
    #machine config changes
    [switch] $Retail
    #setting trust level
    , [switch] $MediumTrust

    #modify applicationHost.config
    , [switch] $AppPoolConfig

    #set CSP headers
    , [switch] $CSP

    #set cookie headers
    , [switch] $RequireHttpCookies
    , [switch] $SecureCookies

    #iis Crypto
    , [switch] $IisCrypto

    #Setup IIS Environment
    , [switch] $IisSetup
    #Allow FTP - Requires IisSetup
    , [switch] $Ftp
    #Installs Web Platform Tools 5.0
    , [switch] $InstallWebPlatformTools
    )
    process {
    #region internal functions
    #

    Function Write-Log {
    Param([string] $message, [string] $logfile)
    #$logfile = (Get-Date).ToString("yyyyMMdd")+".log"
    Write-Host ([String]::Format("[{0}]`t{1}", (Get-Date).ToString("yyyy-MM-dd hh:mm:ss"), $message)).ToString()
    ([String]::Format("[{0}]`t{1}", (Get-Date).ToString("yyyy-MM-dd hh:mm:ss"), $message)).ToString() >> $logfile
    }

    Function Test-CommandExists {
    Param($command)
    try {
    $result = Get-Command -Name $command -ListImported
    return $true
    } catch {
    return $false
    }
    }

    Function Get-ServerInfo {
    Param()
    $q = servermanagercmd -query
    $type = "Role"
    $o = @()
    foreach($i in $q) {
    $i = $i.Trim()
    if($i -match "^Servermanagercmd" -or $i.Length -eq 0) {
    continue
    }
    if($i -match "^----- [\w]* -----$") {
    $regex = [regex] '^----- ([\w]*) -----$'
    $type = $regex.Match($i).Groups[1].Value
    } else {
    $i = $i.Split("[]") | Where-Object { $_.Length -gt 0 }
    $state = if ($i[0] -eq "X") {"Enabled"} else {"Disabled"}
    $o+= @{
    "Installed" = $i[0] -eq "X";
    "Type"= $type;
    "State"= $state;
    "DisplayName"=$i[1].Trim();
    "FeatureName"= $i[2].Trim();
    }
    }

    }
    return (New-Object –TypeName:PSObject –Prop $o) | Format-Table -Property FeatureName, State, DisplayName, Type, Installed
    }

    Function Install-ServerOption {
    Param($name)
    servermanagercmd -install $name
    }

    Function Remove-ServerOption {
    Param($name)
    servermanagercmd -remove $name
    }
    #endregion

    #region script setup

    $logfilename = (Split-Path -parent $MyInvocation.MyCommand.Definition).ToString() + "\" + (Get-Date).ToString("yyyyMMdd") + ".log"
    Write-Host "Log file at" $logfilename
    Write-Log "==============================" $logfilename
    Write-Log "Configure IIS Script" $logfilename
    Write-Log "==============================" $logfilename

    #elevated check
    if((whoami /all | select-string S-1-16-12288) -eq $null ) {
    Write-Log "Administrator Mode Required." $logfilename
    throw (new-object System.Management.Automation.PSSecurityException);
    }

    # create tools directory for downloads if it doesn't exist
    pushd (Split-Path -parent $MyInvocation.MyCommand.Definition) -StackName ConfigureIIS
    if(-not (Test-Path .\tools)) {
    New-Item -Path . -Name tools -ItemType directory
    Write-Log ([String]::Format("tools folder created at {0}.", (Resolve-Path .\tools\).Path)).ToString() $logfilename
    }
    popd -StackName ConfigureIIS
    #endregion

    #region Server Configuration
    #

    if($IisSetup) {
    Write-Log "Begin IIS Setup" $logfilename
    Write-Log "Getting Available PS Modules" $logfilename
    $psModules = Get-Module -ListAvailable
    Write-Log "Available PS Module List Retrieved" $logfilename
    #Server 2012+
    if( (Test-CommandExists Get-WindowsOptionalFeature) -and (Test-CommandExists Enable-WindowsOptionalFeature) -and (Test-CommandExists Disable-WindowsOptionalFeature) ) {
    Write-Log "Windows 6.2+ Detected" $logfilename
    $features = Get-WindowsOptionalFeature -Online | Where-Object { -not $_.State.ToString().Equals("Disabled", [System.StringComparison]::CurrentCultureIgnoreCase) }
    Write-Log "Installed Features Retrieved" $logfilename

    if(($features | Where-Object { $_.FeatureName -eq "IIS-WebServerRole" }).Count -eq 0) {
    Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebServerRole
    Write-Log "IIS-WebServerRole Enabled" $logfilename
    }

    if($ftp) {
    if(($features | Where-Object { $_.FeatureName -eq "IIS-FTPServer" }).Count -eq 0) {
    Enable-WindowsOptionalFeature -Online -FeatureName IIS-FTPServer
    Write-Log "IIS-FTPServer Enabled" $logfilename
    }
    } else {
    if(($features | Where-Object { $_.FeatureName -eq "IIS-FTPServer" }).Count -gt 0) {
    Disable-WindowsOptionalFeature -Online -FeatureName IIS-FTPServer
    Write-Log "IIS-FTPServer Disabled" $logfilename
    }
    }

    if(($features | Where-Object { $_.FeatureName -eq "IIS-WebDAV" }).Count -gt 0) {
    Disable-WindowsOptionalFeature -Online -FeatureName IIS-WebDAV
    Write-Log "IIS-WebDAV Disabled" $logfilename
    }
    }
    elseif ( ($psModules | Where-Object { $_.Name -match "ServerManager" }) -ne $null ) {
    # Windows 2008 R2 way of doing things
    Write-Log "Windows 6.1 Detected" $logfilename
    Import-Module ServerManager
    Write-Log "Installed Features Retrieved" $logfilename

    $features = Get-WindowsFeature | Where-Object { $_.Installed }

    if(($features | Where-Object { $_.Name -eq "Web-Server" }).Count -eq 0) {
    Add-WindowsFeature Web-Server
    Write-Log "IIS-WebServerRole Enabled" $logfilename
    }
    if($ftp) {
    if(($features | Where-Object { $_.Name -eq "Web-Ftp-Server" }).Count -eq 0) {
    Add-WindowsFeature Web-Ftp-Server
    Write-Log "IIS-FTPServer Enabled" $logfilename
    }
    } else {
    if(($features | Where-Object { $_.Name -eq "Web-Ftp-Server" }).Count -gt 0) {
    Remove-WindowsFeature Web-Ftp-Server
    Write-Log "IIS-FTPServer Disabled" $logfilename
    }
    }

    if(($features | Where-Object { $_.Name -eq "Web-DAV-Publishing" }).Count -gt 0) {
    Remove-WindowsFeature Web-DAV-Publishing
    Write-Log "IIS-WebDAV Disabled" $logfilename
    }
    }
    else {
    # Windows 2008 way of doing things (see Get-ServerInfo, et. al. functions)
    Write-Log "Windows 6.0 Detected" $logfilename
    $features = Get-ServerInfo | Where-Object { -not $_.State.ToString().Equals("Disabled", [System.StringComparison]::CurrentCultureIgnoreCase) }
    Write-Log "Installed Features Retrieved" $logfilename

    if(($features | Where-Object { $_.FeatureName -eq "Web-Server" }).Count -eq 0) {
    Install-ServerOption Web-Server
    Write-Log "IIS-WebServerRole Enabled" $logfilename
    }
    if($ftp) {
    if(($features | Where-Object { $_.FeatureName -eq "Web-Ftp-Server" }).Count -eq 0) {
    Install-ServerOption Web-Ftp-Server
    Write-Log "IIS-FTPServer Enabled" $logfilename
    }
    } else {
    if(($features | Where-Object { $_.FeatureName -eq "Web-Ftp-Server" }).Count -gt 0) {
    Remove-ServerOption -remove Web-Ftp-Server
    Write-Log "IIS-FTPServer Disabled" $logfilename
    }
    }

    if(($features | Where-Object { $_.FeatureName -eq "Web-DAV-Publishing" }).Count -gt 0) {
    Remove-ServerOption Web-DAV-Publishing
    Write-Log "IIS-WebDAV Disabled" $logfilename
    }

    }

    #TODO?: Install Administration Pack 1.0 on IIS 7 Machines http://go.microsoft.com/?linkid=9655657

    Write-Log "End IIS Setup"
    } #endif IisSetup

    #region IISCrypto
    #

    if($IisCrypto) {
    Write-Log "Begin SSL Configuration" $logfilename
    pushd (Split-Path -parent $MyInvocation.MyCommand.Definition) -StackName ConfigureIIS

    $iisCryptoPath = ".\tools\IISCryptoCli40.exe"
    if(-not (Test-Path $iisCryptoPath)) {
    $client = New-Object System.Net.WebClient
    $client.DownloadFile("https://www.nartac.com/Downloads/IISCrypto/IISCryptoCli40.exe", ((Resolve-Path .\tools).ToString()+"\IISCryptoCli40.exe"))
    Write-Log "IISCrypto Downloaded" $logfilename
    }

    Invoke-Expression (".\tools\IISCryptoCli40.exe /fips140")
    Write-Log "IISCrypto run with /fips140" $logfilename

    popd -StackName ConfigureIIS
    Write-Log "End SSL Configuration" $logfilename
    }
    #endregion

    #endregion

    pushd $env:SystemRoot\System32\inetsrv -StackName ConfigureIIS

    #region Application Host Configuration
    #

    if($AppPoolConfig) {
    Write-Log "Begin applicationHost.config changes" $logfilename
    # remove X-Powered-By
    .\appcmd.exe set config /section:httpProtocol /-customHeaders.["name='X-Powered-By'"] /commit:apphost
    Write-Log "Removed X-Powered-By Header" $logfilename

    # X-AspNetMvc-Version
    # Can't block AspNetMvc at the server level - it's an app level thing.
    #SEE: https://azure.microsoft.com/en-us/blog/removing-standard-server-headers-on-windows-azure-web-sites/

    # Server
    # Can't block Server header at the server level by default. Can be done in web.config from the app level in later versions of IIS
    #SEE: https://azure.microsoft.com/en-us/blog/removing-standard-server-headers-on-windows-azure-web-sites/

    # Set up URL rewrite rule to empty server header. Works in IIS 6 and beyond
    #SEE: http://www.iis.net/learn/extensions/url-rewrite-module/creating-outbound-rules-for-url-rewrite-module
    #SEE: http://stackoverflow.com/questions/1178831/remove-server-response-header-iis7
    #REQUIRE: mod_rewrite
    #check for url_rewrite
    $norewrite = (Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -match IIS URL Rewrite Module}).Name -eq $null

    if($norewrite) {
    pushd (Split-Path -parent $MyInvocation.MyCommand.Definition) -StackName ConfigureIIS
    #get url_rewrite module
    $client = new-object System.Net.WebClient
    $client.DownloadFile("https://download.microsoft.com/download/6/7/D/67D80164-7DD0-48AF-86E3-DE7A182D6815/rewrite_2.0_rtw_x64.msi", ((Resolve-Path .\tools).ToString()+"\rewrite_2.0_rtw_x64.msi"))
    #install it
    msiexec.exe /i (Resolve-Path .\tools\rewrite_2.0_rtw_x64.msi).Path /qn
    Write-Log "IIS URL Rewrite Module 2 Installed" $logfilename
    popd -StackName ConfigureIIS
    }

    .\appcmd.exe set config -section:system.webServer/rewrite/outboundRules /+["name='server_response'"] /commit:apphost
    .\appcmd.exe set config -section:system.webServer/rewrite/outboundRules /["name='server_response'"].match.serverVariable:"RESPONSE_Server" /["name='server_response'"].match.pattern:".*" /commit:apphost
    #set alternate value here
    .\appcmd.exe set config -section:system.webServer/rewrite/outboundRules /["name='server_response'"].action.type:'Rewrite' /["name='server_response'"].action.value:'Apache' /commit:apphost
    Write-Log "Added Rewrite Rule to Set Server Header to Apache" $logfilename

    # Cache-Control
    .\appcmd.exe set config /section:httpProtocol /+customHeaders.["name='Cache-Control',value='no-cache,no-store'"] /commit:apphost
    Write-Log "Added Cache-Control Header" $logfilename

    # Content-Type-Options
    .\appcmd.exe set config /section:httpProtocol /+customHeaders.["name='X-Content-Type-Options',value='nosniff'"] /commit:apphost
    Write-Log "Added X-Content-Type-Options Header" $logfilename

    # Frame-Options
    .\appcmd.exe set config /section:httpProtocol /+customHeaders.["name='X-Frame-Options',value='SAMEORIGIN'"] /commit:apphost
    Write-Log "Added X-Frame-Options Header" $logfilename

    # XSS-Protection
    .\appcmd.exe set config /section:httpProtocol /+customHeaders.["name='X-XSS-Protection',value='1;mode=block'"] /commit:apphost
    Write-Log "Added X-XSS-Protection Header" $logfilename

    #region hide important .NET folders
    #

    #additional segments to deny
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='global.asax'"] /commit:apphost

    #default IIS denied segments
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='App_Browsers'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='App_Code'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='App_Data'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='App_GLobalResources'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='App_LocalResources'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='Bin'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+hiddenSegments.["segment='web.config'"] /commit:apphost

    #additional file extensions to deny
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.log',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.dll',allowed='false'"] /commit:apphost

    #default IIS denied file extensions
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.vb',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.cs',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.config',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.master',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.resx',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.asax',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ascx',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.skin',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.browser',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.sitemap',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.csproj',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.vbproj',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.webinfo',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.licx',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.resources',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.mdb',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.vjsproj',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.java',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.jsl',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ldb',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.dsdgm',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ssdgm',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.lsad',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ssmap',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.cd',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.dsprototype',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.lsaprototype',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.sdm',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.sdmDocument',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.mdf',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ldf',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ad',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.dd',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.ldd',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.sd',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.adprototype',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.lddprototype',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.exclude',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.refresh',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.compiled',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.msgx',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.vsdisco',allowed='false'"] /commit:apphost
    .\appcmd.exe set config /section:requestFiltering /+fileExtensions.["fileExtension='.rules',allowed='false'"] /commit:apphost

    #endregion

    #region WebDAV
    #

    #disable WebDAV
    #.\appcmd.exe set config /section:system.webServer/webdav/authoring /enabled:false /commit:apphost
    #Write-Host "WebDav authoring disabled" $logfilename

    #endregion

    #region HTTP VERBS

    #DROP TRACING Handler
    #.\appcmd.exe set config /section:handlers /-["name='TRACEVerbHandler'"] /commit:apphost
    #Write-Host "TRACEVerbHandler dropped" $logfilename

    #endregion

    #set DirectoryBrowse to false
    .\appcmd.exe set config /section:system.webServer/directoryBrowse /enabled:false /commit:apphost
    Write-Log "Directory Browsing Disabled" $logfilename

    .\appcmd.exe set config /section:system.web/machineKey /validation:HMACSHA256 /commit:apphost
    Write-Log "machineKey set to HMACSHA256" $logfilename
    } #endif $AppPoolConfig

    # Content-Security-Policy
    #NOTE: requires all content to be served in files from the current FQDN. This is meant to be overridden on a per-application basis.
    if($CSP) {
    .\appcmd.exe set config /section:httpProtocol /+customHeaders.["name='X-Content-Security-Policy',value='default-src%20''self'''"] /commit:apphost
    .\appcmd.exe set config /section:httpProtocol /+customHeaders.["name='Content-Security-Policy',value='default-src%20''self'''"] /commit:apphost
    Write-Log "Added Content-Security-Policy Headers" $logfilename
    }

    #endregion

    #region machine configuration changes
    #

    #$netpaths = Get-NetVersionPaths
    #$web = new-object system.collections.arraylist;
    #$machine = new-object system.collections.arraylist;

    if($Retail) {
    #SEE: https://msdn.microsoft.com/library/ms228298(v=vs.100).aspx
    .\appcmd.exe set config /section:system.web/deployment /retail:true /commit:machine
    Write-Log "Set Retail Mode" $logfilename
    }
    if($MediumTrust) {
    #SEE: https://msdn.microsoft.com/library/ff648665.aspx#c09618429_006
    .\appcmd.exe set config /section:system.web/trust /level:Medium /commit:webroot
    .\appcmd.exe set config /section:system.web/trust /allowOverride:false /commit:webroot
    Write-Log "Set Medium Trust" $logfilename
    }
    if($RequireHttpCookies) {
    # Add httpOnly to Cookie header - means this cookie cannot be read by javascript
    .\appcmd.exe set config /section:system.web/httpCookies /httpOnlyCookies:true /commit:webroot
    Write-Log "Set HTTP Only Cookies" $logfilename
    }
    if($SecureCookies) {
    # Add secure to Cookie header - means this cookie is only sent over https
    .\appcmd.exe set config /section:system.web/httpCookies /requireSsl:true /commit:webroot
    Write-Log "Set Secure Cookies" $logfilename
    }

    #endregion


    if($InstallWebPlatformTools) {
    Write-Log "Begin Installation: Web Platform Tools" $logfilename
    $nowpt = (Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -match Microsoft Web Platform Installer}).Name -eq $null

    if($nowpt) {
    pushd (Split-Path -parent $MyInvocation.MyCommand.Definition) -StackName ConfigureIIS
    #get url_rewrite module
    $client = new-object System.Net.WebClient
    $client.DownloadFile("http://download.microsoft.com/download/C/F/F/CFF3A0B8-99D4-41A2-AE1A-496C08BEB904/WebPlatformInstaller_amd64_en-US.msi", ((Resolve-Path .\tools).ToString()+"\WebPlatformInstaller_amd64_en-US.msi"))
    #install it
    msiexec.exe /i (Resolve-Path .\tools\WebPlatformInstaller_amd64_en-US.msi).Path /qn
    Write-Log "Web Platform Installer 5 Installed" $logfilename
    popd -StackName ConfigureIIS
    }
    Write-Log "Completed Installation: Web Platform Tools" $logfilename
    }

    while( (pwd -Stack -StackName ConfigureIIS).Count > 0) {
    popd -StackName ConfigureIIS
    }
    pushd (Split-Path -parent $MyInvocation.MyCommand.Definition) -StackName ConfigureIIS
    rm .\tools\
    popd -StackName ConfigureIIS
    }
    #REF: http://geekswithblogs.net/nharrison/archive/2011/05/25/updating-the-machine.config--with-powershell.aspx