我有一个 PowerShell 脚本,它使用 Powershell Workflow 在多个远程服务器上同时运行许多 msdeploy。
一切工作正常,除了在每个“Foreach -Parallel”循环结束时,我得到这个异常:
Microsoft.PowerShell.Utility\Write-Error : The workflow was terminated by a Terminate activity.
At Execute-Bootstrapper:28 char:28
+
+ CategoryInfo : NotSpecified: (:) [Write-Error], WorkflowReturnException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Workflow.WorkflowReturnException,Microsoft.PowerShell.Commands.Writ
eErrorCommand
+ PSComputerName : [localhost]
我该如何解决这个问题?有没有特定的方法来结束工作流程?
以下是与并行执行相关的部分:
foreach -Parallel ($remoteHost in $selectedHosts) {
if($Env:FULL -eq "true") {
$process = Start-Process -PassThru -Wait -NoNewWindow "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" "xxx --full"
} else {
$process = Start-Process -PassThru -Wait -NoNewWindow "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" "xxx"
}
if($process.ExitCode -ne 0) {
Exit $process.ExitCode
}
}
谢谢。
答案1
工作流与 Windows PowerShell 不同……工作流看起来像一个函数使用不同的关键字,但...不要被愚弄——了解工作流最重要的一点是,它们看起来像 Windows PowerShell,但实际上不是。
来源:工作流程:基础知识(在下面作业和工作流程主要文章位于嘿,脚本小伙!博客)。
以下部分注释的脚本可能会有所帮助。使用传递给MSDeploy.exe
以下非常简单的参数进行测试:
-help -verb
有效,退出代码 = 0,而其他-help -brew
并且-help -bubu
不是,退出代码= -1。- 还要注意,
-NoNewWindow
如果没有-RedirectStandardOutput
和-RedirectStandardError
会引发以下错误(考虑-NoNewWindow
完全省略该参数):
Microsoft.PowerShell.Utility\Write-Error
:处理来自后台进程的数据时出错。报告错误:无法处理节点类型为“Text”的元素。仅支持 Element 和 EndElement 节点类型。
workflow procWorkflow {
## workflow parameter
param( $selectedHosts )
## $using: prefix allows us to call items that are in the workflow scope
## but not in the function / inlinescript scope.
Function myStartProcess {
param( [string] $lineargs )
$process = Start-Process `
-FilePath "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" `
-PassThru -Wait -NoNewWindow `
-RedirectStandardOutput "$env:TEMP\$using:remoteHost`Out.txt" `
-RedirectStandardError "$env:TEMP\$using:remoteHost`Err.txt" `
-ArgumentList $lineargs
$process.ExitCode # function return value
}
## parallel foreach loop on workflow parameter
foreach -Parallel ($remoteHost in $selectedHosts) {
if($Env:FULL -eq "true") {
# omitted as I know that there is no $Env:FULL variable defined on my comp
} else {
$processEx = myStartProcess "-help -$remoteHost"
### tried instead above function call:
### $lineargs = "-help -$remoteHost"
### $process = Start-Process -FilePath "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -PassThru -Wait -NoNewWindow -RedirectStandardOutput "$env:TEMP\$remoteHost`Out.txt" -RedirectStandardError "$env:TEMP\$remoteHost`Err.txt" -ArgumentList $lineargs
### and then tried following output alternatives:
### $processEx = $process.ExitCode # null !!!
### $processEx = $process.HasExited # false !!!
### $processEx = $process.GetType().FullName # System.Management.Automation.PSObject
### $processEx = $process # System.Diagnostics.Process (msdeploy)
}
Write-Output @{ $remoteHost = $processEx } # workflow return value
}
}
上述工作流程返回一个哈希表数组(大致hostname: exitcode
成对),因为裸退出代码是不够的,因为它是并行运行的,所以输出顺序是随机的。
## example call to above workflow would look like
$procWorkflow = procWorkflow 'verb','brev','bubu'
## example output processing
"`n=== procWorkflow raw:"
$procWorkflow
"`n=== procWorkflow processed:`n"
for ($i=0; $i -lt $procWorkflow.Count; $i++) {
$procWorkflow[$i].Keys | ForEach-Object {
$procExitcode = $procWorkflow[$i][$_]
if ( $procExitcode -eq 0 ) {
$procOutFile = Get-Item "$env:TEMP\$_`Out.txt"
} else {
$procOutFile = Get-Item "$env:TEMP\$_`Err.txt"
}
'{0,-6} {1,6} {2,12} {3}' -f
$_, $procExitcode, $procOutFile.Length, $procOutFile.Name
}
}
输出:
PS D:\PShell> D:\PShell\SF\805314_workflow.ps1
=== procWorkflow raw:
Name Value
---- -----
bubu -1
brev -1
verb 0
=== procWorkflow processed:
bubu -1 56 bubuErr.txt
brev -1 56 brevErr.txt
verb 0 537 verbOut.txt