在cmd批处理中以管理员身份运行PowerShell脚本

3
我有一个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),该路径也不能正常工作。
有什么帮助吗?

1
你已经以管理员身份运行批处理文件了吗? - Abraham Zinala
1
@AbrahamZinala:不是的。cmd批处理的整个目的是要求用户提升权限并临时允许脚本执行。因此,需要使用参数“-Verb runAs”和“ExecutionPolicy bypass”。 - antonio
1
我知道这些论点,只是在尝试提供另一种解决方案的同时获取更多上下文信息。 - Abraham Zinala
1
为什么需要使用Cmd来运行脚本?为什么不使用自我提升的完整PowerShell脚本? - Santiago Squarzon
@SantiagoSquarzon 如果执行策略受限,则首先无法执行自我提升脚本。 - another victim of the mouse
2个回答

6
Windows PowerShell (有关 PowerShell(Core)7 + 的底部部分),使用 Start-Process -Verb RunAs 启动命令时, with elevation (作为管理员)不可避免地使用 C:\ Windows \ SYSTEM32 作为工作目录 - 即使存在 -WorkingDirectory 参数,也会被静默忽略。因此,为了设置自定义工作目录并在其中调用脚本,必须使用 -Command CLI参数,并且必须在指定了相对路径的脚本之前进行{{link1: Set-Location }}( cd )调用。
虽然将传递的参数单独传递给{{link2: Start-Process }} cmdlet的 -ArgumentList 参数在概念上可能更可取,但{{link3:长期存在的错误}}使得最好将所有参数编码为单个字符串 -请参阅this answer
通过 powershell.exe 从 cmd.exe 执行所有这些操作,Windows PowerShell {{link5:CLI}}由于转义要求而使问题复杂化。
适用于你的 powershell.exe 命令行调用,假设工作目录为 C:\path 1 并且脚本文件为 setup 1.ps1
powershell -Command "Start-Process -Verb RunAs powershell '-NoExit -ExecutionPolicy Bypass -Command cd \\\"C:\path 1\\\"; & \\\".\setup 1.ps1\\\"' "

请注意嵌入式的字符",需要进行双重转义,写作\\\"。首先,需要转义成\",以便在外部的powershell.exe调用期间得以保留,然后再次转义,以供内部调用使用。
尽管这种方法通常有效,但存在一些边界情况,如果脚本路径或文件名包含cmd.exe元字符(如&),则仅基于\的转义不足够。此时,第一轮转义需要使用"^""来代替"
powershell -Command "Start-Process -Verb RunAs powershell '-NoExit -ExecutionPolicy Bypass -Command "^"" cd \\"^""C:\path 1\\"^""; & \\"^"".\setup 1.ps1\\"^"" "^""'"

注意:

  • cmd.exe (批处理文件)"^"" (sic) 是将嵌入在整个 "..." 字符串中的 " 传递给 powershell.exe 的最强大的方法,如上所示,而对于 pwsh.exe,PowerShell (Core) CLI (见下文),则为 ""

  • 相比之下,在一个 无 shell 的上下文中(例如计划任务),\" 在两个版本中都能够稳健地工作。

  • 有关详细信息,请参见 this answer


当您调用 pwsh.exe 而不是 PowerShell (Core) 7+ CLI 时,简化操作可能是可行的,甚至可能不需要解决方法:

  • pwsh.exe 默认情况下即使使用 -Verb RunAs,也会保留调用者的工作目录,并且会尊重带有 -Verb RunAs-WorkingDirectory 参数。

  • 除了 " 之外,pwsh.exe 更简单地支持使用 "" 嵌入 "..." 字符串中的 " 字符;后者可以从 cmd.exe 中稳健地工作。

  • pwsh.exe 本身现在具有 -WorkingDirectory 参数,因此允许使用 -File 参数调用脚本:

pwsh.exe -WorkingDirectory "C:\path 1" -Command "Start-Process -Verb RunAs pwsh.exe '-NoExit -ExecutionPolicy Bypass -File ""C:\path 1\setup 1.ps1""'"

1
谢谢您。您的 “^” 解决了这个问题。仍然感到遗憾的是,尽管他们做出了所有努力,微软还是无法给我们一个简单的语法来调用管理员脚本。在Linux中只需要sudo '/path/to/setup'就能实现这个功能。 - antonio

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 "{0}"' -f $PSCommandPath
        )
    }

    Start-Process @params
    return
}

"I'm elevated"
# Code goes here

1
谢谢,但是正如问题所述,我事先不知道目标计算机的执行策略可能是什么,它们可能被设置为受限制的。 - antonio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接