Example for using classes in PowerShell – New-Progressbar

PowerShell is a fairly easy language to learn, but to some extent, creating classes is a bit of a hidden concept. The way to do it is to wrap functions in a module and use Export-ModuleMember to make them externally visible. Here is an easy to understand example of implementing the Write-Progress cmdlet in an even easier way.


function New-Progressbar
{
    [CmdletBinding()]
    Param
    (
        # Total count
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$false,
                   Position=0)]
        [int]$TotalCount,

        # Activity name
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$false,
                   Position=1)]
        [string]$ActivityName = "Running",

        # Time estimation
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$false,
                   Position=2)]
        [boolean]$TimeEstimationEnabled = $true
    )

    # Create new module instance
    $m =  New-Module -ScriptBlock {
        # Internal variables
        $script:total = 1;
        $script:current = 0;
        $script:ActivityName = " ";
        $script:startTime = Get-Date;
        $script:timeEstimation = $false;
        # Functions with obvious method names
        function setActivityName($name) {$script:ActivityName = $name}
        function setTotal($tot) { $script:total = $tot}
        function getTotal($tot) { return $script:total}
        function enableTimeEstimation() {$script:timeEstimation = $true}
        function disableTimeEstimation() {$script:timeEstimation = $false}


        # Progress the progressbar one step. Optional parameter Text for defining the status message
        function Progress {
            Param
            (
                [Parameter(Mandatory=$false,
                    ValueFromPipelineByPropertyName=$false,
                    Position=0)]
                [string]$Text = ("{0}/{1}" -f $script:current, $script:total)
            )

            $params = @{
                Activity = $script:ActivityName
                Status = $Text
                PercentComplete = ($script:current / $script:total * 100)
            }

            if($script:timeEstimation) {
                if($script:current -gt 5) {
                    $params["SecondsRemaining"] = (((Get-Date) - $script:startTime).TotalSeconds / $script:current) * ($script:total - $script:current)
                }
            }

            Write-Progress @params

            if($script:current -lt $script:total) {
                $script:current += 1
            } else {
                Write-Warning "Progressbar incremented too far"
            }
        }
        function Complete() {Write-Progress -Activity $script:ActivityName -Status $script:total -PercentComplete 100 -Completed}
        export-modulemember -function setTotal,getTotal,Progress,Complete,setActivityName,enableTimeEstimation,disableTimeEstimation
    } -AsCustomObject

    # Set initial values
    $m.setTotal($TotalCount)
    $m.setActivityName($ActivityName)

    if($TimeEstimationEnabled) {
        $m.enableTimeEstimation()
    }

    return $m;
}

To use it, simply copy and paste the code into any PowerShell. After doing this, you have a new cmdlet available – New-Progressbar. You can use Get-Help New-ProgressBar -Full to get example usage, but here is a quick example script:

# Get a big list of files of unknown size
$files = @(dir $env:SystemRoot | select -First (Get-Random -Minimum 10 -Maximum 100))

# Create progressbar
$bar = New-Progressbar -TotalCount $files.Count -ActivityName "Processing files"

# Pretend to process files in order to progress the progressbar
$files | foreach {
    $bar.Progress($_.Name)
    sleep -Milliseconds 100
}

# Complete the progressbar
$bar.Complete()

As you can see, $bar is here a custom class with methods presented through the module. You can have internal methods too; only the methods exported by Export-ModuleMember is available externally.

Hope this helps someone as a quick reference to creating a PowerShell module.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s