为什么传递给脚本块的参数不起作用?
Why does an argument passed into a script block fail to work?
完全披露:我的问题可能是基于对 Xen Desktop 的 Citrix PowerShell 模块的不完全理解。
我有以下脚本块。它在循环中被调用,对列表中的每个 VM 调用一次。我正在使用 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
}
Additional examples inspired by the Robert Cotterman
answer
In all cases, I still get the Could not find open sessions to any
XenServers
error
FYI - Using 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
使用参数的示例。变量内容按预期传入和传出
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
作业和调用命令要求您指定您正在使用变量。只需将变量从
$variable
到
$using:variable
内部变量不需要这个。但是从父脚本调用变量就可以了。
或者,由于您将 $xss 作为参数传递,因此您不会使用 $xss 来调用它,而是
$args[0]
因为这是你的第一个论点。第二个是 $args[1] 等等...
原因是因为整个 xss 变量被作为参数打印,并且没有在作业中命名。它被命名为 $args 并在第一个位置 (0) 中占有一席之地。
我更喜欢 $using:variable,因为它可以减少混淆
我只是不认为它是那样工作的。与 Xen 服务器的连接是为您的 PowerShell 会话创建的,有关该连接的信息收集在 $xss 变量中。每个作业都运行自己的 PowerShell 会话。所以只是将$xss传递给作业是不一样的,它只是对连接细节的描述。
完全披露:我的问题可能是基于对 Xen Desktop 的 Citrix PowerShell 模块的不完全理解。
我有以下脚本块。它在循环中被调用,对列表中的每个 VM 调用一次。我正在使用 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
}
Additional examples inspired by the
Robert Cotterman
answerIn all cases, I still get the
Could not find open sessions to any XenServers
errorFYI - Using 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
使用参数的示例。变量内容按预期传入和传出
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
作业和调用命令要求您指定您正在使用变量。只需将变量从
$variable
到
$using:variable
内部变量不需要这个。但是从父脚本调用变量就可以了。
或者,由于您将 $xss 作为参数传递,因此您不会使用 $xss 来调用它,而是
$args[0]
因为这是你的第一个论点。第二个是 $args[1] 等等... 原因是因为整个 xss 变量被作为参数打印,并且没有在作业中命名。它被命名为 $args 并在第一个位置 (0) 中占有一席之地。
我更喜欢 $using:variable,因为它可以减少混淆
我只是不认为它是那样工作的。与 Xen 服务器的连接是为您的 PowerShell 会话创建的,有关该连接的信息收集在 $xss 变量中。每个作业都运行自己的 PowerShell 会话。所以只是将$xss传递给作业是不一样的,它只是对连接细节的描述。