Reputation: 39
I have this script
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
function Hide-Console
{
$consolePtr = [Console.Window]::GetConsoleWindow()
#0 hide
[Console.Window]::ShowWindow($consolePtr, 0)
}
Hide-Console
$docs = [environment]::GetFolderPath("MyDocuments")
$zwift = "$docs\Zwift" # Zwift data directory
$log = "$zwift\Logs\Log.txt" # Path to Zwift log file
$output = "$zwift\Logs\GroupEvents.txt" # File to write output to
$delay = 6000 # Delay in ms between updates of the file
Function Write-SlowOutput {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true,
HelpMessage="How long to pause for (ms)")]
[int32]$waitFor,
[Parameter(Mandatory=$false,
HelpMessage="File to output to")]
[string]$outputFile,
[Parameter(ValueFromPipeline)]
[Object]$input
)
BEGIN {}
PROCESS {
Write-Host $input
if ($outputFile) {
Out-File -Encoding UTF8 -FilePath $outputFile -InputObject $input
}
Start-Sleep -Milliseconds $waitFor
}
END {}
}
Get-Content -Tail 0 -Wait -Encoding "UTF8" $log |
Select-String "GroupEvents: Linedup for group (.*), subgroup" |
% {$_.matches.groups[1].value} |
Write-SlowOutput -outputFile $output -waitFor $delay
This script looks at the log file of my game and extracts some text based on the select-string line
Select-String "GroupEvents: Linedup for group (.*), subgroup" |
Expected output is a simple text phrase or sentence like Group Run. But it's really not important exactly what the text output is.
I have multiple instances of this script running each looking for a different line in the Log file and outputting a different line of text. All to the same output file. Basically the latest line found overwrites the previous one, which is what I require.
So, how can I rewrite this script so I don't need to run multiple instances, please? For example..
Select-String "GroupEvents: Linedup for group (.*), subgroup" |
Select-String "Workout(.*)" |
Select-String "GroupEvents: Started in group (.*), subgroup" |
Select-String "Run Device Selected: (.*)" |
I would like the script to search each of these strings and simply output the latest one found in the Log file to the output file.
I have tried just copying the last three lines of code, but this didn't work. I'm not a coder (clearly!) so just best guessing and using trial and error mostly.
Any help with this greatly appreciated.
Upvotes: 0
Views: 194
Reputation: 751
Updated Answer: I'm solving the problem you are actually asking now, which is "how do I call Select-String
with different patterns on the same input?"
Each time new log entries are found, it will pass all the new entries into the For-Each
loop. We can then pass the current object ($_
) as a pipeline object into the function ProcessLog
. ProcessLog
will test the input with Select-String
for each pattern and pass the item to your Write-SlowOutput
function.
$log = "test.log"
$output = "output.log"
$patterns = @("GroupEvents: Linedup for group (.*), subgroup",
"Workout(.*)",
"GroupEvents: Started in group (.*), subgroup",
"Run Device Selected: (.*)")
function ProcessLog {
[CmdletBinding()] Param([Parameter(ValueFromPipeline)]$item)
Write-Output "Running with $item"
foreach($pattern in $patterns)
{
$save = (Select-String -InputObject $item -Pattern $pattern | % { $_.Matches.Groups[1].Value })
if(-not [string]::IsNullOrWhitespace($save))
{
$save.Trim('(').Trim(')') | Set-Content $output
return
}
}
}
Get-Content -Tail 0 -Wait -Encoding "UTF8" $log | % { $_ | ProcessLog }
I tested this successfully using Set-Content
to write to the output file, so I just have to assume it will work properly with your Write-SlowOutput
function.
Upvotes: 1