Friday, January 31, 2014

Automated installation and configuration of IIS Advanced logging module using Powershell

Recently I had a chance to work on a web application which is hosted in the AWS environment. Throughout the development life cycle we have built an automated deployment process using Powershell. The automated build and deploy process takes care of spinning up new EC2 instances using Windows 2012 base AMI and installs both runtime requirements and application itself.

During this process, I had a chance to build few automation modules in Powershell. I am going to share some snippets of the modules in upcoming posts which I found not so straight forward to build. So that it would be useful to someone who is trying perform the same task.
In this post I am going to cover the automated installation and configuration of IIS Advanced logging module.

Why Advanced Logging module?
Since all of our web servers are behind Elastic Load Balancers (ELB), the remote host address is always set to the internal IP address of the load balancer. ELB puts the actual client IP address is in the X-Forwarded-For request header. The stock standard IIS HTTP logging module doesn't have access to these custom headers therefore we chose to use Advanced Logging module to capture and log additional customer headers.

We only need Advanced Logging module for IIS 7, IIS 7.5 and IIS 8.0. In IIS 8.5 (i.e.: In Windows 2012 R2) the HTTP logging has native support to capture custom fields as part of stock standard HTTP logging.

It was pretty straight forward to install and configure manually but not so easy through Powershell because installation and configuration not fully supported through Powershell alone I had to use appcmd.exe as well.

The Goal
  1. Install Advanced Logging module
  2. Create custom logging folder and assign permissions 
  3. Disable stock standard IIS logging
  4. Add additional headers like X-Forwarded-For, X-Forwarded-Proto to the available logging fields
  5. Disable server level Advanced logging
  6. Enable Advanced logging
  7. Configure custom log directory at server level and default site level 
  8. Configure Advanced Logging by site on the server
Lets dive into detail.....

1. Install Advanced Logging module
msiexec.exe /i C:\data\AdvancedLogging64.msi /passive /log C:\Data\advancedlogging.log
Start-Sleep -Seconds 10
2. Create custom logging folder and assign permissions
   
Give Read & Write access to IIS_IUSERS group (I found out about this in the hard way)
#grant permission to IIS_IUSERS group to the log directory
$Command = "icacls C:\logs /grant BUILTIN\IIS_IUSRS:(OI)(CI)RXMW"
cmd.exe /c $Command
3. Disable stock standard IIS logging
Import-Module WebAdministration 

# Disables http logging module
Set-WebConfigurationProperty -Filter system.webServer/httpLogging -PSPath machine/webroot/apphost -Name dontlog -Value true
4. Add additional headers like X-Forwarded-For, X-Forwarded-Proto to the available logging fields
# Adds AWS ELB aware X-Forwarded-For logging field
Add-WebConfiguration "system.webServer/advancedLogging/server/fields" -value @{id="X-Forwarded-For";sourceName="X-Forwarded-For";sourceType="RequestHeader";logHeaderName="X-Forwarded-For";category="Default";loggingDataType="TypeLPCSTR"}

# Adds AWS ELB aware X-Forwarded-Proto logging field
Add-WebConfiguration "system.webServer/advancedLogging/server/fields" -value @{id="X-Forwarded-Proto";sourceName="X-Forwarded-Proto";sourceType="RequestHeader";logHeaderName="X-Forwarded-Proto";category="Default";loggingDataType="TypeLPCSTR"} 
5. Disable default server level Advanced logging
# Disables the default advanced logging config
Set-WebConfigurationProperty -Filter "system.webServer/advancedLogging/server/logDefinitions/logDefinition[@baseFileName='%COMPUTERNAME%-Server']" -name enabled -value false
6. Enable Advanced logging
   
By default the Advanced Logging is disabled.
# Enable Advanced Logging
Set-WebConfigurationProperty -Filter system.webServer/advancedLogging/server -PSPath machine/webroot/apphost -Name enabled -Value true
7. Configure custom log directory at server level and default site level
# Set log directory at server level
Set-WebConfigurationProperty -Filter system.applicationHost/advancedLogging/serverLogs -PSPath machine/webroot/apphost -Name directory -Value $logDirectory

# Set log directory at site default level
Set-WebConfigurationProperty -Filter system.applicationHost/sites/siteDefaults/advancedLogging -PSPath machine/webroot/apphost -Name directory -Value $logDirectory
8. Configure Advanced Logging by site on the server
function AdvancedLogging-GenerateAppCmdScriptToConfigureAndRun()
{
    param([string] $site) 

    #Get current powershell execution folder
    $currentLocation = Get-Location

    #Create an empty bat which will be populated with appcmd instructions
    $stream = [System.IO.StreamWriter] "$currentLocation\$site.bat"

    #Create site specific log definition
    $stream.WriteLine("C:\windows\system32\inetsrv\appcmd.exe set config `"$site`" -section:system.webServer/advancedLogging/server /+`"logDefinitions.[baseFileName='$site',enabled='True',logRollOption='Schedule',schedule='Daily',publishLogEvent='False']`" /commit:apphost")

    #Get all available fields for logging
    $availableFields = Get-WebConfiguration "system.webServer/advancedLogging/server/fields"

    #Add appcmd instruction to add all the selected fields above to be logged as part of the logging
    #The below section can be extended to filter out any unwanted fields
    foreach ($item in $availableFields.Collection) 
    {
        $stream.WriteLine("C:\windows\system32\inetsrv\appcmd.exe set config `"$site`" -section:system.webServer/advancedLogging/server /+`"logDefinitions.[baseFileName='$site'].selectedFields.[id='$($item.id)',logHeaderName='$($item.logHeaderName)']`" /commit:apphost")
    }

    $stream.close()

    # execute the batch file create to configure the site specific Advanced Logging
    Start-Process -FilePath $currentLocation\$site.bat
    Start-Sleep -Seconds 10
}
#Call the above method by passing in the IIS site names
AdvancedLogging-GenerateAppCmdScriptToConfigureAndRun 'foo.com'

And that’s it :).

I found following two posts to be helpful in building the above.

http://forums.iis.net/t/1193633.aspx?Configure+Advanced+Logging+through+powershell
http://forums.iis.net/t/1161699.aspx?IIS+Advanced+Logging+1+0+Feedback

Comments and suggestions are welcome.

Tuesday, March 31, 2009

MVC chapter ebook

Scott Guthrie has released a chapter of the upcoming "Asp.net MVC 1.0" and it can be found on the following URL:

http://aspnetmvcbook.s3.amazonaws.com/aspnetmvc-nerdinner_v1.pdf

Tuesday, February 26, 2008

TRULY Understanding ViewState, the comment index

This article gives a very good coverage of the problems faced in usage of ViewState.

http://weblogs.asp.net/infinitiesloop/archive/2008/02/
19/truly-understanding-viewstate-comment-index.aspx

User Administration Tool (Part 3)

In Part 2 of this series of the article covered user management features. This final part will deal with role management and profile management.

http://www.dotnetbips.com/articles/
30775db7-379a-4b37-beff-cb32d3734a04.aspx

ASP.NET AJAX Controls and Extenders Tutorial

What are the differences between the Server Control, the ASP.NET AJAX Server Control and the ASP.NET AJAX Server Control Extender, and when should each be used?

This article gives good comparison between each of them.

http://www.codeproject.com/kb/
ajax/ajaxcontrolsandextenders.aspx

Best Practices to Improve ASP.Net Web Application Performance.

This article gives some important points to consider for the performance improvement in asp.net applications.

http://www.dotnetfunda.com/
articles/article45.aspx

Validate XSL Against XML

In this Article, Haissam Abdul Malak shows how to create a class library for validating a certain XSL file against an XML file. He examines the concept with the help of a series of steps with relevant source code and explanations. Finally, he describes how to test the class library which was created in the previous steps.

http://aspalliance.com/
1567_Validate_XSL_Against_XML.all

AJAX localization

This article discusses:
  • Globalization support in ASP.NET AJAX
  • Need for support in JavaScript
  • Assembly-based AJAX localization
  • File-based AJAX localization
http://msdn.microsoft.com/msdnmag/issues/
08/01/InternationalizingASPNETAJAX/#S3

Adding a Build Banner to ASP.NET Pages

This article explains, and provides fully functional code, for a plugin to the HTTP pipeline which will render such a 'development banner' to any ASPX page in the website in question.
The only requirement is to add the appropriate configuration to the Web.config file, and ensure the banner assembly is in the sites bin directory.

http://www.codeproject.com/kb/
aspnet/buildbanner.aspx

Top 10 Best Practices for Production ASP.NET Applications

In no particular order, here are the top ten things I've learned to pay attention to when dealing with production ASP.NET applications. Hopefully they will help you save you some time and headaches.

http://daptivate.com/archive/2008/02/12/
top-10-best-practices-for-production-asp-net-applications.aspx

ASP.NET Memory: If your application is in production… then why is debug=true

This is another article which has some information about the impact of leaving debug=true in the production environment.

http://blogs.msdn.com/tess/archive/
2006/04/13/575364.aspx

App_Offline.htm and working around the "IE Friendly Errors" feature

This article gives a way to overcome the "IE Friendly Errors" feature interfering with the actual message coming from the server when the content length is less than 512 bytes.


http://weblogs.asp.net/scottgu/archive
/2006/04/09/442332.aspx

Tuesday, February 19, 2008

Monday, February 18, 2008

Code Converters (C# to VB.Net)

This is a nice tool to convert C# code to VB.net or wise versa.

  1. Convert C# to VB.NET
  2. Convert VB.NET to C#

Friday, February 15, 2008

Uncover Hidden Data to Optimize Application Performance

This article discusses:
  • Dynamic management views and functions
  • Causes of server waits
  • Common index problems
  • Problems associated with logical I/O
http://msdn.microsoft.com/msdnmag/
issues/08/01/SqlDmvs/default.aspx

Wednesday, February 13, 2008

JSON-Enabled WCF Services in ASP.NET 3.5

This article gives a very good introduction to using WCF services with AJAX.

http://dotnetslackers.com/articles/ajax/
JSON-EnabledWCFServicesInASPNET35.aspx

An Overview of ASP.NET 3.5 and Visual Studio 2008

This article provides an overview of the new features in ASP.NET 3.5 and the new web/ASP.NET-related features in Visual Studio 2008. Read on to learn more!

http://aspnet.4guysfromrolla.com/
articles/112107-1.aspx

ASP.NET Application Life Cycle Overview for IIS 7.0

This topic describes the application life cycle for ASP.NET applications that are running in IIS 7.0 in Integrated mode and with the .NET Framework 3.0 or later. The IIS 7.0 integrated pipeline is a unified request processing pipeline that supports both native-code and managed-code modules.

http://msdn2.microsoft.com/en-us/
library/bb470252.aspx