有没有办法通过start-process将可序列化对象传递给PowerShell脚本?

时间:2015-12-03 21:28:13

标签: powershell start-process

我了解PowerShell作业,但我想使用start-process并将可序列化对象传递给新的PowerShell进程。有没有办法做到这一点?

似乎使用start-process你必须提供一个字符串参数列表,它不会为我删除它。我试图将PSCredential从一个进程转到另一个进程(或者一个SecureString,我会选择其中一个进程)。也许这会绕过安全。

更新 - 在看到其他人的帮助后使用我使用的解决方案(使用@PetSerAl中的解决方案)

我编写了两个测试脚本:父脚本和子脚本。父脚本调用子脚本。

父脚本:

$securePassword = ConvertTo-SecureString "testpassword" -AsPlainText -Force
$cred = New-Object PSCredential("testuser", $securePassword)
$credSerial = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes([Management.Automation.PSSerializer]::Serialize($cred)))

$psFile = "C:\repos\Test\PowerShell Scripts\KirkTestChild.ps1"
$p1 = "-someparam ""this is a test!!!"""
$p2 = "-cred ""$credSerial"""

$proc = Start-Process PowerShell.exe -PassThru:$true -Argument "-File ""$($psFile)""", $p1, $p2
Write-Host "ID" $proc.Id
Write-Host "Has Exited" $proc.HasExited

Start-Sleep -Seconds 15
Write-Host "Has Exited" $proc.HasExited

儿童剧本:

Param(
    $someParam,
    $cred
)

Write-Host "someParam: $($someParam)"
Write-Host "cred (raw): $($cred)"
$realCred=[Management.Automation.PSSerializer]::Deserialize([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($cred)))
Write-Host "cred user: $($realCred.UserName)"
Write-Host "start"
Start-Sleep 5
Write-Host "ending"
Start-Sleep 5

4 个答案:

答案 0 :(得分:2)

是。正如PetSerAl在评论中所写,您可以使用PSSerializer类来处理:

$ser = [System.Management.Automation.PSSerializer]::Serialize($credential)

$cred = [System.Management.Automation.PSSerializer]::Deserialize($ser)

我不知道你的过程是否会理解CliXML格式;你没有指定你正在开始的过程。

由于这将生成多行的XML,因此将其作为参数传递给流程可能无效,这就是为什么PetSerAl将代码包含在Base64编码结果XML中的原因。

您也可以通过STDIN而不是Base64编码传递XML,这也可以确保您不会意外地达到命令行大小限制。

答案 1 :(得分:1)

您可以将脚本块作为参数从父PS进程传递到子PS进程。执行脚本的子进程的结果被序列化并返回给父进程。 (运行powershell -?以获取有关此功能的帮助)。因此,如果您想要移动凭证的方向是从子级到父级,那么这是一种替代方案,或者如果您想要在两个方向上移动数据,那么您可以将之前的答案与此方法结合起来。 (OP不会说出哪个方向)。

<强> 修改

我假设OP想要启动另一个Powershell流程 - 因为他说&#34;新的Powershell流程&#34;。并且他希望将PSCredential从父母传递给孩子,反之亦然。我猜这个前者。根据PetSerAl的解决方案,他可以将信息序列化为CliXML。它会有新的线条。除了可能导致将参数传递给Powershell的问题之外,如果它们位于值的中间,则新行将导致反序列化失败。因此,要避免这些问题,整个脚本可以进行base64编码并通过-EncodedCommand参数传递。它看起来像这样:

$xmlStr = [management.automation.psserializer]::Serialize($cred)
$scriptStr = "$liveCred = " +
  "[management.automation.psserializer]::Deserialize('$xmlstr');" +
  "# PS statements to do something with $liveCred"
$inB64 = [Convert]::ToBase64String( [Text.Encoding]::UTF8.GetBytes($scriptStr))
powershell -EncodedCommand $inB64

如果OP需要从子PS中运行的脚本返回某些内容,并且想要使用本答案前面提到的scriptblock功能,我不能使用这种方法,因为该功能与-Command参数。相反,需要删除换行符,并且可能会发挥逃避问题。

答案 2 :(得分:1)

这是一个使用ScriptBlock而不是脚本文件的变体。请Greg BrayPowershell Start-Process to start Powershell session and pass local variables上查看帖子。

$securePassword = ConvertTo-SecureString 'testpassword' -AsPlainText -Force
$cred = New-Object PSCredential( 'testuser', $securePassword )

$scriptBlockOuter = {
    $sb = {
        Param(
           [Parameter( Mandatory, Position = 0 )]
           [String] $someParam,
           [Parameter( Mandatory, Position = 1 )]
           [String] $credSerial
        )
        $cred = [System.Management.Automation.PSSerializer]::Deserialize( [System.Text.Encoding]::UTF8.GetString( [System.Convert]::FromBase64String( $credSerial )))
        Write-Host "someParam: $someParam"
        Write-Host "cred user: $($cred.UserName)"
        Write-Host 'start'
        Start-Sleep 5
        Write-Host 'ending'
        Start-Sleep 5
    }
}

$p1 = 'this is a test!!!'
$credSerial = [System.Convert]::ToBase64String( [System.Text.Encoding]::UTF8.GetBytes( [System.Management.Automation.PSSerializer]::Serialize( $cred )))

$proc = Start-Process PowerShell -PassThru -ArgumentList '-Command', $scriptBlockOuter, '& $sb', '-someParam', "'$p1'", '-credSerial', "'$credSerial'"
Write-Host 'ID' $proc.Id
Write-Host 'Has Exited' $proc.HasExited

Start-Sleep -Seconds 15
Write-Host 'Has Exited' $proc.HasExited

答案 3 :(得分:0)

使用此ConvertTo-Expression cmdlet:

父脚本:

$Expression = $Cred | ConvertTo-Expression
$credSerial = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Expression))

子脚本:

$Expression = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($credSerial))
$Cred = Invoke-Expression $Expression   # or safer: &([ScriptBlock]::Create($Expression))