How to prevent trailing newline in PowerShell script?
Asked Answered
U

2

6

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:

Too many lines breaks

Ury answered 14/5, 2021 at 17:24 Comment(2)
Use something like (Get-ComputerInfo -Property $LST1 | Format-List | Out-String).Trim() | Add-Content -Path $path -NoNewlineHomemaker
That did it, THANK YOU!!!Ury
M
5

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.

Maltose answered 13/8, 2021 at 22:39 Comment(0)
C
0

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

Cowry answered 14/5, 2021 at 21:34 Comment(1)
That works (with CRLF, but not LF), but note that the enclosing $(...) is unnecessary (and, in general, can have side effects). A more concise (though perhaps conceptually more complex, regex-based) solution that works with both CRLF and LF-only newlines is: $YourVariableHere -replace '\r?\n\z'. '(?:\r?\n)+\z' would remove all trailing newlines; '(?:\r?\n){2}\z' would remove 2, for instance.Maltose

© 2022 - 2024 — McMap. All rights reserved.