HOWTO: Retrieve and Interpret ISAPI Filter Status

Question:

Is there way to script a check on the success or failure of the Filter, ie a vbscript object that contains the state of loaded DLL's?

One can get the list of filters installed from the metabase, but how would one get the state? The metabase doesn't seem to contain that.

Doesn't necessarily validate it but if I look in the UI, the green up arrow tells me enough not to scurry off to the event viewer to see what went wrong. Some COM object contains that, right?

Answer:

Actually, it is not possible to programmatically retrieve the state of loaded ISAPI Filter DLLs. The best you can do is programmatically retrieve the status of the last attempt by IIS to load the ISAPI Filter DLL.

Incidentally, this is the same information displayed in the UI, so based on what you said, it should be sufficient.

BTW, the metabase definitely contains the filter state you are looking for. Here is a sample script tool written in VBScript which enumerates useful data associated with an ISAPI Filter. You can optionally pass in commandline parameters to select whether to enumerate global/site filters as well as remote server. Use /? or -help to get syntax help.

Sample output from the tool:

 Global Filters on server localhost
+ Filter sspifilt - "Microsoft SSPI Encryption Filter, v1.0"
  Filter  DLL = D:\WINNT\System32\inetsrv\sspifilt.dll
  FilterState = 1 (Loaded OK)
  FilterFlags = 134792449
  FilterEvent = ReadRawData PreprocHeaders SendRawData EndOfNetSession
    Listens on SecurePort
    Runs as High Priority

+ Filter Compression - "HTTP 1.1 Compression filter version, v1.0"
  Filter  DLL = D:\WINNT\SYSTEM32\INETSRV\COMPFILT.DLL
  FilterState = 1 (Loaded OK)
  FilterFlags = 524288
  FilterEvent =
    Runs as High Priority

+ Filter md5filt - "Digest Authentication, version 1.0"
  Filter  DLL = D:\WINNT\System32\inetsrv\md5filt.dll
  FilterState = 1 (Loaded OK)
  FilterFlags = 537004547
  FilterEvent = AccessDenied Log
    Listens on SecurePort
    Listens on NonSecurePort
    Runs as Low Priority

Enjoy.

//David

 '
' Enumerates global or specific site's ISAPI Filters
'
' Origin : https://blogs.msdn.com/David.Wang
' Version: February 10 2006
'
' Format of ISAPI Filters stored in IIS metabase
'
' IIS://localhost/W3SVC/Filters = Global Filters
' IIS://localhost/W3SVC/#/Filters = Site Filters
'
' .../Filters/FilterLoadOrder = Order of Filters to load
' .../Filters/Filter1
'    .FilterPath = DLL location of Filter1
'    .FilterState = Status of last filter load
'    .FilterDescription = description set by filter
'    .FilterFlags = events registered by filter
'    .Win32Error = (IIS6 Only) Win32 Errorcode of last load
'    .FilterEnableCache = (IIS6 Only) Hint that filter is cache friendly
'
' TODO:
' Warn about Filters not in FilterLoadOrder
'
'
Option Explicit
On Error Resume Next

const ERROR_SUCCESS             = 0
const ERROR_INVALID_PARAMETER   = 87

Dim strServer, strWebsite, strFilterLoadOrder, strFilters
Dim objFilters, objFilter
Dim arr, i
Dim strHelp
strHelp = "Enumerate global or site's ISAPI Filters" & VbCrLf &_
          VbCrLf &_
          WScript.ScriptName & " [MetaPath] [Server]" & VbCrLf &_
          VbCrLf &_
          "Where:" & VbCrLf &_
          "     MetaPath    W3SVC = Global Filters (Default)" & VbCrLf &_
          "                 W3SVC/ID# = Site ID#'s Filters" & VbCrLf &_
          "     Server      LocalHost (Default)" & VbCrLf &_
          "                 Remote Server's Name"

strServer = "localhost"
strWebsite = "W3SVC"

If WScript.Arguments.Length > 0 Then
    strWebsite = WScript.Arguments( 0 )
End If

If WScript.Arguments.Length > 1 Then
    strServer = WScript.Arguments( 1 )
End If

If Instr( strWebsite, "?" ) > 0 Or _
   Instr( UCase( strWebsite ), "HELP" ) > 0 Or _
   Instr( strServer, "?" ) > 0 Or _
   Instr( UCase( strServer), "HELP" ) > 0 Then
    Err.Number = ERROR_INVALID_PARAMETER
    HandleError strHelp
End If

If WScript.Arguments.Length > 2 Then
    Err.Number = ERROR_INVALID_PARAMETER
    HandleError "Incorrect number of arguments." & VbCrLf &_
                VbCrLf &_
                strHelp &_
                ""
End If

'
' Check if there is a Filters node
'
strFilters = "IIS://" & strServer & "/" & strWebsite & "/Filters"
Err.Clear
Set objFilters = GetObject( strFilters )
HandleError Site2String( strWebsite ) & " on server " &_
            strServer & " were not found."

arr = Split( objFilters.FilterLoadOrder, "," )
LogEcho( Site2String( strWebsite ) & " on server " & strServer )

For i = 0 to UBOUND( arr )
    '
    ' Check if there is a Filter node
    '
    Err.Clear
    Set objFilter = GetObject( strFilters & "/" & arr( i ) )
    If ( Err.Number <> 0 ) Then
        LogEcho "+ Filter " & arr( i ) & " WAS NOT FOUND!" & VbCrLf
    Else
        LogEcho _
            "+ Filter " & arr( i ) & " - " &_
            """" & objFilter.FilterDescription & """" & VbCrLf &_
            "  Filter File = " & objFilter.FilterPath & VbCrLf &_
            "  " & FilterState2String( objFilter.FilterState ) &_
            VbCrLf &_
            "  " & FilterFlags2String( objFilter.FilterFlags ) &_
            ""
    End If
Next

'
' Sub routines and functions
'
Sub HandleError( errorDescription )
    If ( Err.Number <> 0 ) Then
        If ( IsEmpty( errorDescription ) ) Then
            LogEcho Err.Description
        Else
            LogEcho errorDescription
        End If

        WScript.Quit Err.Number
    End If
End Sub

Sub LogEcho( str )
    WScript.Echo str
End Sub

Function Site2String( Site )
    Site2String = ""
    If UCase( Site ) = "W3SVC" Then
        Site2String = "Global Filters"
    Else
        Site2String = "Filters for website " & Site
    End If

End Function

Function FilterState2String( FilterState )
    FilterState2String = "FilterState = " & FilterState

    Select Case FilterState
    Case 1
        FilterState2String = FilterState2String & " (Loaded OK)"
    Case Else
        FilterState2String = FilterState2String & " (**ERROR**)"
    End Select
End Function

Function FilterFlags2String( FilterFlags )
    FilterFlags2String = "FilterFlags = " & FilterFlags & VbCrLf
    FilterFlags2String = FilterFlags2String & "  FilterEvent ="

    If FilterFlags And 32768 Then
        FilterFlags2String = FilterFlags2String & " ReadRawData"
    End If
    If FilterFlags And 16384 Then
        FilterFlags2String = FilterFlags2String & " PreprocHeaders"
    End If
    If FilterFlags And 8192 Then
        FilterFlags2String = FilterFlags2String & " Authentication"
    End If
    If FilterFlags And 4096 Then
        FilterFlags2String = FilterFlags2String & " UrlMap"
    End If
    If FilterFlags And 2048 Then
        FilterFlags2String = FilterFlags2String & " AccessDenied"
    End If
    If FilterFlags And 64 Then
        FilterFlags2String = FilterFlags2String & " SendResponse"
    End If
    If FilterFlags And 1024 Then
        FilterFlags2String = FilterFlags2String & " SendRawData"
    End If
    If FilterFlags And 512 Then
        FilterFlags2String = FilterFlags2String & " Log"
    End If
    If FilterFlags And 128 Then
        FilterFlags2String = FilterFlags2String & " EndOfRequest"
    End If
    If FilterFlags And 256 Then
        FilterFlags2String = FilterFlags2String & " EndOfNetSession"
    End If
    If FilterFlags And 67108864 Then
        FilterFlags2String = FilterFlags2String & " AuthComplete"
    End If
    FilterFlags2String = FilterFlags2String & VbCrLf
    If FilterFlags And 1 Then
        FilterFlags2String = FilterFlags2String &_
            "    Listens on SecurePort" & VbCrLf
    End If
    If FilterFlags And 2 Then
        FilterFlags2String = FilterFlags2String &_
            "    Listens on NonSecurePort" & VbCrLf
    End If
    If FilterFlags And 524288 Then
        FilterFlags2String = FilterFlags2String &_
            "    Runs as High Priority" & VbCrLf
    End If
    If FilterFlags And 262144 Then
        FilterFlags2String = FilterFlags2String &_
            "    Runs as Medium" & VbCrLf
    End If
    If FilterFlags And 131072 Then
        FilterFlags2String = FilterFlags2String &_
            "    Runs as Low Priority" & VbCrLf
    End If
End Function