# encoding: ascii
# api: powershell
# title: 
# description: Read in an IIS *log file saved in format W3C.
# version: 0.1
# type: script
# license: CC0
# x-poshcode-id: 2573
# x-archived: 2016-04-07T10:40:18
#
# The Import-Iis-Log cmdlet provides a way for you to read in data from an IIS *log file (saved in format W3C) and then display that data in tabular format within the Windows PowerShell console.
# Parameters:
# -Path (string, required, position = 0, value from pipeline, not null, not empty)
# Specifies the path to the IIS *.log file to import. You can also pipe a path to Import-Iss-Log.
# -Delimiter (string, position = 1, not null, not empty)
# Specified the delimiter that separated the property values in the IIS *log file. The default value is a spacebar.
# -Encoding (Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding)
# The character encoding for the IIS *.log file. The default value is the UTF8.
# The cmdlet outputs in the pipeline objects with following properties:
# DateTime (System.DateTime)
# Combined “date” and “time” values of a log.
# ClientHost (System.Net.IpAddress)
# “c-ip” value of a log.
# UserName (string or $null for anonymous user)
# “cs-username” value of a log.
# Service (string)
# “s-sitename” value of a log.
# Machine (string)
# “s-computername” value of a log.
# ServerIp (System.Net.IpAddress)
# “s-ip” value of a log.
# ServerPort (int)
# “s-port” value of a log.
# Method (string)
# “cs-method” value of a log.
# ScriptPath (string)
# “cs-uri-stem” value of a log, decoded with System.Web.HttpUtility.UrlDecode.
# QueryString (string or $null for HTTP requests without query string)
# “cs-uri-query” value of a log, decoded with System.Web.HttpUtility.UrlDecode.
# ServiceStatus (int)
# “sc-status” value of a log.
# ServiceSubStatus (int)
# “sc-substatus” value of a log.
# Win32Status (int)
# “sc-win32-status” value of a log.
# BytesSent (System.UInt64)
# “sc-bytes” value of a log.
# BytesRecived (System.UInt64)
# “cs-bytes” value of a log.
# ProcessingTime (int)
# “time-taken” value of a log.
# ProtocolVersion (string)
# “cs-version” value of a log.
# Host (string of $null for HTTP requests without Host header)
# “cs-host” value of a log.
# UserAgent (string or $null for request without an User-Agent header)
# “cs(User-Agent)” value of a log.
# Cookie (string or $null for requests without a cookie)
# “cs(Cookie)” value of a log.
# Referer (string or $null for requests without a referer)
# “cs(Referer)” value of a log, decoded with System.Web.HttpUtility.UrlDecode.
#
param
(
	[Parameter(
		Mandatory=$true,
		Position = 0,
		ValueFromPipeline=$true,
		HelpMessage="Specifies the path to the IIS *.log file to import. You can also pipe a path to Import-Iss-Log."
	)]
	[ValidateNotNullOrEmpty()]
	[string]
	$Path,
	
	[Parameter(
		Position = 1,
		HelpMessage="Specifies the delimiter that separates the property values in the IIS *.log file. The default is a spacebar."
	)]
	[ValidateNotNullOrEmpty()]
	[string]
	$Delimiter = " ",
	
	[Parameter(HelpMessage="The character encoding for the IIS *log file. The default is the UTF8.")]
	[Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding]
	$Encoding = [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding]::UTF8
)
	
begin
{
	$fieldNames = @()
	
	$output = New-Object Object
	Add-Member -InputObject $output -MemberType NoteProperty -Name "DateTime" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ClientHost" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "UserName" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Service" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Machine" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ServerIp" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ServerPort" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Method" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ScriptPath" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "QueryString" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ServiceStatus" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ServiceSubStatus" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Win32Status" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "BytesSent" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "BytesRecived" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ProcessingTime" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "ProtocolVersion" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Host" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "UserAgent" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Cookie" -Value $null
	Add-Member -InputObject $output -MemberType NoteProperty -Name "Referer" -Value $null
}

process
{
	foreach($line in Get-Content -Path $Path -Encoding $Encoding)
	{
		if($line.StartsWith("#Fields: "))
		{
			$fieldNames = @($line.Substring("#Fields: ".Length).Split($Delimiter));
		}
		elseif(-not $line.StartsWith("#"))
		{
			$fieldValues = @($line.Split($Delimiter));
			
			for($i = 0; $i -lt $fieldValues.Length; $i++)
			{
				$name = $fieldNames[$i]
				$value = $fieldValues[$i]
				
				switch($name)
				{
				"date" { $output.DateTime = [DateTime]::Parse($value) }
				"time" { $output.DateTime += [TimeSpan]::Parse($value) }
				"c-ip" { $output.ClientHost = [System.Net.IPAddress]::Parse($value) }
				"cs-username" { $output.UserName = if($value -eq '-') { $null } else { $value } }
				"s-sitename" { $output.Service = $value }
				"s-computername" { $output.Machine = $value }
				"s-ip" { $output.ServerIp = [System.Net.IPAddress]::Parse($value) }
				"s-port" { $output.ServerPort = [int]$value }
				"cs-method" { $output.Method = $value }
				"cs-uri-stem" { $output.ScriptPath = [System.Web.HttpUtility]::UrlDecode($value) }
				"cs-uri-query" { $output.QueryString = if($value -eq '-') { $null } else { [System.Web.HttpUtility]::UrlDecode($value) } }
				"sc-status" { $output.ServiceStatus = [int]$value }
				"sc-substatus" { $output.ServiceSubStatus = [int]$value }
				"sc-win32-status" { $output.Win32Status = [BitConverter]::ToInt32([BitConverter]::GetBytes([UInt32]($value)), 0) }
				"sc-bytes" { $output.BytesSent = [UInt64]$value }
				"cs-bytes" { $output.BytesRecived = [UInt64]$value }
				"time-taken" { $output.ProcessingTime = [int]$value }
				"cs-version" { $output.ProtocolVersion = $value }
				"cs-host" { $output.Host = if($value -eq '-') { $null } else { $value } }
				"cs(User-Agent)" { $output.UserAgent = if($value -eq '-') { $null } else { $value } }
				"cs(Cookie)" { $output.Cookie = if($value -eq '-') { $null } else { $value } }
				"cs(Referer)" { $output.Referer = if($value -eq '-') { $null } else { [System.Web.HttpUtility]::UrlDecode($value) } }
				}
			}
			
			Write-Output $output
		}
	}
}
