我有两个脚本:
脚本 1和脚本2
脚本 1包含:
$Title = "bullshit"
$host.UI.RawUI.WindowTitle = $Title
$Name = Read-Host -Prompt 'Input your name'
Write-Host "Your name is '$Name'"
脚本 2包含:
./Script1.ps1
我需要的是运行 Script2,它将运行 Script1,一旦该脚本要求用户输入,Script2 只需按回车键,让它继续。
我尝试了这里提到的解决方案,但它不起作用 - 它一直在等待用户输入,只有在您手动按 Enter 后,它才会产生按键(输入)。
我发现的其他 Script2 建议解决方案与上述解决方案具有相同的问题:
./Script1.ps1
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('bullshit')
Sleep 2
$wshell.SendKeys('myPassword{ENTER}')
你知道我做错了什么吗? 一旦脚本 1 要求,如何使脚本 2 按回车键?
您的问题的直接答案是,您需要在./Script1.ps1
调用并行运行击键发送代码,因为./Script.ps1
是一个同步调用,其Read-Host
调用会阻止进一步处理,直到提供响应。
但是,正如 kconsiglio 所指出的那样,在您的简单情况下,只需提前发送击键就足够了,依靠它们进行缓冲并稍后由Read-Host
读取,这不需要并行性:
# Send the keystrokes and rely on their getting buffered,
# so that the subsequently launched ./Script.ps1 reads them.
(New-Object -ComObject Wscript.Shell).SendKeys('myPassword{ENTER}')
./Script.ps1
您可能需要并行性才能与交互式脚本进行更复杂的交互,在这种情况下,您可以使用Start-Job
或最好是Start-ThreadJob
(默认情况下在PowerShell (Core) 7+中可用,可在Windows PowerShell中按需安装)进行以下并行执行:
$Title = "bullshit"
$host.UI.RawUI.WindowTitle = $Title
# Launch the keystroke-sending code in parallel, in the background.
# Note: If Start-ThreadJob is available / installed, use it instead.
$jb = Start-Job {
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('bullshit')
Sleep 1
$wshell.SendKeys('myPassword{ENTER}')
}
$Name = Read-Host -Prompt 'Input your name'
Write-Host "Your name is '$Name'"
Remove-Job -Force $jb
但是,发送击键总是很脆弱(可能会中断),并不总是一种选择(例如,在隐藏的计划任务中),如果有强大的替代方案,最好避免:
您可以通过以下两种方式之一自动输入到Read-Host
:
通过PowerShell CLI调用目标脚本,在这种情况下,可以通过管道 (stdin) 提供
Read-Host
响应 - 值得注意的是,这在会话中不起作用:# Note: Use 'pwsh.exe' if you're running PowerShell (Core) 7+ 'myPassword' | powershell.exe -File ./Script.ps1
- 潜在的缺点(除了由于启动另一个 PowerShell 实例而导致的性能下降)是
./Script.ps1
的输出将仅是文本。
- 潜在的缺点(除了由于启动另一个 PowerShell 实例而导致的性能下降)是
定义一个代理
Read-Host
函数,该函数替代内置 cmdlet 并自动返回所需的字符串,而不是提示:
此function Read-Host { 'mypassword' } ./Script.ps1 Remove-Item function:Read-Host
技术是从此答案中借用的,该答案还显示了如何根据提示字符串使自动响应成为条件。
优点是进程内执行,在脚本的输出中保留类型保真度。
请注意,您只需要返回实际所需的响应,例如
'mypassword'
- 这里不涉及击键的模拟,因此不需要诸如{ENTER}
之类的关键说明符(只有.SendKeys()
方法才能理解)。