I like the intention behind @Leo & @rojo's answers but splitting lines is inappropriate for massive amounts of text, and a state machine (or better yet, an easily programmable one..like regex) will be way more efficient.
On top of writing my own complex solution, I made its complexity warranted as it maintains newlines in the original string and even permits you to force a line break on certain characters
Wrap -Length 30 -Force '.' "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
Here I try to break around 30 characters, finding the nearest whitespace, but also forcing a break on full stops, ignoring periods within words, and making sure not to break lines that would have already broken due to a period.
Lorem Ipsum is simply dummy
text of the printing and
typesetting industry.
Lorem Ipsum has been the
industry's standard dummy text
ever since the 1500s, when an
unknown printer took a galley
of type and scrambled it to
make a type specimen book.
It has survived not only five
centuries, but also the leap
into electronic typesetting,
remaining essentially
unchanged.
It was popularised in the
1960s with the release of
Letraset sheets containing
Lorem Ipsum passages, and more
recently with desktop
publishing software like Aldus
PageMaker including versions
of Lorem Ipsum.
Here's the function itself, but note you'll need the stuff at the bottom of this answer to generate the regexes (I put this up higher so you can read the parameters)
Function Wrap {
Param (
[int]$Length=80,
[int]$Step=5,
[char[]]$Force,
[parameter(Position=0)][string]$Text
)
$key="$Length $Step $Force"
$wrap=$_WRAP[$key]
if (!$wrap) {
$wrap=$_WRAP[$key]=_Wrap `
-Length $Length `
-Step $Step `
-Force ($Force -join '') `
| Concat -Join '|' -Wrap '(',')(?:[^\n\r\S])+'
}
return $Text -replace $wrap,$_WRAP['']
}
Here's something a little more meaningful to show its versitility.
Dont worry about the rest of the script, it's colours/backgrounds, emailing, or GridView.
It's basically doing a bunch of pings, tcp checks, and http requests and putting the error messages into an info
property:
$_.info=(
$style.bf.yellow, `
(Wrap -Length 55 -Force ':.' $_.info), `
$colour `
| Concat)

You will need these following utility functions defined above Wrap
Function Concat {
Param ([switch]$Newlines, $Wrap, $Begin='', $End='', $Join='')
Begin {
if ($Newlines) {
$Join=[System.Environment]::NewLine
}
$output=[System.Text.StringBuilder]::new()
$deliniate=$False
if (!$Wrap) {
$output.Append($Begin) | Out-Null
}
elseif ($Wrap -is [string]) {
$output.Append(($End=$Wrap)) | Out-Null
}
else {
$output.Append($Wrap[0]) | Out-Null
$End=$Wrap[1]
}
}
Process {
if (!($_=[string]$_).length) {
}
elseif ($deliniate) {
$output.Append($deliniate) | Out-Null
$output.Append($_) | Out-Null
}
else {
$deliniate=$Join
$output.Append($_) | Out-Null
}
}
End {
$output.Append($End).ToString()
}
}
$_WRAP=@{''="`$1$([System.Environment]::NewLine)"}
Function _Wrap {
Param ($Length, $Step, $Force)
$wrap=$Force -join '' -replace '\\|]|-','\$0'
$chars="^\n\r$wrap"
$preExtra="[$chars\S]*"
$postExtra="[^\s$wrap]"
$chars="[$chars]"
$postChars="$preExtra$postExtra"
if ($wrap) {
$wrap="[$wrap]"
$wrap
$wrap="$wrap(?=\S)"
$chars="$chars|$wrap"
$postChars="$postChars|$preExtra$wrap"
}
for (
($extra=0),($next=$NULL),($prev=$NULL);
($next=$Length - $Step) -gt 0 -and ($prev=$extra + $Step);
($Length=$next),($extra=$prev)
) {
"(?:$chars){$next,$Length}(?=(?:$postChars){$extra,$prev})"
}
}