Welcome back!
Last post I talked about using the Log Parser executable from PowerShell. I also briefly mentioned the Log Parser COM component. In this post I will go into more depth on using the COM component from PowerShell.
The COM component exposes a simple object model consisting of only three main objects.
- LogQuery – Object used to execute queries and batches
- LogRecordSet – Object returned by LogQuery.Execute method
- LogRecord – Child object of LogRecordset. Object returned by LogRecordSet.getRecord method
There are also objects containing the input and output formats. There are several of them and they are well documented in the Log Parser documentation. I will give examples as we progress.
The first step on my task to integrate with the Log Parser COM object was to put together a function library of the basic building blocks.
The library consists of the following functions.
- Get-LPInputFormat – Returns a Log Parser input format object
- Get-LPOutputFormat – Returns a Log Parser output format object
- Invoke-LPExecute – Executes the LogQuery.Execute method and returns a LogRecordSet
- Invoke-LPExecuteBatch – Executes the LogQuery.ExecuteBatch method to output the query in the requested format
- Get-LPRecordSet – Executes a Log Parser Query and returns a LogRecordSet as an array of PowerShell objects
- Get-LPRecord – Returns LogRecord object as a PowerShell object from the current record of a LogRecordSet object
With these functions we can support almost all of the Log Parser functionality in PowerShell. I did not build in support for the custom COM input type or the NAT and Datagrid output types. The NAT and Datagrid output types can be handled in a different way in PowerShell. The COM input format is a challenge I left for another day.
Here is the function library.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# --------------------------------------------------------------------------- ### <library name="Muegge_LogParser_Lib.ps1"> ### <author>David Muegge</author> ### <createdate>20081108</createdate> ### <modifieddate>20081121</modifieddate> ### <description> ### Log Parser function library ### </description> ### <dependencies> ### Log Parser 2.2 COM component ### </dependencies> ### <usage> ### Dot source from calling script ### </usage> ### </library> # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- ### <function name="Get-LPInputFormat"> ### <description> ### Returns Log Parser Input Format object based on passed string ### </description> ### <usage> ### Get-LPInputFormat -InputType <string> ### </string></usage> ### </function> # --------------------------------------------------------------------------- function Get-LPInputFormat{ param([String]$InputType) switch($InputType.ToLower()){ "ads"{$inputobj = New-Object -comObject MSUtil.LogQuery.ADSInputFormat} "bin"{$inputobj = New-Object -comObject MSUtil.LogQuery.IISBINInputFormat} "csv"{$inputobj = New-Object -comObject MSUtil.LogQuery.CSVInputFormat} "etw"{$inputobj = New-Object -comObject MSUtil.LogQuery.ETWInputFormat} "evt"{$inputobj = New-Object -comObject MSUtil.LogQuery.EventLogInputFormat} "fs"{$inputobj = New-Object -comObject MSUtil.LogQuery.FileSystemInputFormat} "httperr"{$inputobj = New-Object -comObject MSUtil.LogQuery.HttpErrorInputFormat} "iis"{$inputobj = New-Object -comObject MSUtil.LogQuery.IISIISInputFormat} "iisodbc"{$inputobj = New-Object -comObject MSUtil.LogQuery.IISODBCInputFormat} "ncsa"{$inputobj = New-Object -comObject MSUtil.LogQuery.IISNCSAInputFormat} "netmon"{$inputobj = New-Object -comObject MSUtil.LogQuery.NetMonInputFormat} "reg"{$inputobj = New-Object -comObject MSUtil.LogQuery.RegistryInputFormat} "textline"{$inputobj = New-Object -comObject MSUtil.LogQuery.TextLineInputFormat} "textword"{$inputobj = New-Object -comObject MSUtil.LogQuery.TextWordInputFormat} "tsv"{$inputobj = New-Object -comObject MSUtil.LogQuery.TSVInputFormat} "urlscan"{$inputobj = New-Object -comObject MSUtil.LogQuery.URLScanLogInputFormat} "w3c"{$inputobj = New-Object -comObject MSUtil.LogQuery.W3CInputFormat} "xml"{$inputobj = New-Object -comObject MSUtil.LogQuery.XMLInputFormat} } return $inputobj } # --------------------------------------------------------------------------- ### <function name="Get-LPOutputFormat"> ### <description> ### Returns Log Parser Output Format object based on passed string ### </description> ### <usage> ### Get-LPOutputFormat -OutputType <string> ### </string></usage> ### </function> # --------------------------------------------------------------------------- function Get-LPOutputFormat{ param([String]$OutputType) switch($OutputType.ToLower()){ "csv"{$outputobj = New-Object -comObject MSUtil.LogQuery.CSVOutputFormat} "chart"{$outputobj = New-Object -comObject MSUtil.LogQuery.ChartOutputFormat} "iis"{$outputobj = New-Object -comObject MSUtil.LogQuery.IISOutputFormat} "sql"{$outputobj = New-Object -comObject MSUtil.LogQuery.SQLOutputFormat} "syslog"{$outputobj = New-Object -comObject MSUtil.LogQuery.SYSLOGOutputFormat} "tsv"{$outputobj = New-Object -comObject MSUtil.LogQuery.TSVOutputFormat} "w3c"{$outputobj = New-Object -comObject MSUtil.LogQuery.W3COutputFormat} "tpl"{$outputobj = New-Object -comObject MSUtil.LogQuery.TemplateOutputFormat} } return $outputobj } # --------------------------------------------------------------------------- ### <function name="Invoke-LPExecute"> ### <description> ### Executes a Log Parser Query and returns a recordset ### </description> ### <usage> ### Invoke-LPExecute -query <string> ### </string></usage> ### </function> # --------------------------------------------------------------------------- function Invoke-LPExecute{ param([string] $query, $inputtype) $LPQuery = new-object -com MSUtil.LogQuery if($inputtype){ $LPRecordSet = $LPQuery.Execute($query, $inputtype) } else { $LPRecordSet = $LPQuery.Execute($query) } return $LPRecordSet } # --------------------------------------------------------------------------- ### <function name="Invoke-LPExecuteBatch"> ### <description> ### Executes Log Parser batch query with passed input and output types ### </description> ### <usage> ### Invoke-LPExecuteBatch -query <string> -inputtype <logparserinputformat> -outputtype <logparseroutputformat> ### </logparseroutputformat></logparserinputformat></string></usage> ### </function> # --------------------------------------------------------------------------- function Invoke-LPExecuteBatch{ param([string]$query, $inputtype, $outputtype) $LPQuery = new-object -com MSUtil.LogQuery $result = $LPQuery.ExecuteBatch($query, $inputtype, $outputtype) return $result } # --------------------------------------------------------------------------- ### <function name="Get-LPRecord"> ### <description> ### Returns PowerShell custom object from Log Parser recordset for current record ### </description> ### <usage> ### Get-LPRecord -rs <recordset> ### </recordset></usage> ### </function> # --------------------------------------------------------------------------- function Get-LPRecord{ param($LPRecordSet) $LPRecord = new-Object System.Management.Automation.PSObject if( -not $LPRecordSet.atEnd()) { $Record = $LPRecordSet.getRecord() for($i = 0; $i -lt $LPRecordSet.getColumnCount();$i++) { $LPRecord | add-member NoteProperty $LPRecordSet.getColumnName($i) -value $Record.getValue($i) } } return $LPRecord } # --------------------------------------------------------------------------- ### <function name="Get-LPRecordSet"> ### <description> ### Executes a Log Parser Query and returns a LogRecordSet as a custom powershell object ### </description> ### <usage> ### Get-LPRecordSet -query <string> ### </string></usage> ### </function> # --------------------------------------------------------------------------- function Get-LPRecordSet{ param([string]$query) # Execute Query $LPRecordSet = Invoke-LPExecute $query $LPRecords = new-object System.Management.Automation.PSObject[] 0 for(; -not $LPRecordSet.atEnd(); $LPRecordSet.moveNext()) { # Add record $LPRecord = Get-LPRecord($LPRecordSet) $LPRecords += new-Object System.Management.Automation.PSObject $RecordCount = $LPQueryResult.length-1 $LPRecords[$RecordCount] = $LPRecord } $LPRecordSet.Close(); return $LPRecords } |
This library provides the basic functionality needed for Log Parser. We can use it in two basic scenarios.
One – We want to execute a Log Parser batch. This mode works exactly as the Log Parser command line tool works it queries an input file of a given type and writes the results to an output file of a given type.
Two – We want the results of a Log Parser query returned to a PowerShell object. This will allow us to further process the results using PowerShell or simply utilize the output facilities to display the results.
Example of Scenario One:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
. .Muegge_LogParser_Lib.ps1 $infile = "D:TempLPTest.log" $outfile = "D:TempLPTest.gif" # Set input format and parameters $inputformat = Get-LPInputFormat "w3c" # Set output format and parameters $outputformat = Get-LPOutputFormat "chart" $outputformat.chartTitle = "Top 10 Pages" $outputformat.chartType = "BarStacked" $outputformat.groupSize = "600x400" $query = @" SELECT Top 10 cs-uri-stem, Count(*) INTO $outfile FROM $infile Group By cs-uri-stem Order by cs-uri-stem desc "@ # Execute batch Invoke-LPExecuteBatch $query $inputformat $outputformat | Out-Null |
The code above provides a good way to create scheduled reports. The syntax is easier to follow than the command line switches at least for me.
Here is the sample output chart.
Yes, I took this log from a box with nothing but hacker traffic J
Now let’s look at the second scenario. We will return the results of a Log Parser query in a PSObject.
Here we are querying for application hang events in the application event log. We will use a Log Parser query to retrieve just the events we want. Then we will use PowerShell to filter out just the events for IE. The we can easily display the output any way we like.
1 2 3 4 5 6 7 8 9 10 11 |
. .Muegge_LogParser_Lib.ps1 $query = @" SELECT * FROM Application WHERE EventID = 1002 "@ $inputformat = Get-LPInputFormat "evt" $records = Get-LPRecordSet $query $inputformat $records | where {$_.Strings -like "*iexplore.exe*"} | ft -property TimeGenerated,SourceName,Strings |
Here is the output.
1 2 3 4 5 6 7 8 9 10 11 |
TimeGenerated SourceName Strings ------------- ---------- ------- 11/1/2008 11:21:02 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/2/2008 6:25:35 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/4/2008 7:32:35 AM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/6/2008 4:21:22 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/8/2008 7:05:20 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/10/2008 3:01:45 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/11/2008 5:10:40 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/14/2008 12:13:06 PM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... 11/17/2008 7:34:29 AM Application Hang iexplore.exe|7.0.6000.16735|hungapp|0.0... |
To me this really seems like the best of both worlds utilizing each tool for its strength.
Now I just have to figure out why IE hangs J
Best Regards,
Dave