Replace new lines in CLXML file - powershell

After generating a CLXML file:
[string]$myString = 'foobar' | Export-Clixml -Path C:\Files\test.clxml
I'm trying to remove line breaks after the right close anchor >. I have tried:
(Get-Content C:\Files\test.clxml) -replace "`n", "" | Set-Content C:\Files\test.clxml
Also tried using -replace r but this strips out r characters from the file.
What am I doing wrong?

Get-Content returns an array holding each single line (not containing any line feeds).
Set-Content writes your array of lines to a single file separating them with line feeds.
Meaning you should do the following to get what you want:
(Get-Content C:\Files\test.clxml) -join "" | Set-Content C:\Files\test.clxml

Your issue is that in your test there are no newlines to replace. Get-Content is returning a string array that is seen as having newlines on screen when rendered. To actually get them inside the string to be manipulated try one of these.
(Get-Content C:\Files\test.clxml -Raw) -replace "`n" | Set-Content C:\Files\test.clxml
(Get-Content C:\Files\test.clxml | Out-String) -replace "`n" | Set-Content C:\Files\test.clxml
The latter would be needed if your have PS Version 2.0

Related

Replacing/inserting newlines using Powershell

(I have read the other threads with similar names...)
I'm new to PowerShell. I am trying to understand how to find and replace newlines. For example, find double newlines and replace them with a single or vice versa.
I have a test document that was created using Notepad:
The quick brown fox jumped over the lazy dog
The quick brown fox jumped over the lazy dog
The quick brown fox jumped over the lazy dog
The quick brown fox jumped over the lazy dog
I am working in the PowerShell ISE for testing/learning.
When I run the following command (attempting to replace one newline with two):
((Get-Content -path $filename -raw) -replace '`n','`n`n') | Set-Content -path $filename
Get-Content -path $filename -raw
The output is unchanged. So I tried the following and it remained unchanged.
((Get-Content -path $filename -raw) -replace '`r`n','`r`n`r`n') | Set-Content -path $filename
So, knowing that PowerShell uses a back-tick rather than a backslash, but out of frustration, I tried the following command:
((Get-Content -path $filename -raw) -replace '\n','\n\n') | Set-Content -path $filename
And, surprisingly (to me), all of the newlines were replaced, but with the string literal '\n\n'. So it seems searching for a newline worked with a backslash but not with a back-tick. The replacement, unfortunately, was the literal string rather than the CRLF I need.
I'm stumped. But for what it's worth, I also tried the following and the string literal was again used for the replacement (i.e., in place of newlines, the document contained '`r`n').
((Get-Content -path $filename -raw) -replace '\n','`r`n') | Set-Content -path $filename
I have seen many posts where people were mistakenly using a backslash, but in my case it seems like a backslash is required for the search, and I don't understand what is required to replace a newline.
Thanks!
'`n' just matches the literal characters [backtick][n], which isn't what you want. You want to interpret those values. For that, you'll need to use double quotes i.e., '`n' should be "`n". According to Microsoft...
The special characters in PowerShell begin with the backtick
character, also known as the grave accent (ASCII 96). ... These
characters are case-sensitive. The escape character is only
interpreted when used within double quoted (") strings.
Use double quotes. You probably also want the -nonewline option to set-content, so that another `r`n doesn't get put at the end of the file.
PS> '`n'
`n
PS> "`n"
PS> (Get-Content -path $filename -raw) -replace "`n","`n`n" |
Set-Content -path $filename -nonewline
There are several ways of doing this. First one is to read the file as a single string and perform a regex -replace on it:
Remember that on Windows machines the Newline is a combination of two characters CR ('\r', ASCII value 13) and LF ('\n', ASCII value 10).
$filename = 'D:\test.txt'
# replace single newlines by a double newline
$replaceWith = '{0}{0}' -f [Environment]::NewLine
(Get-Content -Path $filename -Raw) -replace '\r?\n', $replaceWith | Set-Content -Path 'D:\test-to-double.txt' -Force
# replace double newlines by a single newline
$replaceWith = [Environment]::NewLine
(Get-Content -Path $filename -Raw) -replace '(\r?\n){2}', $replaceWith | Set-Content -Path 'D:\test-to-single.txt' -Force
Another way is to read in the file as string array (let PowerShell deal with single newlines):
# read the file as string array and join the elements with a double newline
$replaceWith = '{0}{0}' -f [Environment]::NewLine
(Get-Content -Path $filename) -join $replaceWith | Set-Content -Path 'D:\test-to-double.txt' -Force
# read the file as string array and join the elements with a single newline
$replaceWith = [Environment]::NewLine
(Get-Content -Path $filename) -join $replaceWith | Set-Content -Path 'D:\test-to-single.txt' -Force
The latter method is also extremely suited for removing empty or whitespace-only lines before you 'normalize' the newlines in the text:
In that case, just replace (Get-Content -Path $filename) with (Get-Content -Path $filename | Where-Object { $_ -match '\S' })

Powershell adds quotes to splitted CSV file

I'm trying to split a csv file by the first digits of the longitude column. Here is a sample:
X,Y,TYPE,SPEED,DirType,Direction
-44.058251,-19.945982,1,30,1,339
-54.629503,-20.497509,1,30,1,263
-54.646202,-20.496151,1,30,1,86
I have no powershell knowledge but I found some script online and it did what I wanted:
Import-Csv maparadar.csv
| Group-Object -Property {($_.x)[0..2] -join ""}
| Foreach-Object {$path=$_.name+".csv" ; $_.group
| Export-Csv -Path $path -NoTypeInformation}
With this I get output files like -44.csv, -54.csv
But it adds unwanted quotes to every field in the output file like:
"X","Y","TYPE","SPEED","DirType","Direction"
"-46.521991","-23.690235","1","30","1","169"
"-46.670774","-23.756021","1","30","1","281"
"-46.549897","-23.120720","1","30","1","99"
Is there any way I can export the csv without adding those quotes?
The following should provide the desired output:
Import-Csv maparadar.csv |
Group-Object -Property {($_.x)[0..2] -join ""} |
Foreach-Object { $path=$_.name+".csv" ; ($_.group |
ConvertTo-Csv -NoTypeInformation) -Replace '"' |
Set-Content -Path $path }
Explanation:
We replaced your Export-Csv with ConvertTo-Csv, which provides the CSV output to the console/pipeline rather than outputting to the file. Those CSV formatted outputs are sent through the -Replace operator to replace the literal " characters. Finally the formatted output is sent to the desired file using Set-Content -Path $path.

Why does this code only output lines that I made a replacement on?

I wrote this code to test out text manipulation. For each line read from my text file I replace tabs/returns/spaces, then I check if the line contains the carachters 'SAAS' and remove an A. I then write the content to an new file.
The issue is that the new file contains only lines that I made a replacement on and deletes any other lines of text from the orinal file when writing to the new file.
$Text = Get-Content -Path C:\Desktop\Phones\Phones_1.txt |
ForEach-Object {($_ -replace '\n','')} |
ForEach-Object {($_ -replace '\r','')} |
ForEach-Object {($_ -replace '\s','')} |
ForEach-Object {IF($_ | Select-String -Pattern 'SAAS'){$_ -replace 'SAAS','SAS'}}
$Text | Out-File 'C:\Desktop\Phones\phone2.txt'
Any help is appriciated.
It probably has to do with your Select-String function, which I don't believe needs to be there. Also, you can chain together replace statements greatly reducing the need to keep piping your code. I don't think it causes any issues, but you don't need to wrap your ForEach-Object blocks in braces either. Here's what that would look like:
$Text = Get-Content -Path C:\Desktop\Phones\Phones_1.txt |
ForEach-Object { $_ -replace '\n','' -replace '\r','' -replace '\s','' -replace 'SAAS','SAS' }
$Text | Out-File 'C:\Desktop\Phones\phone2.txt'
As $Text contains an array of single lines, replacing \r,\n is pretty useless.
You should provide an example of your input and expected output by editing your question.
Using a RegularExpression with lookarounds
(Get-Content .\Phones_1.txt -raw) -replace '\r|\n|\s|(?<=SA)A(?=S)'|Set-Content Phone2.txt
Yields this output from your above questions complete text:
Iwrotethiscodetotestouttextmanipulation.ForeachlinereadfrommytextfileIreplacetabs/returns/spaces,thenIcheckifthelinecontainsthecarachters'SAS'andremoveanA.Ithenwritethecontenttoannewfile.TheissueisthatthenewfilecontainsonlylinesthatImadeareplacementonanddeletesanyotherlinesoftextfromtheorinalfilewhenwritingtothenewfile.$Text=Get-Content-PathC:\Desktop\Phones\Phones_1.txt|ForEach-Object{($-replace'\n','')}|ForEach-Object{($-replace'\r','')}|ForEach-Object{($-replace'\s','')}|ForEach-Object{IF($|Select-String-Pattern'SAS'){$_-replace'SAS','SAS'}}$Text|Out-File'C:\Desktop\Phones\phone2.txt'Anyhelpisappriciated.

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
}

Powershell script for going into texts files within a directory and replacing characters

Morning all,
I'm trying to work out how to go into a number of text files within a directory, and replace the characters with the following:
'BS' = '\'
'FS' = '/'
'CO' = ':'
What I managed to get to so far is:
(get-content C:\users\x\desktop\info\*.txt) | foreach-object {$_ -replace "bs", "\"} | set-content C:\Users\x\desktop\info\*.txt
I have got 6 text files, all with a line of text in them, the script above copies the line of text into all the text files. So what I end up with is 6 text files, each with 6 lines of text, I need 6 text files with 1 line of original text.
If that makes sense, does anyone have any pointers on this?
Some other example, should do the same trick :)
$fileName = Get-ChildItem "C:\users\x\desktop\info\*.txt" -Recurse
$filename | %{
(gc $_) -replace "BS","\" -replace "FS","/" -replace "CO",":" |Set-Content $_.fullname
}
This should do the trick:
Get-ChildItem C:\users\x\desktop\info\*.txt | ForEach-Object {(Get-Content $_.PSPath) | Foreach-Object {$_ -replace "bs", "\" -replace "fs", "/" -replace "co", ":"} | Set-Content $_.PSPath}
The reason yours wasn't acting as you expected it to, is because you were literally taking all the contents out of all files using get-content. This acts as a string concatenation of all text in all files.
You first have to get a list of files, then pipe that into a foreach to get the contents per file, to then replace what you want replaced.