How .Replace() and -replace differ

There are two ways of replacing text in a string: the Replace() method, and the –replace operator. They work fundamentally different.

Replace() is case-sensitive and replaces text with new text:

PS> 'Hello World.'.Replace('o', '0')
Hell0 W0rld

PS> 'Hello World.'.Replace('ell','oo')
Hooo World

The -replace operator is by default case-insensitive (use -creplace if you want case sensitivity). It accepts a regular expression, and that is what most people miss:

PS> 'Hello World.' -replace 'ell', 'oo'
Hooo World.

PS> 'Hello World.' -replace '.', '!'

The second outcome surprises those that don’t know about regular expressions. If you want -replace to replace static text, make sure you escape your text:

PS> 'Hello World.' -replace [Regex]::Escape('.'), '!'
Hello World!

Twitter This Tip! ReTweet this Tip!

HTML Encoding Advanced

The static .NET method HtmlEncode does a good job encoding the usual character codes but fails with many special characters. To encode all characters correctly, here is a function called ConvertTo-EncodedHtml:

function ConvertTo-EncodedHTML($HtmlText)
  $chars = [Web.HttpUtility]::HtmlEncode($HtmlText).ToCharArray()
  $txt = New-Object System.Text.StringBuilder
  $null = . {
      foreach($c in $chars)
        if ([int]$c -gt 127) 
          $txt.Append("&#" + [int]$c + ";")
   return $txt.ToString()

This function checks all characters with ASCII code greater than 127 and converts these characters to encoded versions:

PS> Convert-EncodedHTML -HtmlText "A – s ‘Test’"
A – s  ‘Test’

Twitter This Tip! ReTweet this Tip!

HTML Encoding

There is a static .NET method that you can use to HTML-encode text, for example if you want the text to display correctly in HTML output:

PS>  [System.Web.HttpUtility]::HtmlEncode('Österreich heißt so.')
Österreich heißt so.

Twitter This Tip! ReTweet this Tip!

Bulk Printing Word Documents

This line finds all Word documents in your profile:

Get-ChildItem -Path $home -Filter *.doc* -Recurse 

If you’d like, you can easily print them all. Here is how:

Get-ChildItem -Path $home -Filter *.doc* -Recurse |
  ForEach-Object {
    Start-Process -FilePath $_.FullName -Verb Print -Wait

The most important part of this is the –Wait parameter: if you omit it, PowerShell would try and print all documents in parallel, launching many instances of Word at the same time. This can easily exhaust your system resources. With -Wait, PowerShell waits for Word to end a print before launching the next.

Twitter This Tip! ReTweet this Tip!

Downloading Videos From German Media Databases

In Germany, there are publicly available media databases with most of the TV content broadcasted by public stations. It just takes very little PowerShell code to extract the JSON data, display the TV shows in a list, and let you select some for download.

Note however that the JSON file with the download URLs is quite large, so it may take a moment for the video list to appear.

#requires -Version 3.0

# here is the list of download URLs - get it and 
# convert the JSON format
$url = ''
$web = Invoke-WebRequest -Uri $url -UseBasicParsing 
$videos = $web.Content | ConvertFrom-Json 

# get all videos, create a nice title to display,
# and attach the original data to each entry
$videos |
ForEach-Object {
  $title = '{0} - {1}' -f $_[2], $_[5]
  $title | Add-Member -MemberType NoteProperty -Name Data -Value $_ -PassThru
} |
Sort-Object |
Out-GridView -Title 'Video' -OutputMode Multiple |
ForEach-Object {
  # get the actual download info from the selected videos
  # and do the download
  $url = $_.Data[6]
  $filename = Split-Path -Path $url -Leaf
  # videos are saved into your TEMP folder unless you
  # specify a different folder below
  $filepath = Join-Path -Path $env:temp -ChildPath $filename
  Invoke-WebRequest -Uri $url -OutFile $filepath -UseBasicParsing
  Invoke-Item -Path $filepath

Twitter This Tip! ReTweet this Tip!

Translating Error Records

Whenever PowerShell records an error, it wraps it in an Error Record object. Here is a function that takes such an error record and extracts the useful information:

#requires -Version 3.0
function Get-ErrorDetail
    if ($e -is [Management.Automation.ErrorRecord])
        Reason    = $e.CategoryInfo.Reason
        Exception = $e.Exception.Message
        Target    = $e.CategoryInfo.TargetName
        Script    = $e.InvocationInfo.ScriptName
        Line      = $e.InvocationInfo.ScriptLineNumber
        Column    = $e.InvocationInfo.OffsetInLine
        Datum     = Get-Date
        User      = $env:USERNAME

So if you’d like to know what your latest errors were, try this:

PS C:> $error | Get-ErrorDetail | Out-GridView

PS C:>

Or, you can now easily ask a cmdlet to cache its errors, and evaluate them later. This example recursively searches the Windows folder for PowerShell scripts. You get the results, plus you get detailed information about any error that occurred while searching:

$files = Get-ChildItem -Path c:Windows -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable myErrors

$myErrors| Get-ErrorDetail | Out-GridView

Twitter This Tip! ReTweet this Tip!