powershell - Powershell流水线数据到外部控制台应用程序

标签 powershell console-application buffer stdin pipeline

我有一个控制台应用程序,可以接受标准输入。它缓冲数据直到执行命令,然后执行所有命令,然后将输出发送到标准输出。
目前,我正在Powershell中运行此应用程序,将命令管道传输到其中,然后解析输出。管道中的数据相对较小;但是,此应用程序被调用了大约1000次。每次执行时,都必须加载并创建网络连接。我想知道将所有命令传递到控制台应用程序的单个实例中是否更有效。
我通过将所有为控制台创建标准输入的Powershell脚本添加到函数中,然后将该函数通过管道传递到控制台应用程序来进行尝试。这似乎起初是可行的,但是您最终意识到它正在缓冲Powershell中的所有数据,直到功能完成,然后将其发送到控制台的StdIn。您可以看到此信息,因为我有大量的Write-Host语句在闪烁,然后才看到输出。
例如

Function Run-Command1
{
    Write-Host "Run-Command1"
    "GET nethost xxxx COLS id,name"
    "EXEC"
}

Function Run-Command2
{
    Write-Host "Run-Command2"
    "GET nethost yyyy COLS id,name"
    "GET users yyyy COLS id,name"
    "EXEC"
}

...

Function Run-CommandX 
{
...
}
以前,我将其用作:
Run-Command1 | netapp.exe -connect QQQQ -U user -P password
Run-Command2 | netapp.exe -connect QQQQ -U user -P password
...
Run-CommandX | netapp.exe -connect QQQQ -U user -P password
但是现在我想做的是:
Function Run-Commands
{
    Run-Command1
    Run-Command2
    ...
    Run-CommandX
}

Run-Commands |
netapp.exe -connect QQQQ -U user -P password
理想情况下,我希望将Powershell管道行为扩展到外部应用程序。这可能吗?

最佳答案

编辑:正如@ mklement0指出的那样,在PowerShell Core中这是不同的。
在PowerShell 5.1(及更低版本)中,您必须手动将每个管道项目写入外部应用程序的输入流。
这是为此构建函数的尝试:

function Invoke-Pipeline {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$FileName,

        [Parameter(Position = 1)]
        [string[]]$ArgumentList,

        [int]$TimeoutMilliseconds = -1,

        [Parameter(ValueFromPipeline)]
        $InputObject
    )
    begin {
        $process = [System.Diagnostics.Process]::Start((New-Object System.Diagnostics.ProcessStartInfo -Property @{
            FileName = $FileName
            Arguments = $ArgumentList
            UseShellExecute = $false
            RedirectStandardInput = $true
            RedirectStandardOutput = $true
        }))
        $output = [System.Collections.Concurrent.ConcurrentQueue[string]]::new()
        $event = Register-ObjectEvent -InputObject $process -EventName 'OutputDataReceived' ` -Action {
             $Event.MessageData.TryAdd($EventArgs.Data)
        } -MessageData $output
        $process.BeginOutputReadLine()
    }
    process {
        $process.StandardInput.WriteLine($InputObject)
        [string]$line = ""
        while (-not ($output.TryDequeue([ref]$line))) {
            start-sleep -Milliseconds 1
        }
        do {
            $line
        } while ($output.TryDequeue([ref]$line))
    }
    end {
        if ($TimeoutMilliseconds -lt 0) {
            $exited = $process.WaitForExit()
        }
        else {
            $exited = $process.WaitForExit($TimeoutMilliseconds)
        }
        if ($exited) {
            $process.Close()
        }
        else {
            try {$process.Kill()} catch {}
        }
    }
}

Run-Commands | Invoke-Pipeline netapp.exe "-connect QQQQ -U user -P password"
问题是,没有完美的解决方案,因为根据定义,您不知道外部程序何时将某些内容写入其输出流,或写入多少。
注意:此函数不会重定向错误流。但是,方法是相同的。

关于powershell - Powershell流水线数据到外部控制台应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64662888/

相关文章:

powershell - 在 WASP/powershell 中通过窗口获取进程对象?

powershell - PowerShell中强制参数的默认值

C# 控制台应用程序。 Windows 启动时没有图标

c - RNG 字符打印功能 - 每页有多于一行 RNG 字符? : C

javascript - 字符串在 Node 中的 TLS 套接字连接中的另一端连接

python - 使用缓冲区的最长公共(public)前缀?

.net - 是否存在指定的(子)索引分隔符?

windows - 在 Windows 命令行上运行 raco

c# - 为什么控制台窗口在显示我的输出后立即关闭?

python - 避免缓冲读取 "for line in ..."