Script to install UrlScan v3.0 as a site filter.

Although using WIX to create an MSI to do this task is a cleaner approach, it is too heavy duty for me. I do this often enough to warrant creating a script for it, so I though I would share it out.

To use it you would run: InstallUrlScanAtSite.js -siteid:1 [-dest:c:\foo]. You have to specify the site ID of the site you want it installed at. The 'dest' parameter will be the location where your urlscan.dll and urlscan.ini file will be copied to for use as the filter path. If you don't specify this, it will copy them to your site's ROOT vdir path.

// InstallUrlScatAtSite.js
//
// Install UrlScan 3.0 at a particular site.
//
// Author: Nazim Lala
//
// What it does:
//   1. By default copy urlscan.dll and urlscan.ini from 
//      system32\inetsrv\urlscan dir to root of site you want to install to.
//      Else use the value of Dest as the destination.
//   2. Install this copy of the dll as a site filter of that particular site.
//
// Assumptions:
//   1. You already have UrlScan 3.0 installed globally on the machine.
//   2. The script has access to write to your site's root directory or 
//      Dest
//

var szUsage;
var szSiteID;
var szDest;


var CRLF = "\r\n";

szUsage = "" +
    "Install UrlScan 3.0 as a site filter" + CRLF +
    CRLF +
    WScript.ScriptName + " [[-Parameter:Value]...]" + CRLF +
    CRLF +
    "Where:" + CRLF +
    "    Parameter  Value" + CRLF +
    "    ---------  -------------------------------------------" + CRLF +
    "    SiteID     Site ID # (Required)" + CRLF +
    "    Dest       Destination to copy urlscan.dll/.ini to" + 
    "(Default is Site root)" + CRLF +
    "";
    
if ( ParseCommandline() && ValidateArgs() )
{
    if ( !SetandCheckDestination() ) 
    {
        WScript.Quit( 1 );
    }
    if ( !CopyDllAndConfig() ) 
    {
        WScript.Quit( 2 );
    }
    if ( !AddFilter() )
    {
        WScript.Quit( 3 );
    }
    
}

function ParseCommandline()
{
    var exp = new RegExp( "-([^:]+):(.+)" );
    var args;

    for ( var i = 0; i < WScript.Arguments.length; i++ )
    {
        args = exp.exec( WScript.Arguments( i ) );
        if ( args == null )
        {
            WScript.Echo( "Invalid parameter " + WScript.Arguments( i ) )
            return false;
        }
        else
        {
            switch ( args[1].toLowerCase() )
            {
                case "siteid":
                    szSiteID = args[2];
                    break;
                case "dest":
                    szDest = TrimSlashes( args[2] );
                    break;
                default:
                    WScript.Echo( "Unknown parameter " + args[1] );
                    return false;
            }
        }
    }

    return true;
}

function ValidateArgs()
{
    if ( szSiteID == null )
    {
        WScript.Echo( "Missing Site ID." + szUsage);
        return false;
    }
    else return true;
}

function SetandCheckDestination()
{
    if ( szDest == null )
    {
        // Set destination to site root
        try
        {
            var objSite = GetObject( "IIS://LOCALHOST/W3SVC/" + 
                szSiteID +"/ROOT" );
            szDest = objSite.Path;
        }
        catch ( e )
        {
            WScript.Echo( "Failed to acquire site's ROOT path. " +  
                FormatErrorString( e ) );
            return false;
        }
    }
    else
    {
        // Check if destination path exists. If not try to create it.
        try
        {
            var objFSO = new ActiveXObject( "Scripting.FileSystemObject" );
            if ( !objFSO.FolderExists( szDest ) )
            {
                objFSO.CreateFolder( szDest );
            }
        }
        catch ( e )
        {
            WScript.Echo( "Failed to create folder. " + 
                FormatErrorString( e ) );
            return false;
        }
    }

    return true;
}    

function CopyDllAndConfig()
{
    try
    {
        var objFSO = new ActiveXObject( "Scripting.FileSystemObject" );
        var WshShell = WScript.CreateObject( "WScript.Shell" );
        var objEnv = WshShell.Environment( "Process" );
        var szUrlScanDir = objEnv( "WINDIR" ) + 
            "\\system32\\inetsrv\\urlscan";
        objFSO.CopyFile( szUrlScanDir+"\\urlscan.dll", 
            szDest+"\\urlscan.dll" );
        objFSO.CopyFile( szUrlScanDir+"\\urlscan.ini", 
            szDest+"\\urlscan.ini" );
    }
    catch ( e )
    {
        WScript.Echo( "Failed to copy files." +
            FormatErrorString( e ) );
        return false;
    }
    return true;
}

function AddFilter()
{
    var objSiteFilters;
    var objUrlScanFilter;
    var szLoadOrder;
    
    try
    {
        objSiteFilters = GetObject("IIS://LOCALHOST/W3SVC/" + 
            szSiteID + "/FILTERS");
    }
    catch ( e )
    {
        //
        // Perhaps we don't have any filters.
        // Try to create it.
        //
        try
        {
            objSiteFilters = GetObject( "IIS://LOCALHOST/W3SVC/" + 
                                    szSiteID ).Create( "IIsFilters",
                                                        "Filters" );
            objSiteFilters.SetInfo();
        }
        catch ( e2 )
        {
            //
            // Could not create the filters node. Quit.
            //
            WScript.Echo( "Failed to create filters node." + 
                FormatErrorString( e ) );
            return false;
        }
    }
    
    try
    {
        //
        // Create the actual Filters node and configure path.
        //
        objUrlScanFilter = objSiteFilters.Create( "IIsFilter", 
            "UrlScan 3.0" );
        objUrlScanFilter.FilterPath = szDest;
        objUrlScanFilter.SetInfo();
    }
    catch ( e )
    {
        if ( e.number == -2147024713 )
        {
            WScript.Echo( "UrlScan 3.0 Filter already exists." );
        }
        else
        {
            WScript.Echo( FormatErrorString( e ) );
        }

        return false;
    }
    
    try
    {
        //
        // Update FilterLoadOrder and append to beginning of list
        //
        szLoadOrder = objSiteFilters.FilterLoadOrder;
        
        if ( szLoadOrder == null )
        {
            objSiteFilters.FilterLoadOrder = "UrlScan 3.0";
        }
        else
        {
            objSiteFilters.FilterLoadOrder = "UrlScan 3.0,"+szLoadOrder;
        }
        objSiteFilters.SetInfo();
        
    }
    catch ( e )
    {
        WScript.Echo( "Failed to update filter load order: " + 
            FormatErrorString( e ) );
        return false;
    }
    
    return true;
}

function TrimSlashes( strInput )
{
    return strInput.replace( new RegExp( "^/+|/+$", "g" ), "" );
}

function Int32ToHRESULT( num ) 
{
    if ( num < 0 )
    {
        return "0x" + new Number( 0x100000000 + num ).toString( 16 );
    }
    else
    {
        return "0x" + num.toString( 16 );
    }
}


function FormatErrorString( objError )
{
    return "(" + Int32ToHRESULT( objError.number) + ")" + ": " +
           objError.description;
}

I haven't thoroughly tested it, so if you find any bugs, let me know. You can also easily modify this script to add it to ALL sites on the server if need be.

3 Comments

  • Some day I will try to do this using PowerShell ... that should be a much simpler script.

  • Nazim,

    We've been trying to use URLScan to filter cookies - i've specified encoded (hex) characters in the .ini, but URLScan doesn't seem to be recognizing them. Below is a snippet from the URLScan.ini. Do you see anything wrong with it?

    Is there a way to get URLScan to normalize the headers, like it does the URL (via NormalizeUrlBeforeScan)?

    [Options]
    RuleList= FilterHeaders

    [FilterHeaders]
    AppliesTo=.asp
    DenyDataSection=FilterHeaders Data
    ScanURL=0
    ScanAllRaw=1
    ScanQueryString=0
    ScanHeaders=Cookie:
    DenyUnescapedPercent=1

    [FilterHeaders Data]
    --
    %22
    %27
    %3C
    %3E

    "
    '

  • Deep -
    Can you please post your question to the forums, so we can track it?
    Thanks.

Comments have been disabled for this content.