【问题标题】:PowerShell splatting SecureString is converted to StringPowerShell splatting SecureString 被转换为 String
【发布时间】:2019-03-02 14:56:23
【问题描述】:
param
(
    [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$True)]
    [securestring]
    $securityKey
)

powershell.exe -File $PSCommandPath -thisAppDomain @PSBoundParameters

此代码引发以下错误:

无法处理参数转换 参数“安全密钥”。无法将“System.String”类型的“System.Security.SecureString”值转换为“System.Security.SecureString”类型

如果我检查securityKey 的类型,它在喷出之前是一个 SecureString。我认为它出于某种原因对其进行了序列化。如何防止这种情况发生?

编辑

这个用例可能看起来很奇怪,所以我会提供一些上下文。我需要确保在管道到此脚本时加载特定版本的程序集。我正在使用thisAppDomain 参数在新的应用程序域中重新启动以尝试完成此操作。更大的例子:

.\FirstScript.ps1 | .\SecondScript.ps1

安全字符串按预期输入,但在重新启动时转换为字符串。这就是我重新启动的方式:

if(-not $thisAppDomain)
{
    Write-Host "Invoking script in a new app domain"
    powershell.exe -File $PSCommandPath -thisAppDomain @PSBoundParameters
    return;
}

【问题讨论】:

  • 这个脚本怎么称呼?你能举个例子吗?主要是想看看-thisAppDomain 可能会期待什么。你的powerShell版本是什么
  • powershell.exe 不是 powershell cmdlet,所以我看不出 splatting 是如何工作的。这是一个命令行程序,只在命令行上接受字符串输入。
  • 如果你想直接执行命令,你可以试试:& $PSCommandPath -thisAppDomain @PSBoundParameters(避免使用新的powershell.exe)
  • 添加了更多细节。
  • 您的代码不是一个功能齐全、工作正常的最小示例,因此很难重现和测试一个想法。将securestring转换为base64编码的字符串/结构,将其传递到第二个并转换回来。脚本中可能需要c#代码……不知道……没试过。

标签: powershell


【解决方案1】:

如果您使用-File 调用 PowerShell 的 CLI,所有参数都会转换为 字符串,因此您的安全字符串将不起作用(它会转换为常规文字内容System.Security.SecureString的字符串。

为了(大部分)保留参数类型,您必须传递一个脚本块,这会导致 PowerShell 以保留类型的方式自动序列化和反序列化参数[1],它正确地保留了[securestring] 实例,但请注意,此技术仅在调用 PowerShell(也)时有效:

if (-not $thisAppDomain)
{
  Write-Host "Invoking script in a new app domain"
  powershell -Command { 
      $script, $splat = $Args # parse the args array into distinct variables
      . $script -thisAppDomain @splat # call the script with splatting
    } -args $PSCommandPath, $PSBoundParameters
  return
}

注意必须在脚本块中引用的调用者上下文中的值(将在 new 会话中执行 - 必须通过 作为参数传递-args <arg-array> - 请参阅 Get-Help about_powershell.exe 或运行 powershell -? 以获得更简洁的帮助。

注意:正如 Patrick Meinecke 指出的那样,上述方法在后台使用带有Base64 编码字符串的转换命令行,假设由于超过最大值而失败。命令行长度,在 Windows 10 中为 32,768 个字符(请参阅CreateProcess WinAPI function)。
也就是说,除非您传递异常大的脚本块和/或数百个参数,否则您不太可能遇到此限制。


[1] 例如,PowerShell 远程处理和后台作业也使用相同类型的序列化。请注意,不仅可以忠实地反序列化一组固定的类型,而且 PowerShell 会尽力模拟具有相同属性的 自定义对象的其他类型。

【讨论】:

    【解决方案2】:

    可执行文件(甚至powershell.exe)上的喷溅参数只是转换为字符串。你可以通过运行这个来看看它会如何结束:

    $splat = @{ Test = 'something'; Secret = [securestring]::new() }
    cmd.exe /c echo @splat
    # returns
    # -Test:something -Secret:System.Security.SecureString
    

    您可以在使用SecureString 的同时通过Start-Job 在另一个进程中运行某些内容

    $mySecureString = Read-Host -AsSecureString
    $job = Start-Job {
        & $using:PSCommandPath -thisAppDomain $using:mySecureString
    }
    
    $job | Receive-Job -Wait
    

    注意:using 范围必须用于父会话中的变量。此外,变量仍将被序列化,因为进程不共享内存,但安全字符串将被正确序列化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-23
      • 2023-03-24
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多