I have a text file. Similar to this.
This is a sample data.
This is a sample data.
This is a sample data.
Sat Jun 06 08:17:01 2015
WARNING: Cannot delete file.
E
$curdate
is a string with the format ddMMyyyy
, whereas the string in the log file containing the date is in the format ffffd MMM dd HH:mm:ss yyyy
, which I assume to be the current locale, hence your use of Get-Date -UFormat %c
.
Therefore, your if($_ -eq $curdate)
statement won't work.
if($_ -eq $cur_date1)
will return true if the timestamp contained in $_
represents the exact second your script starts running, but the subsequent Where-Object
statement won't evaluate to $true
(since $_
is currently referring to the line with the date, not the error) and even if it did, wouldn't return anything (you haven't piped anything to Where-Object
or specified an InputObject
parameter argument)
As a general rule, for date comparison, don't use a string representation, use the Date
property of the datetime objects you are comparing.
Wrong/frail approach:
Get-ChildItem |Where-Object { $_.LastWriteTime.ToString("ddMMyyyy") -eq $datestring }
Safe approach:
$today = (Get-Date).Date
Get-ChildItem |Where-Object { $_.LastWriteTime.Date -eq $today }
If you want to extract the preceding date of an error message, the easiest way is to use Select-String
with the Context
parameter:
Select-String -Path C:\samplefile.log -Pattern "^Error" -Context 2 | Select-Object -First 1
C:\samplefile.log:4:Sat Jun 06 08:17:01 2015
C:\samplefile.log:5:WARNING: Cannot delete file.
> C:\samplefile.log:6:Error-101
C:\samplefile.log:7:This is a sample data.
C:\samplefile.log:8:This is a sample data.
You can then use the output data from Select-String
to grab and compare the date:
$Today = (Get-Date).Date
$Format = 'ffffd MMM dd HH:mm:ss yyyy'
Select-String -Path C:\samplefile.log -Pattern '^Error' -Context 2 | Where-Object {
[DateTime]::ParseExact($_.Context.PreContext[0],$Format,$null).Date -eq $Today
} | Select-Object @{Name="Error";Expression={$_.Line}},@{Name="Date";Expression={[DateTime]::ParseExact($_.Context.PreContext[0],$Format,$null).ToString("ddMMyyyy")}}
While you parse error*.txt
file, you can save last seen date in a variable. So, when you encounter Error-*
record, you will know to what date it related to.
$Today=[datetime]::Today
Get-Content D:\Script\system.txt|
ForEach-Object {
$System=$_
Get-ChildItem -Path "filesystem::\\$System\D$\Error" -Filter error*.txt|
# filesystem:: allows code to work, even if current provider is not a filesystem provider.
Where-Object {$_.LastWriteTime.Date-eq$Today}|
ForEach-Object {
Get-Content -LiteralPath $_.PSPath|
ForEach-Object {
$ParseDate=New-Object datetime
$LastSeenDate=$null
} {
if([datetime]::TryParseExact($_,'ffffd MMM dd HH:mm:ss yyyy',[cultureinfo]::InvariantCulture,'None',[ref]$ParseDate)){
$LastSeenDate=$ParseDate
}
if($_.StartsWith('Error-')){
[PSCustomObject]@{
Error=$_
Date=$LastSeenDate
System=$System
}
}
}
}
}|
Where-Object {$_.Date.Date-eq$Today}
I got pinged to the question, so here's my take on a solution:
#Create test file from posted data:
(@'
This is a sample data.
This is a sample data.
This is a sample data.
Sat Jun 06 08:17:01 2015
WARNING: Cannot delete file.
Error-101
Error-100
Error-102
This is a sample data.
This is a sample data.
Error-10666
This is a sample data.
Sat Jun 06 10:17:01 2015
File deleted.
This is a sample data.
This is a sample data.
Sat Jun 06 10:17:01 2015
File deleted.
Sat Jun 06 11:17:01 2015
WARNING: Cannot delete file.
Error-101
This is a sample data.
Sat Jun 06 18:17:01 2015
WARNING: Cannot delete file.
Error-101
This is a sample data.
'@).split("`n") |
#where { -notmatch '^#'} |
foreach {$_.trim()} |sc testfile.txt
#Proxy function for testing
function get-date {[datetime]'06/06/2015 18:17:01'}
#Actual solution code follows:
$DateSearch = (get-date).ToString('MMM dd [0-9:]+ yyyy(.+)')
$DateSearch = '(?ms)' + $DateSearch
if ((Get-Content testfile.txt -Raw) -match $DateSearch)
{ $Matches[1].Split("`n") -like 'Error*' }
#remove the proxy function:
remove-item function:get-date
Error-101
Error-100
Error-102
Error-10666
Error-101
Error-101
This uses the [datetime] tostring()
method to help create a regex to search for today's date in the file. Then it captures everything from that point to the end of the file, splits it at the newlines and filters out everything except the Error records.
Ignore that proxy function for get-date. That's just there to get the script to work with the test data.
You can try converting each line to a datetime. That's not a standard date format, however, so [datetime]::TryParse()
isn't likely to work. That means you'll need to use [datetime]::TryParseExact(), which is moderately more irritating because you have to give it a provider and a style, even though you're probably not using either.
$dateString = 'Sat Jun 06 08:17:01 2015';
[System.Globalization.CultureInfo]$provider = [System.Globalization.CultureInfo]::InvariantCulture;
[System.Globalization.DateTimeStyles]$style = [System.Globalization.DateTimeStyles]::None;
$format = "ffffd MMM dd HH:mm:ss yyyy";
[ref]$parsedDate = get-date;
[DateTime]::TryParseExact($dateString, $format, $provider, $style, $parsedDate);
$parsedDate.Value;
A key thing to note is that both TryParse()
and TryParseExact()
don't return values; they return True when the parsing is successful, and False when it fails. In order to pass the result, you pass a variable by reference and the function modifies the referenced variable. $parsedDate.Value
is where the actual datetime value is because $parsedDate
itself is a reference (pointer).
If the function fails and returns false, $parsedDate
will have a value of [datetime]::MinValue
(Jan 1, 0001).