[CmdletBinding()]param(
    [Parameter(Mandatory, Position=0)]
    [string]$Activity,
    [string]$Status,
    [Parameter(ParameterSetName="Calculate",Mandatory)]
    [int]$ItemProgress,
    [Parameter(ParameterSetName="Calculate")]
    [int]$ItemCount,
    [Parameter(ParameterSetName="PercentComplete",Mandatory)]
    [int]$PercentComplete,
    [Parameter(ParameterSetName="SecondsRemaining",Mandatory)]
    [int]$SecondsRemaining,
    [Parameter(ParameterSetName="Elapsed",Mandatory)]
    [Parameter(ParameterSetName="Calculate")]
    [Timespan]$Elapsed,
    [Parameter(ParameterSetName="Elapsed")]
    [int]$TotalSeconds,
    [string]$CurrentOperation,
    [Parameter(ParameterSetName="Completed",Mandatory)]
    [switch]$Completed
)

$local:progressParams = [ordered]@{
    Activity = $Activity
}
if( $Status           ) { $progressParams.Status           = $Status                              }
if( $PercentComplete  ) { $progressParams.PercentComplete  = $PercentComplete                     }
if( $SecondsRemaining ) { $progressParams.SecondsRemaining = $SecondsRemaining                    }
if( $ItemCount        ) { $progressParams.PercentComplete  = (100.0 * $ItemProgress / $ItemCount) }
if( $CurrentOperation ) { $progressParams.CurrentOperation = $CurrentOperation                    }
if( $Completed        ) { $progressParams.Completed        = $true                                }

if( $Elapsed ) {
    if( -not $Status ) {
        $progressParams.Status = "Running for #Elapsed#"
    }
    $local:TotalTime = [TimeSpan]::Zero
    if( $TotalSeconds ) {
        $progressParams.PercentComplete = [Math]::Floor($(1000 * (($Elapsed.TotalSeconds * 1.0) / ($TotalSeconds * 1.0)))/10.0)
        $TotalTime = [TimeSpan]::FromSeconds($TotalSeconds)
    }
    $progressParams.Status = $progressParams.Status -replace '#Elapsed#',$(ConvertFrom-TimeSpan $Elapsed) -replace "#TotalTime#",$(ConvertFrom-TimeSpan $TotalTime)
}

If( $ItemProgress ) {
    if( $progressParams.Status ) { $progressParams.Status = "    " + $progressParams.Status }
    $progressParams.Status = "#$ItemProgress$(if($ItemCount){" out of $ItemCount"})" + $progressParams.Status
}

$local:VerboseProgress = $("$([datetime]::Now.TimeOfDay.ToString("hh\:mm\:ss")) Progress: $($progressParams.Activity)" + 
        "$(if($progressParams.Status){" ($($progressParams.Status))"})" +
        "$(if($ItemProgress) {" #$ItemProgress$(if($ItemCount){" out of $ItemCount"})"})" +
        "$(if($progressParams.PercentComplete){" %$($progressParams.PercentComplete)"})" +
        "$(if($progressParams.Completed){if(-not $progressParams.Status){" Done."}} else {"..."})"
    )

Write-Verbose $VerboseProgress
if( Test-Path variable:global:psISE ) {
    if( -not $VerbosePreference -eq 'Continue' ) {
        Write-Host -ForegroundColor Cyan $VerboseProgress
    }
} else {
    Write-Progress @progressParams
}