Replace Vertical bar within a text file - powershell

I am trying to replace a | character within a text file. But I am not sure how to do it because the batch is not reading the |.
powershell -Command "(gc output.txt) -replace '|', ' ' | Out-File -encoding ASCII output.txt"
Which takes this input:
80853||OHNED|Mira
And outputs: 8 0 8 5 3 | | O H N E D | M i r a
Where I'd like this output 80853 OHNED Mira
Is there anyway within a batch to replace the | character?
Edit - While googling, I found out that the | character is called a vertical bar.

PowerShell's -replace operator is regex-based; since your intent is to replace all | characters verbatim, you must escape | as \|, given that | is a regex metacharacter (a character with special meaning in the context of a regex (regular expression)):
powershell -Command "(gc output.txt) -replace '\|', ' ' | Out-File -encoding ASCII output.txt"
In cases where escaping individual characters isn't an option or would be cumbersome - e.g. if you're given a search string that you want to treat literally, as a whole - use [regex]::Escape():
powershell -Command "(gc output.txt) -replace [regex]::Escape('|'), ' ' | Out-File -encoding ASCII output.txt"
Alternatively, in your simple case you could use the .Replace() string method, which invariably performs verbatim replacements and therefore does not require escaping:
powershell -Command "(gc output.txt).Replace('|', ' ') | Out-File -encoding ASCII output.txt"
Note:
Unlike PowerShell's operators, the [string] type's .Replace() method is case-sensitive, invariably so in Windows PowerShell, and by default in PowerShell (Core) 6+.
See also:
For general guidance on when to use PowerShell's -replace operator vs. the .NET [string] type's .Replace() method, see the bottom section of this answer.
For robustly escaping all metacharacters in a -replace search regex and/or in its replacement operand in order to treat one or both as verbatim strings, see this answer.

Edit : This can did the trick to replace the special char :
#echo off
powershell -Command "(gc input.txt -raw) -replace '([\^&<>\|\(\)!])', ' ' | Out-File output.txt"
start "" output.txt

Related

Powershell -Replace command and escaping characters

I need to replace some strings multiple text files. I am running into an issue with the following string though. I tried escaping with a backtick ` before any special characters, but no luck, or maybe the backtick isn't in the right place.
I want to replace
Signal\s+:\s+',''
with
Signal\s+:\s+','';if (!`$signal) {`$signal='n/a'}
This is the string in the command that i am having a problem finding --> Signal\s+:\s+',''
Here is the powershell command i am using..
Get-ChildItem "f:\temp\*.ps1" | ForEach-Object -Process {(Get-Content $_) -Replace "Signal\s+:\s+',''" , "Signal\s+:\s+','';if (!`$signal) {`$signal='n/a'}" | Set-Content $_}
thank you
i just needed to escape the \ in the replace text.. thats all
-Replace "Signal\\s\+:\\s\+',''"
thanks

How to prevent trailing newline in PowerShell script?

This code adds lines, even when using "-NoNewline"
$LST1="OsName","OsVersion","TimeZone","CsName"
$LST2="CsManufacturer","CsModel","CsSystemType","BiosBIOSVersion","BiosReleaseDate"
$MEM1 = (Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | Foreach {"{0:N2}" -f ([math]::round(($_.Sum / 1GB),2))})
$Pro1 = "systemname","DeviceID","numberOfCores","NumberOfLogicalProcessors"
Add-Content OutText.txt "OS Information:" -NoNewline
Get-ComputerInfo -Property $LST1 | Format-List | Out-File -Encoding ASCII -FilePath OutText.txt -Append
Add-Content OutText.txt "Hardware Information:" -NoNewline
Get-ComputerInfo -Property $LST2 | Format-List | Out-File -Encoding ASCII -FilePath OutText.txt -Append
Add-Content OutText.txt "RAM: $RAM1 GB" -NoNewline
Get-WmiObject -class win32_processor -Property $Pro1 | Select-Object -Property $Pro1 | Out-File -FilePath OutText.txt -Encoding ASCII -Append
Too many lines breaks:
Theo has provided the crucial pointer in a comment:
(Get-ComputerInfo -Property $LST1 | Format-List | Out-String).Trim() |
Add-Content -Path $path -NoNewline
Let me elaborate:
To prevent leading and trailing empty lines in the output of Format-List from showing up in a file via Out-File / >, use Out-String to create an in-memory string representation of the formatted output first,
which then allows you to apply .Trim() to the resulting multi-line string in order to remove leading and trailing lines (whitespace in general) from Out-String's output.
Since Out-String itself renders the formatting instructions output by Format-List, you can then use Set-Content or Add-Content to save / append the resulting string to a file.
The behavior of Out-String:
Out-String produces the same for-display representation that you get by default in the console - or via other Out-* cmdlets, notably Out-File / > - as a single, multi-line string by default.
While this representation may itself contain empty lines, as is typical, Out-String additionally appends a trailing newline, even though there's no good reason to do so, as discussed in GitHub issue #14444.
In cases where you want to remove this extraneous trailing newline only, you can use the following approach, via the -replace operator (the operation works with both Windows-style CRLF newlines (\r\n) and Unix-style LF-only ones (\n)):
(... | Out-String) -replace '\r?\n\z'
Or, less efficiently, using the -Stream switch to output lines individually and then re-join them with newlines without a trailing one ("`n" creates a LF-only newline, which PowerShell accepts interchangeably with CRLF newlines ("`r`n"):
(... | Out-String -Stream) -join "`n"
Out-String applied to output from external programs:
Out-String can also be used to capture the lines output by external programs as a single, multi-line string (by default, PowerShell captures output line by line, resulting in an array of strings when captured in a variable).
However, this use of Out-String is problematic:
There too the trailing newline that is appended can be a nuisance.
In Windows PowerShell there's an additional nuisance (which has since been corrected in PowerShell (Core) 7+): If you use a 2>&1 to merge stderr output into the success output stream, the first stderr line is formatted like a PowerShell error.
Run cmd /c 'echo yes & echo no >&2' 2>&1 | Out-String to see the problem.
The following idiom avoids both problems (... represents your external-program call):
$multiLineString = [string[]] (... 2>&1) -join "`n"
Note: The above uses a LF-only newline to join the array elements, which is usually sufficient. Use "`r`n" for CRLF newlines or [Environment]::NewLine for the OS-appropriate newline sequence.
Example:
The following cmd.exe CLI call outputs both a stdout line and a stderr line, with 2>&1 on the PowerShell side merging the two into the success output stream.
PS> [string[]] (cmd /c 'echo yes & echo no >&2' 2>&1) -join "`n" |
ForEach-Object { "[$_]" } # just to visualize the string boundaries
[yes
no ]
Note: The trailing space after no is owed to the unusual behavior of cmd.exe's built-in echo command: it includes the space before the >&2 redirection in its output.
I use the following to strip the Cr/Lf added by Out-String.
$YourVariableHere = $($YourVariableHere.Substring(0,($YourVariableHere.Length-2)))
You can adjust the number at the end if there is more than one Cr/Lf you want to remove.
HTH

Difficulty escaping quote character in powershell script (Azure Devops Yaml)

My azure piplines yaml script uses powershell to replace a placeholder string in a .CS file with the current date string. This is the line with the value to be replaced (20200101000000)
[assembly: MyCompany.Net.Attributes.BuildDateAttribute("20200101000000")]
This is the powershell step that does it
pwsh: (get-content -path $(versionFile)) | foreach-object {$_ -replace "20200101000000", (get-date -f 'yyyyMMddhhmmss')} | set-content -path $(versionFile)
displayName: 'Update time stamp file'
I want to alter this step to include the quote characters " around the search string and write them into the new output value along with the new date. But I cannot seem to make that happen.
I mistakenly tried just putting escaped quote characters \" in the search and replace strings. But I guess you cannot escape inside of a single-quoted string so it did not work
pwsh: (get-content -path $(versionFile)) | foreach-object {$_ -replace "\"20200101000000\"", (get-date -f '\"yyyyMMddhhmmss\"')} | set-content -path $(versionFile)
This was the error:
##[command]"C:\Program Files\PowerShell\7\pwsh.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\a\_temp\80625e52-1302-4e35-a799-223ab893bcf1.ps1'"
ParserError: D:\a\_temp\80625e52-1302-4e35-a799-223ab893bcf1.ps1:3
Line |
3 | … lyInfo.cs) | foreach-object {$_ -replace "\"20200101000000\"", (get-d …
| ~~~~~~~~~~~~~~~~~
| Unexpected token '20200101000000\""' in expression or statement.
##[error]PowerShell exited with code '1'.
I also tried to just using double quotes around the get-date part of the script so I could escape the quote characters but that doesn't seem to work either. I'm guessing that's a limitation of writing script this way.
Is there some other way to achieve what I want?
The escape character in Powershell is backtick (`), not backslash (\). Try e.g. "`"20200101000000`"".
You can use the Get-Date -UFormat instead to add arbitrary characters similar to the DateTime.ToString() function in .NET
'[Attrib("20200101000000")]' -replace '"20200101000000"', (get-date -UFormat '"%Y%m%d%H%M%S"')

Need to substitute \x0d\x0a to \x2c\x0d\x0a in a file using powershell

Need to replace \x0d\x0a with \x2c\x0d\x0a in a file.
I can do it relatively easy on Unix:
awk '(NR>1){gsub("\r$",",\r")}1' $file > "fixed_$file":
Need help with implementing this in PowerShell.
Thank you in advance.
Assuming that you're running this on Windows (where \r\n (CRLF) newlines are the default), the following command
is the equivalent of your awk command:
Get-Content $file | ForEach-Object {
if ($_.ReadCount -eq 1) { $_ } else { $_ -replace '$', ',' }
} | Set-Content "fixed_$file"
Caveat: The character encoding of the input file is not preserved, and
Set-Content uses a default, which you can override with -Encoding.
In Windows PowerShell, this default is the system's "ANSI" encoding, whereas in PowerShell Core it is BOM-less UTF-8.
Get-Content $file reads the input file line by line.
The ForEach-Object loop passes the 1st line ($_.ReadCount -eq 1) through as-is ($_), and appends , (which is what escape sequence \x2c in your awk command represents) to all others ($_ -replace '$', ',').
Note: $_ + ',' or "$_," are simpler alternatives for appending a comma; the regex-based -replace operator was used here to highlight the PowerShell feature that is similar to awk's gsub().
Set-Content then writes the resulting lines to the target file, terminating each with the platform-appropriate newline sequence, which on Windows is CRLF (\r\n).

How to properly escape quotes in powershell v2?

How do you properly escape quotes in powershell v2 (called from within a batch file)?
I have tried:
powershell -Command "(gc file1.txt) -join "`n" | Out-File file2.txt"
and
powershell -Command "(gc file1.txt) -join ""`n"" | Out-File file2.txt"
and
powershell -Command "(gc file1.txt) -join '"`n`" | Out-File file2.txt"
but they all fail.
Editor's note: The purpose of the command is to transform Windows CRLF line breaks to Unix LF-only ones, so as to create a file that will be processed on Linux.
From a batch file (cmd.exe), you must \-escape embedded " instances
(even though PowerShell-internally it is ` (the backtick) that serves as the escape character):
As wOxxOm points out in a comment on the question, in Windows PowerShell using """ to embed a single " is also an option.
However, given that most command-line utilities support \", \" is easier to remember. However, both """ and \" can break on the cmd.exe side, in which case "^"" (sic) is required ("" in PowerShell (Core) 7+).
powershell -Command "(gc file1.txt) -join \"`n\" | Set-Content -NoNewLine file2.txt"
Note:
Set-Content -NoNewline requires PSv5+.
Set-Content writes "ANSI"-encoded files by default (e.g., based on code page Windows-1252 on US-English systems); use the -Encoding parameter to change that.
Since you're only dealing with strings, Set-Content is preferable to Out-File, which is only needed if you have non-string objects that must have PowerShell's default formatting applied to them first.
Consider using powershell -NoProfile ... to suppress loading of PowerShell's profile files, both for faster execution and for a more predictable execution environement.
PSv2 solution:
Unfortunately, prior to PSv5, only the Write-Host cmdlet supports the -NoNewline parameter (introduced in v2), which is of no help here, so the .NET framework must be used:
powershell -Command "[IO.File]::WriteAllText(\"$PWD/file2.txt\", ((gc $PWD/file1.txt) -join \"`n\") + \"`n\")"
Note the need to use path prefix $PWD explicitly, because the .NET Framework's current directory typically differs from PowerShell's.
Also, the output file's encoding will be UTF-8, without a BOM, but you can pass a different encoding as the 3rd argument to [IO.File]::WriteAllText(), such as [System.Text.Encoding]::Default to match Set-Content's default behavior (as of Windows PowerShell v5.1).
Optional reading: platform-specific line breaks "`n" vs. "`r`n" vs. [Environment]::Newline
Implicit choice of newlines (line breaks):
when reading, PowerShell accepts LF-only (Unix-style) and CRLF (Windows-style) newlines (line breaks) interchangeably.
when writing (e.g., when sending an array of lines / objects to a file with > / Out-File / Set-Content), PowerShell uses the platform-appropriate newline sequence.
Note, however, that any newline sequences embedded in a given string input object are sent to the file as-is.
As for escape sequences / constants:
[Environment]::Newline contains the platform-appropriate newline.
"`n" is always just LF (\n)
as evidenced by "`n".Length returning 1 and [char] 10 -eq [char] "`n" returning $True (10 is the decimal Unicode/ASCII code point of LF).
The documentation isn't explicit about this: Get-Help about_Special_Characters mentions "new line" and "line break", without mentioning what specific character [sequence] that represents. (As mentioned, LF by itself is just as valid a line break as CRLF is in PowerShell).
Therefore, to create CRLF sequences, you must use "`r`n".
If you need to match newlines in either format, you can use regex '\r?\n', with operators such as -match, -replace, and -split
As for multi-line string literals in scripts (including here-documents):
They reflect their source file's newline style. That is, if your script uses CRLF newlines, so will the newlines embedded in the multi-line string.
Here's one way to do it from the PowerShell command line:
(Get-Content Input.txt -Raw) -replace "`r`n","`n" | Out-File Output.txt -Encoding ASCII -NoNewline
As others have noted this is a PowerShell v5 solution (-Raw appeared in v3, and -NoNewline appeared in v5).
Here's a PowerShell v2 version of the same thing:
$content = [IO.File]::ReadAllText("C:\Path\Input.txt") -replace "`r`n","`n"
[IO.File]::WriteAllText("C:\Path\Output.txt", $content)
(The paths are needed because the .NET methods don't use PowerShell's "current location".)