From 9e247082fb6bb589867a544a08de5c6aa1ce9115 Mon Sep 17 00:00:00 2001 From: Philippe Vaucher Date: Tue, 6 Jan 2026 16:00:56 +0100 Subject: [PATCH] Add ETA to progress reporting --- .../Private/ImportHardwareCsv.ps1 | 10 +++++++ .../ImportVmsHardwareExcelFunctions.ps1 | 30 +++++++++++++++++++ .../Public/Rules/Import-VmsRule.ps1 | 8 ++++- docs/scripts/Group-CamerasByModel.ps1 | 7 +++++ docs/scripts/Group-DevicesByModel.ps1 | 7 +++++ docs/scripts/Set-AdaptiveStreaming.ps1 | 18 +++++++++-- 6 files changed, 77 insertions(+), 3 deletions(-) diff --git a/MilestonePSTools/Private/ImportHardwareCsv.ps1 b/MilestonePSTools/Private/ImportHardwareCsv.ps1 index f6cd2ad..abb2125 100644 --- a/MilestonePSTools/Private/ImportHardwareCsv.ps1 +++ b/MilestonePSTools/Private/ImportHardwareCsv.ps1 @@ -56,6 +56,7 @@ function ImportHardwareCsv { } $records = [pscustomobject[]](ValidateHardwareCsvRows -Rows $rows) $recordsProcessed = 0 + $progressStopwatch = [diagnostics.stopwatch]::StartNew() # Set RecordingServer property on all records to match RecordingServer parameter if provided. # Warn user that the RecordingServer from the CSV, if present, will be ignored. @@ -167,6 +168,15 @@ function ImportHardwareCsv { foreach ($hardwareGroup in $recordsByHardware) { $recordsProcessed += $hardwareGroup.Count $progress.PercentComplete = $recordsProcessed / $records.Count * 100 + $completedRecords = [math]::Max(($recordsProcessed - $hardwareGroup.Count), 0) + if ($completedRecords -gt 0 -and $records.Count -gt 0) { + $timePerRecord = $progressStopwatch.ElapsedMilliseconds / $completedRecords + $remainingRecords = $records.Count - $completedRecords + $remainingTime = [timespan]::FromMilliseconds($remainingRecords * $timePerRecord) + $progress.SecondsRemaining = [int]$remainingTime.TotalSeconds + } else { + $progress.Remove('SecondsRemaining') + } Write-Progress @progress # If hardware already exists, update DriverNumber for related CSV records diff --git a/MilestonePSTools/Private/ImportVmsHardwareExcelFunctions.ps1 b/MilestonePSTools/Private/ImportVmsHardwareExcelFunctions.ps1 index 89928c2..cd25329 100644 --- a/MilestonePSTools/Private/ImportVmsHardwareExcelFunctions.ps1 +++ b/MilestonePSTools/Private/ImportVmsHardwareExcelFunctions.ps1 @@ -987,6 +987,7 @@ function Export-VmsHardwareExcel { PercentComplete = 0 CurrentOperation = 'Preparing' } + $progressStopwatch = [diagnostics.stopwatch]::StartNew() Write-Progress @progress if ($IncludedDevices) { @@ -1040,6 +1041,15 @@ function Export-VmsHardwareExcel { $Hardware | ForEach-Object { $hw = $_ $progress.PercentComplete = [math]::Round(($processedHardwareCount++) / $totalHardwareCount * 100) + $completedHardwareCount = [math]::Max(($processedHardwareCount - 1), 0) + if ($completedHardwareCount -gt 0 -and $totalHardwareCount -gt 0) { + $timePerHardware = $progressStopwatch.ElapsedMilliseconds / $completedHardwareCount + $remainingHardware = $totalHardwareCount - $completedHardwareCount + $remainingTime = [timespan]::FromMilliseconds($remainingHardware * $timePerHardware) + $progress.SecondsRemaining = [int]$remainingTime.TotalSeconds + } else { + $progress.Remove('SecondsRemaining') + } $progress.CurrentOperation = '{0} "{1}"' -f [VideoOS.Platform.Proxy.ConfigApi.ConfigurationItemPath]::new($_.Path).ItemType, $_.Name Write-Progress @progress if (($EnableFilter -eq 'Enabled' -and -not $hw.Enabled) -or ($EnableFilter -eq 'Disabled' -and $hw.Enabled)) { @@ -1701,6 +1711,7 @@ function Import-VmsHardwareExcel { PercentComplete = 0 CurrentOperation = 'Preparing' } + $importStopwatch = [diagnostics.stopwatch]::StartNew() Write-Progress @progressParams $recorders = @{} @@ -1718,6 +1729,15 @@ function Import-VmsHardwareExcel { foreach ($row in $data.Hardware | Sort-Object RecordingServer) { $progressParams.PercentComplete = [math]::Round(($processedRows++) / $totalRows * 100) + $completedRows = [math]::Max(($processedRows - 1), 0) + if ($completedRows -gt 0 -and $totalRows -gt 0) { + $timePerRow = $importStopwatch.ElapsedMilliseconds / $completedRows + $remainingRows = $totalRows - $completedRows + $remainingTime = [timespan]::FromMilliseconds($remainingRows * $timePerRow) + $progressParams.SecondsRemaining = [int]$remainingTime.TotalSeconds + } else { + $progressParams.Remove('SecondsRemaining') + } $progressParams.CurrentOperation = '{0} ({1})' -f $row.Name, $row.Address Write-Progress @progressParams try { @@ -2095,10 +2115,20 @@ function Import-VmsHardwareExcel { Id = 43 PercentComplete = 0 } + $relatedStopwatch = [diagnostics.stopwatch]::StartNew() Write-Progress @progressParams foreach ($row in $data.Hardware | Sort-Object RecordingServer) { $progressParams.PercentComplete = [math]::Round(($processedRows++) / $totalRows * 100) + $completedRows = [math]::Max(($processedRows - 1), 0) + if ($completedRows -gt 0 -and $totalRows -gt 0) { + $timePerRow = $relatedStopwatch.ElapsedMilliseconds / $completedRows + $remainingRows = $totalRows - $completedRows + $remainingTime = [timespan]::FromMilliseconds($remainingRows * $timePerRow) + $progressParams.SecondsRemaining = [int]$remainingTime.TotalSeconds + } else { + $progressParams.Remove('SecondsRemaining') + } $progressParams.CurrentOperation = '{0} ({1})' -f $row.Name, $row.Address Write-Progress @progressParams diff --git a/MilestonePSTools/Public/Rules/Import-VmsRule.ps1 b/MilestonePSTools/Public/Rules/Import-VmsRule.ps1 index 16aa1a5..c794680 100644 --- a/MilestonePSTools/Public/Rules/Import-VmsRule.ps1 +++ b/MilestonePSTools/Public/Rules/Import-VmsRule.ps1 @@ -46,6 +46,7 @@ function Import-VmsRule { Activity = 'Importing rules' PercentComplete = 0 } + $progressStopwatch = [diagnostics.stopwatch]::StartNew() Write-Progress @progressParams if ($PSCmdlet.ParameterSetName -eq 'FromFile') { $Path = (Resolve-Path -Path $Path -ErrorAction Stop).Path @@ -58,6 +59,12 @@ function Import-VmsRule { $progressParams.CurrentOperation = "Importing rule '$($exportedRule.DisplayName)'" $progressParams.PercentComplete = $processed / $total * 100 $progressParams.Status = ($progressParams.PercentComplete / 100).ToString('p0') + if ($processed -gt 0 -and $total -gt 0) { + $timePerRule = $progressStopwatch.ElapsedMilliseconds / $processed + $remainingRules = $total - $processed + $remainingTime = [timespan]::FromMilliseconds($remainingRules * $timePerRule) + $progressParams.SecondsRemaining = [int]$remainingTime.TotalSeconds + } Write-Progress @progressParams if ($PSCmdlet.ShouldProcess($exportedRule.DisplayName, "Create rule")) { @@ -77,4 +84,3 @@ function Import-VmsRule { } } } - diff --git a/docs/scripts/Group-CamerasByModel.ps1 b/docs/scripts/Group-CamerasByModel.ps1 index 0ce5042..b5682e3 100644 --- a/docs/scripts/Group-CamerasByModel.ps1 +++ b/docs/scripts/Group-CamerasByModel.ps1 @@ -86,6 +86,7 @@ function Group-CamerasByModel { $modelGroups = $ms.RecordingServerFolder.RecordingServers.HardwareFolder.Hardwares | Group-Object Model | Sort-Object Name $totalCameras = ($modelGroups.Group.CameraFolder.Cameras).Count $camerasProcessed = 0 + $progressStopwatch = [diagnostics.stopwatch]::StartNew() $parentProgress.Status = 'Processing' Write-Progress @parentProgress @@ -102,6 +103,12 @@ function Group-CamerasByModel { $childProgress.Status = "Current: $BaseGroupPath/$modelName" $parentProgress.PercentComplete = $camerasProcessed / $totalCameras * 100 + if ($camerasProcessed -gt 0 -and $totalCameras -gt 0) { + $timePerCamera = $progressStopwatch.ElapsedMilliseconds / $camerasProcessed + $remainingCameras = $totalCameras - $camerasProcessed + $remainingTime = [timespan]::FromMilliseconds($remainingCameras * $timePerCamera) + $parentProgress.SecondsRemaining = [int]$remainingTime.TotalSeconds + } Write-Progress @parentProgress Write-Verbose "Creating groups for $totalForModel cameras of model '$modelName'" diff --git a/docs/scripts/Group-DevicesByModel.ps1 b/docs/scripts/Group-DevicesByModel.ps1 index b152483..200ae0f 100644 --- a/docs/scripts/Group-DevicesByModel.ps1 +++ b/docs/scripts/Group-DevicesByModel.ps1 @@ -132,6 +132,7 @@ function Group-DevicesByModel { $modelGroups = $ms.RecordingServerFolder.RecordingServers.HardwareFolder.Hardwares | Where-Object $filterScript | Group-Object Model | Sort-Object Name $totalDevices = ($DeviceType | ForEach-Object { ($modelGroups.Group."$($_)Folder"."$($_)s").Count } | Measure-Object -Sum).Sum $devicesProcessed = 0 + $progressStopwatch = [diagnostics.stopwatch]::StartNew() foreach ($type in $DeviceType) { try { $childProgress = @{ @@ -156,6 +157,12 @@ function Group-DevicesByModel { $childProgress.Status = "Current: $BaseGroupPath/$modelName" $parentProgress.PercentComplete = $devicesProcessed / $totalDevices * 100 + if ($devicesProcessed -gt 0 -and $totalDevices -gt 0) { + $timePerDevice = $progressStopwatch.ElapsedMilliseconds / $devicesProcessed + $remainingDevices = $totalDevices - $devicesProcessed + $remainingTime = [timespan]::FromMilliseconds($remainingDevices * $timePerDevice) + $parentProgress.SecondsRemaining = [int]$remainingTime.TotalSeconds + } Write-Progress @parentProgress Write-Verbose "Creating groups for $totalForModel $type devices of model '$modelName'" diff --git a/docs/scripts/Set-AdaptiveStreaming.ps1 b/docs/scripts/Set-AdaptiveStreaming.ps1 index edc60a7..579b493 100644 --- a/docs/scripts/Set-AdaptiveStreaming.ps1 +++ b/docs/scripts/Set-AdaptiveStreaming.ps1 @@ -103,6 +103,7 @@ function Set-AdaptiveStreaming { } } $camProcessed = 1 + $progressStopwatch = [diagnostics.stopwatch]::StartNew() if ($null -ne $FPS) { [decimal]$FPS = $FPS @@ -111,7 +112,20 @@ function Set-AdaptiveStreaming { foreach ($rec in $recs) { foreach ($hw in $rec | Get-VmsHardware | Where-Object Enabled) { foreach ($cam in $hw | Get-VmsCamera -EnableFilter Enable -Name $CameraName) { - Write-Progress -Activity "Configuring streams for camera $($camProcessed) of $($camQty) (or possibly less)" -PercentComplete ($camProcessed / $camQty * 100) + $completedCameras = [math]::Max($camProcessed - 1, 0) + $progressParams = @{ + Activity = "Configuring streams for camera $($camProcessed) of $($camQty) (or possibly less)" + PercentComplete = ($camProcessed / $camQty * 100) + } + if ($completedCameras -gt 0 -and $camQty -gt 0) { + $timePerCamera = $progressStopwatch.ElapsedMilliseconds / $completedCameras + $remainingCameras = $camQty - $completedCameras + if ($remainingCameras -gt 0) { + $remainingTime = [timespan]::FromMilliseconds($remainingCameras * $timePerCamera) + $progressParams.SecondsRemaining = [int]$remainingTime.TotalSeconds + } + } + Write-Progress @progressParams # Get all streams that support a codec other than just JPEG/MJPEG $totalSupportedStreams = $cam | Get-VmsCameraStream -WarningAction SilentlyContinue | Where-Object { $_.ValueTypeInfo.Codec.Value -ne 'JPEG' -and $_.ValueTypeInfo.Codec.Value -ne 'MJPEG' } @@ -333,4 +347,4 @@ function Set-AdaptiveStreaming { } } } -} \ No newline at end of file +}