【问题标题】:PowerShell progress Bar invocation fails in Runspace运行空间中的 PowerShell 进度条调用失败
【发布时间】:2021-01-02 16:20:07
【问题描述】:

我正在创建一个带有 GUI 的 PowerShell 脚本,它将用户配置文件从选定的源磁盘复制到目标磁盘。我已经使用 VS Community 2019 在 XAML 中创建了 GUI。

我的复制函数是从运行空间调用的并且工作正常。我想在此运行空间中放置一个进度条,以便复制的每个文件夹都会增加进度条,但我不知道如何。

这是我的运行空间:

function RunspaceBackupData {
    $Runspace = [runspacefactory]::CreateRunspace()
    $Runspace.ApartmentState = "STA"
    $Runspace.ThreadOptions = "ReuseThread"
    $Runspace.Open()
    $Runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
    $Runspace.SessionStateProxy.SetVariable("SelectedFolders",$global:SelectedFolders)
    $Runspace.SessionStateProxy.SetVariable("SelectedUser",$global:SelectedUser)
     $Runspace.SessionStateProxy.SetVariable("ReturnedDiskSource",$global:ReturnedDiskSource)
    $Runspace.SessionStateProxy.SetVariable("ReturnedDiskDestination",$global:ReturnedDiskDestination)
    $code = {
        foreach ($item in $global:SelectedFolders) {
            copy-item -Path "$global:ReturnedDiskSource\Users\$global:SelectedUser\$item" -Destination "$global:ReturnedDiskDestination\Users\$global:SelectedUser\$item" -Force -Recurse
        }
    }

    $PSinstance = [powershell]::Create().AddScript($Code)
    $PSinstance.Runspace = $Runspace
    $job = $PSinstance.BeginInvoke()
}

这是我的事件处理程序:

$var_btnStart.Add_Click( {
    RunspaceBackupData -syncHash $syncHash -SelectedFolders $global:SelectedFolders -SelectedUser $global:SelectedUser -ReturnedDiskSource $global:ReturnedDiskSource -ReturnedDiskDestination $global:ReturnedDiskDestination 
})

你能帮帮我吗?

【问题讨论】:

  • 我的理解是运行空间没有用户界面。它被设计成非交互式的,所以没有地方显示你的进度条。如果你想这样显示,你需要手动设置运行空间和主线程之间的某种通信。
  • 是的,这正是重点:/
  • 那么“运行空间内的进度条”是什么意思?您想在您的 GUI 中添加一个进度条来反映运行空间中代码的进度吗?
  • 是的。对不起,如果我没有更好地解释
  • @OscarLoret - 搜索 powershell runspace return data 以了解从运行空间获取信息的方法。

标签: wpf powershell progress-bar runspace


【解决方案1】:

好的,我已经设法让我的进度条正常工作。首先,您必须将其添加到您的哈希表变量中: $syncHash.ProgressBar = $syncHash.Window.FindName("ProgressBar") 然后你可以像这样创建你的事件处理程序:

$var_btnStart.Add_Click( { 
$Runspace = [runspacefactory]::CreateRunspace()
$Runspace.ApartmentState = "STA"
$Runspace.ThreadOptions = "ReuseThread"
$Runspace.Open()
$Runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$Worker = 
[PowerShell]::Create().AddScript({$syncHash.ProgressBar.Dispatcher.Invoke([action] 
{$SyncHash.ProgressBar.IsIndeterminate = $true }, "Normal")}
##YOUR CODE HERE
$syncHash.Error = $Error
$syncHash.ProgressBar.Dispatcher.Invoke([action]{$SyncHash.ProgressBar.IsIndeterminate = $false }, "Normal")    
        })
    $Worker.Runspace = $Runspace
    $Worker.BeginInvoke()})

请注意,在此示例中,您的进度条是不确定的,因此当您单击按钮时它开始循环,并在您编码结束时停止。 不要忘记处置你的运行空间:

$Runspace.PowerShell.Close($Runspace) $Runspace.PowerShell.Dispose($Runspace)

【讨论】:

    【解决方案2】:

    $code 内部你需要保持计数,所以我建议使用 for 循环。

    在循环内部,您可以在窗口对象中调用调度程序:

    $syncHash.Window.Dispatcher.Invoke([action]{$syncHash.Progressbar.Value = [double] <code for finished percentage>}, "Normal") 
    

    我怀疑你在$syncHash 中有窗口和进度条

    【讨论】:

    • 感谢您的回复,我已经尝试使用 $syncHash.Window.Dispatcher.Invoke 但它根本没有用。但是现在我不记得我是否已将进度条放入同步变量中...我只知道 Window 在。您认为我的所有控件都应该在 $synchash 中,即使是那些不会相互影响的控件与运行空间?
    • 我真的不明白,我尝试了一个简单的$syncHash.Window.Dispatcher.invoke([action]{$syncHash.Window.Background='Black'},"Normal"),但窗口没有变黑。即使$SyncHash = [hashtable]::Synchronized(@{ Form = $synchash.Window; ProgressBar = $synchash.ProgressBar }) 放早了..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    相关资源
    最近更新 更多