67579


お世話になります。

掲題の件で原因が分からずに困っております。

BeginOutputReadLineの実行直後に、呼び出し元のPowershell.exe（またはPowershell_ise.exe）が  
ハングアップしてしまう事象が発生しております。非同期ではなく、  
同期による標準出力の読み取りでは問題無いのですが、標準エラーも扱いたいため、  
少なくとも一方を非同期で読み取らせる様にしたいのです。

この問題に関する解決策や、何かしら解決につながるヒントをいただければと存じます。

■当方環境  
Windows 10 32bit  
Powershell v5.1  
.Net Framework 4.7.2

■テストソース

[code]

    Using Namespace System.Diagnostics
    Using Namespace System.Text
    Using Namespace System.Windows.Forms
    
    Add-Type -Assembly System.Windows.Forms
    
    $args = "-Command `"& {Get-Date}`""
    $passwd = [System.Security.SecureString]::new()
    "qwerty123".ToCharArray() | %{$passwd.AppendChar($_)}
    $StartInfo = [ProcessStartInfo]::new('Powershell.exe', $args)
    $StartInfo.RedirectStandardOutput = $true
    $StartInfo.UseShellExecute = $false
    $StartInfo.UserName = $env:USERNAME
    $StartInfo.Password = $passwd
    $StartInfo.Domain = $env:USERDOMAIN
    $StartInfo.LoadUserProfile = $true
    $StartInfo.WorkingDirectory = $env:HOMEPATH
    $p = [Process]::new()
    $p.StartInfo = $StartInfo
    $p.Start()
    $stdout = [StringBuilder]::new()
    $p.add_OutputDataReceived( {
        param( $p, $e )
        $stdout.AppendLine( $e.Data )
    } )
    $p.BeginOutputReadLine()
    
    [MessageBox]::Show($stdout.ToString(), "test")
    
[/code]

【追記】  
また、以下の様にイベントログに記録されています。

障害バケット 1454065438036662408、  
種類 5  
イベント名: PowerShell  
応答: 使用不可  
Cab ID: 0  
問題の署名:  
P1: powershell_ise.exe  
P2: 10.0.18362.752  
P3: Management.Automation.PSInvalidOperation  
P4: Management.Automation.PSInvalidOperation  
P5: anagement.Automation.ScriptBlock.GetContextFromTLS P6:
anagement.Automation.ScriptBlock.GetContextFromTLS P7: unknown P8: P9: P10:


CC BY-SA 4.0
2020-06-12T03:19:43.423
67565
2020-06-13T05:20:46.693
2020-06-12T12:39:54.123
19048
19048
question
.net powershell
PowershellでDiagnostics.ProcessのBeginOutputReadLineを実行するとアプリケーションがハングアップする


指摘事項が多数あるため、再度整理します。

  * [`Process.OutputDataReceived`イベントの例](https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.process.outputdatareceived?view=netframework-4.7.2#-)を見ると`$p.Start()`よりも前にイベントを登録しています。順序を入れ替えてください。
  * [`add_OutputDataReceived`はダメ](https://github.com/PowerShell/PowerShell/issues/12338)でPowerShell v5.1では修正予定がないそうです。[`Register-ObjectEvent`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/register-objectevent?view=powershell-5.1)を使う必要があります。
  * `Register-ObjectEvent`で登録したイベントはきちんと[`Unregister-Event`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/unregister-event?view=powershell-5.1)で解除する必要があります。
  * `Unregister-Event`でイベント解除する前に[`Process.WaitForExit`](https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.process.waitforexit?view=netframework-4.7.2)でプロセスの終了を待つ必要があります。

あといくつか推奨事項も

  * パスワードを指定することがセキュリティを高めることではありません。同じ権限を引き継ぐだけであれば、指定すべきではありません。
  * `RedirectStandardOutput = $true`が期待する動作かと思います。

はどうでしょうか？

[code]

    $args = "Get-Date"
    $stdout = [System.Text.StringBuilder]::new()
    
    $p = [System.Diagnostics.Process]@{
        StartInfo = @{
            FileName = 'Powershell.exe'
            Arguments = $args
            RedirectStandardOutput = $true
            UseShellExecute = $false
            WorkingDirectory = $env:HOMEPATH
        }
    }
    $ev = Register-ObjectEvent $p -EventName OutputDataReceived -MessageData $stdout -Action {
         $Event.MessageData.AppendLine($Event.SourceEventArgs.Data)
    }
    $p.Start()
    $p.BeginOutputReadLine()
    $p.WaitForExit()
    Unregister-Event $ev.Id
    
    [MessageBox]::Show($stdout.ToString(), "test")
    
[/code]

* * *

身もふたもないですが、標準出力と標準エラー出力を混ぜてもよいならこれだけでできます。

[code]

    $args = "Get-Date"
    & powershell.exe $args 2>&1 | Set-Variable stdout
    
    [MessageBox]::Show($stdout, "test")
    
[/code]


CC BY-SA 4.0
2020-06-12T09:30:39.130
67579
2020-06-13T05:20:46.693
2020-06-13T05:20:46.693
4236
4236
67565
answer