views:

109

answers:

4

Is there any way to run import-clixml cmdlet on a string or xml object? It requires a file path as input to produce ps objects and can't get input from an xml object. Since there is convertto-xml cmdlet which serializes ps object into xml object, why isn't there a convertfrom-xml, which would do the opposite? I am aware of System.Xml.Serialization.XmlSerializer class which would do just that, however I would like to stick with cmdlets to do this.

Is there any way to do this with cmdlets (probably just with import-clixml), without creating temporary files?

A: 

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
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
A: 

Someone wrote a ConvertTo-CliXml function: http://poshcode.org/1672

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

There is also a bug report on Connect about this: https://connect.microsoft.com/PowerShell/feedback/details/537755/support-converting-to-from-clixml-format-without-unnecessary-file-i-o?wa=wsignin1.0

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.

JasonMArcher
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
A: 

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

Enjoy

David Sjöstrand
A: 

Hmm.. something went wrong with the code tagging. Sorry about that. Let's try again ....

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: $_"
            }
        }
    }
}
David Sjöstrand