Powershell Return-Job 有时会返回空值

Posted

技术标签:

【中文标题】Powershell Return-Job 有时会返回空值【英文标题】:Powershell Return-Job sometimes returns empty values 【发布时间】:2020-07-25 01:23:15 【问题描述】:

我正在使用 Powershell 脚本通过 Start-Job API 并行检查多个 TFS 构建的状态。

一切似乎都运行良好,但如果我在构建启动后立即取消构建,Receive-Job 似乎返回 null,尽管任务已完成。

这是充当看门人的代码:

While (@(Get-Job | Where  $_.State -eq "Running" ).Count -ne 0)

    ForEach ($Job in (Get-Job)) 
       $currentJobOutput = Receive-Job $job 6>&1  
    
   Start-Sleep -Seconds $buildCheckingIntervalInSeconds


$jobsReturnData = @()
ForEach ($Job in (Get-Job)) 
Write-Host $job.State
    Wait-Job $job | out-null
   $hastBaleResult = Receive-Job $Job -Wait:$true;
   $jobsReturnData += New-Object PSObject -property $hastBaleResult
   Remove-Job $Job


Write-Host "`n`nBuilds recap`n"
Write-Host "Build Definition Name".PadRight(29,' ')"Build Status".PadRight(14,' ')"Build Execution URL"
$hasAnyBuildFailed=$false;

foreach($jobReturnData in $jobsReturnData)

Write-Host "JobReturnedData"$jobReturnData
    $currentForegroundColor="White";
    switch($jobReturnData.buildStatus)
        "succeeded" $currentForegroundColor="Green"; break
        "partiallySucceeded" $currentForegroundColor="Yellow"; break
        "failed" $currentForegroundColor="Red"; break
        "canceled" $currentForegroundColor="Red"; break
    

    Write-Host -ForegroundColor $currentForegroundColor "$($jobReturnData.buildDefinitionName.PadRight(30,' '))$($jobReturnData.buildStatus.PadRight(15,' '))$($jobReturnData.buildUrl)"
    if(($jobReturnData.buildStatus -eq "failed") -or ($jobReturnData.buildStatus -eq "canceled"))
        $hasAnyBuildFailed = $true;
    


if($hasAnyBuildFailed)
    throw "Not all builds completed successfully";

大多数时候它工作正常,但如上所述,在某些情况下我得到的输出是

Completed
Completed
Pull Request - Full Build      - ExecID=247764 - Build Status: canceled        - You can access the build execution at myTfs/_build/index?buildId=247764&_a=summary
DeleteMe:Returning System.Collections.DictionaryEntry System.Collections.DictionaryEntry System.Collections.DictionaryEntry


Builds recap

Build Definition Name         Build Status   Build Execution URL
JobReturnedData 
You cannot call a method on a null-valued expression.
At myScript.ps1:377 char:60
+ ... undColor "$($jobReturnData.buildDefinitionName.PadRight(30,' '))$($jo ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At myScript.ps1:377 char:114
+ ... adRight(30,' '))$($jobReturnData.buildStatus.PadRight(15,' '))$($jobR ...
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull


JobReturnedData @buildStatus=canceled; buildDefinitionName=Pull Request - Full Build; buildUrl=myTfs/_build/index?buildI
d=247764&_a=summary
Pull Request - Full Build     canceled       myTfs/_build/index?buildId=247764&_a=summary
Not all builds completed successfully
At myScript.ps1:384 char:5
+     throw "Not all builds completed successfully";
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Not all builds completed successfully:String) [], RuntimeException
    + FullyQualifiedErrorId : Not all builds completed successfully

这是什么原因造成的?

【问题讨论】:

我尝试使用 -keep 但得到了相同的结果。你能扩展第二部分吗?我不太明白 在您的 while 循环条件下,您正在运行 get-job。在while 内的foreach 循环中,您正在运行另一个get-job。那里的内部foreach 循环有什么意义?如果作业在您的第一次get-job 和第二次get-job 调用之间完成,那么$currentJobOutput 将有您的作业输出,并且您永远不会在脚本中再次调用该变量。此时,下一个get-job 将不会产生任何结果,因为您的receive-job 命令将其删除。如果您的作业碰巧流式输出,那么在每个循环中,$currentJobOutput 中捕获的所有内容都会被覆盖。 TL;DR:我认为while 中的第一个foreach 会破坏一切。如果你真的想要它,它需要在receive-job 命令上使用-keep 【参考方案1】:

我最终将排队的作业存储在一个数组中并对其进行迭代。

$jobsReturnData = @()
While (@($jobs | Where  $_.State -eq "Running" ).Count -ne 0) 

    #Redirect the transient output from each job to the main output window
    ForEach ($job in @($jobs | Where  $_.State -eq "Running" )) 
        $currentJobOutput = Receive-Job $job 6>&1
        if($job.HasMoreData)
            Wait-Job $Job -Timeout $buildCheckingIntervalInSeconds
        
    
    #Get return values from each completedjob without waiting for all jobs to finish
    ForEach ($job in @($jobs | Where  ($_.State -eq "Completed"))) 
        $jobReturnData = Receive-Job $Job -Wait:$true;
        $jobsReturnData += New-Object PSObject -property $jobReturnData
        Remove-Job $Job
        $jobs[[array]::IndexOf($jobs, $Job)] = $null
    


    Start-Sleep -Seconds $buildCheckingIntervalInSeconds


#Get return values from each completedjob
ForEach ($job in @($jobs | Where  ($_.State -eq "Completed"))) 
    $jobReturnData = Receive-Job $Job -Wait:$true;
    $jobsReturnData += New-Object PSObject -property $jobReturnData
    Remove-Job $Job
    $jobs[[array]::IndexOf($jobs, $Job)] = $null

我注意到有时一项工作已经完成,但一直运行到等待工作完成,这很令人费解。

我添加了两个检查以从已完成的作业中获取返回值,这样就不必等待所有作业都完成后才能在屏幕上显示更新。

【讨论】:

请尽可能Accept it as an Answer,这对阅读此主题的其他社区成员会有所帮助。

以上是关于Powershell Return-Job 有时会返回空值的主要内容,如果未能解决你的问题,请参考以下文章

将当前时间分配给powershell变量

隐藏用户建立(Powershell)

控制台窗口和powershell运行服务会卡住的解决办法

命令行转义PowerShell的单引号

如果文件存在,Powershell 移动项目重命名

如果 IP 地址已配置,如何使用 Powershell 脚本检查