Automate copying IIS logs to SQL Database using Powershell, Log Parser and Task Scheduler
I decided not to go down the route of writing an SSIS package as mentioned in my previous post
So how else can you do what I wanted to achieve?
- Remove all copied logs from the Database server
- Copy yesterdays logs from 9 web servers
- Import the logs to a SQL Database
This is how I did it:
Step 1 : Create 3 Powershell scripts
Copy IIS files from yesterday:
$Date = Get-Date
$Date = $Date.adddays(-1)
$Date2Str = $Date.ToString("yyyMMdd")
$Files1 = gci "\\server1\c$\inetpub\logs\LogFiles\W3SVC2"
ForEach ($File in $Files1){
$FileDate = $File.creationtime
$CTDate2Str = $FileDate.ToString("yyyyMMdd")
if ($CTDate2Str -eq $Date2Str) {Copy-Item $File.Fullname "C:\\Logs\\1718\\server1"}
}
$Files2 = gci "\\server2\c$\inetpub\logs\LogFiles\W3SVC2"
ForEach ($File in $Files2){
$FileDate = $File.creationtime
$CTDate2Str = $FileDate.ToString("yyyyMMdd")
if ($CTDate2Str -eq $Date2Str) {Copy-Item $File.Fullname "C:\\Logs\\1718\\server2"}
}
$Files3 = gci "\\server3\c$\inetpub\logs\LogFiles\W3SVC2"
ForEach ($File in $Files3){
$FileDate = $File.creationtime
$CTDate2Str = $FileDate.ToString("yyyyMMdd")
if ($CTDate2Str -eq $Date2Str) {Copy-Item $File.Fullname "C:\\Logs\\1718\\server3"}
}
Remove all local iis log files:
$ErrorActionPreference = "Stop"
Import-Module Pscx -EA 0
function RemoveLogFiles
{
Write-Host "Removing log files..."
Remove-Item ($httpLogPath1)
Remove-Item ($httpLogPath2)
Remove-Item ($httpLogPath3)
Remove-Item ($httpLogPath4)
Remove-Item ($httpLogPath5)
Remove-Item ($httpLogPath6)
Remove-Item ($httpLogPath7)
Remove-Item ($httpLogPath8)
Remove-Item ($httpLogPath9)
}
function Main
{
[string] $httpLogPath1 = "C:\Logs\1718\server1\*.log"
[string] $httpLogPath2 = "C:\Logs\1718\server2\*.log"
[string] $httpLogPath3 = "C:\Logs\1718\server3\*.log"
[string] $httpLogPath4 = "C:\Logs\1718\server4\W3SVC1\*.log"
[string] $httpLogPath5 = "C:\Logs\1718\server5\W3SVC1\*.log"
[string] $httpLogPath6 = "C:\Logs\1718\server6\W3SVC1\*.log"
[string] $httpLogPath7 = "C:\Logs\1718\server7\W3SVC2\*.log"
[string] $httpLogPath8 = "C:\Logs\1718\server8\W3SVC2\*.log"
[string] $httpLogPath9 = "C:\Logs\1718\server9\W3SVC2\*.log"
RemoveLogFiles
Write-Host -Fore Green "Successfully removed log files."
}
Main
Import Website Logs to Database:
$ErrorActionPreference = "Stop"
Import-Module Pscx -EA 0
function ExtractLogFiles(
[string] $httpLogPath)
{
If ([string]::IsNullOrEmpty($httpLogPath) -eq $true)
{
Throw "The log path must be specified."
}
[string] $httpLogArchive = $httpLogPath + "c:\logs\1718\*.log"
If ((Test-Path $httpLogArchive) -eq $false)
{
Write-Host "Creating archive folder for compressed log files..."
New-Item -ItemType directory -Path $httpLogArchive | Out-Null
}
Write-Host "Extracting compressed log files..."
Get-ChildItem $httpLogPath -Filter "*.zip" |
ForEach-Object {
Expand-Archive $_ -OutputPath $httpLogPath
Move-Item $_.FullName $httpLogArchive
}
}
function ImportLogFilesServer1(
[string] $httpLogPath1)
{
If ([string]::IsNullOrEmpty($httpLogPath1) -eq $true)
{
Throw "The log path must be specified."
}
[string] $logParser = "${env:ProgramFiles(x86)}" `
+ "\Log Parser 2.2\LogParser.exe "
[string] $query = `
[string] $query = `
"SELECT" `
+ " LogFilename" `
+ ", RowNumber" `
+ ", TO_TIMESTAMP(date, time) AS EntryTime" `
+ ", s-ip AS sIp" `
+ ", cs-method AS csMethod" `
+ ", cs-uri-stem AS csUriStem" `
+ ", cs-uri-query AS csUriQuery" `
+ ", s-port AS sPort" `
+ ", TO_STRING(cs-username) AS csUsername" `
+ ", c-ip AS cIp" `
+ ", cs(User-Agent) AS csUserAgent" `
+ ", cs(Referer) AS csReferer" `
+ ", sc-status AS scStatus" `
+ ", sc-substatus AS scSubstatus" `
+ ", sc-win32-status AS scWin32Status" `
+ ", time-taken AS timeTaken" `
+ " INTO IisLogs" `
+ " FROM $httpLogPath1"
[string] $connectionString = "Driver={SQL Server Native Client 11.0};" `
+ "Server=;Database=;Trusted_Connection=yes;"
[string[]] $parameters = @()
$parameters += $query
$parameters += "-i:W3C"
$parameters += "-e:-1"
#$parameters += "-recurse:-1"
$parameters += "-o:SQL"
$parameters += "-createTable:ON"
$parameters += "-oConnString:$connectionString"
Write-Debug "Parameters: $parameters"
Write-Host "Importing log files to database..."
& $logParser $parameters
}
function ImportLogFilesServer2(
[string] $httpLogPath2)
{
If ([string]::IsNullOrEmpty($httpLogPath2) -eq $true)
{
Throw "The log path must be specified."
}
[string] $logParser = "${env:ProgramFiles(x86)}" `
+ "\Log Parser 2.2\LogParser.exe "
[string] $query = `
[string] $query = `
"SELECT" `
+ " LogFilename" `
+ ", RowNumber" `
+ ", TO_TIMESTAMP(date, time) AS EntryTime" `
+ ", s-ip AS sIp" `
+ ", cs-method AS csMethod" `
+ ", cs-uri-stem AS csUriStem" `
+ ", cs-uri-query AS csUriQuery" `
+ ", s-port AS sPort" `
+ ", TO_STRING(cs-username) AS csUsername" `
+ ", c-ip AS cIp" `
+ ", cs(User-Agent) AS csUserAgent" `
+ ", cs(Referer) AS csReferer" `
+ ", sc-status AS scStatus" `
+ ", sc-substatus AS scSubstatus" `
+ ", sc-win32-status AS scWin32Status" `
+ ", time-taken AS timeTaken" `
+ " INTO IisLogs" `
+ " FROM $httpLogPath2"
[string] $connectionString = "Driver={SQL Server Native Client 11.0};" `
+ "Server=;Database=;Trusted_Connection=yes;"
[string[]] $parameters = @()
$parameters += $query
$parameters += "-i:W3C"
$parameters += "-e:-1"
#$parameters += "-recurse:-1"
$parameters += "-o:SQL"
$parameters += "-createTable:ON"
$parameters += "-oConnString:$connectionString"
Write-Debug "Parameters: $parameters"
Write-Host "Importing log files to database..."
& $logParser $parameters
}
function ImportLogFilesServer3(
[string] $httpLogPath3)
{
If ([string]::IsNullOrEmpty($httpLogPath3) -eq $true)
{
Throw "The log path must be specified."
}
[string] $logParser = "${env:ProgramFiles(x86)}" `
+ "\Log Parser 2.2\LogParser.exe "
[string] $query = `
[string] $query = `
"SELECT" `
+ " LogFilename" `
+ ", RowNumber" `
+ ", TO_TIMESTAMP(date, time) AS EntryTime" `
+ ", s-ip AS sIp" `
+ ", cs-method AS csMethod" `
+ ", cs-uri-stem AS csUriStem" `
+ ", cs-uri-query AS csUriQuery" `
+ ", s-port AS sPort" `
+ ", TO_STRING(cs-username) AS csUsername" `
+ ", c-ip AS cIp" `
+ ", cs(User-Agent) AS csUserAgent" `
+ ", cs(Referer) AS csReferer" `
+ ", sc-status AS scStatus" `
+ ", sc-substatus AS scSubstatus" `
+ ", sc-win32-status AS scWin32Status" `
+ ", time-taken AS timeTaken" `
+ " INTO IisLogs" `
+ " FROM $httpLogPath3"
[string] $connectionString = "Driver={SQL Server Native Client 11.0};" `
+ "Server=;Database=;Trusted_Connection=yes;"
[string[]] $parameters = @()
$parameters += $query
$parameters += "-i:W3C"
$parameters += "-e:-1"
#$parameters += "-recurse:-1"
$parameters += "-o:SQL"
$parameters += "-createTable:ON"
$parameters += "-oConnString:$connectionString"
Write-Debug "Parameters: $parameters"
Write-Host "Importing log files to database..."
& $logParser $parameters
}
function Main
{
[string] $httpLogPath1 = "C:\Logs\1718\Server1\*.log"
[string] $httpLogPath2 = "C:\Logs\1718\Server2\*.log"
[string] $httpLogPath3 = "C:\Logs\1718\Server3\*.log"
#Repeat above for all other server
ImportLogFilesServer1 $httpLogPath1
ImportLogFilesServer2 $httpLogPath2
ImportLogFilesServer3 $httpLogPath3
#Repeat above for all other server
Write-Host -Fore Green "Successfully imported log files."
}
Main
Finally you need to setup some scheduled tasks:
There’s a few little bits here which wouldn’t work for me without the following arguments:
Powershell.exe in Program/script:
-ExecutionPolicy Bypass -file “C:\powershell iis scripts\remove all iis log files.ps1” in Add arguments (optional):

The ‘Copy IIS files from yesterday’ script required some work with our server and storage team to add a service account to be able to run batch scripts without being logged on, this is in the Local Group Policy, This was due to being on a domain and the policy was set to not allow me to set this for my user. More details to come on this, its time consuming to explain in great detail.
I used your code as the basis for a IISlog parse/loader, so many thanks for that. It worked perfectly for 6 months. They changed the format/ codepage somehow so that the code for the import failed
Kept on getting “Error setting locale info for codepage 65001: The data area passed to a system call is too small.”
Only way to fix it was to change -i:W3C to -i:IISW3C (line 122 on your code) and change RowNumber to LogRow in the select query (line 150)
Just check and see if your code still works. I am still not certain what the route cause was.
Thanks David.. Blogs written at a point in time occasionally need updating.