PowerShell喷射SecureString转换为String

时间:2018-09-26 18:53:12

标签: powershell

param
(
    [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$True)]
    [securestring]
    $securityKey
)

powershell.exe -File $PSCommandPath -thisAppDomain @PSBoundParameters

此代码引发以下错误:

  

无法处理参数转换   参数“ securityKey”。无法将类型为“ 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;
}

2 个答案:

答案 0 :(得分:1)

可执行文件(甚至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范围必须用于父会话中的变量。此外,由于进程不共享内存,因此变量仍将被序列化,但是安全字符串将被正确序列化。

答案 1 :(得分:1)

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

为了(主要)保留参数类型,您必须传递 script块 ,这会导致PowerShell以保留类型的方式自动序列化和反序列化参数< sup> [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会尽力使用具有相同属性的自定义对象模拟其他类型。