7

Is there a way to run the Import-Clixml cmdlet on a string or XML object?

It requires a file path as input to produce PowerShell objects and can't get input from an XML object. Since there is the ConvertTo-Xml cmdlet which serializes a PowerShell object into an XML object, why isn't there a convert from XML, which would do the opposite?

I am aware of the System.Xml.Serialization.XmlSerializer class which would do just that. However, I would like to stick with cmdlets to do this.

Is there a way to do this with cmdlets (probably just with Import-Clixml), without creating temporary files?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rocku
  • 141
  • 1
  • 5

4 Answers4

4

Short Form

[Management.Automation.PSSerializer]::Deserialize($cliXmlString)

Long Form

Proof of Concept

@{ a=1; b = 2,3,4; c = 3.14 } |  Export-Clixml -Path ~\Test.clixml
$cliXmlString = ( Get-Content -Path ~\Test.clixml ) -join ''
[Management.Automation.PSSerializer]::Deserialize($cliXmlString)

Expected and Observed Output

Name                           Value
----                           -----
c                              3.14
a                              1
b                              {2, 3, 4}

Further Reading

PSSerializer.Deserialize(String) Method

Tim Dunn
  • 41
  • 3
  • This is the perfect answer! Now I can embed Credential , or several Credentials, as .XML in a script in a secure way without needing an extra .XML file just for the auth information! Tested several times, and already in use in some environments, works! Thanks! – Joachim Otahal Sep 03 '22 at 10:11
2

I wrote this based on ConvertFrom-CliXml. It seems to work though I didn't test it very thoroughly.

function ConvertFrom-CliXml {
    param(
        [parameter(position=0, mandatory=$true, valuefrompipeline=$true)]
        [validatenotnull()]
        [string]$string
    )
    begin
    {
        $inputstring = ""
    }
    process
    {
        $inputstring += $string
    }
    end
    {
        $type = [type]::gettype("System.Management.Automation.Deserializer")
        $ctor = $type.getconstructor("instance,nonpublic", $null, @([xml.xmlreader]), $null)
        $sr = new-object io.stringreader $inputstring
        $xr = new-object xml.xmltextreader $sr
        $deserializer = $ctor.invoke($xr)
        $method = @($type.getmethods("nonpublic,instance") | where-object {$_.name -like "Deserialize"})[1]
        $done = $type.getmethod("Done", [reflection.bindingflags]"nonpublic,instance")
        while (!$done.invoke($deserializer, @()))
        {
            try {
                $method.invoke($deserializer, "")
            } catch {
                write-warning "Could not deserialize object: $_"
            }
        }
    }
}
Akhil Jain
  • 13,872
  • 15
  • 57
  • 93
1

The obvious attempt would be to just give the path to the variable:

PS Home:\> $xmldata = gci | ConvertTo-Xml
PS Home:\> Import-Clixml Variable:\xmldata
Import-Clixml : Cannot open file because the current provider (Microsoft.PowerShell.Core\Variable) cannot open a file.
At line:1 char:14
+ Import-Clixml <<<<  Variable:\xmldata
    + CategoryInfo          : InvalidArgument: (:) [Import-Clixml], PSInvalidOperationException
    + FullyQualifiedErrorId : ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ImportClixmlCommand

... which sadly fails. So I'd assume that there isn't really a way that works without temporary files.

The main point of ConvertTo-XML is to allow further processing of the XML in PowerShell after conversion of an object into XML. So the question is why you can't just make your changes to the object directly instead of manipulating the XML and converting it back?

Otherwise you can still wrap the temporary file stuff into a function.

Joey
  • 344,408
  • 85
  • 689
  • 683
  • 1
    I want to store the XML somewhere else instead of a file (possibly a DB), that's why I would like to be able to use some other input instead of a file. Anyway, thanks for your answer, I just thought there was some obvious way which I didn't think of in the first place. – rocku Mar 04 '10 at 11:18
1

Someone wrote a ConvertTo-CliXml function.

So it should be possible to write a ConvertFrom-CliXml function in the similar way. You should examine the Export-CliXml cmdlet in .NET Reflector to make sure there is nothing else that needs to be done.

There is also a bug report on Connect about this:

I know this doesn't solve your problem immediately, but the only other way would be to use temporary files as input and output to the *-CliXml cmdlets.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
  • Writing my own function for the project I am working on would be overkill and possibly error-prone. I'll just stick with temp files. – rocku Mar 07 '10 at 15:14