当我使用cmd
并将管道输送到使用powershell
来读取输入的ReadLine()
时,它会按预期接受管道输入:
C:\Users\ohnob>ECHO hi|powershell -Command "write-host $host.UI.ReadLine()"
hi
hi
但是,当使用cmd
并使用powershell
管道连接到ReadLineAsSecureString()
时,它将一直挂起,直到我在终端中键入return为止:
C:\Users\ohnob>ECHO hi|powershell -Command "write-host $host.UI.ReadLineAsSecureString()"
当会话是交互式的时,我需要阅读为安全字符串(使用星号)。但是我需要在有管道输入时读取管道输入。如何在powershell
中完成此操作?我希望能够以某种方式检测到stdin是否是管道,然后有条件地使用ReadLine()
而不是ReadLineAsSexcureString()
,但是我不知道如何在powershell中获取标准输入的句柄-我只能访问此PSHostUserInterface
对象。
编辑:为明确起见,当我使用ReadLineAsSecureString()
或ReadLine()
时,我希望它从输入中读取一行。这样就可以多次使用它,并且用户可以为脚本提供多个值。我希望所有答案都能代替我使用的功能,除非没有我要避免的问题。谢谢!
答案 0 :(得分:1)
Jeroen Mostert在注释中提出了一些要点,尤其是$host.UI.ReadLineAsSecureString()
/ Read-Host -AsSecureString
大概 设计为不接受管道输入,出于安全原因 [1] 。
因此,您必须明确区分接收管道输入和不接收任何管道输入:
PowerShell通过自动$Input
变量提供对从外部管道输入的stdin输入的访问。
$MyInvocation.ExpectingInput
通常指示是否存在管道输入。
如果有管道输入,请将其第一行 [2] 传递到ConvertTo-SecureString
;
如果没有,请致电Read-Host -AsSecureString
:
$secStr = if ($MyInvocation.ExpectingInput) {
# Alternatively, use $firstLine = [console]::ReadLine() - thanks, @binki
$firstLine = $($null = $Input.MoveNext(); $Input.Current)
ConvertTo-SecureString -AsPlainText -Force $firstLine
} else {
Read-Host -AsSecureString -Prompt 'Enter secret'
}
作为要从cmd.exe
进行调用的命令行,它还会输出结果:
C:>echo hi| powershell -Command "$secStr = if ($MyInvocation.ExpectingInput) { $firstLine = $($null = $Input.MoveNext(); $Input.Current); ConvertTo-SecureString -AsPlainText -Force $firstLine } else { Read-Host -AsSecureString -Prompt 'Enter secret' }l$secStr"
不过,请注意,安全字符串在设计上通常会以System.Security.SecureString
的形式打印,这就是您所看到的全部内容。
[1]我正在推测,而没有有关这方面的文档。将{<1>}的纯文本字符串 Piping 肯定具有不安全的更大的潜力:通过管道传输的纯文本字符串可以这样保存在某个地方,并且至少假设,如果使用Read-Host -AsSecureString
之类的东西,则该进程的命令行将反映该机密信息。
无论哪种方式,将纯文本传递到MyCustomEcho.exe secret | ...
始终是一种选择,其中其他需要传递ConvertTo-SecureString -AsPlainText
的同时也表示PowerShell考虑使用未键入的纯文本输入互动。
[2]自动-Force
变量是枚举器(类型),用于按需枚举来自stdin 的行。 不支持这样的索引访问权限,例如$Input
;相反,必须使用$Input[0]
开始枚举,然后访问.MoveFirst()
属性以获取第一行。这样,剩下的元素就不会被消耗,以后使用.Current
会产生剩下的行。
$Input
周围的$(...)
的唯一原因是,为了概念清晰起见,可以将两个语句包装在返回第一行的 single 语句中。先使用$null = $Input.MoveNext(); $Input.Current
和$null = $Input.MoveNext()
也很好。