Replace text in first line of tab-delimited file using Powershell - powershell

I have a tab delimited file that has 10k+ rows. I need to change a specific field of the first(header) record to a specific value..
I am using the following script, but it messes up the format.
$contents = Get-Content $PATH -Delimiter "`t"
$contents[1] = 'Replaced Text'
$contents | Out-File $PATH
I can see that the format will mess up, but i am not sure how to keep the file exactly as it is and just change what I need to.
Also, I would like to know if there is an efficient way.. Because i am just concerned with the first line of the file.
I tried a different approach, it works "ok" but introduces extra blank lines after each line:
$content = Get-Content $PATH -Delimiter "`n"
$content |
ForEach-Object {
if ($_.ReadCount -le 1) {
$_ -replace 'A','B'
} else {
$_
}
} |
Set-Content $PATH

One option:
$content = {Get-Content $PATH}.Invoke()
$content[0].Replace('A','B') | Set-Content $PATH
$content.RemoveAt(0)
$content | Add-Content $PATH
Using .invoke() on the script block causes Get-Content to return a collection rather than an array, which simplifies removing the first element.

Related

PowerShell script to read excel and write into text file

I am trying to write a script in power shell to read the first column value in excel, find the value in text file and replace that value with value in second column of the excel file.I am new to the power shell. Please help. Below is the code:
$excel = Import-Csv -Path C:\Users\abc\Desktop\newnbc.csv
foreach ($ex in $excel)
{
$name = $ex.first
$match = Get-Content -Path 'C:\Users\abc\Desktop\all.txt'
foreach ($ma in $match)
{
if ($match | %{$_ -replace $ex.first,$ex.last})
{
((Get-Content -Path C:\Users\abc\Desktop\all.txt -Raw) -replace $name,$ex.last) | Set-Content -Path C:\Users\abc\Desktop\all.txt
}
}
}
Judging by the info from your comment, it looks like the input CSV is a space-delimited file, something like this:
first last
i3-chq-nbc-dt-comcleanup-cmd i3-chq-nbc-dt-d-com-cleanup
Of course, if the delimiter character is something other than a space, change the value for the -Delimiter parameter.
$fileName = 'C:\Users\abc\Desktop\all.txt'
# get the original content of the text file BEFORE the loop
$content = Get-Content -Path $fileName -Raw
# then, import the csv with the replacement strings and start replacing the content
Import-Csv -Path 'C:\Users\abc\Desktop\newnbc.csv' -Delimiter ' ' | ForEach-Object {
$content = $content -replace $_.first, $_.last
}
# finally, save the updated content to file
$content | Set-Content -Path $fileName

Powershell split string - one works and one doesn't. Why?

I wrote this one without the variable while figuring out how to go about doing what I needed:
#Variables
$replace='2.55'
$filepath= 'C:\folder\path\bond.out'
#go straight to the line I want to change something in
$data = Get-Content $filepath | select -skip 38 -first 1
#split it all, find the other variable and overwrite it
$split=$data.split("{|}")
$split[3]=$replace
#put it all back again
$join = $split -join "|"
write-output $join
This works perfectly.
I then changed the "$data" line to select the variable instead:
#Variables
$replace='2.55'
$filepath= 'C:\folder\path\bond.out'
#find the variable
$data = Get-Content $filepath | select-string $bond
#split it all, find the other variable and overwrite it
$split=$data.split("{|}")
$split[3]=$replace
#put it all back again
$join = $split -join "|"
write-output $join
Now I get the below error:
I understand the second error block is because the first error block occurred, but don't understand why it now doesn't work at all?
As others have said, Select-String outputs a MatchInfo, not a String. Also, you don't need Get-Content with Select-String. It does that for you already.
Try this:
$data = Select-String -Path $filepath -Pattern $bond | Select-Object -ExpandProperty Line

Change and save .nc files

I have a massive amount of .nc files (text files) where I need to change different lines based on their linenumer and content.
Example:
So far I have:
Get-ChildItem I:\temp *.nc -recurse | ForEach-Object {
$c = ($_ | Get-Content)
$c = $c -replace "S355J2","S235JR2"
$c = $c.GetType() | Format-Table -AutoSize
$c = $c -replace $c[3],$c[4]
[IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
}
This is not working, however, since it returns only a few PowerShell lines to each file, instead of the original (changed) content.
I don't know what you expect $c = $c.GetType() | Format-Table -AutoSize to do, but it most likely doesn't do whatever it is you're expecting.
If I understand your question correctly you essentially want to
remove the line pos,
replace the code S355J2 with S235JR2, and
remove a section SI if it exists.
The following code should work:
Get-ChildItem I:\temp *.nc -Recurse | ForEach-Object {
(Get-Content $_.FullName | Out-String) -replace 'pos\r\n\s+' -replace 'S355J2', 'S235JR2' -replace '(?m)^SI\r\n(\s+.*\n)+' |
Set-Content $_.FullName
}
Out-String mangles the content of the input file into a single string, and the daisy-chained replacement operations modify that string before it's written back to the file. The expression (?m)^SI\r\n(\s+.*\n)+ matches a line beginning with SI and followed by one or more indented lines. The (?m) modifier is to allow matching start-of-line in a multiline string, otherwise ^ would only match the beginning of the string.
Edit: If you need to replace variable text in the 3rd line with the text from the 4th line (thus duplicating the 4th line) you're indeed better off working with an array for that. Delay the mangling of the string array until after that replacement:
Get-ChildItem I:\temp *.nc -Recurse | ForEach-Object {
$txt = #(Get-Content $_.FullName)
$txt[3] = $txt[4]
($txt | Out-String) -replace 'S355J2', 'S235JR2' -replace '(?m)^SI\r\n(\s+.*\n)+' |
Set-Content $_.FullName
}

Filtering sections of data including the starting and ending lines- PowerShell

I have a text file that looks like this:
Data I'm NOT looking for
More data that doesn't matter
Even more data that I don't
&Start/Finally the data I'm looking for
&Data/More data that I need
&Stop/I need this too
&Start/Second batch of data I need
&Data/I need this too
&Stop/Okay now I'm done
Ending that I don't need
Here is what the output needs to be:
File1.txt
&Start/Finally the data I'm looking for
&Data/More data that I need
&Stop/I need this too
File2.txt
&Start/Second batch of data I need
&Data/I need this too
&Stop/Okay now I'm done
I need to do this for every file in a folder (sometimes there will be multiple files that will need to be filtered.) The files names can be incrementing: ex. File1.txt, File2.txt, File3.txt.
This is what I have tried with no luck:
ForEach-Object{
$text -join "`n" -split '(?ms)(?=^&START)' -match '^&START' |
Out-File B:\PowerShell\$filename}
Thanks!
Looks like you were pretty close: your code correctly extracted the paragraphs of interest, but intra-paragraph out-filtering of non-&-starting lines was missing, and you needed to write to paragraph-specific output files:
$text -join "`n" -split '(?m)(?=^&Start)' -match '^&Start' |
ForEach-Object { $ndx=0 } { $_ -split '\n' -match '^&' | Out-File "File$((++$ndx)).txt" }
This creates sequentially numbered files starting with File1.txt for every paragraph of interest.
To do it for every file in a folder, with output filenames using fixed naming scheme File<n> across all input files (and thus cumulative numbering):
Get-ChildItem -File . | ForEach-Object -Begin { $ndx=0 } -Process {
(Get-Content -Raw $_) -split '(?m)(?=^&Start)' -match '^&Start' |
ForEach-Object { $_ -split '\n' -match '^&' | Out-File "File$((++$ndx)).txt" }
}
To do it for every file in a folder, with output filenames based on the input filenames and numbering per input file (PSv4+, due to use of -PipelineVariable):
Get-ChildItem -File . -PipelineVariable File | ForEach-Object {
(Get-Content -Raw $_) -split '(?m)(?=^&Start)' -match '^&Start' |
ForEach-Object {$ndx=0} { $_ -split '\n' -match '^&' | Out-File "$($File.Name)$((++$ndx)).txt" }
}
You post a second question (against the rules) and it was deleted but here is my quick answer for it. I hope it will help you and give you more sense how PS works:
$InputFile = "C:\temp\test\New folder (3)\File1.txt"
# get file content
$a=Get-Content $InputFile
# loop for every line in range 2 to last but one
for ($i=1; $i -lt ($a.count-1); $i++)
{
#geting string part between & and / , and construct output file name
$OutFile = "$(Split-Path $InputFile)\$(($a[$i] -split '/')[0] -replace '&','').txt"
$a[0]| Out-File $OutFile #creating output file and write first line in it
$a[$i]| Out-File $OutFile -Append #write info line
$a[-1]| Out-File $OutFile -Append #write last line
}
Something like this?
$i=0
gci -path "C:\temp\ExplodeDir" -file | %{ (get-content -path $_.FullName -Raw).Replace("`r`n`r`n", ";").Replace("`r`n", "~").Split(";") | %{if ($_ -like "*Start*") {$i++; ($_ -split "~") | out-file "C:\temp\ResultFile\File$i.txt" }} }

Powershell: addin line into the .txt file

I have a text (.txt) file with following content:
Car1
Car2
Car3
Car4
Car5
For changing Car1 for random text I used this script:
Get-ChildItem "C:\Users\boris.magdic\Desktop\q" -Filter *.TXT |
Foreach-Object{
$content = Get-Content $_.FullName
$content | ForEach-Object { $_ -replace "Car1", "random_text" } | Set-Content $_.FullName
}
This is working ok, but now I want to add one text line under Car2 in my text file.
How can I do that?
Just chain another -replace and use a new line!
Get-ChildItem "C:\Users\boris.magdic\Desktop\q" -Filter *.TXT |
Foreach-Object{
$file = $_.FullName
$content = Get-Content $file
$content | ForEach-Object { $_ -replace "Car1", "random_text" -replace "(Car2)","`$1`r`nOtherText" } | Set-Content $file
}
First thing is that | Set-Content $_.FullName would not work since the file object does not exist in that pipe. So one simple this to do it save the variable for use later in the pipe. You can also use the ForEach($file in (Get-ChildItem....)) construct.
The specific change to get what you want is the second -replace. We place what you want to match in brackets to that we can reference it in the replacement string with $1. We use a backtick to ensure PowerShell does not treat it as a variable.
We can remove some redundancy as well since -replace will work against the strings of file as a whole
Get-ChildItem "c:\temp" -Filter *.TXT |
Foreach-Object{
$file = $_.FullName
(Get-Content $file) -replace "Car1", "random_text" -replace "(Car2)","`$1`r`nOtherText" | Set-Content $file
}
While this does work with your sample text I want to point out that more complicated strings might require more finesse to ensure you make the correct changed and that the replacements we are using are regex based and do not need to be for this specific example.
.Replace()
So if you were just doing simple replacements then we can update your original logic.
Foreach-Object{
$file = $_.FullName
$content = Get-Content $_.FullName
$content | ForEach-Object { $_.replace("Car1", "random_text").replace("Car2","Car2`r`nOtherText")} | Set-Content $file
}
So that is just simple text replacement chained using the string method .Replace()