PowerShell strip all characters after first tab - powershell

I have a file I am trying to import from. The first column is an IDnum, Second is Name, Third is Version. What I want is just the IDNum column. The file is tab delimited so I was wondering how do I capture only the first column before the tab? The rest of the text on each line is not needed. The line looks like this:
4809490 WebGoat 5.0
So in this example, I only want 4809490. I do not need the rest of that stuff.

This can be done via Select-String as a one-liner.
Select-String -Path file.txt -Pattern '^\w+' -AllMatches |%{$_.Matches.Value} > newfile.txt

I sat back and thought about it and found a way myself too :)
ForEach ($line in $content) {
$thisappid = $line.Split("`t")
Write-Host $thisappid.GetValue(0)
}
Those are good answers as well so thank you!

You can either use the Import-CSV with a specified tab delimiter to load the file and select only the first column, or you can use the Get-Content cmdlet to load the file, iterate over it using ForEach-Object and use a regex to extract the ID:
Get-Content 'PATH_TO_YOUR_FILE' | ForEach-Object {
[regex]::Match($_, '\d+').Groups[0].Value
}

Related

How to extract a value out of a file, and save it in a new file, using Powershell

I recently started using Powershell and I'm trying out some code.
I have a .cfg file with several rules of code. The code is written like this:
ad.name=1
ad.virtual=active
ad.set=none
ad.partition=78
Now I want to export the value of ad.partition, which is 78, to a new file. I don't want to export ad.partition or = but only the number 78.
So far I got this:
Get-Content -Path C:\file.cfg | Where-Object {$_ -like 'ad.partition=78'}
But then I -obviously- just get the variable and the value. Not sure how to continue...
I hope someone has a way of achieving what I want.
After saving the value in a new file, would it be possible to add spaces? For example, the value consists out of 9 digits, e.g. 123456789. The desired output result would be 123 456 789.
Use ConvertFrom-StringData cmdlet to create a hash table from your file, then simply index the key you are after:
$h=(Get-Content -Path C:\file.cfg | ConvertFrom-StringData)
$h.("ad.partition") -replace ('^(\d{1,3})(\d{1,3})?(\d{1,3})?','$1 $2 $3') > C:\out.cfg
You can use the Select-String cmdlet to capture your desired value using a regex. Then just pipe the result to the Out-File cmdlet. To get your desired output with spaces, you can use a simple format string:
"{0:### ### ###}" -f [int](Select-string 'ad\.partition=(.*)' -Path C:\file.cfg).Matches.Groups[1].Value |
Out-File C:\result.cfg

Powershell Set-Content is duplicating lines in .ini file

Go easy on me, first time posting.
I'm trying to use Powershell to Get-Content from an INI file. Particularly, I need to change two separate lines in the file. It runs, but instead of just replacing those 2 lines, it duplicates everything. It also doesn't replace the line I'm trying to tell it to replace, but instead it just adds my new line leaving the original in as well.
$FilePath = "C:\Users\folder\*.ini"
(Get-Content $FilePath) |
ForEach-Object {
$_ -replace "MailBell=0","MailBell=1"
$_ -replace "MailWindow=0","MailWindow=1"
} |
Set-Content $FilePath
There is a look at the code. Any help is greatly appreciated.

How to process Custom log data using Powershell?

I have a log file which has data separated with "|" symbol. Like
"Username|servername|access|password|group"
"Username|servername|access|password|group"
I need to validate the data. And, If the group column(record) is missing information or empty. I need to write only that row into another file. Please help me. Thanks in Advance.
If you're just checking for missing data, you can run a quick check using a regex of '(\S+\|){4}\S+'. Use Get-Content with the -ReadCount parameter, and you can work in batches of a few thousand records at a time, minimizing disk i/o and memory usage without going through them one record at a time.
Get-Content $inputfile -ReadCount 2000 |
foreach {
$_ -notmatch '(\S+\|){4}\S+' |
Add-Content $outputfile
}
You could use 'Import-CSV with -Delimiter '|'. If your file doesn't have a header line, you would also need to use -Header to define it. You could then use Where to filter for the empty Group lines and Export-CSV with -Delimiter again to create a new file of just those lines.
For example:
Import-CSV 'YourLog.log' -Delimiter '|' -Header 'Username','Servername','Access','Password','Group' |
Where {$_.'Group' -eq ''} |
Export-CSV 'EmptyGroupLines.log' -Delimiter '|'
If your group column is always in the same place, which it looks like it is, you could use the split method. You can certainly neaten the code up. I have used the below as an example as to how you could use split.
The foreach statement is to iterate through each line in your file.
if (!$($groupstring.Split('|')[4])) checks if it is null.
$groupstring = 'Username|servername|access|password|group'
$groupstring.Split('|')[4]
foreach ($item in $collection)
{
if (!$($groupstring.Split('|')[4]))
{
Write-Host "variable is null"
}
}
Hope this helps.
Thanks, Tim.

Extract specific data

Please help. I am trying to extract multiple filenames from the following .xml file. I then need to copy the list of files from one folder to another. A part of the XML I have posted below:
<component>
<altname>HP Broadcom Online Firmware Upgrade Utility for VMware 5.x</altname>
<filename>CP021404.scexe</filename>
<name>HP Broadcom Online Firmware Upgrade Utility for VMware 5.x</name>
<description>This package contains vSphere 5.1 and VMware </description>
<component>
<component>
<altname>Online ROM Flash - Power Management Controller </altname>
<filename>CP021615.scexe</filename>
I used Windows PowerShell as below and got the output, but the output contains filenames (CP021404.scexe, CP021614.scexe below), line# and symbol still in it. What am I doing wrong on my first PS attempt?
PowerShell
$input_path = ‘C:\PowerShell\hpsum_inventory.xml’
$output_file = ‘C:\powershell\hpsum_inventory-o.xml’
$regex = ".exe"
select-string -Path $input_path -Pattern $regex -AllMatches > $output_file
Output
PowerShell\hpsum_inventory.xml:8: <filename>CP021404.scexe</filename>
PowerShell\hpsum_inventory.xml:18: <filename>CP021614.scexe</filename>
The problem is that you're using a RegEx match and the period character in RegEx matches any character except Line Feed/New Line characters, so it's matching any character followed by 'exe'. Really what you want to do is read the file as XML, and just output the <filename> nodes.
$input_path = ‘C:\PowerShell\hpsum_inventory.xml’
$output_file = ‘C:\powershell\hpsum_inventory-o.xml’
$regex = "exe$"
(Select-Xml -Path $input_path -XPath //filename).node.InnerText | ?{$_ -match $regex} | out-file $output_file
Edit: Ok, you need to incorporate that into a string, that's easy enough. We'll add a ForEach loop (I use the alias % for that) to the last line to insert the file name into a string.
(Select-Xml -Path $input_path -XPath //filename).node.InnerText | ?{$_ -match $regex} | %{"copy c:\powershell\$_ x:\firmware\"} | out-file $output_file
Edit2: Ok, so you want the knowledge in general of how to match text in a file. Can do! Select string will do what you want actually, it just wasn't the best method in general for the example you gave earlier. This gets a bit more interesting, since you need to be familiar with RegEx matching patterns, but other than that it's fairly straight forward. You want to use the -Pattern match again, but let me suggest a better pattern:
"filename>(.*?)<"
That looks for the filename tag, including closing > on it, and grabs everything up to the next < character. The () denote a capturing group, so the rest is ignored as far as the capture goes. Then we pipe to a ForEach loop, and for each line that it finds that matches we select the Matches property, and the second Group property of that (the first contains the whole text, including the filename> and < bits). So it looks like this:
$input_path = 'C:\PowerShell\hpsum_inventory.xml'
$output_file = 'C:\powershell\hpsum_inventory-o.xml'
$regex = "filename>(.*?)<"
select-string -Path $input_path -Pattern "filename>(.*?)<"|%{$_.matches.groups[1].value}
Now that only gets the file names. If we want to incorporate the rest of your thing about inserting it into text you enclose the part in the ForEach loop inside a sub-expression $() and then put that into your double quoted string like such:
select-string -Path $input_path -Pattern "filename>(.*?)<"|%{"copy c:\powershell\$($_.matches.groups[1].value) x:\firmware"}|Out-File $output_file
Personally I would suggest not doing that directly as it limits you. I'd collect the data in an array, then pipe that array into a process that does what you want, but then at least you have the collection so you can do with it what you want.
$input_path = 'C:\PowerShell\hpsum_inventory.xml'
$output_file = 'C:\powershell\hpsum_inventory-o.xml'
$regex = "filename>(.*?)<"
$Filenames = select-string -Path $input_path -Pattern "filename>(.*?)<"|%{$_.matches.groups[1].value}
$Filenames|%{"copy c:\powershell\$_ x:\firmware"}|Out-File $output_file
Why do it that way? What if you don't want to over-write something? Then you can do something like:
$Filenames|?{$_ -notin (GCI X:\firmware -file|select -expand name)}|%{"copy c:\powershell\$_ x:\firmware"}|Out-File $output_file
For your collection of serial numbers, try the regex pattern of:
"Serial Number: (\S*)"
In RegEx there are a few escaped characters that have special meaning, and capitalizing them inverts that meaning. \s means whitespace, so spaces, tabs, what not. Doing it as a capital means something that is NOT whitespace. The asterisk means however many of the previous thing (not whitespace) it can find. So this looks for 'Serial Number: ' and then captures everything after that until it reaches the end of the line or encounters whitespace. Check out this link to see how it works.

Powershell extract values from file

I have a log file that has a lot of fields listed in it. I want to extract the fields out of the file, but I don't want to search through the file line by line.
I have my pattern:
$pattern="Hostname \(Alias\):(.+)\(.+Service: (.+)"
This will give me the two values that I need. I know that if I have a string, and I'm looking for one match I can use the $matches array to find the fields. In other words, If I'm looking at a single line in the file using the string variable $line, I can extract the fields using this code.
if($line -matches $pattern){
$var1=$matches[1]
$var2=$matches[2]
}
But how can I get these values without searching line by line? I want to pass the whole file as a single string, and add the values that I am extracting to two different arrays.
I'm looking for something like
while($filetext -match $pattern){
$array1+=$matches[1]
$array2+=$matches[2]
}
But this code puts me in an infinite loop if there is even one match. So is there a nextMatch function I can use?
PowerShell 2.0 addressed this limitation by adding the -AllMatches parameter to the Select-String cmdlet e.g.:
$filetext | Select-String $pattern -AllMatches |
Foreach {$_.Matches | Foreach {$_.Groups[1] | Foreach {$_.Value}}}