‘Overriding’ PowerShell Command functionality to provide custom functionality – Sort of!
October 17, 2020 at 4:44 pm Leave a comment
The scenario:
I have a PowerShell command that wraps an Exif tool (ExifTool by Phil Harvey ) that uses the Write-Progress command as it takes a long time to run (about 2.5 seconds per image file and I have 1000s) as shown below.
The problem:
I want to use the command in a GUI application written using PowerShell Studio and the Write-Progress command does not work for me in this context.
The solution:
Override the functionality that shows the progress by displaying a message in PowerShell Studio GUI’s status bar:
The method:
One of the benefits of PowerShell is that everything is an object, that includes code. You can create a variable of type ScriptBlock to store the code and then execute it when needed. In the Get-CCMetaData command I have a switch to indicate that I want the progress to be displayed. The code to do this is:
if ($ShowProgress)
{
Invoke-Command -ScriptBlock $ProgressScript
}
ProgressScript is a parameter for the command. The default value for it is:
[ScriptBlock]$ProgressScript = {Write-Progress -Activity $Global:progressActivity -Status $Global:progressStatus -PercentComplete (100*$Global:progressIndex/$Global:progressCount)}
I found that I need to declare the variables at a Global: scope to be able to provide access to the various script scopes.
In my GUI application I have a status bar to enable information to be displayed to the user. In the GUI application I call Get-CCMetaData with a new ProgressScript block:
Get-CCMetaData -IncludeExifData -ProgressScript ({ Set-StatusMessage -Message ("{0}: {1} ({2:N2}%)" -f $Global:progressActivity, $Global:progressStatus, (100 * $Global:progressIndex/$Global:progressCount))}) -ShowProgress
Because I am running this code block in the scope of the GUI application it has access to the GUI components such as the Set-StatusMessage command that writes to the status bar.
This means that rather than using a Progress bar, I see the progress displayed as a message telling me what file I am processing and how far through the processing I am as shown above.
I appreciate that I am not truly overriding a command’s functionality. I am writing the original command to support the injecting of functionality. Rather than embedding the code in the command I provide it as a ScriptBlock as the default value for a parameter. The critical part is to make the information needed to indicate progress as known variables. I set the variables at the Global scope so other ScriptBlocks can access them. This approach does require a greater knowledge of the internals of the command that would normally be available. I have added information into the comment based help to support this:
.PARAMETER ProgressScript
This is the ScriptBlock that will be executed when the -ShowProgress switch is set.
The default ScriptBlock uses the Write-Progress command. There are several variables
that are prepared and controlled to enable custom code to display progress.
The Variables are:
[int]$Global:progressCount: The number of files to process.
[int]$Global:progressIndex: The index for the current file
being processed.
[String]$Global:progressStatus: The name of the file currently being processed.
[String]$Global:progressActivity: The text "Processing"
I have also added an example demonstrating a way to use this to simply write the percentage complete on the console line rather than the progress bar:
.EXAMPLE
Get-CCMetaData -Path (Get-ChildItem D:\PhotoAlbum\Europe2013*.JPG) -ProgressScript {Write-Host ("r{0:N2}%" -f (100*$Global:progressIndex/$Global:progressCount)) -NoNewline} -ShowProgress
NOTE: This does not work properly with the console in PowerShell_ISE as it does not process the `r as a carriage return properly.
Entry filed under: Uncategorized. Tags: Overriding command functionality, PowerShell, PowerShell Studio.
Trackback this post | Subscribe to the comments via RSS Feed