从批处理文件或命令行打开我的 PowerShell 脚本时,它不起作用,但在直接运行时可以工作

My PowerShell script does not work when opening it from a batch file or the command line, but it works when running directly

提问人:StrangerDanger 提问时间:11/18/2023 最后编辑:mklement0StrangerDanger 更新时间:11/18/2023 访问量:66

问:

我正在尝试做什么:

使用 .bat 文件调用生成自签名证书和密钥对 (.pem) 的 .ps1 文件(不要询问),然后 .bat 文件会将每个 .pem 移动到新目录。

我做了什么:

我有 .ps1 文件正常工作,它生成两个文件,但它确实需要以管理员身份运行 PowerShell。我有 .bat 文件在应该调用 .ps1 文件时调用。在批处理文件中,我正在打开 PowerShell,然后以管理员身份打开另一个 PowerShell 实例(因为无法从命令行以管理员身份运行 PS,如果我错了,请纠正我)。下面是代码行:

PowerShell -Command "& {Start-Process PowerShell -ArgumentList '-NoExit -File ""cert-gen.ps1""' -Verb RunAs}"

发生了什么事情:

运行此行时,我看到弹出一个 PS 窗口并立即关闭,它不会生成我的证书和密钥。由于它立即关闭,我看不到该窗口中是否有任何错误,并且命令行确实显示任何错误。我很确定我在正确的地方。-NoExit

奖金:

这需要完全自动化,无需用户交互,因此 UAC 提升的提示将不起作用。我最终也需要找到解决这个问题的方法,所以如果有一个解决方案可以一次性解决所有这些问题,那就更好了!

PowerShell 批处理文件 SSL 证书 UAC 提升权限

评论

0赞 Olaf 11/18/2023
启动(命令行界面)以启动会话(另一个命令行界面),在该会话中启动另一个会话(再次是另一个命令行界面)。对不起,但我不能“(不要问)”......🤷🏼‍♂️🤔CMD.exePowerShell.exePowerShell.exe
1赞 SomethingDark 11/18/2023
@Olaf - 当我遇到 PowerShell 的默认执行策略不允许直接执行它的情况时,我经常使用该技术,例如在使用体面的安全策略时。
2赞 SomethingDark 11/18/2023
如果批处理脚本以管理员身份运行,则后续的 PowerShell 调用也将以管理员身份运行。
0赞 StrangerDanger 11/18/2023
@Olaf - 我明白,这是一团糟。这正在被实施到现有的复杂批处理脚本链中。实际上,还有其他几层脚本调用了我故意遗漏的其他脚本。启动 PowerShell 并启动另一个 PowerShell 的唯一原因是以管理员身份运行该 PowerShell,这是我找到的唯一方法,stackoverflow.com/questions/19335004/......
0赞 StrangerDanger 11/18/2023
@SomethingDark - 是的,这奏效了。我将 .bat 行简化为只是,.ps1 正在做它应该做的事情。现在我唯一的挂断是我不确定链中的先前脚本是否以管理员身份启动。我不认为他们是。但无论如何,这让我回到了正轨。谢谢!PowerShell -File "cert-gen.ps1"

答:

3赞 mklement0 11/18/2023 #1
:: From a batch file
PowerShell -Command "Start-Process PowerShell -ArgumentList '-NoExit -File \"%CD%\cert-gen.ps1\"' -Verb RunAs"
  • 主要问题是,当使用提升调用 powershell.exe(Windows PowerShell CLI)时,它总是使用 C:\Windows\System32 作为工作目录。因此,它无法在那里找到您的脚本。cert-gen.ps1

    • %CD%\cert-gen.ps1确保脚本通过其完整路径传递,从而解决该问题。 按 up front 展开,到当前目录的完整路径。%CD%cmd.exe

    • 请注意,您的脚本必须准备好处理作为工作目录运行的问题;例如,如果需要,它可以使用自动$PSScriptRoot变量来引用自己的目录。C:\Windows\System32

    • 顺便说一句:不幸的是,如果找不到目标脚本,则通过调用的 CLI 会话会自动关闭(当与失败的命令一起使用时,会话保持打开状态);GitHub 问题 #10471 建议更改此行为。-NoExit-File-Command

  • 移除了不必要的外壳:& { ... }

    • 没有理由使用通过 () 参数传递给 PowerShell 的 CLI 的代码 - 直接使用即可。旧版本的 CLI 文档错误地建议这是必需的,但此后已得到纠正。"& { ... }"-Command-c"..."& { ... }
  • 虽然转义嵌入的字符恰好在这种情况下起作用,但它不能稳健地工作,所以改用:"""\"

    • 但是,使用 pwsh.exe,PowerShell (Core) 7+ 确实可以稳健地工作,并且比 更可取,因为它避免了 cmd.exe 的解析可能会破坏命令的边缘情况 - 有关详细信息,请参阅此答案""\"

至于问题的UAC部分

  • 防止批处理文件触发 UAC 提示的唯一安全方法是从已提升的会话运行它 - 但请注意,启动此类会话本身将触发 UAC 提示。

    • 因此,如果确保批处理文件作为一个整体以提升方式运行(如果并非其中的所有操作实际上都需要提升,这本身可能被视为安全风险),则可以简化对 PowerShell CLI 的调用(如果只是为了进行故障排除,请考虑将其删除):-NoExit

      PowerShell -NoExit -File cert-gen.ps1
      
    • 也就是说,直接调用是可能的,因为从提升的进程启动的子进程也会被提升。

  • 本答案讨论了不安全的替代方案