close

As discussed on the Top 10 IIS Configuration Tips article, the Shared Configuration feature is a must have for building web farms with IIS. But let’s look at how we can use Powershell to script IIS Shared Configuration. If we’re building and managing multiple farms or one very large farm, being able to automate the setup will save us time and improve the quality of our setup.

IIS Shared Configuration Requirements

Script IIS Shared ConfigurationBefore getting into the scripting, lets review the requirements for enabling IIS Shared Configuration. There’s not a lot needed to setup IIS Shared Configuration, but here are the basic requirements.

  1. You need to be running IIS 7.0 at a minimum to use Shared Configuration, it was not available in earlier versions of IIS. For this example I’ll use 2 servers, ServerA and ServerB, with ServerA being the master.
    [cow_johnson general_width=”400″ general_bgcolor=”#dddddd”] IIS 7.5 introduced a property  called “enableUncPolling” for controlling if IIS should directly check the Shared Configuration path for changes instead of depending on File Change Notification which is the default. You may need this if you’re using a non-Windows file server. This property can only be modified by editing the redirection.config file manually or via script, its not visible in the IIS Manager UI. There’s also a “pollingPeriod” property to control how often to check the path for changes. IIS 8.0 and IIS 8.5 did not introduce any changes to Shared Configuration.
    [/cow_johnson]
  2. A File Share is needed to store the IIS config files and Encryption Keys. You can make Shared Configuration work using a local path if you have concerns about the stability of a remote UNC.
  3. A service account is needed to access the UNC path where the configuration files will be stored. Technically, you can also use local accounts, but I would recommend using domain accounts unless you have no choice.If you’re using a local path on each server to store configuration files then this is not necessary. The System account is used by default and will have access to the local file path.
  4. IIS Encryption Keys will need to be synchronized between the two servers. You need to export the Keys from the Master IIS Server to the File Share, and then import as needed on the Nodes.
How to Script IIS Shared Configuration

The script below performs the following functions:

  • When run with no arguments it will display the servers current status.
  • The “Enable” argument will turn on Shared Configuration and import IIS Encryption Keys if they don’t match the Farm Keys. You need to specify a 2nd argument with the UNC Path to the Farm Config.
  • The “Disable” argument will turn off Shared Configuration and revert IIS to using the previous local configuration.
  • The “Export” argument will copy the current Config and IIS Keys to the UNC Path. This should be run once on the Farm Master. You need to specify a 2nd argument with the UNC Path to export the files to.

 

Script IIS Shared ConfigThe highlights of this script are:

  • The Microsoft.Web.Administration.ServerManager object gives us access to read and modify the “configurationRedirection”.
  • We call aspnet_regiis directly to export and import Encryption Keys
  • The $script:uncUser and $script:uncPwd variables can be hard coded if you prefer, by default the script will prompt you to enter the values at runtime.
  • The Compare-Key function will compare the local servers RSA Key against the exported Key in the farm’s share.

Script IIS Shared ConfigThe important thing to note about this script is that we’re not only exporting the IIS Config but also the IIS Encryption Keys, and then importing both on our other servers. When we check the Shared Configuration Status it will also show you if the Keys match. Keeping Encryption Keys in sync will save you a lot of problems down the road. You can also download this script directly if you prefer.

 

param (
    [Parameter(Mandatory=$false)]
    [String]$Action="List",
    [Parameter(Mandatory=$false)]
    [String]$UNCPath
)

Write-Host ""
Write-Host "                                                                       " -BackgroundColor DarkCyan
Write-Host "          IIS Shared Configuration Manager                             " -BackgroundColor DarkCyan
Write-Host "                                                                       " -BackgroundColor DarkCyan
Write-Host ""

#### Variables ####
$iisWASKey = "iisWASKey"
$iisConfigKey = "iisConfigurationKey"
$script:uncUser = ""
$script:uncPwd = ""

#### Load Web Administration DLL ####
[System.Reflection.Assembly]::LoadFrom("C:\windows\system32\inetsrv\Microsoft.Web.Administration.dll") | Out-Null
$serverManager = New-Object Microsoft.Web.Administration.ServerManager
$config = $serverManager.GetRedirectionConfiguration()
$redirectionSection = $config.GetSection(“configurationRedirection”)

function Check-UNC()
{
	if (!($UNCPath))
	{ Write-Warning "UNC Path for Shared Config is required."; exit;}
}

function Check-User()
{
	if (!($script:uncUser))
	{
		$script:uncUser = Read-Host "Enter UNC Service Account"
	}

	if (!($script:uncPwd))
	{
		$sstr = Read-Host "Enter UNC Service Account Password" -AsSecureString
		$marshal = [System.Runtime.InteropServices.Marshal]
		$ptr = $marshal::SecureStringToBSTR( $sstr )
		$script:uncPwd = $marshal::PtrToStringBSTR( $ptr )
		$marshal::ZeroFreeBSTR( $ptr )
	}
}

function Compare-Key($KeyName)
{
	$myConfigkey = Join-Path $env:temp $KeyName
	$remotekeyPath = Join-Path $UNCPath $KeyName

	& $env:windir\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -px $KeyName $myConfigkey -pri 

	if (!(Test-Path $myConfigkey ))
	{
		Write-Host "Could not export $KeyName. Check for any issues exporting Keys" -ForegroundColor DarkYellow
		return $false
	}

	$key1 = Get-Content $remotekeyPath
	$key2 = Get-Content $myConfigkey

	if (Compare-Object $key1 $key2)
	{
		return $false
	}else
	{
		return $true
	}
}

switch ($Action)
{
	"List" {
		Write-Host "Current Shared Configuration Setup"
		Write-Host ""
		if ($redirectionSection.Attributes["enabled"].Value -eq "true")
		{
			Write-Host "Shared Configuration is Enabled"
			Write-Host "Config Path: " $redirectionSection.Attributes["path"].Value
			Write-Host "User Name: " $redirectionSection.Attributes["userName"].Value

			$UNCPath = $redirectionSection.Attributes["path"].Value

			if (Compare-Key $iisWASKey )
			{ Write-Host "$iisWASKey Check: In sync with Farm"}else
			{ Write-Host "$iisWASKey Check: NOT in sync with Farm" -ForegroundColor DarkYellow}

			if (Compare-Key $iisConfigKey  )
			{ Write-Host "$iisConfigKey Check: In sync with Farm"}else
			{ Write-Host "$iisConfigKey Check: NOT in sync with Farm" -ForegroundColor DarkYellow}

		}else{

			Write-Host "Shared Configuration is NOT Enabled"
		}
	}
	"Enable" {
		Write-Host "Enabling Shared Configuration"
		Write-Host ""

		# Ensure UNC was provided
		Check-UNC

		# If Service Account isn't hard coded, prompt for it
		Check-User

		# Import iisWASKey if needed
		if (Compare-Key $iisWASKey )
		{ Write-Host "$iisWASKey Check: In sync with Farm"}else
		{
			Write-Host "$iisWASKey Check: NOT in sync with Farm, updating..."
			$wasKey = Join-Path $UNCPath $iisWASKey
			& $env:windir\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pi "iisWasKey" $wasKey -exp
		}

		# Import iisConfigKey if needed
		if (Compare-Key $iisConfigKey  )
		{ Write-Host "$iisConfigKey Check: In sync with Farm"}else
		{
			Write-Host "$iisConfigKey Check: NOT in sync with Farm, updating..."
			$configKey = Join-Path $UNCPath $iisConfigKey
			& $env:windir\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pi $iisConfigKey $configKey -exp
		}

		# Update Shared Config Settings
		$redirectionSection.Attributes["enabled"].Value = “true”
		$redirectionSection.Attributes["path"].Value = $UNCPath
		$redirectionSection.Attributes["userName"].Value = $script:uncUser
		$redirectionSection.Attributes["password"].Value = $script:uncPwd
		$serverManager.CommitChanges()
		Write-Host ""
		Write-Host "Shared Configuration Enabled using $uncpath"
	}
	"Disable" {
		Write-Host "Disable Shared Configuration"
		Write-Host ""

		if ($redirectionSection.Attributes["enabled"].Value -eq "true")
		{
			$redirectionSection.Attributes["enabled"].Value = “false”
			$serverManager.CommitChanges()

			Write-Host "Shared Configuration Disabled"
		}else
		{
			Write-Host "Shared Configuration is NOT Enabled"
		}
	}
	"Export" {
		Write-Host "Export Shared Configuration"
		Write-Host ""

		Check-UNC

		### Copy applicationHost.config
		$appConfig = Join-Path $UNCPath "applicationHost.config"
		cpi $env:windir\system32\inetsrv\config\applicationHost.config $appConfig

		### Copy administration.config
		$adminConfig = Join-Path $UNCPath "administration.config"
		cpi $env:windir\system32\inetsrv\config\administration.config $adminConfig

		### Export Keys
		$wasKey = Join-Path $UNCPath $iisWASKey
		& $env:windir\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -px $iisWASKey $wasKey -pri 

		$ConfigKey = Join-Path $UNCPath $iisConfigKey
		& $env:windir\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -px $iisConfigKey $ConfigKey -pri 

	}
    default {"$Action is not a valid action. Exiting. "; exit}
 }

Write-Host ""
Write-Host "                                                                       " -BackgroundColor DarkCyan


Tags : featurediispowershellshared configuration
Byron Pate

The author Byron Pate

  • Eric Miller

    Byron, thank you for posting this, especially since it seems to be a clear follow on response to our comment discussion in one of your previous posts. I’ve x-posted this to /r/sysadmin.

  • No problem. It was a good question about the Crypto Key that the UI prompts you for. You definitely do not need that extra Crypto Key when you script it, or even manually enable Shared Config.

  • Deadly-Bagel

    Great tool for enabling and disabling Shared Config, but is there any way to retain the configuration files and encryption keys while disabling it? (When disabled through IIS7 a prompt appears asking if you want to keep them)

  • Brad Perich

    Just found a bug in your code. Because the function Compare-Key has untrapped output from ASPNET_REGIIS.EXE it always returns true even if the keys are different. You have to pipe the key export to >$null to fix this…

    & $env:windirMicrosoft.NETFramework64v4.0.30319aspnet_regiis.exe -px $KeyName $myConfigkey -pri > $null