How to Copy PowerShell Here-Strings Without Breakage
PowerShell has two cmdlets for the clipboard: Set-Clipboard (write) and Get-Clipboard (read). They look simple. They are not. The two failure modes that catch developers are the trailing newline that Set-Clipboard adds to multi-line input, and the CRLF line endings that PowerShell uses on Windows but that other tools (bash, Python on Linux, JSON parsers in strict mode) do not expect. Neither failure mode is documented prominently. Both produce bugs that are hard to trace because the clipboard contents look correct until they are piped into something that cares about whitespace.
This guide covers PowerShell here-strings (the cleanest way to put a multi-line block on the clipboard) and the gotchas of Set-Clipboard and Get-Clipboard. It is written for developers using PowerShell on Windows 10 and 11. For neighbouring topics, see copying from Windows Terminal without garbled codes, JSON payloads: keep them as files, not clips, and developer copy-paste hygiene.
What a PowerShell here-string is
A here-string is a multi-line string literal in PowerShell. It starts with @" (or @') on its own line and ends with "@ (or '@) at the start of a line. Everything in between is the string content, including newlines, quotes, and special characters.
$block = @"
Line 1
Line 2 with "quotes"
Line 3 with `$(variable interpolation)
"@
Key points:
@"must be the last thing on its line. Nothing can follow it, not even a comment."@must be the first thing on its line. No leading whitespace, no trailing characters.@"..."@is an expanding here-string. Variables and subexpressions are interpolated.@'...'@is a literal here-string. No interpolation; everything is taken literally.- The closing
"@is not included in the string. The string ends at the newline before the closing"@.
Here-strings are the cleanest way to put a multi-line block on the clipboard, because they preserve the line structure exactly and avoid the quoting issues that single-line string concatenation introduces.
Putting a here-string on the clipboard
The pattern is straightforward:
$snippet = @"
function Get-Greeting {
param([string]$Name = "World")
"Hello, $Name!"
}
"@
Set-Clipboard -Value $snippet
After running this, the snippet is on the clipboard. Pasting into VS Code, Slack, or a file produces the multi-line block correctly.
For a here-string that contains PowerShell variables that should be interpolated, use @"..."@. For a here-string that contains literal text (including PowerShell variable syntax that should not be interpolated), use @'...'@. The literal form is safer when the content is code in another language that uses $ for variables.
The trailing newline gotcha
Set-Clipboard adds a trailing newline to multi-line input in some PowerShell versions. The exact behaviour has shifted across versions and is not consistently documented. The symptom is that pasting into a text editor shows an extra blank line at the end, or piping to a command that counts lines returns one more line than expected.
To verify whether your PowerShell version adds the trailing newline:
"hello" | Set-Clipboard
(Get-Clipboard).Length # Should be 5; if it's 6, a newline was added
If a trailing newline is being added and it matters for the target, strip it:
$snippet = $snippet -replace "\r?\nquot;
Set-Clipboard -Value $snippet
For most paste targets (chat, code editors, ticket descriptions), the trailing newline does not matter. For targets that parse the clipboard content (a JSON parser, a YAML parser, a hash calculator), it does.
The CRLF gotcha
PowerShell on Windows uses CRLF (\r\n) line endings for Set-Clipboard and Get-Clipboard. This is correct for Windows tools (Notepad, Word, Outlook) but causes failures when the clipboard content is piped into tools that expect LF (\n):
- bash in WSL receives the CRLF and treats the
\ras part of the last line.echo $(Get-Clipboard)in WSL with a multi-line clipboard will have stray\rcharacters that break parsing. - Python in WSL receives the CRLF and may include the
\rin strings read from stdin. - JSON parsers in strict mode reject
\rinside strings; the clipboard content fails to parse. - YAML parsers in strict mode may reject
\rinside block scalars.
The fix is to convert CRLF to LF when reading from the clipboard in a context that expects Unix line endings:
# PowerShell: read clipboard, convert CRLF to LF
$clean = (Get-Clipboard) -replace "`r`n", "`n"
# bash: read Windows clipboard, strip \r
content=$(powershell.exe -Command Get-Clipboard | tr -d '\r')
The tr -d '\r' pattern is the standard idiom in WSL; see WSL and Windows clipboard: what crosses the boundary for more.
Reading the clipboard
Get-Clipboard reads the current clipboard content as a string. For multi-line content, the result is a single string with embedded newlines. For an array of lines, use -Split:
$lines = (Get-Clipboard) -Split "`r`n"
This splits on CRLF and returns an array of lines. For LF-only content (rare on Windows), split on ` "n" `` instead.
For raw clipboard content (including any formatting), Get-Clipboard -Raw returns the entire clipboard as a single string without splitting on newlines. This is useful when the content is a JSON or YAML blob that should be preserved exactly.
Set-Clipboard versus clip.exe
PowerShell has two ways to put text on the clipboard:
Set-Clipboard -Value $text— the PowerShell cmdlet. Adds the trailing newline in some versions; uses CRLF.$text | clip.exe— pipes to the Windowsclip.execommand. Does not add a trailing newline; uses CRLF.
The behaviour difference matters. For a single-line string, both produce the same result. For a multi-line string, Set-Clipboard may add a trailing newline and clip.exe may not. For a string that ends with a newline already, Set-Clipboard may add a second newline.
The practical rule: use Set-Clipboard for PowerShell-internal workflows (the cmdlet is more discoverable and pipeline-friendly); use clip.exe when the trailing newline matters and you want to control it explicitly.
Common patterns
Put a code snippet on the clipboard
$snippet = @'
function Get-Hash {
param([string]$Path)
Get-FileHash -Path $Path -Algorithm SHA256
}
'@
Set-Clipboard -Value $snippet
Read a JSON blob from the clipboard and pretty-print it
$json = Get-Clipboard
$obj = $json | ConvertFrom-Json
$obj | ConvertTo-Json -Depth 10 | Set-Clipboard
This is useful for reformatting minified JSON copied from a browser's network panel. See JSON payloads: keep them as files, not clips for the limits of this pattern.
Copy a file's contents to the clipboard
Get-Content -Path .\config.json -Raw | Set-Clipboard
For files larger than a few KB, prefer sending the file path rather than the contents. See how to copy a file path that works in the terminal for the path-copying pattern.
Copy command output to the clipboard
Get-Process | Select-Object -First 10 | Format-Table | Out-String | Set-Clipboard
The Out-String is necessary because Set-Clipboard expects a string, not a process object. Without Out-String, PowerShell stringifies the object using its default formatter, which may not match the table layout.
A note on cross-platform PowerShell
PowerShell 7 (the open-source, cross-platform version) runs on Linux and macOS as well as Windows. The clipboard cmdlets behave differently on non-Windows platforms:
Set-ClipboardandGet-Clipboardon Linux rely onxcliporxselbeing installed. If neither is present, the cmdlets fail silently or throw an error depending on the version.Set-ClipboardandGet-Clipboardon macOS rely onpbcopyandpbpaste, which are always present on macOS.- The CRLF line-ending gotcha does not apply on Linux and macOS, which use LF natively.
Set-Clipboardon Linux writes LF;Get-Clipboardon Linux reads whatever is on the clipboard.
For developers using PowerShell 7 cross-platform, the practical rule is: test clipboard behaviour on each target platform, and do not assume Windows-specific behaviour. The here-string syntax is portable; the line-ending behaviour is not.
Common pitfalls summary
A short list of the pitfalls covered above, for quick reference:
@"must be the last thing on its line;"@must be the first thing on its line. No exceptions.Set-Clipboardmay add a trailing newline. Strip it with-replace "\r?\nquot;if it matters for the target.- PowerShell on Windows uses CRLF. Convert to LF with
-replace "\rn", "\n"for targets that expect Unix line endings. Get-Clipboardreturns a single string by default. Use-Split "\r\n"for an array of lines, or-Rawto preserve everything as one string.Set-Clipboardexpects a string. Pipe throughOut-Stringfirst if the source is objects.clip.exeis an alternative that does not add a trailing newline. Use it when the trailing newline matters.Get-Clipboardon non-Windows platforms requiresxclip/xsel(Linux) orpbcopy/pbpaste(macOS).
These seven pitfalls cover most of the failure modes developers encounter with PowerShell and the clipboard. Internalising them takes a few weeks of practice; forgetting them takes one bad paste.
Related reading
- JSON Payloads: Keep Them as Files, Not Clips
- API Keys on the Clipboard Are an Incident
- Best Clipboard Habits for Developers in 2026
- Clipboard Tools on Multi-Monitor Windows Setups
Sources
- Microsoft Learn — Set-Clipboard cmdlet — official documentation for
Set-Clipboard, including parameter reference and version notes - Microsoft Learn — Get-Clipboard cmdlet — official documentation for
Get-Clipboard, including the-Rawparameter - Microsoft Learn — About quoting rules — official documentation for here-strings, including the difference between
@"..."@(expanding) and@'...'@(literal) - Microsoft Learn — clip command — official documentation for
clip.exe, the Windows command-line alternative toSet-Clipboard - PowerShell GitHub — Issues on Set-Clipboard — the open-source PowerShell repository, where the trailing-newline behaviour and other clipboard quirks are tracked in issues
Deepender Yadav is a B.Tech Computer Science Engineering student and software developer interested in building practical software and open-source projects.
GitHub · LinkedInCopy. Stack. Drop.
Transform your clipboard into an interactive edge shelf. Stack, pin, and drag assets into any app with zero friction.
Download for Windows Get from Microsoft Store
How to Install Guide · First 10 Minutes Guide · Drag & Drop Guide · Edge-Drop vs Win+V · Support
Free · Lightweight · Privacy First