Advertisements

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:

  1. Declares variables
  2. Creates the LogFiles folder, if it exists remove everything inside it
  3. Copy IIS server logs from the previous month to the LogFiles local folder
  4. Runs LogParser.exe to generate per server reports into CSV files
  5. Runs LogParser.exe to generate per site reports into CSV files
  6. Runs LogParser.exe to generate per server chart images
  7. Runs LogParser.exe to generate chart image with combined servers
  8. Tests if the site hits CSV files were actually generated by Log Parser and imports them into variables
  9. Counts the server-wide page hits by using an array
  10. Adds a thousands separator to the server-wide hit numbers
  11. Puts the chart images into a variable
  12. Sends an email containing server-wide, site-wide hits with chart images as attachments
  13. Nullify the variables
  14. 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 Parsern"
 }
 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 Parsern"
 }
 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 $LastMonthNamen Report:n hits for SERVER1: $sumIIS1sep nTotal hits for SERVER2: $sumIIS2sepnSite Hits (SERVER1):$SiteHitsIIS1nSite Hits (SERVER2):$SiteHitsIIS2"
 send-mailmessage -to "Administrator <[email protected]>" -from "Webserver Reporting <[email protected]>" -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:

Advertisements

chart-totals

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 😉

Advertisements
Page generated in 0.5454 seconds.
Advertisment ad adsense adlogger