The ConvertTo-XML Cmdlet

The information in this article was written against the second Community Technology Preview (CTP2) of Windows PowerShell 2.0. This information is subject to change in future releases of Windows PowerShell 2.0.

Dress Up Your XML Output with the ConvertTo-XML Cmdlet

In a way, the Scripting Guys feel sorry for the Windows PowerShell cmdlet Export-CliXML. That’s probably because we can empathize with poor old Export-CliXML; after all, no one understands the Scripting Guys (admittedly, for good reason) and no one understands Export-CliXML. Because of the name, people assume that Export-CliXML will let them save their data as a standard XML file; as many of you probably know by now, that isn’t the case. For example, suppose you run the following command:

Get-ChildItem C:\Scripts | Export-CliXML C:\Scripts\Test.xml

This works, but if you open up Test.xml you’ll see a mishmash of properties and property values:

The information you’re looking for is there (trust us on this one), but it’s hard to find; that’s because the formatting applied to the XML file leaves a little something to be desired. What you were really hoping to get back was something a little cleaner and easier to read:

For better or worse, however, Export-CliXML isn’t going to give you output like that.

But wait; don’t blame poor little Export-CliXML. After all, Export-CliXML was never designed to give you standard – and aesthetically-appealing – XML output. Instead, Export-CliXML was designed to let you save Windows PowerShell objects as objects; once those objects have been saved, you can then use the Import-CliXML cmdlet to retrieve and restore those items. And that’s it, that’s all Export-CliXML was designed to do. If you’re looking for pretty XML output you’re going to have to look somewhere else.

Like, say, the ConvertTo-XML cmdlet found in the second Windows PowerShell 2.0.

Unlike Export-CliXML, ConvertTo-XML is designed to provide you with standard XML output, output that is easy to read and easy to use in XML editors and similar tools. Want to save the results of a Get-ChildItem command as XML? Then use a command similar to this:

(Get-ChildItem C:\Scripts | ConvertTo-XML).Save("C:\Scripts\Test.xml")

As you can see, there’s nothing very fancy going on here. To begin with, we use Get-ChildItem to retrieve the contents of C:\Scripts, then pipe that data to ConvertTo-XML, which will create an XML object from that data. (Notice that all this activity takes place inside a set of parentheses; that’s to ensure that we get our XML object before we do anything else.) And because ConvertTo-XML gives us back an XML object, we can save our data by doing nothing more than calling the Save method and passing this method the path to the XML file we want to create:

.Save("C:\Scripts\Test.xml")

That’s all there is to it. If we open up C:\Scripts\Test.xml we should see something similar to this:

- <Object Type="System.IO.FileInfo">
  <Property Name="PSPath" Type="System.String">Microsoft.PowerShell.Core\FileSystem::C:\scripts\cmdlib.wsc</Property>
  <Property Name="PSParentPath" Type="System.String">Microsoft.PowerShell.Core\FileSystem::C:\scripts</Property>
  <Property Name="PSChildName" Type="System.String">cmdlib.wsc</Property>
  <Property Name="PSDrive" Type="System.Management.Automation.PSDriveInfo">C</Property>
  <Property Name="PSProvider" Type="System.Management.Automation.ProviderInfo">Microsoft.PowerShell.Core\FileSystem</Property>
  <Property Name="PSIsContainer" Type="System.Boolean">False</Property>

That’s much better.

But not perfect; after all, even this aesthetically-pleasing output still includes information of minimal use to us. For example, do we really care that the PSIsContainer property has a data type of System.Boolean?

If the answer is no, we don’t care, then we can simply tack on the –NoTypeInformation parameter, like so:

(Get-ChildItem C:\Scripts | ConvertTo-XML -NoTypeInformation).Save("C:\Scripts\Test.xml")

That will clean up our output more:

- <Object>
  <Property Name="PSPath">Microsoft.PowerShell.Core\FileSystem::C:\scripts\cmdlib.wsc</Property>
  <Property Name="PSParentPath">Microsoft.PowerShell.Core\FileSystem::C:\scripts</Property>
  <Property Name="PSChildName">cmdlib.wsc</Property>
  <Property Name="PSDrive">C</Property>
  <Property Name="PSProvider">Microsoft.PowerShell.Core\FileSystem</Property>
  <Property Name="PSIsContainer">False</Property>

Even better.

Incidentally, because this is an XML object you can do a lot more than simply save the data; for a complete list of methods and properties available to you run this command:

(Get-ChildItem C:\Scripts | ConvertTo-XML -NoTypeInformation) | Get-Member

Here’s a very simple example; after creating our XML object we call the Get-Enumerator method:

(Get-ChildItem C:\Scripts | ConvertTo-XML -NoTypeInformation).GetEnumerator()

And here’s what we get back:

Version         : 1.0
Encoding        :
Standalone      :
Value           : version="1.0"
InnerText       : version="1.0"
Name            : xml
LocalName       : xml
NodeType        : XmlDeclaration
PreviousSibling :
NextSibling     : Objects
ParentNode      : #document
ChildNodes      : {}
Attributes      :
OwnerDocument   : #document
FirstChild      :
LastChild       :
HasChildNodes   : False
NamespaceURI    :
Prefix          :
IsReadOnly      : False
OuterXml        : <?xml version="1.0"?>
InnerXml        :
SchemaInfo      : System.Xml.Schema.XmlSchemaInfo
BaseURI         :

Object : {Object, Object, Object, Object...}

Thanks, ConvertTo-XML; that’s just what we were hoping to get back.