Wednesday 10 August 2016

IIS; 3 ways to redirect

Using IIS 8.5 there are three was to re-direct traffic to another location. In my case I needed to redirect traffic from one IIS site to another. Requirements for redirection are not always the same, and sometimes an individual page or file may need to be redirected. In all cases a variation of one of the examples below should be sufficient to redirect traffic in the way you need.

Method 1 HTTP ReDirect

Redirect traffic using the HTTP Redirection feature.

Http Redirect should be the most simple method of redirecting traffic to another location, however in my case it caused the most confusion and led me to explore the other methods listed below. 

The Http Redirection feature must be installed before this method can be used.

When adding a redirect rule using this method, the system.webServer section of the web.config file for the site is updated with the redirection rule. In my case I wanted to redirect traffic from site1 to site2. However site1 and site2 were both sharing the same physical folder and site content. This meant that changing the HTTP Redirect setting for one changed it for both, leaving me with a situation where neither site was working.

The extract below shows the system.webServer section of the web.config file updated with the <httpRedirect> setting.

    <location path="www.mysite.co.uk">
        <system.webServer>
            <security>
                <authentication>
                    <anonymousAuthentication userName="" />
                </authentication>
                <access sslFlags="Ssl" />
            </security>
   <httpRedirect enabled="true" destination="https://www.myothersite.co.uk" exactDestination="true" httpResponseStatus="Permanent" />
        </system.webServer>
    </location

To get around this problem I moved the <httpRedirect> tag into the applicationHost.config file, (I suggest making a backup of applicationHost.config before making any changes)

This is how I did it:

1. Open this file:
C:\Windows\System32\inetsrv\config\applicationHost.config

2. Search for www.mysite.co.uk

3. Scroll through the results until you see the result in the <location> element. 

4. Add the httpRedirect rule inside the system.webServer tags.

It will probably look something like this:

<location path="www.mysite.co.uk">
        <system.webServer>
            <security>
                <authentication>
                    <anonymousAuthentication userName="" />
                </authentication>
                <access sslFlags="Ssl" />
            </security>
   <httpRedirect enabled="true" destination="https://www.myothersite.co.uk" exactDestination="true" httpResponseStatus="Permanent" />
        </system.webServer>
</location>

You can then delete httpRedirect out of the web.config file.


Redirecting is much simpler using the IIS Management Console, and can be done like this:

Select whatever it is you want to redirect, then double click HTTP Redirect (make sure Features View is enabled)




You can then enable redirection by ticking the "Redirect requests to this destination" box and clicking Apply. 






Method 2 Bindings

Redirect traffic by changing the site bindings

The site Bindings tell IIS which site should receive the traffic it is to process. A single site can have many different bindings, and as long as traffic is routed correctly to the server it will be processed by IIS and passed to the relevant site.

If I want to redirect traffic for site1 to site2, I can add the binding for site1 to site2. See below for an example



In this example the site will receive traffic for both www.mysite.co.uk and www.myothersite.co.uk (as long as the public dns record exists and is routing to the server).

One thing to note is that each site binding must be unique. Two identical bindings on different sites will cause an error in IIS meaning only one of the sites can be started.

For this example it is not necessary for the other sites to exist in IIS, only the binding is required for the data to reach the site.



Method 3 URL ReWrite

Redirect traffic using the URL Rewrite module.

This is the most difficult and complicated method of redirecting traffic, however it is also the most flexible.

There are a lot of resources available for the URL Rewrite module, but I found this page to be the most useful.

URL Rewrite can be be used to accomplish multiple different tasks, so to keep things simple I will only describe how I used it to redirect traffic from one site to another.

Step 1
Install URL Rewrite module

Once installed, the URL Rewrite module is available from the IIS Management Console in Features View.



Step 2
Create a Rewrite rule

There are two types of scope:

Global - will edit the applicationHost.config file using the <rewrite> tag, and will affect all traffic to all sites
Rule - can be defined on any other level. From the documentation "This type of rule can be added on any configuration level by using Web.config files or by using <location> tags within ApplicationHost.config or Web.config files."

I used a global rule, and added a condition that matches the site(s) I wanted to redirect.

1. Open the URL Rewrite module

2. Select Add Rule(s)... > Blank Rule

3. Give the rule a name

4. Match URL

This section is used to match anything after the host part of the site address, as shown below

Http://www.mysite.co.uk/MatchURL

I want to redirect every request for the site, so I'm matching everything. The setting for this is:

Requested URL = Matches the Pattern
Using = Regular Expressions
Pattern = (.*)

The data matched here can be used for rewriting and redirecting using a process known as back-references. Back-references to rule patterns are identified by {R:N} where N is from 0 to 9. The match here would be represented by {R:0}. If the regular expression produced multiple results, they would be represented by {R:1} and so on.

5. Conditions

Conditions are optional. They allow filtering based on the host part of the site address, so I am using conditions to identify the parts of the address to be redirected.

Logical grouping = Match All/Match Any (depending on requirements)

Select Add

Condition input = {HTTP_HOST}
Check if input string: = Matches the Pattern
Pattern: = ^(www\.)(.*)$
Ignor case = ticked

Clicking Test Pattern allows us to test the regular expression and discover how the back references will be used.



Back-references to condition patterns are identified by {C:N} where N is from 0 to 9. This can be seen in the image above. To redirect the site to new.mysite.co.uk we can now create a redirect action using http://new.{C:2}

To redirect the site to www.myothersite.co.uk we can create a redirect action using http://{C:1}myothersite.co.uk

To filter the rule to apply to certain sites, we can create additional conditions




The condition above will only apply to www.mysite.co.uk

The combination of regular expression matching and back references provide an unlimited number of combinations for matching a redirecting.




   
References http://www.andrewwestgarth.co.uk/blog/post/2008/07/31/creating-http-redirects-in-iis7-on-virtual-directories-like-iis6.aspx
https://www.stokia.com/support/misc/web-config-response-redirect.aspx
https://www.iis.net/configreference/system.webserver/httpredirect

Friday 12 February 2016

Automating IIS App Pool Compliance


Background

With many servers comes the need to simply configuration management. I find application pools to be a constant source of headaches when it comes to keeping things consistent. They have loads of settings, which often get changed when trying to troubleshoot a problem (and not changed back). There’s also many other situations where they need to be configured; moving an application to another server, operating system upgrades, migrations, rationalisation, enforcing consistency - to name a few.

This has led me to automate the process of app pool configuration.

There are two scenarios to be covered – an ‘Online’ and an ‘Offline’ version. The Online version uses PowerShell remoting to connect to another IIS server that contains all the app pools and their required configurations. It then takes those settings and applies them to the target server.

The Offline version uses an existing IIS server and exports the app pool settings to a csv file, and then uses that to apply the settings to a target server.

Note that this process does not cover how to create app pools. This can easily be done by using MS Web Deploy if migrating a site, or New-WebAppPool if setting up a new site.

The process only works for IIS versions 7 and above. It is possible to migrate app pool settings from IIS v6 to IIS v7 onwards but it is more complicated than the process described here. The app pool settings are not the same between these versions, plus standard PowerShell commands and the IIS: drive are not available due to the limitations of PowerShell v2 (which is the highest version that can be used on an IIS 6.0 server).


Preparation

The first step is to decide which settings need to be configured. I like to set my app pool defaults first, and then explicitly set anything which hasn’t been caught by the default settings.

Setting the app pool defaults will change any app pool setting that isn’t the same as the new default setting or hasn’t been explicitly set, so use with caution. Setting app pool defaults is usually a one off setting when the server is new, or for a new global setting where there is a requirement to overwrite all existing settings.

To keep things simple I won’t go into the details of how to set app pool defaults, what I use for defaults, and how to revert an explicit app pool setting to inherit the default, I’ll try and cover that in a future blog post.

For now, what is important is that I want to set some app pool settings to a value that is different to the default.

The following settings need to be assessed as they may need to be different to the defaults:

.NET CLR Version
Enable 32 bit Applications
Managed Pipeline Mode
Identity

I also want to change the Recycling > Specific Times setting. My default is to recycle at 02:00am every day. I want to change this so that each app pool recycles at a random time between 02:00 – 02:59. I already have a separate script for this, see here for a blog post.
 

Offline Mode – export

This method uses an existing IIS server and exports the app pool settings to a csv file, and then uses that to apply the settings to a target server.

The following script is used to obtain and export these settings to csv file.

Import-Module webadministration

$AppPoolProperties = @()

foreach ( $pool in (get-item IIS:\AppPools\*) ) {

$Properties = New-Object System.Object

$Properties | Add-Member -type NoteProperty -name AppPoolName `
    -Value $($pool.name)

$Properties | Add-Member -type NoteProperty -name Enable32bit `
    -Value $($pool.enable32BitAppOnWin64)

$Properties | Add-Member -type NoteProperty -name Runtime `
    -Value $($pool.managedRuntimeVersion)

$Properties | Add-Member -type NoteProperty -name Pipeline `
    -Value $($pool.managedPipelineMode)

$Properties | Add-Member -type NoteProperty -name ProcessModel `
    -Value $($pool | Get-ItemProperty -name processModel.identityType)

$AppPoolProperties += $Properties
}

$AppPoolProperties | Export-Csv D:\AppPools.csv -NoTypeInformation

 
Breakdown

Import-Module WebAdministration
This loads the WebAdministration module which is required to make the IIS: drive available.

    $AppPoolProperties = @()
Creates an empty variable called AppPoolProperties and declares it as an array

Foreach loop

    foreach ( $pool in (get-item IIS:\AppPools\*) )

$pool is a temporary variable that only exists in the loop. This variable represents each member of the second command in the brackets –

    (get-item IIS:\AppPools\*)

This returns a list of app pool objects, so $pool will represent each app pool object in turn.

    $Properties = New-Object System.Object

Creates a new temporary object, see this link for an excellent explanation of custom objects:


The next section creates a variable for each of the app pool settings I want. This is generally straightforward and can be done by using $pool.property

    $pool.enable32BitAppOnWin64

To see all the app pool properties available use

    get-item IIS:\AppPools\* | Select-Object –first 1| Format-List –property *

Some of the properties cannot be obtained by using $pool.property

ProcessModel is an object type Microsoft.IIs.PowerShell.Framework.ConfigurationElement

To get its value I have to use Get-ItemProperty. This command will return the Identity Type for Process Model

    $pool | Get-ItemProperty -name processModel.identityType

Next I need to create on object that has each app pool value as a property. I use Add-Member to assign each of the app pool properties to the $properties object. Piping the $properties object created earlier to Add-Member assigns a name and value for each app pool property.

Viewing the $properties object after adding the properties for a single app pool looks like this

PS D:\scripts\modules> $Properties
AppPoolName  : .NET v2.0 Classic
Enable32bit  : False
Runtime      : v2.0
Pipeline     : Classic
ProcessModel : ApplicationPoolIdentity

    $AppPoolProperties += $Properties

Finally the $properties object is added to the $AppPoolProperties variable, and each time the foreach loop runs, another set of app pool properties are added to this variable. Using += adds the current object to the variable rather than overwriting the existing contents of the variable.

Once the loop is complete the final command uses Export-CSV to write $AppPoolProperties to CSV

    $AppPoolProperties | Export-Csv -Path D:\AppPools.csv –NoTypeInformation

Copy the CSV file to your target server, then run the Import script.
 
 
Offline Mode - import

The following script uses the exported CSV file to set each app pool property. It takes the App Pool name, and looks for a matching app pool, then sets the properties according to the setting in the CSV file. Once the app pool settings are in the CSV file, and the CSV file is stored on the server, this script can be run as a one off, or repeatedly to enforce the settings that are stored in the CSV file.
 

Import-Module webadministration

$AppPools = (Import-Csv D:\AppPools.csv)

foreach ( $pool in ( Get-Item IIS:\AppPools\* )) {

Set-ItemProperty IIS:\AppPools\$($pool.name) -Name enable32BitAppOnWin64 -Value `
    "$($AppPools | where { $_.AppPoolName -eq $pool.name } | Select-Object -ExpandProperty Enable32bit)"

Set-ItemProperty IIS:\AppPools\$($pool.name) -Name managedRuntimeVersion -Value `
    "$($AppPools | where { $_.AppPoolName -eq $pool.name } | Select-Object -ExpandProperty Runtime)"

Set-ItemProperty IIS:\AppPools\$($pool.name) -Name managedPipelineMode -Value `
    "$($AppPools | where { $_.AppPoolName -eq $pool.name } | Select-Object -ExpandProperty Pipeline)"

Set-ItemProperty IIS:\AppPools\$($pool.name) -Name processModel.identityType -Value `
    "$($AppPools | where { $_.AppPoolName -eq $pool.name } | Select-Object -ExpandProperty ProcessModel)"

}


Breakdown

    Import-Module WebAdministration

This loads the WebAdministration module which is required to make the IIS: drive available.

  $AppPools = (Import-Csv D:\AppPools.csv)

Creates a variable from the contents of the CSV file

Foreach loop

This is the same as the previous script. The purpose is to cycle through each local app pool, then change the settings accordingly.

    foreach ( $pool in (get-item IIS:\AppPools\*) )

The Set-ItemProperty command is quite long, so I will break it down.

    Set-ItemProperty IIS:\AppPools\$($pool.name)

The item property to be set is defined as the app pool in the current $pool variable, and is selected using the name property

    -Name enable32BitAppOnWin64

The name parameter is the name of the property being changed

    -Value

For the Value parameter I obtain the app pool value stored in the CSV file for the –name property

    "$($AppPools | where { $_.AppPoolName -eq $pool.name } | Select-Object -ExpandProperty Runtime)"

    $AppPools
Starts with the CSV contents in the variable

    where { $_.AppPoolName -eq $pool.name }
Filter with Where-Object to select only the row in the CSV file that matches the current app pool ($pool object) using the name property.

    Select-Object -ExpandProperty Runtime
Select the Property value with Select-Object, in this case the Runtime value, which is the managedRuntimeVersion

The whole command is then wrapped in $(), this returns the contents of the value object rather than the object itself.


Online mode - tbc ....
 

Wednesday 13 January 2016

PowerShell: List all IPv4 Addresses

A very short blog post today. I'm not sure why this is so complicated, maybe there's an easier way, or a more recent cmdlet that allows it to be obtained in an easier way.

I want to list all IP (v4) addresses and nothing else with a single line PowerShell command that is backwards compatible with all versions of PowerShell.

Here's what I came up with:

foreach ( $i in (Get-WmiObject Win32_NetworkAdapterConfiguration -Namespace "root\CIMV2" | where { $_.IPEnabled -eq "True" } | select IPAddress) ) { $i.IPAddress[0] }

Here's a quick breakdown of the command

It's basic structure uses a foreach loop

Foreach ( $TempVariable in $MyVariableList ) { do this }

$i is my temporary variable, that exists only for the purposes of the loop. The Foreach loop will cycle through each object in the second variable, and each time it will be represented by $i

$MyVariableList is a variable that contains many objects, and is often obtained in a script by a separate command. As I want a one-liner, I have substituted this variable with a command that produces a list of objects.

This is my command:

Get-WmiObject Win32_NetworkAdapterConfiguration -Namespace "root\CIMV2" | where { $_.IPEnabled -eq "True" } | select IPAddress)

It uses Get-WMIObject to return the WMI class Win32_NetworkAdapterConfiguration. I chose the Get-WMIObject command to return the IP address data because I know it is compatible with all version of PowerShell. This command on its own returns a large amount of data, so I have piped the results to the Where-Object command. This filters to return only network adapters that are enabled. These results are then piped to the Select-Object command, and this selects the single property of IP address.


IP Address properties






The result is an IP address object for each adapter. Each contains both an IPv4 and IPv6 address.

{ do this } Finally the Foreach loop will carry out an action on each object that is returned. In this case it simply takes the object and calls the IPAddress property (which is the only one available). The square brackets specify the 1st result only will be displayed.

IP Address list




Simple.




Wednesday 6 January 2016

Scripting IIS App Pools (v8.5) with PowerShell



App Pools

It's quite common to automate the process for creating a web site and its associated application pools. Creating an app pool is a simple process, but the many different settings that can be used is where things can get complicated. In my experience I found that PowerShell's Set-ItemProperty can get complicated when it's used with IIS app pools, so here's a few things I found out.

The IIS:\ provider doesn't work unless the WebAdministration module is first imported. So the following command must be run at the beginning of any script

Import-Module WebAdministration or ipmo webadministration

To fetch a list of app pools, run

Get-Item IIS:\AppPools\*


Whenever I'm working with something for the first time, I select one object, then pass it to the Format-List cmdlet which enables me to see every available property.

Get-Item IIS:\AppPools\* | select-object -First 1 | Format-List -Property * 


This displays all the properties that were hidden from the results of the first Get-Item command. I could also select a specific app pool

Get-Item IIS:\AppPools\MyAppPool | Format-List -Property *

I can see several results display Microsoft.IIs.PowerShell.Framework.ConfigurationElement rather than an actual value.

App Pool properties


 


This is where we need to switch to the Get-ItemProperty cmdlet to see the property details in full.

Get-Item IIS:\AppPools\* | select-object -First 1 | Get-ItemProperty -name processmodel

or for a specific App Pool

Get-Item IIS:\AppPools\MyAppPool | Get-ItemProperty -name processmodel
this can also be written as

(Get-ItemProperty IIS:\AppPools\MyAppPool).processmodel
or

Get-ItemProperty IIS:\AppPools\MyAppPool -name processmodel
The results show that processmodel has several properties.

processModel properties









I expected to be able to change one of these properties by running a command like this

Set-ItemProperty IIS:\AppPools\MyAppPool -name processmodel.identitytype -Value ApplicationPoolIdentity

When I run this command, it executes without an error, but no changes are made.

Similarly with other App Pool settings the Set-ItemProperty command does not make changes.

Set-ItemProperty IIS:\AppPools\MyAppPool -name managedPipeLineMode -value Integrated

After some experimentation I found that the name parameter of Set-ItemProperty is case sensitive

When I go back and examine my previous commands, I can see that processmodel is in fact processModel, and identitytype is identityType. Also I should've been using managedPiplineMode.

Once I change my commands accordingly, the Set-ItemProperty command correctly makes the changes.

Set-ItemProperty IIS:\AppPools\MyAppPool -name processModel.identityType -Value ApplicationPoolIdentity

Set-ItemProperty IIS:\AppPools\MyAppPool -name managedPipelineMode -value Integrated