After spending significant time Googling for an easy way to report IIS traffic on a per server basis and coming up empty handed I have decided to write my own Powershell script that will report web traffic server-wide, site-wide, chart images and automatically email it. The real magic behind it is Microsoft’s Log Parser. The query I have configured for mine is to count all the hits on aspx pages to give me the most accurate report. If you use anything else, you can add in an OR clause or replace aspx with whatever you need in the Log Parser lines: WHERE (cs-uri-stem LIKE '%aspx%'). This script was designed to search two IIS hosts, but you could modify it with a little Powershell knowledge.
*9/9/2016 update* After revisiting this page much later after posting, I realize how rudimentary the coding is and would like to encourage someone who uses this to clean it up and break it up into functions and enable the use of parameters so as to make it easier for the end user. Please either post the code on github or visit my Contact page and I’ll revise this post with credit to you.
I’ve added as many comment sections as I could to make this more understandable but here is a breakdown of what it is doing:
- Declares variables
- Creates the LogFiles folder, if it exists remove everything inside it
- Copy IIS server logs from the previous month to the LogFiles local folder
- Runs LogParser.exe to generate per server reports into CSV files
- Runs LogParser.exe to generate per site reports into CSV files
- Runs LogParser.exe to generate per server chart images
- Runs LogParser.exe to generate chart image with combined servers
- Tests if the site hits CSV files were actually generated by Log Parser and imports them into variables
- Counts the server-wide page hits by using an array
- Adds a thousands separator to the server-wide hit numbers
- Puts the chart images into a variable
- Sends an email containing server-wide, site-wide hits with chart images as attachments
- Nullify the variables
- Deletes the locally copied log files
To get started:
- Requires Powershell 3.0+
- Install Log Parser and Microsoft Office 2003 Web Components
- Enable logging of date, cs-uri-stem, cs-host on your IIS servers
- Create the folders: D:\WebserverReport and D:\WebserverReport\ReportTemp
- Modify the script paths and server names to your needs
#Purpose: IIS Server Log Monthly Hit Counter
#By: Travis Runyard
#Date: 1/8/2015
#Variables
$LastMonth = (Get-Date).AddMonths(-1)
$LastMonthName = Get-Date -year $LastMonth.year -month $LastMonth.month -format Y
$CurrentDate = Get-Date
$FirstDayofLastMonth = Get-Date -year $LastMonth.year -month $LastMonth.month -day 1 -format d
$FirstDayofThisMonth = Get-Date -year $CurrentDate.year -month $CurrentDate.month -day 1 -format d
$RemoteLogPathIIS1 = "\\SERVER1\logfiles"
$RemoteLogPathIIS2 = "\\SERVER2\logfiles"
$LocalLogPathIIS1 = "D:\WebserverReport\LogFiles\SERVER1"
$LocalLogPathIIS2 = "D:\WebserverReport\LogFiles\SERVER2"
$SiteHitsIIS1path = "D:\WebserverReport\ReportTemp\results-IIS1-sitehits.csv"
$SiteHitsIIS2path = "D:\WebserverReport\ReportTemp\results-IIS2-sitehits.csv"
$ReportTemp = "D:\WebserverReport\ReportTemp"
#Create folders and delete logs if they exist
if(!(Test-Path -Path $LocalLogPathIIS1 )){
New-Item -ItemType directory -Path $LocalLogPathIIS1
}
Else
{
Remove-Item -path ( $LocalLogPathIIS1 + "\*") -Recurse -Force
}
if(!(Test-Path -Path $LocalLogPathIIS2 )){
New-Item -ItemType directory -Path $LocalLogPathIIS2
}
Else
{
Remove-Item -path ( $LocalLogPathIIS2 + "\*") -Recurse -Force
}
#Copy IIS1 log files from last month
Get-ChildItem -Path $RemoteLogPathIIS1 -Recurse | ? { $_.LastWriteTime -gt $FirstDayofLastMonth -and (($_.LastWriteTime -lt $FirstDayofThisMonth) -or ($_.PSIsContainer)) } |
Copy-Item -Destination {
if ($_.PSIsContainer) {
Join-Path $LocalLogPathIIS1 $_.Parent.FullName.Substring($RemoteLogPathIIS1.length)
} else {
Join-Path $LocalLogPathIIS1 $_.FullName.Substring($RemoteLogPathIIS1.length)
}
} -Force
#Remove-Item ($LocalLogPathIIS1 + "\*.*") | Where { ! $_.PSIsContainer }
#Copy IIS2 log files from last month
Get-ChildItem -Path $RemoteLogPathIIS2 -Recurse | ? { $_.LastWriteTime -gt $FirstDayofLastMonth -and (($_.LastWriteTime -lt $FirstDayofThisMonth) -or ($_.PSIsContainer)) } |
Copy-Item -Destination {
if ($_.PSIsContainer) {
Join-Path $LocalLogPathIIS2 $_.Parent.FullName.Substring($RemoteLogPathIIS2.length)
} else {
Join-Path $LocalLogPathIIS2 $_.FullName.Substring($RemoteLogPathIIS2.length)
}
} -Force
CD "C:\Program Files (x86)\Log Parser 2.2\"
#Run the Log Parser utility and generate the server report CSV file (SERVER1)
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT date, cs-uri-stem AS Page, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\results-IIS1-svrhits.csv FROM D:\WebserverReport\LogFiles\SERVER1\*.log WHERE (cs-uri-stem LIKE '%aspx%') GROUP BY Date,Page ORDER BY Hits DESC" -o:CSV -headers:ON -recurse
#Run the Log Parser utility and generate the server report CSV file (SERVER2)
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT date, cs-uri-stem AS Page, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\results-IIS2-svrhits.csv FROM D:\WebserverReport\LogFiles\SERVER2\*.log WHERE (cs-uri-stem LIKE '%aspx%') GROUP BY Date,Page ORDER BY Hits DESC" -o:CSV -headers:ON -recurse
#Run the Log Parser utility and generate website hit stats (SERVER1)
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT cs-host AS Host, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\results-IIS1-sitehits.csv FROM D:\WebserverReport\LogFiles\SERVER1\*.log WHERE (cs-uri-stem LIKE '%aspx%') AND cs-host IS NOT NULL GROUP BY Host ORDER BY Hits, Host DESC" -o:CSV -headers:ON -recurse
#Run the Log Parser utility and generate website hit stats (SERVER2)
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT cs-host AS Host, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\results-IIS2-sitehits.csv FROM D:\WebserverReport\LogFiles\SERVER2\*.log WHERE (cs-uri-stem LIKE '%aspx%') AND cs-host IS NOT NULL GROUP BY Host ORDER BY Hits, Host DESC" -o:CSV -headers:ON -recurse
#Run the Log Parser utility and generate chart for (SERVER1)
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT cs-host AS Host, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\chart-iis1.gif FROM D:\WebserverReport\LogFiles\SERVER1\*.log WHERE (cs-uri-stem LIKE '%aspx%') AND cs-host IS NOT NULL GROUP BY Host ORDER BY Hits, Host DESC" -o:chart -chartType:ColumnClustered -chartTitle:"Traffic IIS1" -config:FormatChart.js -recurse
#Run the Log Parser utility and generate chart for (SERVER2)
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT cs-host AS Host, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\chart-iis2.gif FROM D:\WebserverReport\LogFiles\SERVER2\*.log WHERE (cs-uri-stem LIKE '%aspx%') AND cs-host IS NOT NULL GROUP BY Host ORDER BY Hits, Host DESC" -o:chart -chartType:ColumnClustered -chartTitle:"Traffic IIS2" -config:FormatChart.js -recurse
#Run the Log Parser utility and generate chart all servers
&"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" --% -i:IISW3C "SELECT cs-host AS Host, COUNT(*) AS Hits INTO D:\WebserverReport\ReportTemp\chart-totals.gif FROM D:\WebserverReport\LogFiles\*.log WHERE (cs-uri-stem LIKE '%aspx%') AND cs-host IS NOT NULL GROUP BY Host ORDER BY Hits, Host DESC" -o:chart -chartType:ColumnClustered -chartTitle:"Traffic Totals" -config:FormatChart.js -recurse
#Test if file exists and Import IIS1 site hits
if(!(Test-Path -Path $SiteHitsIIS1path )){
$SiteHitsIIS1 = "There were no website statistics generated by Log Parser`n"
}
Else
{
$SiteHitsIIS1 = Import-CSV D:\WebserverReport\ReportTemp\results-IIS1-sitehits.csv | Format-Table @{Expression={$_.Host};Label="Host";width=45;align='left'}, `
@{Expression={$_.Hits};Label="Hits";width=15;align='left'} | Out-String
}
#Test if file exists and Import IIS2 site hits
if(!(Test-Path -Path $SiteHitsIIS2path )){
$SiteHitsIIS2 = "There were no website statistics generated by Log Parser`n"
}
Else
{
$SiteHitsIIS2 = Import-CSV D:\WebserverReport\ReportTemp\results-IIS2-sitehits.csv | Format-Table @{Expression={$_.Host};Label="Host";width=45;align='left'}, `
@{Expression={$_.Hits};Label="Hits";width=15;align='left'} | Out-String
}
#Count all server hits for email report IIS1
[int] $sumIIS1 = 0;
$File = Import-CSV D:\WebserverReport\ReportTemp\results-IIS1-svrhits.csv
foreach ($arrayHits in $File)
{
#Write-Host $arrayHits.Hits;
$sumIIS1 = $sumIIS1 + $arrayHits.Hits;
}
$arrayHits = $NULL
#Count all server hits for email report IIS2
[int] $sumIIS2 = 0;
$File = Import-CSV D:\WebserverReport\ReportTemp\results-IIS2-svrhits.csv
foreach ($arrayHits in $File)
{
#Write-Host $arrayHits.Hits;
$sumIIS2 = $sumIIS2 + $arrayHits.Hits;
}
#Add thousands separator
$sumIIS1sep = [string]::Format('{0:N0}',$sumIIS1)
$sumIIS2sep = [string]::Format('{0:N0}',$sumIIS2)
#Get attachments from Temp folder
$Attachments = Get-ChildItem $ReportTemp\*.* -include *.gif
#Send the report by email
$body = "Report is for the month of $LastMonthName`n`nServer Report:`n`nTotal hits for SERVER1: $sumIIS1sep `nTotal hits for SERVER2: $sumIIS2sep`n`nSite Hits (SERVER1):`n$SiteHitsIIS1`nSite Hits (SERVER2):`n$SiteHitsIIS2"
send-mailmessage -to "Administrator <administrator@company.com>" -from "Webserver Reporting <logs@company.com>" -subject "Webserver Report" -body $body -Attachments $Attachments -smtpserver YourEmailServer
#Release variables
$arrayHits = $NULL
$sumIIS1 = $NULL
$sumIIS1sep = $NULL
$sumIIS2 = $NULL
$sumIIS2sep = $NULL
$SiteHitsIIS1 = $NULL
$SiteHitsIIS2 = $NULL
#Remove Log files
Remove-Item -path ( $LocalLogPathIIS1 + "\*") -Recurse -Force
Remove-Item -path ( $LocalLogPathIIS2 + "\*") -Recurse -Force
Once you’ve tweaked enough and get it working you’ll end up with an email that looks a little something like this:
Report is for the month of December 2014
Server Report:
Total hits for Server1: 6,701
Total hits for Server2: 68,190
Site Hits (Server1):
Host Hits
---- ----
blah1.company.com 1485
whatever.company.com 1429
weee.company.com 1398
whoami.company.com 1380
test.company.com 1009
Site Hits (Server2):
Host Hits
---- ----
blah2.company.com 5324
whatever2.company.com 2135
weee2.company.com 1632
whoami2.company.com 5
test2.company.com 59094
And the chart should look like this:
The reason the chart is so pretty and colorful is because I used this color script by Robert McMurray
As always if you have any questions or run into issues with the script, leave a comment below and I will address them as soon as possible ;)
