none
ジョブ管理下のコマンド実行で例外が発生する RRS feed

  • 質問

  • お世話になっております。

    Powershellで、O365のとあるテナント約8,500ユーザーからメールボックス設定等の情報を収集し

    CSV出力するスクリプトを組んでおります。

    パラメータとして、プリンシパル名が必須のコマンド(Get-MailboxFolderPermissionなど)は

    ユーザー毎にコマンド実行し情報取得していたのですが、コマンド実行後にスクリプトが応答なしになり

    処理を継続できない状況が度々発生したため、下記の様にコマンドをジョブ管理下に置き

    一定時間経過後にコマンド実行を打ち切って応答なしにならないよう調整しました。

    [調整前例]

    $MailBoxStatItem = Get-MailboxStatistics -Identity {プリンシパル名} | select -First 1

    [調整後例]

    # JOB管理下でコマンド実行
    $job = Invoke-Command -Session (Get-Pssession) -ScriptBlock {
        Get-MailboxStatistics -Identity $args[0] | select-object -First 1
    } -AsJob -ArgumentList {プリンシパル名}
    
    # 60秒間 JOBの応答を待機
    Wait-Job -Job $job -Timeout 60 | Out-Null
    
    # JOBの結果(コマンド完了または待機時間経過)
    if($job.State -eq "Completed"){
        # コマンド完了
        $MailBoxStatItem = Receive-Job $job    #結果を取得
        break
    }else{
        # コマンド未完了
        Stop-Job $job    #JOB強制停止
    }
    
    Remove-Job -force $job    #cleanup

    すると、今度はある程度処理が進んだところで、ジョブが"Failed"で失敗し

    以降も全て"Failed"でコマンド実行が行えない状況となりました。

    その際発生した例外は下記となります。

    --------------------

    "System.Management.Automation.Runspaces.InvalidRunspaceStateException: 実行空間の状態が Opened ではないため、パイプラインを呼び出せません。実行空間の現在の状態は 'Broken' です。
       場所 System.Management.Automation.RemoteRunspace.AddToRunningPipelineList(RemotePipeline pipeline)
       場所 System.Management.Automation.RemoteRunspace.DoConcurrentCheckAndAddToRunningPipelines(RemotePipeline pipeline, Boolean syncCall)
       場所 System.Management.Automation.RemotePipeline.InitPowerShell(Boolean syncCall, Boolean invokeAndDisconnect)
       場所 System.Management.Automation.RemotePipeline.InvokeAsync()
       場所 Microsoft.PowerShell.Commands.ExecutionCmdletHelperRunspace.StartOperation()"

    --------------------

    実施した調整内容が正しくないという可能性もあるとは思いますが、

    まずこのエラー内容自体の情報が少ないため、詳細についてお伺いしたいと考えた次第です。

    ・この例外エラーは、どのような意味合いを持っているのでしょうか。(「実行空間」とは何を指すのでしょうか)

    ・この例外エラーは、どのような状況で発生するのでしょうか。

    ・この例外エラーが発生した場合、回復方法はあるのでしょうか。

    ご教示を頂けると幸いです。

    宜しくお願い致します。

    2017年11月20日 1:23

回答

  • それでしたら、New-PSSessionコマンドレットでPSSessionを作成するときに、-SessionOptionパラメータでPSSessionOptionを付与することで解決しそうに思います。

    PSSessionOptionは、New-PSSessionOptionコマンドレットを用いて作成します。おそらく-OperationTimeoutパラメータでPSSessionの生存時間を長めに指定することでタイムアウトを回避できるのではないかと思います。

    もし、タイムアウト以外の原因でPSSessionが壊れてしまっている場合は、仰る通り再接続でジョブの結果を取得できるかもしれません。ただし、Connect-PSSessionで再接続できるのはDisconnected状態のPSSessionのみで、Brokenの場合は無理だったように思います。

    • 回答としてマーク 堂本大輔 2017年11月29日 1:30
    2017年11月20日 17:27
    モデレータ

すべての返信

  • Invoke-Command -Session -Scriptblock -AsJobは、「PSSession(リモートセッション)上でコマンドを実行する」操作をバックグラウンドジョブとして実行する、という挙動をします。

    ご提示のスクリプトでは-Sessionパラメータに対して、Get-PSSessionコマンドレットの出力値を与えています。ここではGet-PSSessionコマンドレットをパラメータなしで実行しているので、現在実行中のセッション上に存在するPSSessionが出力されます。このPSSessionの出所がちょっとわからないのですが、エラーメッセージを見る感じでは、Opened、すなわち接続状態になっていないのでコマンドが失敗しているように見えます。

    いずれにせよ、今回のケースでは、何らかのPSSessionに接続してそこでコマンドを実行する必要は無いように思います。つまり、Invoke-Commandではなく、単純にStart-Jobコマンドレットを使い、現在のセッション上でコマンドをジョブとして実行すれば良いかと思います。

    具体的には、

    $job = Start-Job -ScriptBlock {
        Get-MailboxStatistics -Identity $args[0] | select-object -First 1
    } -ArgumentList {プリンシパル名}
    

    に置き換えてみてください。


    2017年11月20日 5:04
    モデレータ
  • 牟田口様

    ご返信いただき有難うございます。

    説明不足で申し訳ありません。

    コードに記述しているPSSessionは、スクリプトの冒頭で実施している

    Office365への接続セッションを示しています。

    下記コードで接続しています。

    Import-Module MSOnline	
    $O365Password = ConvertTo-SecureString "********" -AsPlainText -Force
    $O365Cred = New-Object System.Management.Automation.PSCredential hoge@hoge.onmicrosoft.com,$O365Password
    Connect-MsolService -Credential $O365Cred												
    $O365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $O365Cred -Authentication Basic -AllowRedirection						
    Import-PSSession $O365Session

    ご教示頂いたStart-Jobで試してみたところ、"Get-MailboxStatisticsをコマンドレットとして認識できない"となるので、

    やはりInvoke-CommandでPSSessionを渡さないといけないのかな、と考えております。

    ご回答いただいた中で、いましがたごく安易に考えたのですが、

    >Opened、すなわち接続状態になっていないのでコマンドが失敗しているように見えます。

    ということは、Office365への接続セッションを再確立させれば、後続処理はリカバリー可能なのかな、と思い立っています。


    • 編集済み 堂本大輔 2017年11月20日 6:44 一部文言修正
    2017年11月20日 6:42
  • それでしたら、New-PSSessionコマンドレットでPSSessionを作成するときに、-SessionOptionパラメータでPSSessionOptionを付与することで解決しそうに思います。

    PSSessionOptionは、New-PSSessionOptionコマンドレットを用いて作成します。おそらく-OperationTimeoutパラメータでPSSessionの生存時間を長めに指定することでタイムアウトを回避できるのではないかと思います。

    もし、タイムアウト以外の原因でPSSessionが壊れてしまっている場合は、仰る通り再接続でジョブの結果を取得できるかもしれません。ただし、Connect-PSSessionで再接続できるのはDisconnected状態のPSSessionのみで、Brokenの場合は無理だったように思います。

    • 回答としてマーク 堂本大輔 2017年11月29日 1:30
    2017年11月20日 17:27
    モデレータ
  • お世話になっております。

    ご返答が遅くなり、申し訳ございませんでした。

    対処として、エラー発生時にセッションのStateを確認し、

    BrokenであればRemove-PSSession->前述のセッション生成コード で

    セッションを再生成し、コマンドを再リトライするように処置しました。

    一旦、この状態で様子を見ようと思います。

    この度はご助言頂き有難うございました。

    2017年11月29日 1:30