Reputation: 647
Team, Thanks in advance, I'm an ITPro and learning PowerShell. I've a log file which has the data in below format. I've attached the image. I'm finding all the line which has finished transfer in it and then running foreach loop to find the line in which the date matches the current date using -eq operator
I wanted to then get the specific file name from that current line where the foreach loop is running. Example from my sample : first finished transfer line in the log matches the current date hence i wanted to get the file name which is HardwareEvents.evtx.
But I'm unable to find any method which can help me parse a file name in the current running for each line.
If i get the file name i can then delete the file using powersell cmdlet.
$var = Select-String -Path "C:\Creds\AzCopyVerbose.log" -Pattern 'Finished Transfer' | `
Select-Object -Last 20 | ForEach-Object `
{
if (($_.Line).Substring(1,10) -eq (Get-Date).ToString('yyyy/MM/dd'))
{
$_.Line. // There is no method which I'm aware of need help in this if statement
}
Else {Write-Host "The date present in the azcopy verbose log is older"}
}
Upvotes: 2
Views: 2962
Reputation: 437090
To complement Theo's helpful answer:
It is not obvious, but it is possible to access a Select-String
command's [named] capture-group matches in a ForEach-Object
script block (no need to repeat matching with -match
):
PS> '... File transfer: C:\path\to\file => ...' |
Select-String '\bFile transfer: (?<file>.+?) =>' |
ForEach-Object { $_.Matches[0].Groups['file'].Value }
C:\path\to\file # Value of named capture group 'file'
$_.Matches
is the collection of matches for the current input line; unless -AllMatches
was specified, there's only one entry, with index 0
.
.Groups
accesses the collection of capture-group matches (with the entry at index 0
containing the overall match).
['file']
accesses the match for named capture group file
, but note that at index-based access works equally (for unnamed capture groups), starting with index 1
; that is, $_.Matches[0].Groups[1].Value
in the command above would have yielded the same result.
In terms of data types, Select-String
emits [Microsoft.PowerShell.Commands.MatchInfo]
instances, whose .Matches
property is an array of [System.Text.RegularExpressions.Match]
instances.
Upvotes: 1
Reputation: 61028
To get the filenames from the log where the date is for today, you can use this:
$logfile = 'C:\Creds\AzCopyVerbose.log'
$today = Get-Date -UFormat "%Y/%m/%d"
$pattern = '^\[(?<date>\d{4}/\d{2}/\d{2}).*Finished transfer:\s+(?<filename>.*)\s+=>.*$'
Select-String -Path $logfile -Pattern $pattern | Select-Object -Last 20 | ForEach-Object {
$null = $_.Line -match $pattern
if ($matches['date'] -eq $today) {
Write-Host $matches['filename']
}
else {
Write-Host "The date present in the azcopy verbose log is older"
}
}
Instead of using Select-String
, you can also do this which requires to match the pattern only once, so a bit cleaner in my opinion:
$logfile = 'C:\Creds\AzCopyVerbose.log'
$today = Get-Date -UFormat "%Y/%m/%d"
$pattern = '^\[(?<date>\d{4}/\d{2}/\d{2}).*Finished transfer:\s+(?<filename>.*)\s+=>.*$'
Get-Content -Path $logfile | Select-Object -Last 20 | Where-Object { $_ -match $pattern } | ForEach-Object {
if ($matches['date'] -eq $today) {
Write-Host $matches['filename']
}
else {
Write-Host "The date present in the azcopy verbose log is older"
}
}
p.s. I use Get-Date -UFormat "%Y/%m/%d"
because (Get-Date).ToString('yyyy/MM/dd')
on my Dutch machine outputs 2018-11-10
Regex Details
^ Assert position at the beginning of the string
\[ Match the character “[” literally
(?<date> Match the regular expression below and capture its match into backreference with name “date”
\d Match a single digit 0..9
{4} Exactly 4 times
\/ Match the character “/” literally
\d Match a single digit 0..9
{2} Exactly 2 times
\/ Match the character “/” literally
\d Match a single digit 0..9
{2} Exactly 2 times
)
. Match any single character that is not a line break character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
Finished\ transfer: Match the characters “Finished transfer:” literally
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
(?<filename> Match the regular expression below and capture its match into backreference with name “filename”
. Match any single character that is not a line break character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
=> Match the characters “=>” literally
. Match any single character that is not a line break character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
$ Assert position at the end of the string (or before the line break at the end of the string, if any)
Upvotes: 2
Reputation: 3043
Below is an approach using regex for date.
$var = Select-String -Path "C:\Creds\AzCopyVerbose.log" -Pattern 'Finished Transfer' |
Select-Object -Last 20 | ForEach-Object -Process {
$_.Line -match '\d{4}/\d{2}/\d{2}' | Out-Null
[string]$Match = $Matches.Values
if ([Datetime]$Match -eq (Get-Date).ToString('yyyy/MM/dd'))
{
$_.Line. // There is no method which I'm aware of need help in this if statement
}
Else {Write-Host "The date present in the azcopy verbose log is older"}
}
Upvotes: 0