xProgress.psm1
$script:ProgressTracker = @{} Function Write-xProgress { <# .SYNOPSIS Writes powershell progress output using Write-Progress based on a previous Initialize-xProgress identity .DESCRIPTION Writes powershell progress output using Write-Progress based on a previous Initialize-xProgress identity .EXAMPLE Write-xProgress -Identity $xProgressID calls Write-Progress with previously defined activity and automatically generated counter, progress, and seconds remaining #> [cmdletbinding()] param( [guid]$Identity #GUID or GUID string provided from a previously run Initialize-xProgress ) $ProgressGUID = $Identity.guid #set the ProgressGUID to the string represenation of the Identity GUID if (-not $Script:ProgressTracker.containsKey($ProgressGUID)) { throw("No xProgress Instance found for identity $ProgressGUID") } $Script:ProgressTracker.$($ProgressGUID).Counter++ #advance the counter $counter = $Script:ProgressTracker.$($ProgressGUID).Counter #capture the current counter $progressInterval = $Script:ProgressTracker.$($ProgressGUID).ProgressInterval #get the progressInterval for the modulus check if ($counter % $progressInterval -eq 0 -or $counter -eq 1) { #modulus check passed so w $activity = $Script:ProgressTracker.$($ProgressGUID).Activity $stopwatch = $script:ProgressTracker.$($ProgressGuid).Stopwatch $total = $script:ProgressTracker.$($ProgressGuid).total $elapsedSeconds = [math]::Ceiling($stopwatch.elapsed.TotalSeconds) $secondsPerItem = [math]::Ceiling($elapsedSeconds/$counter) $secondsRemaining = $($total - $counter) * $secondsPerItem $progressItem = $counter + $progressInterval - 1 $wpParams = @{ Activity = $activity Status = "Processing $counter through $progressItem of $total" PercentComplete = $counter/$total * 100 SecondsRemaining = $secondsRemaining } if ($Script:ProgressTracker.$($ProgressGUID).containsKey('Id')) { $wpParams.Id = $Script:ProgressTracker.$($ProgressGUID).Id } if ($Script:ProgressTracker.$($ProgressGUID).containsKey('ParentId')) { $wpParams.Id = $Script:ProgressTracker.$($ProgressGUID).ParentId } Write-Progress @wpParams } } Function Initialize-xProgress { <# .SYNOPSIS Initializes an instance of xProgress for later display using Write-xProgess .DESCRIPTION Initializes an instance of xProgress for later display using Write-xProgess. Automatically sets up counters, timers, and incremental progress tracking. Can show progress only at a selected interval to improve performance (write-progress is expensive). .EXAMPLE $xProgressID = Initialize-xProgress -ArrayToProcess $MyListOfItems -CalculatedProgressInterval 1Percent -Activity "Process MyListOfItems" Sets up xProgress to display progress for a looped operation on $MyListOfItems. When Write-xProgress is called will update progress at each one percent increment of processing and will use -activity as the activity for Write-Progress. .EXAMPLE $xProgressID = Initialize-xProgress -ArrayToProcess $MyListOfItems -ExplicitProgressInterval 5 -Activity "Process MyListOfItems" Sets up xProgress to display progress for a looped operation on $MyListOfItems. When Write-xProgress is called will update progress once for each 5 items of processing and will use -activity as the activity for Write-Progress. Will throw an error if MyListOfItems is less than 5 items. #> [cmdletbinding(DefaultParameterSetName = 'CalculatedInterval')] param( [parameter(Mandatory)] [psobject[]]$ArrayToProcess #The array of items to be processed , [parameter(ParameterSetName = 'CalculatedInterval')] [alias('CalculatedInterval','CPI')] [ValidateSet('1Percent','10Percent','20Percent','25Percent','Each')] [string]$CalculatedProgressInterval = '1Percent' #Select a progress interval. Default is 1 Percent (1Percent). , [parameter(ParameterSetName = 'ExplicitInterval')] [alias('ExplicitInterval','EPI')] [int32]$ExplicitProgressInterval #specify an explicity item count at which to show progress. , [parameter(Mandatory)] [string]$Activity #displayed in the progress bar Activity field (passed through to Write-Progress -Activity). , [parameter()] [int32]$Id #set the Id for Write-Progress, if desired. , [parameter()] [int32]$ParentId #set the ParentId for Write-Progress, if desired. ) $ProgressGuid = $(New-Guid).guid $total = $ArrayToProcess.Count switch ($PSCmdlet.ParameterSetName) { 'CalculatedInterval' { $divisor = switch ($CalculatedProgressInterval) { '1Percent' {100} '10Percent' {10} '20Percent' {5} '25Percent' {4} 'Each' {$total} } $Interval = [math]::Ceiling($total / $divisor) } 'ExplicitInterval' { if ($ExplicitProgressInterval -gt $total) { throw ("ExplicitProgressInterval $ExplicitProgressInterval is greater than the provided ArrayToProcess total count: $total") } else { $Interval = $ExplicitProgressInterval } } } $script:ProgressTracker.$($ProgressGuid) = @{} $script:ProgressTracker.$($ProgressGuid).Activity = $Activity $script:ProgressTracker.$($ProgressGuid).ProgressInterval = $Interval $script:ProgressTracker.$($ProgressGuid).total = $total $script:ProgressTracker.$($ProgressGuid).Stopwatch = [System.Diagnostics.Stopwatch]::StartNew() $script:ProgressTracker.$($ProgressGuid).counter = 0 if ($Id) {$script:ProgressTracker.$($ProgressGuid).Id = $Id} if ($ParentId) {$script:ProgressTracker.$($ProgressGuid).ParentId = $ParentId} $ProgressGuid } Function Complete-xProgress { <# .SYNOPSIS Completes xProgress for a specific xProgress identity created by Initialize-xProgress .DESCRIPTION Completes xProgress for a specific xProgress identity created by Initialize-xProgress. Removes the progress bar display in Powershell by calling Write-Progress with -Complete parameter. Removes the xProgress identity from xProgress module memory .EXAMPLE Complete-xProgress -Identity $xProgressId removes the progress bar from display and removes the xProgressId from xProgress module memory #> [cmdletbinding()] param( [parameter(Mandatory)] [guid]$Identity #the xProgress Identity to complete ) $ProgressGUID = $Identity.guid #set the ProgressGUID to the string represenation of the Identity GUID $script:ProgressTracker.$($ProgressGuid).Stopwatch.Stop() #stop the stopwatch $activity = $Script:ProgressTracker.$($ProgressGUID).Activity $stopwatch = $script:ProgressTracker.$($ProgressGuid).Stopwatch $elapsedSeconds = [math]::Ceiling($stopwatch.elapsed.TotalSeconds) $total = $script:ProgressTracker.$($ProgressGuid).total $wpParams = @{ Activity = $activity Status = "Processed all $total iterations. Elapsed seconds: $elapsedSeconds" PercentComplete = 100 SecondsRemaining = 0 } if ($Script:ProgressTracker.$($ProgressGUID).containsKey('Id')) { $wpParams.Id = $Script:ProgressTracker.$($ProgressGUID).Id } if ($Script:ProgressTracker.$($ProgressGUID).containsKey('ParentId')) { $wpParams.Id = $Script:ProgressTracker.$($ProgressGUID).ParentId } #Remove progress bar Write-Progress @wpParams -Completed #Remove Progress Identity GUID $script:ProgressTracker.remove($ProgressGUID) } |