我了解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
答案 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 Bray在Powershell 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))