rocku
rocku

Reputation: 161

PowerShell's Import-Clixml from a string

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?

Upvotes: 9

Views: 6154

Answers (4)

Tim Dunn
Tim Dunn

Reputation: 41

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

Upvotes: 4

JasonMArcher
JasonMArcher

Reputation: 15011

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.

Upvotes: 1

David Sjöstrand
David Sjöstrand

Reputation: 21

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: $_"
            }
        }
    }
}

Upvotes: 2

Joey
Joey

Reputation: 354734

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.

Upvotes: 1

Related Questions