PowerShell:来自非提升脚本的提升代码,访问变量和函数

问题描述 投票:0回答:1

我正在准备新电脑。应用图像后,我运行 PowerShell 脚本以执行一些图像后部署步骤。某些步骤必须以新(当前)用户身份运行,例如 HCCU 中的注册表设置,而其他通过脚本穿插的步骤必须以提升权限运行。

在我的脚本中,我为需要提升的代码调用下面的

RunElevated
函数。我想在提升和非提升代码块之间共享值和函数,但这可能吗?我尝试在调用 Start-Process powershell.exe 时传递参数,但遇到了引号中的引号、参数中的参数的“Inception”问题。

function RunElevated($ScriptBlock)
{
    write-host -NoNewline "`nStarting a new window with elevated privileges. Will return here after..."

    $scriptBlockWithBefore = {
        write-host "`nSTEPS RUNNING WITH ELEVATED PRIVILEGES...`n" @mildAlertColours
    }

    $scriptBlockAfter = {
        Write-Host -nonewline "`nHit Enter to exit this mode. "
        Read-Host
    }

    $scriptBlockToUse = [scriptblock]::Create($scriptBlockWithBefore.ToString() + "`n" + $ScriptBlock.ToString() + "`n" + $scriptBlockAfter)

    $proc = Start-Process "powershell.exe" -Verb runas -ArgumentList "-command `"$scriptBlockToUse`"" -PassThru -WorkingDirectory $pwd.ToString()

    $proc.WaitForExit()

    if($proc.ExitCode -ne 0) {
        write-host "ran into a problem."
    }
}
powershell elevated-privileges
1个回答
0
投票

zett42 所述,您可以使用

powershell.exe
,Windows PowerShell CLI 的
-EncodedCommand
参数 安全地将任意代码传递给 PowerShell 子进程

通过arguments安全,你需要(目前未记录)

-EncodedArguments
参数。

这种基于Base64编码的方法

  • 不仅消除引用头痛,
  • 而且 为参数启用丰富的数据类型支持(在 PowerShell 的基于 XML 的跨进程序列化基础结构(也用于远程处理)可以提供的类型保真度范围内)[1]

这里是独立的示例代码演示了该技术:

# Sample script block to execute in the elevated child process.
$scriptBlock = {
  # Parameters
  param([string] $Foo, [int] $Bar, [hashtable] $Hash)
  # Embedded function
  function Get-Foo { "hi: " + $args }
    
  # Show the arguments passed.
  $PSBoundParameters | Out-Host

  # Call the embedded function
  Get-Foo $Bar

  Read-Host 'Press Enter to exit.'
}

# List of sample arguments to pass to the child process.
$passThruArgs = 'foo!', 42, @{ SomeKey = 'Some Value' }

# Call via `Start-Process -Verb RunAs` to achieve elevation, and pass the 
# Base64-encoded values to `-EncodedCommand` and `-EncodedArgument`
Start-Process -Wait -Verb RunAs powershell.exe -ArgumentList (
  '-EncodedCommand', (
    [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptBlock))
  ),
  '-EncodedArguments', (
    [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes(
        [System.Management.Automation.PSSerializer]::Serialize($passThruArgs)
    ))
  )
)

注:

  • 在这种特殊情况下,使用

    Start-Process
    -ArgumentList
    参数是安全的,因为按定义传递的参数不包含空格或其他元字符。

    • 一般来说,由于一个长期存在的错误不会为了向后兼容而被修复,在一个单个字符串中传递all参数最终会更简单,使用嵌入式双引号作为需要 - 请参阅这个答案
  • Cpt.Whale 提出了一个很好的观点:如果您将需要提升的部分外包到 separate scripts

    *.ps1
    文件),通过
    Start-Process -Verb RunAs
    的调用变得更简单,因为这样您就不必通过 CLI 传递 code,并且可以使用
    -File
    CLI 调用而不需要 Base64 编码。但是,您随后仅限于 strings 或具有 string-literal representations.

    的参数

可选阅读:为什么selective elevation可能是首选/必要的

  • 您可能 prefer 选择性提升以获得更好的安全性:它允许您将使用提升运行的内容限制为仅真正需要它的代码。

  • 需要选择性海拔:

    • 如果提升发生在不同的用户上下文中并且您的部分代码需要在当前用户的上下文中运行。

      • 当请求提升时,会自动且总是涉及不同的用户上下文如果当前用户不是管理员:UAC 对话框然后会自动要求管理员 的凭据。
    • 即使在 same 用户上下文中发生提升,在以提升运行时明显 not 执行的操作 - 至少在默认情况下 - 是 establish persistent drive mappings for the current user:

      • 尝试悄悄地建立持久驱动器映射会导致非持久映射(并且用户的提升化身看不到其非提升化身的预先存在的持久化映射),除非您的系统被明确配置为在之间共享持久化映射高架和非高架会话 - 有关详细信息,请参阅这个答案

[1] 有关详细信息,请参阅此答案

© www.soinside.com 2019 - 2024. All rights reserved.