在 Powershell 中获取并使用 UAC 凭据以完成 运行 作业

Obtain and use UAC credential in Powershell to run job

我正在编写一个配置脚本,它必须做一些需要 UAC 批准的事情,我希望理想地实现近似“$session = sudo -v”,这样我就可以混合 elevated/non-elevated并且不需要用户在屏幕前等待 15-30 分钟的设置,以防万一它需要另一个批准。

理想情况下,我尽量避免打开新的 console/terminal window,因为这既会丢失输出又会导致屏幕闪烁,这对我的某些用户来说可能是个问题。

这表明我可能想要做的是使用凭据开始作业,这样我就可以等待完成并检索输出。

所以现在我有两个问题:

  1. 有没有办法在会话中存储用户的 UAC 同意,例如通过使用它来获取我可以重复使用的凭据?
  2. 我可以使用什么 Start- 或 Invoke- 命令来 运行 具有不会将块转换为字符串的高度的脚本块?

我使用 ScriptBlock 的尝试失败了,因为需要对进入 ScriptBlock 构造的字符串进行多重转义:

{ [System.Environment]::SetEnvironmentVariable("TEST", "OK", "Machine") }

当我试图将它传递给 Start-Process -verb runAs powershell -ArgumentList @('-NoLogo', '-NoProfile', '-Command', $ScriptBlock) 时对我来说失败了:

At line:1 char:46
+ [System.Environment]::SetEnvironmentVariable(TEST, OK, Machine)
+                                              ~
Missing ')' in method call.
At line:1 char:46
+ [System.Environment]::SetEnvironmentVariable(TEST, OK, Machine)
+                                              ~~~~
Unexpected token 'TEST' in expression or statement.
At line:1 char:50
+ [System.Environment]::SetEnvironmentVariable(TEST, OK, Machine)
+                                                  ~
Missing argument in parameter list.
At line:1 char:63
+ [System.Environment]::SetEnvironmentVariable(TEST, OK, Machine)
+                                                               ~
Unexpected token ')' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndParenthesisInMethodCall

或者如果我尝试使用 System.Diagnostics.Process

  • 不,很遗憾,无法缓存 UAC 确认。

    • 可以想象 - 虽然我认为这不值得 - 你可以在后台启动一个单独的、提升的会话,你可以在其中滚动你自己的 IPC,例如从文件中读取命令并将结果保存回来与前台会话协调到不同的文件。
  • 使用提升调用需要使用Start-Process,使用-Verb RunAsStart-Process基本上只支持string参数(进程命令行)。

    • 要传递给 PowerShell CLI(可能位置隐含)-Command/-c 参数的字符串需要 " 个字符。将作为要传递的命令的一部分保留为 \"(有关解释,请参阅 );应用于您的通话:

      Start-Process -Verb RunAs powershell -ArgumentList @(
        '-NoLogo', 
        '-NoProfile', 
        '-Command', 
        "`"$($ScriptBlock -replace '"', '\"')`""
      )
      
    • 警告:在将 pass-through 参数 单独 传递给 -ArgumentList 时,作为以上,在概念上可能更可取,a long-standing bug unfortunately makes it better to encode all arguments in a single string - see this answer;该错误也是在上面嵌入的 " 中明确包含 -Command 参数的原因;虽然它通常在没有它的情况下也能正常工作,但它可以防止多个 space 的运行折叠成一个 space,这在嵌入式字符串文字中可能很重要。