从 Start-Job (Powershell) 更新 winforms GUI
Update winforms GUI from Start-Job (Powershell)
我正在尝试在 powershell 中创建自定义 Robocopy 状态 GUI,这是我的基本代码。
$script:Robocopy = Start-Process -FilePath robocopy.exe -ArgumentList $ArgumentList -Verbose -PassThru -NoNewWindow;
$RCStatus = Start-Job -Name RCLOOP -ArgumentList $Robocopy, $ReportGap, $RobocopyLogPath, $RegexBytes, $RobocopyFileProgress, $RobocopyMBProgress, $RobocopyGBProgress, $RobocopyPcntProgress, $RobocopySpeed {
param ($Robocopy, $ReportGap, $RobocopyLogPath, $RegexBytes, $RobocopyFileProgress, $RobocopyMBProgress, $RobocopyGBProgress, $RobocopyPcntProgress, $RobocopySpeed)
$iterations = 0
[array]$avgSpeedarray = @()
while (!$Robocopy.HasExited) {
Start-Sleep -Milliseconds $ReportGap;
$BytesCopied = 0;
$LogContent = Get-Content -Path $RobocopyLogPath;
$BytesCopied = [Regex]::Matches($LogContent, $RegexBytes) | ForEach-Object -Process { $BytesCopied += $_.Value; } -End { $BytesCopied; };
$global:MBCopied = ($BytesCopied / 1048576)
$global:GBCopied = ($BytesCopied / 1073741824)
$script:CopiedFileCount = $LogContent.Count - 1;
$iterations++
if ($iterations % 2 -eq 1) {
$M = $MBCopied
}
else {
$B = $MBCopied
$script:TSpeed = ($B - $M) * 8
$avgSpeedarray += $script:TSpeed
if ($avgSpeedarray.count -gt 4) {
$script:avgSpeed = (($avgSpeedarray[-1..-10] | Measure-Object -sum).sum) / 10
if ($avgSpeedarray.count -gt 19) {
$keep = $avgSpeedarray[-1..-9]
$avgSpeedarray = @()
$avgSpeedarray += $keep
}
}
}
if ($iterations % 20 -eq 0) {
$keepAwake
}
Write-Verbose -Message ('MB copied: {0}' -f $MBCopied);
Write-Verbose -Message ('Files copied: {0}' -f $LogContent.Count);
$Percentage = 0;
if ($BytesCopied -gt 0) {
$Percentage = (($BytesCopied / $BytesTotal) * 100)
}
#Write-Progress -Activity Robocopy -Status ("Copied {0} of {1} | {2}GB of {3}GB | {4}MB of {5}MB | {6}% Complete (Average: {7}Mbps)" -f $CopiedFileCount, $TotalFileCount, [Math]::Round($GBCopied, 2), [Math]::Round($GBTotal, 2), [Math]::Round($MBCopied, 2), [Math]::Round($MBTotal), [Math]::Round($Percentage, 2), [Math]::Round($script:avgSpeed,2)) -PercentComplete $Percentage
$RobocopyFileProgress.Text = ("Files: {0} of {1}" -f $CopiedFileCount, $TotalFileCount)
$RobocopyMBProgress.Text = ("Data: {0}MB of {1}MB" -f [Math]::Round($MBCopied, 2), [Math]::Round($MBTotal, 2))
$RobocopyGBProgress.Text = ("Data: {0}GB of {1}GB" -f [Math]::Round($GBCopied, 2), [Math]::Round($GBTotal, 2))
$RobocopyPcntProgress.Text = ("Percentage: {0}%" -f [Math]::Round($Percentage, 2))
$RobocopySpeed.text = ("Speed: {0}Mbps" -f [Math]::Round($script:avgSpeed, 2))
}
}
$RobocopyProgressGUI.Show()
#endregion Progress loop
Register-ObjectEvent -InputObject $script:Robocopy -EventName OutputDataReceived -SourceIdentifier 'RobocopyStatus' -Action {
$RobocopyFileProgress.Text = ("Files: {0} of {1}" -f $CopiedFileCount, $TotalFileCount)
$RobocopyMBProgress.Text = ("Data: {0}MB of {1}MB" -f [Math]::Round($MBCopied, 2), [Math]::Round($MBTotal, 2))
$RobocopyGBProgress.Text = ("Data: {0}GB of {1}GB" -f [Math]::Round($GBCopied, 2), [Math]::Round($GBTotal, 2))
$RobocopyPcntProgress.Text = ("Percentage: {0}%" -f [Math]::Round($Percentage, 2))
$RobocopySpeed.text = ("Speed: {0}Mbps" -f [Math]::Round($script:avgSpeed, 2))
}
我的一个问题是我的表单只是打开和关闭而没有任何脚本告诉它关闭,另一个是上面输出的所有代码都是关于作业的信息,而不是作业正在输出什么。
我知道我的代码非常冗长,它是故障排除过程的一部分,我知道 C# 是一个更好的选择,但我试图在 powershell 中实现它,因为我不太擅长 C#。任何帮助或建议都会很棒。如果您需要我的程序中我遗漏的任何其他代码,请告诉我,我会提供
这里是一个例子,说明如何在 powershell 中使用带有进度条的 robocopy。我改编了一个现有的答案,然后根据我在使用它时发现的一些问题进一步完善它。希望对您有所帮助。
Progress during large file copy (Copy-Item & Write-Progress?)
如果您想做一个 GUI,我还建议您使用 WPF/xaml 而不是 winforms。 Winforms 在 PowerShell 中似乎有些不稳定。此外,您可以在 visual studio 中创建 xaml,然后在 copy/paste 中创建。这还允许您将可视化与功能分开。
我正在尝试在 powershell 中创建自定义 Robocopy 状态 GUI,这是我的基本代码。
$script:Robocopy = Start-Process -FilePath robocopy.exe -ArgumentList $ArgumentList -Verbose -PassThru -NoNewWindow;
$RCStatus = Start-Job -Name RCLOOP -ArgumentList $Robocopy, $ReportGap, $RobocopyLogPath, $RegexBytes, $RobocopyFileProgress, $RobocopyMBProgress, $RobocopyGBProgress, $RobocopyPcntProgress, $RobocopySpeed {
param ($Robocopy, $ReportGap, $RobocopyLogPath, $RegexBytes, $RobocopyFileProgress, $RobocopyMBProgress, $RobocopyGBProgress, $RobocopyPcntProgress, $RobocopySpeed)
$iterations = 0
[array]$avgSpeedarray = @()
while (!$Robocopy.HasExited) {
Start-Sleep -Milliseconds $ReportGap;
$BytesCopied = 0;
$LogContent = Get-Content -Path $RobocopyLogPath;
$BytesCopied = [Regex]::Matches($LogContent, $RegexBytes) | ForEach-Object -Process { $BytesCopied += $_.Value; } -End { $BytesCopied; };
$global:MBCopied = ($BytesCopied / 1048576)
$global:GBCopied = ($BytesCopied / 1073741824)
$script:CopiedFileCount = $LogContent.Count - 1;
$iterations++
if ($iterations % 2 -eq 1) {
$M = $MBCopied
}
else {
$B = $MBCopied
$script:TSpeed = ($B - $M) * 8
$avgSpeedarray += $script:TSpeed
if ($avgSpeedarray.count -gt 4) {
$script:avgSpeed = (($avgSpeedarray[-1..-10] | Measure-Object -sum).sum) / 10
if ($avgSpeedarray.count -gt 19) {
$keep = $avgSpeedarray[-1..-9]
$avgSpeedarray = @()
$avgSpeedarray += $keep
}
}
}
if ($iterations % 20 -eq 0) {
$keepAwake
}
Write-Verbose -Message ('MB copied: {0}' -f $MBCopied);
Write-Verbose -Message ('Files copied: {0}' -f $LogContent.Count);
$Percentage = 0;
if ($BytesCopied -gt 0) {
$Percentage = (($BytesCopied / $BytesTotal) * 100)
}
#Write-Progress -Activity Robocopy -Status ("Copied {0} of {1} | {2}GB of {3}GB | {4}MB of {5}MB | {6}% Complete (Average: {7}Mbps)" -f $CopiedFileCount, $TotalFileCount, [Math]::Round($GBCopied, 2), [Math]::Round($GBTotal, 2), [Math]::Round($MBCopied, 2), [Math]::Round($MBTotal), [Math]::Round($Percentage, 2), [Math]::Round($script:avgSpeed,2)) -PercentComplete $Percentage
$RobocopyFileProgress.Text = ("Files: {0} of {1}" -f $CopiedFileCount, $TotalFileCount)
$RobocopyMBProgress.Text = ("Data: {0}MB of {1}MB" -f [Math]::Round($MBCopied, 2), [Math]::Round($MBTotal, 2))
$RobocopyGBProgress.Text = ("Data: {0}GB of {1}GB" -f [Math]::Round($GBCopied, 2), [Math]::Round($GBTotal, 2))
$RobocopyPcntProgress.Text = ("Percentage: {0}%" -f [Math]::Round($Percentage, 2))
$RobocopySpeed.text = ("Speed: {0}Mbps" -f [Math]::Round($script:avgSpeed, 2))
}
}
$RobocopyProgressGUI.Show()
#endregion Progress loop
Register-ObjectEvent -InputObject $script:Robocopy -EventName OutputDataReceived -SourceIdentifier 'RobocopyStatus' -Action {
$RobocopyFileProgress.Text = ("Files: {0} of {1}" -f $CopiedFileCount, $TotalFileCount)
$RobocopyMBProgress.Text = ("Data: {0}MB of {1}MB" -f [Math]::Round($MBCopied, 2), [Math]::Round($MBTotal, 2))
$RobocopyGBProgress.Text = ("Data: {0}GB of {1}GB" -f [Math]::Round($GBCopied, 2), [Math]::Round($GBTotal, 2))
$RobocopyPcntProgress.Text = ("Percentage: {0}%" -f [Math]::Round($Percentage, 2))
$RobocopySpeed.text = ("Speed: {0}Mbps" -f [Math]::Round($script:avgSpeed, 2))
}
我的一个问题是我的表单只是打开和关闭而没有任何脚本告诉它关闭,另一个是上面输出的所有代码都是关于作业的信息,而不是作业正在输出什么。
我知道我的代码非常冗长,它是故障排除过程的一部分,我知道 C# 是一个更好的选择,但我试图在 powershell 中实现它,因为我不太擅长 C#。任何帮助或建议都会很棒。如果您需要我的程序中我遗漏的任何其他代码,请告诉我,我会提供
这里是一个例子,说明如何在 powershell 中使用带有进度条的 robocopy。我改编了一个现有的答案,然后根据我在使用它时发现的一些问题进一步完善它。希望对您有所帮助。
Progress during large file copy (Copy-Item & Write-Progress?)
如果您想做一个 GUI,我还建议您使用 WPF/xaml 而不是 winforms。 Winforms 在 PowerShell 中似乎有些不稳定。此外,您可以在 visual studio 中创建 xaml,然后在 copy/paste 中创建。这还允许您将可视化与功能分开。