Creating Custom XML in PowerShell


I hope you’ve been following along in our exploration of working with XML in PowerShell. If you are just jumping in, I encourage you to take a few minutes to read the previous articles in this series. In the last article, I demonstrated a number of ways to get PowerShell output into an XML file. But sometimes, you have to take matters into your own hands to create the exact XML format that you need. Before you begin, I want to re-iterate the importance of planning ahead. How will you be using the XML files? Will you be re-using them in a PowerShell session? Will they be processed by some external XML-driven application or process? Will humans need to interact with them or machines? I’m going to demonstrate several techniques but understand that there is no single best practice.



Sponsored Content

Maximize Value from Microsoft Defender

In this ebook, you’ll learn why Red Canary’s platform and expertise bring you the highest possible value from your Microsoft Defender for Endpoint investment, deployment, or migration.

In the previous article, I introduced you to ConvertTo-Xml. Because the cmdlet doesn’t immediately create a file, you have the option of modifying the XML first. Here’s one scenario.

I have a list of computers.

#process list of computers filtering out those offline
$computers = Get-Content S:\myservers.txt | Where { Test-WSMan $_ -ErrorAction SilentlyContinue}

I want to get disk information from each computer and save the results to an XML file. This XML file will be consumed by an external trend reporting process. In addition to the information I get back from Get-CimInstance, I need to include at least one custom property and I want to change a few other things in the file. Here’s my code to create an XML stream and save it to a variable.
#get disk data and convert to an XML stream
$xmlStream = Get-Ciminstance Win32_logicaldisk -filter "drivetype=3" -ComputerName $computers |
select * -ExcludeProperty CimClass,Cim*Properties |
Add-Member -MemberType ScriptProperty -Name "PctFree" -Value {[math]::round(($this.freespace/$this.size)*100,4)} -PassThru |
ConvertTo-XML -as Stream

I am excluding any of the CIM system properties and using Add-Member to create a custom property. The XML stream will include my custom property.

Converted XML
Converted XML (Image Credit: Jeff Hicks)

I know that eventually, I will want to change ‘PSComputername’ and instead of Object and Objects, use more meaningful node names.

The variable, $xmlStream is actually an array of different XML elements. Item 0 is the XML declaration.

The XML directive
The XML directive (Image Credit: Jeff Hicks)

Technically, the declaration should include an encoding directive, so I’ll simply assign a new value.

$xmlStream[0] = '<?xml version="1.0" encoding="utf-8"?>'

Next, instead of ‘Objects’ and ‘Object’, I want the outer node to be ‘Disks’ and ‘Disk’. The outer tags are simple enough to change.
$xmlStream[1] = "<Disks>"
$xmlStream[-1] = "</Disks>"

Don’t forget that XML is case-sensitive, so your tags must match. Next, I need to modify each of the nodes, replacing key pieces of text. I’ll use a FOR loop to go through each disk element.
for ($i = 2;$i -lt $($xmlStream.count -1);$i++) {
 $xmlStream[$i] = $xmlStream[$i] -replace "PSComputername","Computername"
 $xmlStream[$i] = $xmlStream[$i] -replace "(?<=\<(\/?))Object","Disk"

The last replacement is done with a fancy regular expression pattern utilizing a lookback, so I can change both <Object> and </Object> with a single line of code. But now my array of XML elements is properly formatted. All that remains is to send the results to a file.
$xmlStream | Out-File -FilePath c:\work\Disks.xml -Encoding utf8

Note that I encoded the file to match the XML declaration. To simplify the process I would wrap all of this up in a PowerShell function or a script.

Another approach might be to convert everything to a single string.

$xmlString = Get-Ciminstance Win32_logicaldisk -filter "drivetype=3" -ComputerName $computers |
select * -ExcludeProperty CimClass,Cim*Properties |
Add-Member -MemberType ScriptProperty -Name "PctFree" -Value {[math]::round(($this.freespace/$this.size)*100,4)} -PassThru |
ConvertTo-XML -as String

I can easily make the same kind of adjustments.
$xmlString = $xmlString -replace 'xml version="1.0"', 'xml version="1.0" encoding="utf-8"' 
$xmlString = $xmlString -replace "PSComputername","Computername" 
$xmlString = $xmlString -replace "(?<=\<(\/?))Object","Disk"  
$xmlString | Out-File -FilePath c:\work\Disks-string.xml -encoding utf8

There are additional ways to create custom XML from scratch, but I think this may be enough for now. There’s plenty here for you to experiment with and try on your own. And don’t worry, I’ll address how to bring these custom files back into PowerShell in a future article. As always, comments and questions are welcome.

Related Topics:


Don't have a login but want to join the conversation? Sign up for a Petri Account

Comments (0)

Leave a Reply

External Sharing and Guest User Access in Microsoft 365 and Teams

This eBook will dive into policy considerations you need to make when creating and managing guest user access to your Teams network, as well as the different layers of guest access and the common challenges that accompany a more complicated Microsoft 365 infrastructure.

You will learn:

  • Who should be allowed to be invited as a guest?
  • What type of guests should be able to access files in SharePoint and OneDrive?
  • How should guests be offboarded?
  • How should you determine who has access to sensitive information in your environment?

Sponsored by:

Live Webinar: Active Directory Security: What Needs Immediate Priority!Live on Tuesday, October 12th at 1 PM ET

Attacks on Active Directory are at an all-time high. Companies that are not taking heed are being punished, both monetarily and with loss of production.

In this webinar, you will learn:

  • How to prioritize vulnerability management
  • What attackers are leveraging to breach organizations
  • Where Active Directory security needs immediate attention
  • Overall strategy to secure your environment and keep it secured

Sponsored by: