on 27-Jan-2009 08:42
Welcome to this addition of the PowerShell ABC's where you'll find 26 posts detailing a component of the PowerShell scripting language, one letter at a time. For today's letter of "X", I'll discuss PowerShell's ability to work natively with XML.
XML (Extensible Markup Language) is being used more and more in today's computing environments. PowerShell is no exception in that it uses XML for its type and configuration files as well as for it's help system.
Since PowerShell uses XML so much internally, it makes sense that it has to expose a way to process XML documents in a simple way.
The [xml] Data Type
PowerShell supports XML documents as a primitive data type. This is powerful in that it allows you to access a XML Document just as you would an object with elements and child elements being properties on that object. By using the [xml] type literal you can convert a string containing XML text into a System.XML.XmlDocument object. The following example illustrates creating a XML object and
PS C:\> $x = [xml]"hithere"
PS C:\> $x | Get-Member
TypeName: System.Xml.XmlDocument
Name MemberType Definition
---- ---------- ----------
ToString CodeMethod static System.String XmlNode(PSObject instance)
add_NodeChanged Method System.Void add_NodeChanged(XmlNodeChangedEventHandler value)
add_NodeChanging Method System.Void add_NodeChanging(XmlNodeChangedEventHandler value)
add_NodeInserted Method System.Void add_NodeInserted(XmlNodeChangedEventHandler value)
add_NodeInserting Method System.Void add_NodeInserting(XmlNodeChangedEventHandler value)
add_NodeRemoved Method System.Void add_NodeRemoved(XmlNodeChangedEventHandler value)
add_NodeRemoving Method System.Void add_NodeRemoving(XmlNodeChangedEventHandler value)
AppendChild Method System.Xml.XmlNode AppendChild(XmlNode newChild)
Clone Method System.Xml.XmlNode Clone()
CloneNode Method System.Xml.XmlNode CloneNode(Boolean deep)
...
PS C:\> $x
a
-
a
PS C:\> $x.a.b
hi
there
Manipulating XML Documents
Since the [xml] type object is a true object, you can do more than look at it. You have the full abilities to add, modify, and remove content with the underlying System.Xml.XmlDocument methods and properties. The following example adds and removes child elements with the AppendChild and RemoveChild XmlDocument methods.
PS C:\> $x = New-Object -TypeName xml
PS C:\> $el = $x.CreateElement("root")
PS C:\> $x.AppendChild($el)
PS C:\> $x
child1
------
PS C:\> $x.RemoveChild($el)
PS C:\> $x.get_HasChildNodes()
False
PS C:\> $x.AppendChild($el)
PS C:\> $x.get_HasChildNodes()
True
PS C:\> $x
child1
------
Loading and Saving XML Files
You can load and save XML documents to and from the file system with the Load() and Save() methods in the XmlDocument object. The following illustrates how to save the previously created document and then reload it again into another variable.
PS C:\> $x.Save("c:\temp\foo.xml")
PS C:\> Get-Content c:\temp\foo.xml
PS C:\> $x2 = New-Object xml
PS C:\> $x2.Load("c:\temp\foo.xml")
$x2
child1
------
Serializing objects
There are a couple of Cmdlet's that are specifically designed for the serialization of objects. Serialization is the process of saving and restoring an object or objects to a file or network stream. The Two Cmdlet's are Export-Clixml and Import-Clixml. In the following example, I'll show how to export the contents of an arbitrary object to an XML stream and restore it.
PS C:\> $o = New-Object -TypeName System.Object
PS C:\> $o | Add-Member -MemberType noteProperty -Name name1 -Value value1
PS C:\> $o | Add-Member -MemberType noteProperty -Name name2 -Value value2
PS C:\> $o | Export-Clixml -Path c:\temp\foo.xml
PS C:\> Get-Content -Path c:\temp\foo.xml
http://schemas.microsoft.com/powershell/2004/04">
System.Object
value1
value2
PS C:\> $o2 = Import-Clixml -Path c:\temp\foo.xml
PS C:\> $o2
name1 name2
----- -----
value1 value2
These Cmdlets provide an easy way to save and restore collections of objects but there are some limitations. These Cmdlets can only load and save a fixed number of primitive types. Other types are broken apart, or shredded, into a property bag composed of primitive types. Unfortunately, this means that objects with non-primitive types, cannot be restored to exactly the same type they were originally.
Another issue with serialization is the matter of property depth. An object can have properties, which in turn can have properties, and so on. The chain of properties that have properties is referred to as property depth. Since this could ultimately yield a very large output file for even the simplest of objects, the Export-Cmlxml defaults to a property depth of 2 for exports. You can override this with the -depth parameter if you wish.