Reputation: 12434
I am writing an IIS log
parser and having trouble wrapping a variable value in quotes while doing some string processing.
Here is a truncated log file, as an example:
#Fields: date time s-ip cs-method ...
2021-08-09 19:00:16.367 0.0.0.0 GET ...
2021-08-09 19:01:42.184 0.0.0.0 POST ...
Here is how I am executing the code below:
.\Analyse.ps1 cs-method -eq `'POST`'
If the line marked with #PROBLEM
is executed as is, the output looks like this:
> .\Analyse.ps1 cs-method -eq `'POST`'
"""""G""E""T""""" ""-""e""q"" ""'""P""O""S""T""'""
"""""P""O""S""T""""" ""-""e""q"" ""'""P""O""S""T""'""
But if I replace $quoted
with $value
, so that the code reads like this:
$thisInstruction = $thisInstruction -replace $key , $value #PROBLEM
The output looks like this:
> .\Analyse.ps1 cs-method -eq `'POST`'
GET -eq 'POST'
POST -eq 'POST'
The problem is that I want the first value on each line of the output (the GET
and the POST
before the -eq
) to be wrapped in quotes.
How can I achieve this?
Here is my code:
# compile cli args into single line instruction
$instruction = $args -join " "
# define key array
$keys = @('date','time','s-ip','cs-method','cs(Host)','cs-uri-stem','cs-uri-query','s-computername','s-port','cs-username','c-ip','s-sitename','cs(User-Agent)','cs(Referer)','sc-status','sc-substatus','sc-win32-status','TimeTakenMS','x-forwarded-for')
# <#
# get current execution folder
$currentFolder = Get-Location
# define string splitter regex https://www.reddit.com/r/PowerShell/comments/2h5elx/split_string_by_spaces_unless_in_quotes/ckpkydh?utm_source=share&utm_medium=web2x&context=3
$splitter = ' +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)'
# process *.log files in folder
Get-Childitem -Path $currentFolder *.log1 | ForEach-Object {
# process each line in the file
Get-Content $_.Name | ForEach-Object {
# duplicate instruction
$thisInstruction = $instruction
# exclude comment lines
if (!$_.StartsWith('#')) {
# split line into array
$logEntryArr = $_ -Split $splitter
# populate dictionary with contents of array
For ($i=0; $i -le $keys.length; $i++) {
# get key
$key = $keys[$i]
# get value
$value = $logEntryArr[$i]
$quoted = "`""+$value+"`""
# replace mention of key in instruction with dictionary reference
$thisInstruction = $thisInstruction -replace $key , $quoted #PROBLEM
}
# process rule from command line against dictionary
echo $thisInstruction
}
}
}
#>
Upvotes: 0
Views: 98
Reputation: 12434
I do know why, thanks to @mathias-r-jessen commenting
I don't know why, but altering the For
loop to iterate one fewer fixed the problem and does not appear to leave out any keys. The only significant change is this:
For ($i=0; $i -le $keys.length-1; $i++) {
This PowerShell
script can be used to query a folder of log files echo out matching rows, eg:
.\Analyse.ps1 cs-method -eq 'GET
'
The above would print out all log entries with a cs-method
value of GET
.
Here's the code:
# compile cli args into single line instruction
$instruction = $args -join " "
# define key array
$keys = @('date','time','s-ip','cs-method','cs(Host)','cs-uri-stem','cs-uri-query','s-computername','s-port','cs-username','c-ip','s-sitename','cs(User-Agent)','cs(Referer)','sc-status','sc-substatus','sc-win32-status','TimeTakenMS','x-forwarded-for')
# get current execution folder
$currentFolder = Get-Location
# define string splitter regex https://www.reddit.com/r/PowerShell/comments/2h5elx/split_string_by_spaces_unless_in_quotes/ckpkydh?utm_source=share&utm_medium=web2x&context=3
$splitter = ' +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)'
# process *.log files in folder
Get-Childitem -Path $currentFolder *.log | ForEach-Object {
# process each line in the file
Get-Content $_.Name | ForEach-Object {
# duplicate instruction
$thisInstruction = $instruction
# exclude comment lines
if (!$_.StartsWith('#')) {
# split line into array
$logEntryArr = $_ -Split $splitter
# populate dictionary with contents of array
For ($i=0; $i -lt $keys.length; $i++) {
# get key
$key = $keys[$i]
# get value
$quoted = "`'"+$logEntryArr[$i]+"`'"
# replace mention of key in instruction with dictionary reference
$thisInstruction = $thisInstruction -replace $key , $quoted
}
# process rule from command line against dictionary
$answer = Invoke-Expression $thisInstruction
if ($answer) {
echo $_
}
}
}
}
Upvotes: 1