PowerShell Here-String: Multiline Text Made Easy

SQL queries in scripts, HTML email bodies, JSON payloads, multi-line error messages — embedding any of these as a plain string means quoting nightmares, awkward concatenation, and code that’s hard to read. PowerShell here-string syntax lets you define a block of text that spans multiple lines with all the whitespace and special characters preserved. This post covers both flavors — literal and expanding — with practical examples for the scenarios where here-strings make the biggest difference.
Single-Quoted Here-String Syntax
A single-quoted here-string starts with @' on its own line and ends with '@ at the beginning of a line (column zero — no leading whitespace). Everything inside is treated as a literal string — no variable expansion, no escape processing.
$literal = @'
SELECT *
FROM Users
WHERE Department = 'Engineering'
AND Active = 1
ORDER BY LastName
'@
Write-Output $literal
SELECT *
FROM Users
WHERE Department = 'Engineering'
AND Active = 1
ORDER BY LastName
Use single-quoted here-strings when you don’t need variable expansion — SQL queries, raw JSON templates, regex patterns with backslashes, and any content where you want literal text preserved exactly.
Double-Quoted Here-String with Variables
A double-quoted here-string starts with @" and ends with "@ at column zero. Inside, PowerShell expands variables and expressions — exactly like a regular double-quoted string but across multiple lines.
$computerName = $env:COMPUTERNAME
$currentDate = Get-Date -Format "yyyy-MM-dd"
$freeGB = [math]::Round((Get-PSDrive C).Free / 1GB, 1)
$report = @"
=== Daily System Report ===
Computer : $computerName
Date : $currentDate
C: Free : $freeGB GB
Generated : $(Get-Date -Format 'HH:mm:ss')
"@
Write-Output $report
=== Daily System Report ===
Computer : WORKSTATION
Date : 2026-05-04
C: Free : 98.4 GB
Generated : 08:22:11
Building HTML Email Templates
Here-strings are the cleanest way to build HTML bodies for email alerts. Combine a double-quoted here-string with Send-MailMessage -BodyAsHtml for formatted reports.
$status = "Completed"
$rowCount = 1482
$duration = "00:03:22"
$server = $env:COMPUTERNAME
$htmlBody = @"
<html><body style='font-family:Arial'>
<h2>Nightly ETL Job Report</h2>
<table border='1' cellpadding='5' style='border-collapse:collapse'>
<tr><td><b>Status</b></td><td>$status</td></tr>
<tr><td><b>Records Processed</b></td><td>$rowCount</td></tr>
<tr><td><b>Duration</b></td><td>$duration</td></tr>
<tr><td><b>Server</b></td><td>$server</td></tr>
</table>
</body></html>
"@
Embedding SQL Queries
SQL scripts that span multiple lines are unreadable as concatenated strings. A single-quoted here-string lets you write the SQL exactly as you would in SQL Server Management Studio.
$query = @'
SELECT
u.UserName,
u.Email,
d.DepartmentName,
COUNT(l.LoginId) AS LoginCount
FROM dbo.Users u
JOIN dbo.Departments d ON u.DeptId = d.DeptId
LEFT JOIN dbo.Logins l ON u.UserId = l.UserId
AND l.LoginDate >= DATEADD(DAY, -30, GETDATE())
WHERE u.IsActive = 1
GROUP BY u.UserName, u.Email, d.DepartmentName
ORDER BY LoginCount DESC
'@
# Execute via SqlClient or Invoke-Sqlcmd
# Invoke-Sqlcmd -ServerInstance "SQL01" -Database "AppDB" -Query $query
Here-String Gotchas with Closing Marker
The closing marker ('@ or "@) must be at column zero — the very beginning of the line with no spaces or tabs before it. This is the source of nearly every here-string parsing error. PowerShell throws a “The string is missing the terminator” error if the closing marker is indented.
# CORRECT — closing marker at column zero
$text = @'
Line one
Line two
'@
# WRONG — closing marker is indented (common mistake in indented code blocks)
# $text = @'
# Line one
# Line two
# '@ <-- this '@' at column 4 will cause a parsing error
Here-String vs String Concatenation
Compare readability when building a multiline string with and without here-strings:
# Painful string concatenation
$body = "Dear $name,`r`n`r`n" +
"Your password will expire in $days days.`r`n" +
"Please change it at: https://portal.example.com`r`n`r`n" +
"IT Support Team"
# Clean here-string equivalent
$body = @"
Dear $name,
Your password will expire in $days days.
Please change it at: https://portal.example.com
IT Support Team
"@
Here-strings preserve literal newlines, tabs, and special characters without any escape sequences.
Common Errors and Fixes
- Closing @’ must be at column 0: Indenting the closing marker even by one space or one tab causes a “missing terminator” parse error. If you’re inside a function or conditional block and habit makes you indent, the here-string will fail. Use the editor’s “Go to column 0” feature or simply ensure there is nothing before the
'@or"@on its line. - Single-quoted here-string does not expand variables: Inside
@' '@,$variablesare printed literally as$variablename. If your here-string output shows literal dollar signs instead of variable values, you’re using single quotes when you need double quotes: switch to@" "$syntax for the expanding variant.
Related Cmdlets / See Also
Wrapping Up
Here-strings make multi-line text in PowerShell scripts readable and maintainable — no escape characters, no concatenation, just text. As a next step, find any script where you’ve built an HTML email body or SQL query through string concatenation and convert it to a here-string. The improvement in readability will be immediate.


