VDirHits.js
Description
This script generates a report containing all the hits received by any IIS VDir in the specified site. The optional 'maxdepth' parameter specifies the maximum search depth in the IIS VDir tree. The script works by mapping logged URL's to their corresponding Virtual Directories.
Requirements
You must install and use the Log Parser.
Supported Platforms
Windows Server 2003 |
Yes |
Windows XP |
Yes |
Windows 2000 |
Yes |
Script Code
//Parse arguments first
var szSiteID=null;
var nMaxDepth=-1;
var szServerName="localhost";
var szArgs = WScript.Arguments;
if(szArgs.length<1)
{
WScript.Echo("Usage:");
WScript.Echo(" -site:<site_id>");
WScript.Echo(" [ -maxdepth:<max_
depth> ]");
WScript.Echo(" [ -servername:<server_
name> ]");
WScript.Quit(-2);
}
for (var i=0; i < szArgs.length; i++)
{
if(szArgs(i).substr(0,6).toLowerCase()=="-site:")
{
szSiteID=szArgs(i).substr(6);
}
else
if(szArgs(i).substr(0,10).toLowerCase()==
"-maxdepth:")
{
nMaxDepth=parseInt(szArgs(i).substr(10));
}
else
if(szArgs(i).substr(0,12).toLowerCase()
=="-servername:")
{
szServerName=szArgs(i).substr(12);
}
else
{
WScript.Echo("Unrecognized argument: " +
szArgs(i));
WScript.Quit(-1);
}
}
if( szSiteID==null || nMaxDepth==null )
{
WScript.Echo("Not all the parameters have
been specified");
WScript.Quit(-1);
}
//Create VDir tree
WScript.Echo("Storing current VDir tree for
site /"
+ szServerName + "/" + szSiteID + "...");
var g_tree=new Array(0);
var szRootPath="IIS://" + szServerName +
"/W3SVC/"
+ szSiteID + "/ROOT";
var objRoot=GetObject(szRootPath);
CreateTree(g_tree, objRoot, 0, nMaxDepth);
WScript.Echo("...done.");
//Do the work
DoQuery(szServerName, szSiteID);
//Dump the tree count result
WScript.Echo("\r\nHit results:");
DumpTree(g_tree, " ");
//Exit
WScript.Quit(0);
/*
This function stores an in-memory representation
of the
IIS virtual directories and web directories tree.
Each 'node' in the tree is an array structured in the
following way:
0 - Node name
1 - Hits received by this node
2..N - Child nodes of this node
*/
function CreateTree(tree, objVDir, nDepth,
nMaxDepth)
{
var szIndent=" ";
for(var d=0;d<nDepth;d++)
szIndent+=" ";
WScript.Echo(szIndent + "Storing child VDir \""
+ objVDir.Name + "\"");
//Save node name
tree[0]=objVDir.Name;
//Init hit counter
tree[1]=0;
if(nMaxDepth==-1 || nDepth<nMaxDepth)
{
//Get all child VDirs and recursively add them
to the tree
for( var objChildNodes=new Enumerator
(objVDir);
!objChildNodes.atEnd();
objChildNodes.moveNext())
{
var objChildNode=objChildNodes.item();
if ( objChildNode.Class == "IIsWebVirtualDir" ||
objChildNode.Class == "IIsWebDirectory" )
{
//Store this child node
var child=new Array();
CreateTree(child, objChildNode, nDepth+1,
nMaxDepth);
tree[tree.length]=child;
}
}
}
}
function DoQuery(szServerName, szSiteID)
{
//Create the main Log Parser Query object
var myQuery=new ActiveXObject("MSUtil.
LogQuery");
//Get the site object
var objSite=GetObject("IIS://" + szServerName
+ "/W3SVC/" + szSiteID);
//Get the current log format of this site
var szLogPluginCLSId=objSite.LogPluginCLSId;
//Create the SELECT clause text
var szSelectClause="SELECT ";
var szWhereClause="WHERE ";
switch(szLogPluginCLSId.toUpperCase())
{
case "{FF160663-DE82-11CF-
BC0A-00AA006111E0}":
{
//W3C Format
szSelectClause+="cs-uri-stem AS UriStem";
szWhereClause+="sc-status<400 AND cs-uri-stem
IS NOT NULL";
break;
}
case "{FF16065F-DE82-11CF-BC0A-00AA006111E0}":
{
//NCSA Format
WScript.Echo("NCSA log format is not supported
- aborting query for site " + szSiteID);
return;
}
case "{FF160657-DE82-11CF-BC0A-00AA006111E0}":
{
//IIS Format
szSelectClause+="Target AS UriStem";
szWhereClause+="StatusCode<400
AND Target IS NOT NULL";
break;
}
case "{FF16065B-DE82-11CF-BC0A-00AA006111E0}": {
//ODBC Format
szSelectClause+="Target AS UriStem";
szWhereClause+="ServiceStatus<400 AND
Target IS NOT NULL";
break;
}
default: {
WScript.Echo("Unknown log format "
+ szLogPluginCLSId);
return;
}
}
WScript.Echo("\r\nQuerying the log files for site /"
+ szServerName + "/" + szSiteID + "...");
try
{
//Execute the query and get a recordset
var recordSet=myQuery.Execute(szSelectClause +
", COUNT(*) AS Total FROM </" + szServerName
+ "/W3SVC/" + szSiteID + "> " + szWhereClause
+ " GROUP BY UriStem");
//Walk thru the recordset
for(; !recordSet.atEnd(); recordSet.moveNext())
{
var record=recordSet.getRecord();
try
{
//Break the url into components
var szUrlComponents=record.getValue(0).split("/");
//Update the tree count
UpdateTreeCount(g_tree, 0, szUrlComponents,
record.getValue(1));
}
catch(e)
{
WScript.Echo("Unexpected error processing
Url \"" + record.getValue(0) + "\": " + e.description);
}
}
recordSet.close();
WScript.Echo("...done.");
}
catch(e)
{
WScript.Echo("Error querying the log files: " + e.description);
WScript.Quit(-1);
}
}
/*
This function finds the node corresponding to
the requested Url, and updates its Hit count.
*/
function UpdateTreeCount(tree, nDepth,
szUrlComponents, nCount)
{
//Check if it's a child node
for(var c=2; c<tree.length; c++)
{
if(szUrlComponents[nDepth+1].toLowerCase()
==tree[c][0].toLowerCase())
{
//It's for this child node...
UpdateTreeCount(tree[c], nDepth+1,
szUrlComponents, nCount);
break;
}
}
if(c==tree.length)
{
//It's for this node...update the count
tree[1]+=nCount;
}
}
function DumpTree(tree, szIndent)
{
WScript.Echo(szIndent + "/" + tree[0] + ": " + tree[1]);
//Dump child nodes
for(var c=2;c<tree.length;c++)
DumpTree(tree[c], szIndent + "/" + tree[0]);
}
For any feedback regarding the content of this sample script, please write to Microsoft TechNet.
Disclaimer
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.