Parsing lines no older than a specific date - parsing

I am working on some PowerShell scripting stuff not having a strong PowerShell skill under my belt. Basically I am more into Java, but I need to use PowerShell to get some things done at work.
What I have so far is a little snippet that parses my desired log file, returns an object and writes it to a file.
# find all lines with "successfully installed":
Select-String -Path $env:windir\WindowsUpdate.log -Pattern 'successfully installed' |
ForEach-Object {
$information = $_ | Select-Object -Property Date, Product
$parts = $_.Line -split '\t'
[DateTime]$information.Date = $parts[0] + ' ' + $parts[1].SubString(0,8)
$information.Product = ($_.Line -split 'following update: ')[-1]
$information
} | Out-File parsedUpdate.log
My output looks like this
What I would love to do next is to
Get rid of the line that labels the Properties and the line below it as well as I would send the output to EventLog soon.
Select only the lines that are no older than a specific date.
So how would I go about rejecting these two lines? Regarding the date problem I would love the exclude lines older than a specific date which I specify.
I have read that that Select-String has an -Exclude <String> property.
Would it be smart (and of course possible) to use this Directive to Exclude lines with a specific date and how would I do that - lets say for example, to reject any line older than a week from now?
thanks in advance.
Andrew

The timestamps on the actual log entries are in string sortable format, so you can do your date filtering early, before object creation:
$Start = (get-date).AddDays(-7).ToString('yyyy-MM-dd')
Select-String -Path $env:windir\WindowsUpdate.log -Pattern 'successfully installed' |
Where {$_.line -gt $Start} |

All you have to do for the (2) part of your question is add a filter to your result set, since you've already got objects with the Date property. The filter clause will look like Where-Object { $_.Date -ge "2/6/2015" } just replace with the date you are interested in.
# find all lines with "successfully installed" no older than 2/6/2015:
Select-String -Path $env:windir\WindowsUpdate.log -Pattern 'successfully installed' |
ForEach-Object {
$information = $_ | Select-Object -Property Date, Product
$parts = $_.Line -split '\t'
[DateTime]$information.Date = $parts[0] + ' ' + $parts[1].SubString(0,8)
$information.Product = ($_.Line -split 'following update: ')[-1]
$information
} | Where-Object { $_.Date -ge "2/6/2015" } | Out-File parsedUpdate.log

Related

PowerShell Parse INF file

I am trying to parse an INF; specifically, driver version from the file. I am new to PowerShell, so I've gotten only this far.
The file looks like this:
[Version]
Signature = "$WINDOWS NT$"
Class = Bluetooth
ClassGuid = {e0cbf06c-cd8b-4647-bb8a-263b43f0f974}
Provider = %PROVIDER_NAME%
CatalogFile = ibtusb.cat
DriverVer=11/04/2014,17.1.1440.02
CatalogFile=ibtusb.cat
The second last line has the information I am looking for. I am trying to parse out just 17.1.1440.02.
One file may contain multiple lines with DriverVer=..., but I am only interested in the first instance.
Right now I've the following script.
$path = "C:\FilePath\file.inf"
$driverVersoin = Select-String -Pattern "DriverVer" -path $path
$driverVersoin[0] # lists only first instance of 'DriverVer'
$driverVersoin # lists all of the instances with 'DriverVer'
Output is:
Filepath\file.inf:7:DriverVer=11/04/2014,17.1.1440.02
But I am only looking for 17.1.1440.02
Make your expression more specific and make the part you want to extract a capturing group.
$pattern = 'DriverVer\s*=\s*(?:\d+/\d+/\d+,)?(.*)'
Select-String -Pattern $pattern -Path $path |
select -Expand Matches -First 1 |
% { $_.Groups[1].Value }
Regular expression breakdown:
DriverVer\s*=\s* matches the string "DriverVer" followed by any amount of whitespace, an equals sign and again any amount of whitespace.
(?:\d+/\d+/\d+,)? matches an optional date followed by a comma in a non-capturing group ((?:...)).
(.*) matches the rest of the line, i.e. the version number you want to extract. The parentheses without the ?: make it a capturing group.
Another option (if the version number is always preceded by a date) would be to just split the line at the comma and select the last field (index -1):
Get-Content $path |
Where-Object { $_ -like 'DriverVer*' } |
Select-Object -First 1 |
ForEach-Object { $_.Split(',')[-1] }

Remove numerous characters including underscore

I have a large number of files in numerous directories with this type of naming convention: "filename_yymmdd.csv", etc. I need to remove the underscore and the yymmdd. So the new file name would be "filename.csv". i need to recursively search through for .csv files and remove the date and underscore in powershell V2.0
$pattern = '(.*)_\d{6}(.csv)'
Get-ChildItem -Recurse | ? { $_.Name -match $pattern } |
Rename-Item -NewName { $_.Name -replace $pattern, '$1$2' }

How to parse a File in power shell with conditional and garbage

I need to get part of this file for example, I need extract the following
Main, Branches\Branch1
in one variable also the I cannot have duplicate values
It is possible with powershell?
This is the file:
This is a garbage line
This is another garbage line
c:\Folder\Main\Folder\..\Folder
c:\Folder\Main\Folder\..\Folder
c:\Folder\Branches\Branch1\Folder\..\Folder
c:\Folder\Branches\Branch1\Folder\..\Folder
c:\Folder\Branches\Branch1\Folder\..\Folder
c:\Folder\Main\Folder\..\Folder
c:\Folder\Main\Folder\..\Folder
this is the final line..
But of course ...
According to the fact $files contain your lines
$files = Get-content "your file"
You can use the following to be sure that there is no duplicate :
$files | Sort-Object -Unique
Then you can use Test-path to be sure that path exists
$files | Sort-Object -Unique | where {Test-Path $_ -ErrorAction SilentlyContinue}
This will extract those values from the sample data using a -like filter to take out the garbage and a -replace to do the extract. The sort -unique will remove the duplicates, but it won't keep the extracted values in the same order they were in the file.
(get-content testfile.txt) -like 'c:\Folder*' -replace 'c:\\Folder\\(.+?)\\Folder.+','$1' |
sort -unique

Given repeating sections, how do I find sections matching certain criteria using Powershell

I need to parse a text file and retrieve data from it... based on other data in the same file..
I need to find the lines that say not ok.. and then find the Nodes they are under..
I know how to pull the data in..and find the Not Ok's and the Nodes. I also have an idea that I'm sure is overly complicated to find what I'm looking for. I can parse the Node lines into an array so like
$test = (select-string -path C:\error.txt -Pattern "Node:").linenumber
then find the line number of the not oks and backup lol but this seems like the most difficult way to do this. I'm familiar with PS but not an expert.
$test2 = (select-string -path C:\error.txt -Pattern "Not ok").linenumber
so to spell out what I need ..
parse file for Node.. find lines below that are not ok.. and if so set node to variable...if not ok isn't found move on to next node.
Thanks for any help
example txt file below
Node: Server
*********************
Line 1 ok
line 2 ok
line 3 ok
Line 4 Not ok
line 5 ok
line 6 ok
*********************
Node: Server2
*********************
Line 1 ok
line 2 ok
line 3 Not ok
Line 4 ok
line 5 ok
line 6 ok
*********************
$errorNodes = #()
Get-Content C:\temp\test.txt | ForEach-Object {
if ($_ -imatch 'Node: (.+)$') {
$node = $Matches[1]
}
if ($_ -imatch 'not ok') {
$errorNodes += $node
}
}
$errorNodes
Explanation
Get-Content reads a file line by line.
For each line, first check to see if it's a node; if so, set the $node variable to the current node's name.
Then check to see if the line matches the text 'not ok'. If so, add the node name to the list of error nodes (the array variable $errorNodes.
So at the end, $errorNodes will contain the nodes with problems.
If your list is long, this should be a quicker way to parse (also less code :)):
$nodes = [Regex]::Split((Get-Content info.txt), 'Node:')
# '?' is an alias for Where-Object
$bad = $nodes | ? { $_.ToLower().Contains('not ok') }
$bad now also contains all the text under the node containing "not ok" (in the even there are multiple lines that are not ok).
This answer is most likely more complicated than it needs to be but it returns useful objects that, depending what else op needs to do in his code, can be useful for further processing. For this example I used the file structure of the OP and added some extra nodes to make the output a little more verbose.
$file = Get-Content "c:\temp\test.txt" -Raw
$file -split '\s+(?=Node: \w+)' |
%{ $stringData = (($_ -replace ": "," = ") -replace 'line\W+(\d+)\W+','Line$1 = ') -replace '\*+'
New-Object PSObject -Property $(ConvertFrom-StringData $Stringdata)
} | select node,line* | Format-Table
Using PowerShell 3.0: The code will read the file as a whole string (Not creating a string array) using the -Raw parameter. The $file is the string split at the text "Node: " which will break up the Nodes as separate objects.
In order to create the custom object we need to make sure all the items of the Node contain name=value pairs. To accomplish this I nested some -replace operations.
$_ -replace ": "," = " - To change the first line to "Node = Servername"
-replace 'line\W+(\d+)\W+','Line$1 = ' - Convert Line # ok into Line# = Ok\Not Ok Where # is the particular line 1-6
-replace '\*+' - To remove the lines that contain just astericks ( or whatever the plural of astericks is)
The formated string is used as input for New-Object PSObject -Property $(ConvertFrom-StringData $Stringdata)
After that we can control the piped output like we would almost any other object. To ensure that node appears first in the list the select-object statement.
The following is my sample output:
Node Line4 Line5 Line6 Line1 Line2 Line3
---- ----- ----- ----- ----- ----- -----
Server Not ok ok ok ok ok ok
Server2 ok ok ok ok ok Not ok
Server4 ok ok ok Not ok ok ok
Server3 ok ok ok ok ok ok

Removing lines from a CSV

I have a csv document with multiple headers like:
"Date","RQ","PM","SME","Activity","Status code"
"2/2/12","6886","D_WV","John Smith","Recent","2004"
and a text document that is just a list of status codes, one per line.
I am trying to figure out how to remove all lines from the CSV that contain the status codes from the text file.
So far I have tried using:
$m = gc textfile.txt
Select-String data.csv -Pattern $m -NotMatch
However that leaves me with extra data such as
data.csv:1"Date","RQ","PM","SME","Activity","Status code"
data.csv:2"2/2/12","6886","D_WV","John Smith","Recent","2004"
I have also tried:
gc data.csv | ? { $_ -notlike $m }
That uses the proper formatting but does not want to remove any of the values. Any help is much appreciated.
Those matchinfo objects from select-string can be confusing.
Does this do what you need?
$m = gc textfile.txt
select-string data.csv -pattern $m -notmatch |
select -expand line
I'd suggest a different approach to avoid false positives:
$m = Get-Content textfile.txt
Import-Csv data.csv `
| ? { $m -notcontains $_."Status code" } `
| Export-Csv output.csv -NoTypeInformation

Resources