powershell - 我可以在 Powershell 中打开无缓冲程序输出吗?
问题描述
我正在尝试将 Putty 的 plink.exe 用作 Powershell 脚本的一部分,但在输出时遇到了麻烦。
一些命令调用交互式响应(例如:输入密码)。具体来说,我正在针对 Isilon 进行测试。
示例代码:
$command = '&"C:\Program Files\Putty\plink.exe" root@10.0.0.141 -pw "password" -t -batch "isi auth users create testuser --set-password"'
iex $command
预期结果:
- 我收到提示
password:
- 我输入密码
- 我收到提示
confirm:
- 我再次输入密码
- 命令结束
如果我尝试 tee 输出,使用iex $command | tee-object -variable result
,甚至只是重定向iex $command *>test.log
,提示文本直到我响应它之后才会显示。虽然在技术上仍然可以正常工作,但如果您不确切知道会出现什么提示,那么它是无用的。
我试过使用 Start-Transcript,但这根本没有捕获输出。我也尝试过使用 plink 的 -sshlog 参数,但是记录太多了,格式不可读。
有没有办法让标准输出在控制台中不受缓冲,并将其存储在变量中?
要回答一些潜在的问题:
-这是在不允许模块的环境中运行的,因此不能使用 Posh-SSH。
- 可用的 Powershell 版本不够新,无法使用内置的 openssh 功能。
解决方案
这都是关于重定向流的。
当您使用重定向时,所有输出都从流中重定向,并传递以写入文件。当你执行:
Write-Host "Some Text" *>out.txt
您看不到任何输出,并且全部重定向到该文件。
关键说明:重定向是逐行(简化)工作的,因为重定向是通过一次一行地写入文件来工作的。
同样,当您使用 时Tee-Object
,所有输出都从流重定向到管道。这将传递给 cmdlet Tee-Object
。Tee-Object
接受输入,然后将该输入写入您想要的变量/文件和屏幕。这发生在收集和处理输入之后。
这意味着重定向和Tee-Object
命令都是逐行工作的。重定向和命令都以这种方式工作是有意义Tee-Object
的,因为在尝试编辑和维护打开的文件的同时,很难处理诸如删除字符、四处移动和动态编辑文本之类的事情。它只设计为单向的,一旦语句完成,输出。
在这种情况下,交互运行时,password:
提示会写入屏幕,您可以做出响应。
重定向/Teeing 输出时,password:
文本提示被重定向并缓冲,等待您的响应。这是有道理的,因为该语句尚未完成。您不想发送半个可能更改的语句,或半个对象到管道中。只有在您完成语句(例如输入密码 + 回车)之后,整个语句才会沿流/管道传递。发送整个语句后,它会被重定向/输出 Tee'd 并可以显示。
@Bill_Stewart 是正确的,因为您应该选择交互式提示或全自动解决方案。
编辑:从评论中添加更多信息。
如果我们使用Tee-Object
它依赖于管道。管道只能将完整的对象传递到管道中(例如,完整的字符串,包括新线)。管道必须与其他命令交互,例如ForEach-Object
or Select-Object
,并且它们无法处理将不完整的数据传递给它们。这就是PowerShell 控制台的工作方式,您无法更改它。
同样,重定向是逐行进行的。背后的原因,我稍后会解释为什么。
所以,如果你想逐个字符地与它交互,那么你正在处理流。而如果你想直接处理流,它会复杂100倍,因为你不能使用PowerShell控制台的便利,你必须直接手动运行进程并自己处理所有输入和输出。
首先,您必须手动启动该过程。为此,我们使用System.Diagnostics.Process类。伪代码看起来像这样:
$p = [System.Diagnostics.Process]::New()
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.RedirectStandardError = $true
$p.StartInfo.RedirectStandardInput = $true
$p.StartInfo.UseShellExecute = $false
#$p.StartInfo.CreateNoWindow = $true
$p.StartInfo.FileName = "plink.exe"
$p.StartInfo.Arguments = 'root@10.0.0.141 -pw "password" -t -batch "isi auth users create testuser --set-password"'
$p.EnableRaisingEvents = $true
....
我们实质上是创建进程,指定我们将重定向标准输出(StartInfo.RedirectStandardOutput = $true
)以及标准输入到其他东西以供我们处理。我们如何知道何时读取数据?好吧,这个类有Process.OutputDataReceived Event。您绑定到此事件以读取附加数据。但:
OutputDataReceived 事件表明关联的 Process 已将一行以换行符结尾的行写入其重定向的 StandardOutput 流。
因此,即使流程类也围绕流数据的换行符展开。这就是为什么甚至重定向*>
都是逐行工作的。PowerShell、cmd等都使用Process类作为运行进程的基础。它们都绑定到相同的事件和方法来进行处理。因此,为什么一切都围绕换行符和语句完成。
(大口喘气)所以。您仍然想一次一个角色以交互方式处理事物吗?那么你不能使用事件的便利。您将不得不回退到使用 Stream Reader 并直接绑定到Process.StandardOutput Property。不幸的是,这就是我停下来的地方,并说要实现这一点超出了 SO 的范围,并且需要更多的研究才能完成。
推荐阅读
- python - 根据最后 4 个字符从两个列表中返回匹配字符串
- ruby - Bundler 找不到 gem "globalize" 的兼容版本:
- redirect - 同站点内容安全策略
- python - 如果它们相似,如何通过元素而不是索引在熊猫系列中进行切片
- firebase - FLUTTER 个人资料图片在用户离开页面时消失
- authentication - 使用一个用户数据库对 2 个不同的基于云 (aws/gcp) 中的用户进行身份验证,并且只验证一次
- aws-cdk - 如何通过 AWS CDK 使用“域名”引用 ACM 证书
- javascript - 在类型脚本/角火中三个点是什么意思
- python - PySpark - 为 24 小时窗口提取列的最大值,然后删除重复项
- javascript - addEventListener 中 this 的值