Is there a way to pass serializable objects to a PowerShell script with start-process?

Solution 1:

Yes. As PetSerAl wrote in a comment, you can use the PSSerializer class to handle that:

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

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

I don't know if your process will understand the CliXML format though; you don't specify what process you're starting.

Since this will produce XML which is multi-line, it may not work to pass this to a process as a parameter which is why PetSerAl is including the code to Base64 encode the resulting XML.

You might also be able to pass the XML over STDIN instead of Base64 encoding, which also ensures that you won't accidentally hit the command line size limit.

Solution 2:

You can pass a scriptblock as an argument from a parent PS process to a child PS process. The result of the child process executing the script is serialized and returned to the parent. (Run powershell -? to get help on this feature). So if the direction you want to move the credential is from child to parent then this is an alternative, or if you want to move data in both directions, then you could combine the previous answers with this approach. (The OP doesn't say which direction).

EDIT

I'm assuming OP wants to start another Powershell process - because he said "new Powershell process". And he wants to pass a PSCredential from either the parent to the child or vice versa. I'd guess the former. Based on PetSerAl's solution he could serialize the cred as CliXML. It would have new lines. Besides potentially causing problems with passing the arguments to Powershell, the newlines will cause the Deserialize to fail if they are in the middle of a value. So to avoid those problems the whole script can be base64 encoded and passed via the -EncodedCommand parameter. It'll look something like this:

$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

If OP needs something back from the script that ran in the child PS, and wanted to use the scriptblock feature mentioned earlier in this answer, I don't he could use this approach, because that feature is related to the -Command parameter. Rather newlines would need to be removed and escaping concerns might come into play.