为什么传递给脚本块的参数无法正常工作?

时间:2018-10-05 18:52:16

标签: powershell scope xen scriptblock

全面披露:我的问题可能是由于对Xen Desktop的Citrix PowerShell模块的不完全了解。

我有以下脚本块。对于一个列表中的每个虚拟机,它被循环调用一次。我之所以使用PowerShell Jobs是因为我想让UI线程保持自由,以便在作业运行时更新UI。

代码“ A”

$j = Start-Job -Name $jobName -ScriptBlock {
    param($url, $uuid, $cred, $snapshotName)
    $ErrorActionPreference = "Stop" 
    try
    {
        $error.clear()
        $xSS = $cred | Connect-XenServer -url $url -NoWarnCertificates -SetDefaultSession -PassThru; 
        $vm = (Get-XenVM -SessionOpaqueRef $xss.opaque_ref -uuid $uuid)
        #Create snapshot
        Invoke-XenVM -Async -SessionOpaqueRef $xss.opaque_ref -VM $vm -XenAction Snapshot -NewName $snapshotName
        return "OK"
    }
    catch
    {
        return ("ERROR: "+$error)
    }
} -ArgumentList $global:configFileVmMetaData.poolUrl, $xenVm.key, $global:cred, $snapshotName

代码“ A” 可以正常运行,但是所需的时间更长,因为每次调用脚本块时我都会执行Connect-XenServer cmdlet。

因此,我尝试一次在循环外调用Connect-XenServer并传入会话变量,如下所示,代码“ B” 。结果是在脚本块中引发了错误Could not find open sessions to any XenServers。我假设$ xss会话变量在传递到脚本块时以某种方式被挂起。

有人知道为什么$ xss会话变量变了吗?

代码“ B”

$xSS = $cred | Connect-XenServer -url $global:configFileVmMetaData.poolUrl -NoWarnCertificates -SetDefaultSession -PassThru; 

loop
{

    $j = Start-Job -Name $jobName -ScriptBlock {
        param($xss, $uuid, $snapshotName)
        $ErrorActionPreference = "Stop" 
        try
        {
            $error.clear()
            $vm = (Get-XenVM -SessionOpaqueRef $xss.opaque_ref -uuid $uuid)
            #Create snapshot
            Invoke-XenVM -Async -SessionOpaqueRef $xss.opaque_ref -VM $vm -XenAction Snapshot -NewName $snapshotName
            return "OK"
        }
        catch
        {
            return ("ERROR: "+$error)
        }
    } -ArgumentList $xss, $xenVm.key, $snapshotName

}
  

Robert Cotterman答案启发的其他示例

     

在所有情况下,我仍然会遇到Could not find open sessions to any XenServers错误

     

仅供参考-使用PowerShell 5.1

使用$using的示例。可变内容按预期方式传入和传出

cls

$aLocal = "AAA"
$bLocal = "BBB"

$j = Start-Job -Name "TestJob" -ScriptBlock {
    return ($using:aLocal + " *** " + $using:bLocal)
    }

while ($true)
{
    $g = get-job -name "TestJob"

    write-host ("get-job " + $g.Name + " is " + $g.State)

    if ($g.State -ne "Running")
    {
        break
    }

    start-sleep -Seconds 1
}

write-host ("receive-Job='" + (receive-Job -Name "TestJob") +"'")

$g = get-Job -Name "TestJob"
Write-Host ("get-Job "+$g.name + " " + $g.state + " " + $g.HasMoreData + " " + $g.id)

if($g)
{
    Remove-Job -Name "TestJob"
}

输出

get-job TestJob is Running
get-job TestJob is Completed
receive-Job='AAA *** BBB'
get-Job TestJob Completed False 45
Remove-Job

使用args的示例。可变内容按预期方式传入和传出

cls

$aLocal = "AAA"
$bLocal = "BBB"

$j = Start-Job -Name "TestJob" -ScriptBlock {
    return ($args[0] + " *** " + $args[1])
    } -ArgumentList ($aLocal, $bLocal)

while ($true)
{
    $g = get-job -name "TestJob"

    write-host ("get-job " + $g.Name + " is " + $g.State)

    if ($g.State -ne "Running")
    {
        break
    }

    start-sleep -Seconds 1
}

write-host ("receive-Job='" + (receive-Job -Name "TestJob") +"'")

$g = get-Job -Name "TestJob"
Write-Host ("get-Job "+$g.name + " " + $g.state + " " + $g.HasMoreData + " " + $g.id)

if($g)
{
    Remove-Job -Name "TestJob"
}

输出

get-job TestJob is Running
get-job TestJob is Completed
receive-Job='AAA *** BBB'
get-Job TestJob Completed False 49

使用命名参数的示例。可变内容按预期方式传入和传出

cls

$aLocal = "AAA"
$bLocal = "BBB"

$j = Start-Job -Name "TestJob" -ScriptBlock {
    param($a, $b)
    return ($a + " *** " + $b)
    } -ArgumentList ($aLocal, $bLocal)

while ($true)
{
    $g = get-job -name "TestJob"

    write-host ("get-job " + $g.Name + " is " + $g.State)

    if ($g.State -ne "Running")
    {
        break
    }

    start-sleep -Seconds 1
}

write-host ("receive-Job='" + (receive-Job -Name "TestJob") +"'")

$g = get-Job -Name "TestJob"
Write-Host ("get-Job "+$g.name + " " + $g.state + " " + $g.HasMoreData + " " + $g.id)

if($g)
{
    Remove-Job -Name "TestJob"
}

输出

get-job TestJob is Running
get-job TestJob is Completed
receive-Job='AAA *** BBB'
get-Job TestJob Completed False 55

2 个答案:

答案 0 :(得分:1)

Jobs和invoke-command要求您指定您正在使用变量。只需从

更改变量
$variable

收件人

$using:variable

内部变量不需要此。但是从父脚本中调用变量确实可以。

或者,由于您将$ xss作为参数传递,因此您不会使用$ xss来调用它,而是

$args[0]

因为这是您的第一个论点。 $ args [1]用于第二个等等... 原因是因为整个xss变量都被打印为参数,而未在作业内部命名。它的名称为$ args,在第一个插槽(0)中有一个位置。

我更喜欢$ using:variable,因为它可以减少混乱

答案 1 :(得分:1)

我只是认为这种方式不起作用。 Xen服务器的连接是为PowerShell会话创建的,有关该连接的信息收集在$ xss变量中。每个作业都运行自己的PowerShell会话。因此,只是将$ xss传递给作业是不一样的,只是对连接详细信息的描述。