Replace command using post.context to add new line - powershell

Trying to add a line break here but it's not working. Tried also using the `r, but no luck.
My code:
$extract = #()
Select-String -Path $outfile -Pattern "text" -Context 0,12 |
ForEach-Object {
$extract += $_.Line | foreach {$_.Replace("text", "DD/MM")}
$extract += $_.Context.PostContext | foreach {$_.Replace(',', "`n")}
}
$extract | Out-File $outfile1
My Input:
DD/MM
27,28
14
21
1
15
7
12
2,15
25
What I'm trying to do is to add a line break for 27,28 and 2,15 so it reads each number in a separate line:
27
28
2
15
Any idea why the replace is not working here?

Related

Powershell - Trying to calculate the average of a csv file using a function

Below you can see my code. I' trying to calculate the average line by line of my csv file. The only way I have been able to do this is by using it as an array. My question is, is there a way to pass each line through the function so that I don't have to create multiple functions?
The file looks like this:
V1 V2 V3
5 9 3
5 6 2
Script:
Function Average($a) {
Foreach ($line in $a) {
$total = [int]$a[0].V1 + [int]$a[0].V2 + [int]$a[0].V3
}
return "The Average is $($total / 3)"
}
#Variables
$a = (Import-Csv "Document.csv")
#Logic
Average
You can access the properties of each line (without knowing their names) through the psobject reference:
function Get-CsvAverage
{
param(
[psobject[]]$Lines
)
# Loop through all lines of input
foreach($Line in $Lines){
# For each "line" object, loop through its properties
$Numbers = $Line.psobject.Properties |ForEach-Object {
# Attempt to cast the property's value as an integer
$_.Value -as [int]
}
# Output the average for the current line
Write-Output ($numbers | Measure-Object -Average).Average
}
}
Then use like:
$CsvLines = Import-Csv Document.csv
Get-CsvAverage $CsvLines
For your sample input this would produce:
5.66666666666667
4.33333333333333
if your data separator is a space in your file
Solution 1 :
import-csv C:\temp\test.csv -Delimiter ' ' | select #{Name="Average";Expression={[math]::Round(([Decimal]$_.V1 + [Decimal]$_.V2 + [Decimal]$_.V3)/3, 2)}}
Solution 2
import-csv C:\temp\test.csv -Delimiter ' ' | %{[math]::Round(([Decimal]$_.V1 + [Decimal]$_.V2 + [Decimal]$_.V3)/3, 2)}
Solution 3
Get-Content C:\temp\test.csv | select -Skip 1 | %{$avg=0; $_ -split " " | %{$avg+=[decimal]$_};[math]::Round($avg/3, 2) }

Replace white spaces in strings in a pipe in PowerShell

I have the following in PowerShell:
$objects = git -C "$localRepoPath" verify-pack -v (Get-ChildItem "$PackFiles\pack-*.idx")`
| Select-String -Pattern "blob"`
| Select -First 5
# Output each line
$objects | % {
$_.Line
}
When I run the above I get:
1ff0c423042b46cb1d617b81efb715defbe8054d blob 2518 701 5081449
dc9a583bf4927685d9ceb3f9381b6a232a609281 blob 2390 1203 5082150
876f3b37e51d0af2d090104e22352171eca12bff blob 11 40 5083353 1 dc9a583bf4927685d9ceb3f9381b6a232a609281
3faa5832a9e087a5d4cf2b493c52f97eda478242 blob 21 51 5083393 2 876f3b37e51d0af2d090104e22352171eca12bff
15a0d10cde33f1d3fe5c2acda9fc1eb52def6dc6 blob 62 92 5083444 3 3faa5832a9e087a5d4cf2b493c52f97eda478242
I would like to replace one or more of the white spaces in the above output with '___' in the same pipe. I have tried:
$objects = git -C "$localRepoPath" verify-pack -v (Get-ChildItem "$PackFiles\pack-*.idx")`
| Select-String -Pattern "blob"`
| % { $_.Line -replace '\s+', '___' }`
| Select -First 5
# Output each line
$objects | % {
$_.Line
}
But the output is empty. How do I accomplish that?

Using a variable within a PowerShell Select-String

I have this one section of my PowerShell script that I'm currently stuck on. Basically, I have two files that I want to do a comparison on via select-string...In detail
For each item in FileA.txt I want to do a select-string to FileB.txt to discover if it exist. If the line item in FileA.txt doesn't exist in FileB.txt, then print the FileA.txt line item to the screen.
This is what the text files looks like..more or less
FileA.txt
1
2
3
4
6
FileB.txt
6
7
8
9
10
Desired output would be the following:
1
2
3
4
This is what my PS code looks like now. My thought process was that I could use the variable within the select-string but its not working out for me :(
$IPs = Get-Content "C:\\FileA.txt"
Get-Content C:\FileB.txt | Select-String -InputObject $IPs
Could someone please help me out and point out what I am doing wrong.
Based on your limited sample data, here is an example of how you could do this :
"1 2 3 4 6" > "fileA.txt"
"6 7 8 9 10" > "fileB.txt"
$arrayA = (Get-Content "fileA.txt").Split(" ")
$arrayB = (Get-Content "fileB.txt").Split(" ")
$arrayResult = #()
foreach($valueA in $arrayA) {
if($arrayB -notcontains $valueA) {
$arrayResult += $valueA
}
}
$arrayResult -join " "
Now I believe the input files will be quite different eventually
EDIT :
Using line breaks :
"1
2
3
4
6" > "fileA.txt"
"6
7
8
9
10" > "fileB.txt"
$arrayA = Get-Content "fileA.txt"
$arrayB = Get-Content "fileB.txt"
$arrayResult = #()
foreach($valueA in $arrayA) {
if($arrayB -notcontains $valueA) {
$arrayResult += $valueA
}
}
$arrayResult -join "`n"
NB : the 2 scripts begin by filling the needed files, I guess you won't need to do it
In this specific example, Compare-Object would probably be a better choice. It is designed to find the differences between two lists.
You would use something like:
Compare-Object -ReferenceObject $(gc .\FileA.txt) -DifferenceObject $(gc .\FileB.txt) | where { $_.SideIndicator -eq '<=' } | select -expand InputObject
However, you could also do this with select-string:
gc .\FileA.txt | select-string -Pattern $(gc .\FileB.txt) -NotMatch
which just finds the lines of FileA that don't match the lines of FileB, however the lines of FileB are interpreted as regular expressions, which probably isn't appropriate for IP addresses since '.' is a wildcard.

Powershell - Search and output line by line

UPDATE
I have got a log file of 1000 lines containing some reference.
Time Reference Date of start Date of end
12:00 AT001 13 November 2011 15 November 2011
13:00 AT038 15 December 2012 17 December 2012
14:00 AT076 17 January 2013 19 January 2013
$ref1 = AT038
Basically, I want to parse the log file and have an output (line by line) for $ref1 such as :
Time : 13h
Reference : AT038
Date of start : 15 December 2012
Date of end : 17 December 2012
Thanks in advance
try:
$ref1 = "AT038"
$csv = Import-Csv .\myfile.txt -Delimiter ' '#Import file as CSV with space as delimiter
$csv | ? { $_.reference -EQ $ref1 } | FL #Piping each line of CSV to where-object cmdlet, filtering only line where value of column reference is equal to $ref1 variable value. Piping the result of the filtering to file-list to have output as requested in OP.
Code added after requisite are changed in OP:
$ref1 = "AT038"
$txt = gc .\myfile.txt
$txt2 = $txt | % { $b = $_ -split ' '; "$($b[0]) $($b[1]) $($b[2])_$($b[3])_$($b[4]) $($b[5])_$($b[6])_$($b[7])" }
$csv = convertfrom-csv -InputObject $txt2 -Delimiter ' '
$csv | ? { $_.reference -EQ $ref1 } | FL
How about this:
Get-Content SourceFileName.txt |
% { ($_ -Replace '(\d{2}):\d{2} (\w{2}\d{3})', 'Time : $1h|Reference : $2').Split('|')} |
Out-File TargetFileName.txt
Here is my revised version:
$regex = '(\d{2}):\d{2} (\w{2}\d{3}) (\d{2} \b\w+\b \d{4}) (\d{2} \b\w+\b \d{4})'
$replace = 'Time : $1h|Reference : $2|Date of start : $3|Date of end : $4'
Get-Content SourceFileName.txt |
% { ($_ -Replace $regex, $replace).Split('|')} |
Out-File TargetFileName.txt

PowerShell: How to remove columns from delimited text input?

I have a text file with 5 columns of text delimited by whitespace. For example:
10 45 5 23 78
89 3 56 12 56
999 4 67 93 5
Using PowerShell, how do I remove the rightmost two columns? The resulting file should be:
10 45 5
89 3 56
999 4 67
I can extract the individual items using the -split operator. But, the items appear on different lines and I do not see how I can get them back as 3 items per line.
And to make the question more generic (and helpful to others): How to use PowerShell to remove the data at multiple columns in the range [0,n-1] given an input that has lines with delimited data of n columns each?
Read the file content, convert it to a csv and select just the first 3 columns:
Import-Csv .\file.txt -Header col1,col2,col3,col4,col5 -Delimiter ' ' | Select-Object col1,col2,col3
If you want just the values (without a header):
Import-Csv .\file.txt -Header col1,col2,col3,col4,col5 -Delimiter ' ' | Select-Object col1,col2,col3 | Format-Table -HideTableHeaders -AutoSize
To save back the results to the file:
(Import-Csv .\file.txt -Header col1,col2,col3,col4,col5 -Delimiter ' ') | Foreach-Object { "{0} {1} {2}" -f $_.col1,$_.col2,$_.col3} | Out-File .\file.txt
UPDATE:
Just another option:
(Get-Content .\file.txt) | Foreach-Object { $_.split()[0..2] -join ' ' } | Out-File .\file.txt
One way is:
gc input.txt | %{[string]::join(" ",$_.split()[0..2]) } | out-file output.txt
(replace 2 by n-1)
Here is the generic solution:
param
(
# Input data file
[string]$Path = 'data.txt',
# Columns to be removed, any order, dupes are allowed
[int[]]$Remove = (4, 3, 4, 3)
)
# sort indexes descending and remove dupes
$Remove = $Remove | Sort-Object -Unique -Descending
# read input lines
Get-Content $Path | .{process{
# split and add to ArrayList which allows to remove items
$list = [Collections.ArrayList]($_ -split '\s')
# remove data at the indexes (from tail to head due to descending order)
foreach($i in $Remove) {
$list.RemoveAt($i)
}
# join and output
$list -join ' '
}}