PowerShell Write-Host Secrets: Why String Concatenation (+) and Newlines Fail
Understanding the "Why": PowerShell's Dual Parsing Modes
If you come from languages like C#, Java, or JavaScript, using the + operator to concatenate strings feels like second nature. However, in PowerShell, doing this inside a cmdlet call like Write-Host often leads to unexpected results, such as literal + signs appearing in your console output.
This behavior is caused by two fundamental PowerShell concepts: Parsing Modes and Variable Scopes. Let's break down exactly why your code is behaving this way and how to write it cleanly and professionally.
1. The Scope Issue: Why $this.NewLine is Empty
In your script, you defined a variable: [String] $NewLine = [Environment]::NewLine. However, in your Write-Host statements, you referenced $this.NewLine.
In PowerShell, $this is an automatic variable reserved for specific contexts, such as class methods or custom script blocks (like in Register-ObjectEvent or Add-Member). Outside of these special scopes, $this is $null. Therefore, $this.NewLine evaluates to nothing, which is why your newlines are not rendering.
The Fix: Reference your variable directly as $NewLine, or use the .NET class directly inside an expression: $([Environment]::NewLine).
2. Argument Mode vs. Expression Mode (The + Operator Mystery)
PowerShell operates in two parsing modes depending on what it encounters:
- Expression Mode: Used for mathematical operations, variable assignments, and string manipulation. Here,
+acts as a concatenation operator. - Argument Mode: Used when calling commands or cmdlets (like
Write-Host). In this mode, PowerShell treats values as command-line arguments. Spaces separate arguments, and special characters like+are treated as literal strings.
When you write:
Write-Host "3" + "4"PowerShell parses this in Argument Mode. It interprets this as passing three separate string arguments to Write-Host: "3", "+", and "4". By default, Write-Host outputs its arguments separated by spaces, which is why you see 3 + 4 in your console.
3. Line Continuation and the Backtick (`)
In Case 3, you omitted the backtick after the + sign at the end of the line:
Write-Host `
"6, $( $this.NewLine )" +
"7, $( $this.NewLine )" +
"8. $( $this.NewLine ) $( $this.NewLine )"When a line ends with an operator like +, PowerShell's parser assumes the statement is incomplete and implicitly continues onto the next line. However, because it is still parsing arguments for the Write-Host cmdlet, it continues to treat those + symbols as literal arguments, leading to highly inconsistent output.
How to Write This Cleanly (The Solutions)
You don't have to "dumb down" your code to get the desired output. Here are the best, most idiomatic ways to handle multi-line console output in PowerShell.
Solution A: Force Expression Mode with Parentheses
If you want to use string concatenation, you must wrap the entire expression in parentheses. This forces PowerShell into Expression Mode before passing the final, concatenated string to Write-Host:
Write-Host ("0, $NewLine" +
"1, $NewLine" +
"2. $NewLine$NewLine")Solution B: Use Here-Strings (Recommended)
For multi-line text blocks, the most elegant solution in PowerShell is a Here-String. It preserves formatting, newlines, and variables without needing concatenation operators or line continuation backticks:
$multiLineText = @"
0,
1,
2.
"@
Write-Host $multiLineTextSolution C: Use Double-Quoted Multi-line Strings
PowerShell naturally supports multi-line strings within standard double quotes. You can simply hit Enter inside the string:
Write-Host "0,
1,
2.
"Solution D: Use the Native Newline Character (`n)
Instead of relying on [Environment]::NewLine, you can use PowerShell's native newline escape character, which is a backtick followed by 'n' (`n), inside double-quoted strings:
Write-Host "0,`n1,`n2.`n`n"