Using Finally for Crucial Cleanup Tasks

by Mar 6, 2015

PowerShell 2.0 and later

In a previous tip we introduced an “acoustic progress bar” that made PowerShell play a sound for as long as it was busy. Here is the code again:

# find first available WAV file in Windows folder
$WAVPath = Get-ChildItem -Path $env:windir -Filter *.wav -Recurse -ErrorAction SilentlyContinue |
  Select-Object -First 1 -ExpandProperty FullName


# load file and play it

$player = New-Object Media.SoundPlayer $WAVPath
$player.PlayLooping()

1..100 | ForEach-Object { 
  Write-Progress -Activity 'Doing Something. Hang in' -Status $_ -PercentComplete $_
  Start-Sleep -MilliSeconds (Get-Random -Minimum 300 -Maximum 1300)
  }
$player.Stop()

This script works fine – unless you interrupt it, for example by pressing CTRL+C. If you do, the script immediately stops, and $player.Stop() has no chance to execute and stop the sound.

This is when you need the finally() construct in PowerShell. It guarantees that cleanup code runs before a script aborts:

# find first available WAV file in Windows folder
$WAVPath = Get-ChildItem -Path $env:windir -Filter *.wav -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 1 -ExpandProperty FullName


# load file and play it

$player = New-Object Media.SoundPlayer $WAVPath

try
{

  $player.PlayLooping()
  
  1..100 | ForEach-Object { 
    Write-Progress -Activity 'Doing Something' -Status $_ -PercentComplete $_
    Start-Sleep -MilliSeconds (Get-Random -Minimum 300 -Maximum 1300)
  }
}

finally
{
  $player.Stop()
}

Twitter This Tip! ReTweet this Tip!