Adding Progress to Long-Running Cmdlets

Share |

Join PowerShell.com!
Subscribe to Feed

PowerShell eBook
Sign up for
Your PowerTip of the Day:

Award-winning PowerShellPlus


Admin Guide to PowerShell Remoting


Mastering PowerShell eBook

Sometimes cmdlets take some time, and unless they emit data, the user gets no feedback. Here are three examples for calls that take a long time without providing user feedback:

$hotfix = Get-Hotfix
$products = Get-WmiObject Win32_Product
$scripts = Get-ChildItem $env:windir *.ps1 -Recurse -ea 0

To provide your scripts with better user feedback, here's a function called Start-Progress. It takes a command and then executes it in a background thread. The foreground thread will output a simple progress indicator. Once the command completes, the results are returned to the foreground thread.

It's really simple and can make a heck of a difference to the user:

$hotfix = Start-Progress {Get-Hotfix}
$products = Start-Progress {Get-WmiObject Win32_Product}
$scripts = Start-Progress {Get-ChildItem $env:windir *.ps1 -Recurse -ea 0}

And here's the function code you need:

function Start-Progress {
  param(
    [ScriptBlock]
    $code
  )
  
  $newPowerShell = [PowerShell]::Create().AddScript($code)
  $handle = $newPowerShell.BeginInvoke()
  
  while ($handle.IsCompleted -eq $false) {
    Write-Host '.' -NoNewline
    Start-Sleep -Milliseconds 500
  }
  
  Write-Host ''
  
  $newPowerShell.EndInvoke($handle)
  
  $newPowerShell.Runspace.Close()
  $newPowerShell.Dispose()
}

Twitter This Tip! ReTweet this Tip!


Posted Apr 20 2012, 06:00 AM by ps1

Comments

Anders wrote re: Adding Progress to Long-Running Cmdlets
on 04-22-2012 1:32 PM

Just what the doctor ordered! :-)

I had to do a little fine-tuning to make it extra user-informative:

function Start-Progress {

  param(

    [parameter(mandatory=$true)]

[ScriptBlock] $Code,

[parameter(mandatory=$false)]

[string] $Statusmessage

 )

  $newPowerShell = [PowerShell]::Create().AddScript($Code)

  $handle = $newPowerShell.BeginInvoke()

if (-not [string]::IsNullOrEmpty($Statusmessage)){ Write-Host $Statusmessage -NoNewline -ForegroundColor DarkCyan}

  while ($handle.IsCompleted -eq $false) {

    Write-Host '.' -NoNewline -ForegroundColor DarkCyan

    Start-Sleep -Milliseconds 500

  }

  Write-Host ' Done' -NoNewline -ForegroundColor DarkCyan

Write-Host ''  

$newPowerShell.EndInvoke($handle)  

  $newPowerShell.Runspace.Close()

  $newPowerShell.Dispose()

}

clear

$hotfix = Start-Progress {Get-Hotfix} -Statusmessage "Inventoring hotfixes"

$products = Start-Progress {Get-WmiObject Win32_Product} -Statusmessage "Inventoring installed products"

$lookHere = $env:windir

$scripts = Start-Progress {Get-ChildItem $lookHere *.ps1 -Recurse -ea 0} -Statusmessage "Inventoring Powershellfiles found in '$lookHere'"

Irwin Strachan wrote re: Adding Progress to Long-Running Cmdlets
on 04-23-2012 3:32 AM

Nice !!!

Copyright 2012 PowerShell.com. All rights reserved.