使用多行字符串参数启动提升的 Powershell 会话

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

我试图在启动提升的 powershell 会话时将脚本块作为命令传递以运行,但我找不到使其工作的方法。我认为这是因为文件内容是多行的?

$content = @"
This is a
multiline
file content.
"@

$path = 'C:\test.txt'

$scriptBlock = {
    param($fileContent, $filePath)
    Write-Host "PATH: $filePath`n`n"
    Write-Host "CONTENT:`n$fileContent"
    [System.IO.File]::WriteAllText($filePath, $fileContent, [System.Text.Encoding]::GetEncoding('Windows-1252'))
    Pause
}

Start-Process -FilePath 'PowerShell' -Verb 'RunAs' -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command '&{$scriptBlock} `"$content`" `"$path`"'" -Wait

Pause

我错过了什么?有没有更好的方法来实现这一目标?

我尝试了上面的代码,但提升的 Powershell 会话在打开后立即关闭。我认为 Start-Process 行是错误的。

编辑:

我尝试用函数包装脚本块内容并稍微更改 Start-Process,现在它可以工作了:

$content = @"
This is a
multiline
file content.
"@

$path = 'C:\test.txt'


$scriptBlock = {
    function wrappingFunc {
        param(
            $filePath,
            $fileContent
        )

        Write-Host "PATH: $filePath"
        Write-Host "CONTENT: $fileContent"
        [System.IO.File]::WriteAllText($filePath, $fileContent, [System.Text.Encoding]::GetEncoding('Windows-1252'))
        Pause
    }
}

Start-Process -FilePath 'PowerShell' -Verb 'RunAs' -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command & {$scriptBlock wrappingFunc -filePath '$path' -fileContent '$content'}" -Wait

Pause

我实际上并不完全理解为什么它会这样工作。有人可以澄清吗?

我还注意到一个非常奇怪的行为。如果我更改脚本块中的以下行:

    Write-Host "PATH: $filePath"
    Write-Host "CONTENT: $fileContent"

至:

    Write-Host -Object "PATH: $filePath"
    Write-Host -Object "CONTENT: $fileContent"

它停止工作。为什么简单地添加

-Object
会破坏它?

powershell
1个回答
0
投票

[1] 另请注意 zdan 的有用调试提示:在 PowerShell CLI 调用中的

-NoExit
之前临时添加
-Command
以保持会话打开,这样您就可以检查错误消息。

问题不在于使用multiline命令字符串,它与quoting有关:

  • 不要在

    '...'
    参数中使用
    -Command
    引号(除非那些
    '
    字符是要执行的 PowerShell 代码的一部分) - 当从外部调用 时 - 使用
    Start-Process
    是一个示例 - PowerShell 将其
    process 命令行
    上的 '...' 字符串视为 verbatim string.

    • 从 PowerShell 外部(包括从
      cmd.exe
      调用或从计划任务调用时)只有 powershell.exe
       引用具有 
      syntactic
      功能(在进程命令行上)。
      
      
      Escape 
      pwsh 字符将成为 PowerShell 命令的一部分以执行 "..."
    • - 否则 PowerShell 的初始
    CLI
  • 解析将删除它们。
  • 根据这些要求让你的代码健壮地工作有点麻烦(一个
    here-string
    用于引用方便和可读性): "

\"操作确保任何

# ... Start-Process -FilePath PowerShell -Verb RunAs -Wait -ArgumentList @" -NoProfile -ExecutionPolicy Bypass -Command " & { $($scriptBlock -replace '(\\*)"', '$1$1\"') } \"$($content -replace '(\\*)"', '$1$1`\"')\" \"$path\" " "@
字符。作为引用的变量值的一部分被转义为
-replace
    以保护它们免受初始CLI解析。
  • 正则表达式中的

    "
     捕获值中紧接在 
    \"
     之前的任何 
    (\\*)

    字符,这些字符必须被
      doubled
    • 以保留原样,这就是替换表达式中的
      \
      所做的。
      
      
      "
       的情况下,它们必须 
      additionally
    $1$1
  • -escaped,因为发生在
  • embedded

    $content
    字符串之间(对于 ` 没有必要,因为文件系统路径不能包含
    "..."
    字符。在 Windows 上)。
    
    
    如果您不想单独处理 
    $path
     操作,则必须对脚本块(包括其参数)进行 Base64 编码,并将其与 
    "

    CLI 参数一起使用:
-replace

请注意,

one
- 尽管更简单 -
-EncodedCommand
操作仍然是必要的,即将嵌入

# ... # Create a Base64 representation of the bytes that make up the # "Unicode" (UTF-16LE) encoding of the command string, for use # with the -EncodedCommand PowerShell CLI parameter. $encodedCommand = [Convert]::ToBase64String( [Text.Encoding]::Unicode.GetBytes(@" & { $scriptBlock } "$($content -replace '"', '`"')" "$path" "@ ) ) # Note the use of -EncodedCommand Start-Process -FilePath 'PowerShell' -Verb 'RunAs' -Wait -ArgumentList @" -NoProfile -ExecutionPolicy Bypass -EncodedCommand $encodedCommand "@
 中的任何 
-replace

转义为 ".

    

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