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.