Installing MSI on Remote System

Here is some code that may or may not work for you. It requires that you have Admin access to a remote system.

$ComputerName = 'NameOfMachineToInstall'
$TargetPathMSI = '\softwareserverproductpackage.msi'

$class = [wmiclass]"\$ComputerNameROOTcimv2:Win32_Product"
$class.Install($TargetPathMSI)

If permissions and network connectivity allow for it, this code installs an MSI package on a remote system. Make sure you adjust the variables at the start. The first one is the name of the machine that should install the MSI. The second is the path to the MSI package to install.

Twitter This Tip! ReTweet this Tip!

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 + ";")
        }
        else
        {
          $txt.Append($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 = 'http://www.mediathekdirekt.de/good.json'
$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!