Use PowerShell to Simplify Working with XML Data

ScriptingGuy1

Summary: Learn how to use Windows PowerShell to simplify working with XML data.   Hey, Scripting Guy! Question   Hey, Scripting Guy! How can I use Windows PowerShell to work with XML? — FD   Hey, Scripting Guy! Answer Hello FD, Microsoft Scripting Guy Ed Wilson here. We are in the middle of Guest Blogger Week, so today your question goes over to Guest Blogger Doug Finke. Doug Finke is a Microsoft PowerShell MVP working for Lab49, a company that builds advanced applications for the financial service industry. Over the last 20 years, Doug has been a developer and author working with numerous technologies. You can catch up with Doug on his blog.   Windows PowerShell: A Better XML XML is used in many places. Working with XML in Windows PowerShell is one of its sweet spots. XML to-do lists, web pages, insurance claims, and configuration files are all examples of ways to use XML to represent information. XML Here is a simple to-do list:

<todo name=”housework”>

<todoItem priority=”high”>Clean the house.</todoItem>

<todoItem priority=”medium”>Wash the dishes.</todoItem>

<todoItem priority=”medium”>Buy more soap.</todoItem>

</todo>

Let’s unleash Windows PowerShell on it. There are three steps to get this done: 1. Use a Windows PowerShell here-string to hold our XML to-do list data. 2. Use the [XML] accelerator to create a .NET dom document. 3. Use the convenient Windows PowerShell dot notation to drill down into the data and print it out.

$housework = [xml] @”

<todo name=”housework”>

<todoItem priority=”high”>Clean the house.</todoItem>

<todoItem priority=”medium”>Wash the dishes.</todoItem>

<todoItem priority=”medium”>Buy more soap.</todoItem>

</todo>

“@

This parses the XML into memory and into objects. Let’s print out the to-do items using the Windows PowerShell dot notation:

$housework.todo.todoItem

priority      #text          

——–        —–          

high          Clean the house.

medium     Wash the dishes.

medium     Buy more soap. 

Windows PowerShell As easy as XML is to work with in Windows PowerShell, many network administrators still shy away from using XML. The great thing about Windows PowerShell is that it can also arrange hierarchical data in a manner that is easier to read for IT pros, developers, and others. Moreover, it is easier to produce. Let’s explore how Windows PowerShell can make working with hierarchical data (such as computer configuration data, to-do lists, and shopping lists) more accessible. Now, let’s rework the XML into a Windows PowerShell representation. This involves creating two custom Windows PowerShell functions, New-ToDoList and New-ToDoItem. We’ll tackle New-ToDoList function first:

New-ToDoList housework {

New-ToDoItem high “Clean the house.”

New-ToDoItem medium “Wash the dishes.”

New-ToDoItem medium “Buy more soap.”

}

New-ToDoList takes two parameters. The first is a string, “housework,” and the second is a Windows PowerShell script block, which is everything from the left brace ({) to the right brace (}). If you ran this Windows PowerShell script it would fail with the error: “The term ‘New-ToDoList’ is not recognized as the name of a cmdlet.” Let’s define the New-ToDoList function:

Function New-ToDoList ($todoListName, $PowerShellScriptBlock) {}

If you run the now, it won’t fail but it won’t output anything either. Next, we’ll execute/invoke/run the $PowerShellScriptBlock using the call operator &:

Function New-ToDoList ($todoListName, $PowerShellScriptBlock) {

& $PowerShellScriptBlock

}

Running the Windows PowerShell script again, we get a new error: “The term ‘New-ToDoItem’ is not recognized as the name of a cmdlet.” We will solve that by defining the New-ToDoItem function that will take two strings: “priority” and “task.”

Function New-ToDoList ($todoListName, $PowerShellScriptBlock) {

Function New-ToDoItem ($priority, $task) {}

& $PowerShellScriptBlock

}

Now we can run the script with no errors, but there still is no output. Next, we flesh out the New-ToDoItem function so that it prints out data:

Function New-ToDoList ($todoListName, $PowerShellScriptBlock) {

Function New-ToDoItem ($priority, $task) {

New-Object PSObject -Property @{

ToDoListName = $todoListName

Priority = $priority

Task = $task

}

}

& $PowerShellScriptBlock

}

Results Run the script:

New-ToDoList housework {

New-ToDoItem high “Clean the house.”

New-ToDoItem medium “Wash the dishes.”

New-ToDoItem medium “Buy more soap.”

}

And get this:

Priority      ToDoListName   Task

——–        ————               —-

high           housework          Clean the house.

medium    housework          Wash the dishes.

medium    housework           Buy more soap.   

The Special Sauce The function, New-ToDoList, takes a Windows PowerShell script block as a parameter, which is invoked using the call operator &. This opens the door to include any valid Windows PowerShell.

New-ToDoList housework {

New-ToDoItem high “Clean the house.”

New-ToDoItem medium “Wash the dishes.”

New-ToDoItem medium “Buy more soap.”

“Buy Microsoft Stock.”, “Learn to build DSLs/DSVs.”, “Get Beer.” |

ForEach { New-ToDoItem medium $_}

}

You cannot do that with XML. This technique is not new. Other languages support similar approaches. We have built an internal domain specific language (DSL). Search for “DSL” or “Internal DSL” for posts on this topic if you’d like to dive deeper. Alternatives Look at the function, New-ToDoItem. We are outputting a new PSObject with three properties. We could have chosen to do any number of things here: output a hash table, a string, an XML node, a PSObject with more or less information. Alternatively, we could write the information to a file, call a web service, or insert it to a database table. Where Else Can We Use This? These little languages are easy to construct. Below is a configuration example that describes a component, how it is configured, and where it can be copied from. You could describe many components this way in a single Windows PowerShell file, run it, and then return an array that can be sliced and diced with Where, Group, and more. In addition, you could peel off each item in an array and operate on it, say, using RoboCopy to mirror it to a different destination.

New-Component TestComponent {

Set-Location “C:Temp”

Set-Port 9999

Set-ConnectPoolSize 100

}

Call to Action Using and invoking script blocks in your Windows PowerShell solutions is a powerful concept. Languages such as Python and Ruby use this to cut down on the “noise” from formats such as XML. Compare the to-do list in XML to the one in Windows PowerShell. The Windows PowerShell list requires less typing, is more readable, and is self-describing. Building the Windows PowerShell script that processes the Windows PowerShell to-do list, though different, is relatively simple—only 10 lines of code. Give it a whirl, and practice coming up with your own little languages. It is easy, fun, and productive.   FD, that is all there is to using Windows PowerShell to work with XML. I want to thank Doug for taking his time to write the blog for us today and sharing his knowledge. Guest Blogger Week will continue tomorrow when Rob Campbell will join us. I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace. Ed Wilson, Microsoft Scripting Guy

0 comments

Discussion is closed.

Feedback usabilla icon