2

我有一个 PowerShell 设置,我想在可能执行策略受到限制并且需要管理员权限的计算机上执行它。
理想情况下,我可以将它包装在一个 cmd 批处理中,如下所示:

powershell -Command "Start-Process powershell -Verb runAs -ArgumentList '-noexit','-ExecutionPolicy','bypass','-File','C:\path\setup.ps1'"

问题是当包含空格时我无法使其工作,并且如果是相对路径(带有)C:\path\setup.ps1,路径也不起作用。 有什么帮助吗?cd C:\path

4

2 回答 2

5
  • 虽然将传递参数单独传递给Start-Processcmdlet 的 -ArgumentList参数在概念上可能更可取,但不幸的是,一个长期存在的错误使得将所有参数编码在单个字符串中更好- 请参阅此答案

  • -Verb RunAs用于启动具有提升的命令(以管理员身份),总是使用SYSTEM32 目录作为工作目录 - 即使是-WorkingDirectory参数,如果存在,也会被悄悄地忽略。因此,为了设置自定义工作目录并调用 ,-Command必须使用 CLI 参数,并且Set-Location( cd) 调用必须在调用相对路径指定的脚本之前。

  • cmd.exe通过powershell.exeWindows PowerShell CLI执行所有这些操作会使事情变得复杂,因为需要转义。

应用于您的powershell.exeCLI 调用(假设 dir.C:\path 1和 script file setup 1.ps1):

powershell -Command "Start-Process -Verb RunAs powershell '-NoExit -ExecutionPolicy Bypass -Command "^"" cd \\"^""C:\path 1\\"^""; & \\"^"".\setup 1.ps1\\"^"" "^""'"

笔记:

  • From cmd.exe, "^""(sic) 是将"嵌入在整个"..."字符串中的内容传递到powershell.exe(从无壳上下文,例如计划任务,使用"""或更简单地说,\".

  • 为简单起见,对于双重嵌套的"字符。上面使用了\-escaping 技术,带有\字符。自己需要转义为\\.

注意:从 PowerShell CLI 的角度来看 - 包括在 PowerShell (Core) 7+ 中(见下文) -\" 总是有效,但它的使用是有问题cmd.exe,它不能理解\"转义 "字符。因此将其视为常规字符串定界符,这可能会导致它误解\"...\"作为未引用字符串的一部分的内容,其中元字符(例如)&可能会破坏命令,因为它们是由cmd.exe自身预先解释的;例如,powershell -c " \"Abbot & Costello\" "break from cmd.exe,需要^&代替,"或者,如上所示,转义嵌入""^""
powershell -c " "^""Abbot & Costello"^"" "


当您pwsh.exe改为调用 PowerShell (Core) 7+ CLI时,可以进行两种简化:

  • 此外\"pwsh.exe更简单地支持""嵌入"字符。在"..."字符串中;后者从cmd.exe

  • pwsh.exe现在有一个单独的-WorkingDirectory参数,因此允许使用-File参数调用脚本 - 但是请注意,文件路径在设置工作目录之前已解析,因此下面使用完整路径。

pwsh.exe -Command "Start-Process -Verb RunAs pwsh.exe '-NoExit -ExecutionPolicy Bypass -WorkingDirectory ""C:\path 1"" -File ""C:\path 1\setup 1.ps1""'"
于 2022-01-17T03:33:49.877 回答
1

在这里,您有一个脚本示例,该示例检查进程是否正在运行提升,如果不是,它会尝试启动一个提升的新进程。在这种情况下不需要嵌套文件或使用 CMD。

这显然伴随着 UAC 提示的警告,就像任何其他以提升的权限启动的进程一样。

$isAdmin = [System.Security.Principal.WindowsPrincipal]::new(
    [System.Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole('Administrators')

if(-not $isAdmin)
{
    $params = @{
        FilePath = 'powershell' # or pwsh if Core
        Verb = 'RunAs'
        ArgumentList = @(
            "-NoExit"
            "-ExecutionPolicy ByPass"
            "-File `"$PSCommandPath`""
        )
    }
    Start-Process @params
    Exit
}

"I'm elevated"
# Code goes here
于 2022-01-17T03:02:51.493 回答