Powershell: Working with XML
A few tips and tricks for handling XML data with Powershell.
This is only a very brief overview/cheatsheet of common tasks when dealing with XML data (based on this article), because I recently needed to handle XML again, after quite a while (I usually prefer JSON nowadays).
Contents
Create a new XML document and save it to a file
The end result will be an XML file that contains the following:
<?xml version="1.0"?>
<!--
Powershell Version: 7.5.3
Powershell Edition: Core
-->
<RootNode>
<MainNode Language="Powershell">
<FooBar Foo="ABC" Bar="123" />
<Entry Ticks="638971946370073046">E. #1</Entry>
<Entry Ticks="638971946370074780">E. #2</Entry>
<Entry Ticks="638971946370075446">E. #3</Entry>
</MainNode>
</RootNode>
And it was generated by this code:
$XMLDoc = New-Object System.Xml.XmlDocument
# Adding the declaration: Without the encoding (second parameter, would be "UTF-8"),
# because that would cause .Save() to store it with a BOM (which we don't want!).
# Quick-&-Dirty solution: https://stackoverflow.com/questions/63476408/powershell-xmldocument-save-as-utf-8-without-bom
$XMLDeclaration = $XMLDoc.CreateXmlDeclaration("1.0", $null, $null);
$XMLDoc.AppendChild($XMLDeclaration) | Out-Null
# Adding a header comment:
$HeaderCommentString = @"
Powershell Version: $($PSVersionTable.PSVersion.ToString())
Powershell Edition: $($PSVersionTable.PSEdition)`n
"@
$HeaderComment = $XMLDoc.CreateComment($HeaderCommentString)
$XMLDoc.AppendChild($HeaderComment) | Out-Null
# Adding the root node:
$Root = $XMLDoc.CreateElement("RootNode")
$XMLDoc.AppendChild($Root) | Out-Null
# Adding a element beneath the root node:
$MainNode = $XMLDoc.CreateElement("MainNode")
$MainNode.SetAttribute("Language", "Powershell")
$Root.AppendChild($MainNode) | Out-Null
# Adding a tag to the main node:
$FooBar = $XMLDoc.CreateElement("FooBar")
$FooBar.SetAttribute("Foo", "ABC")
$FooBar.SetAttribute("Bar", "123")
$MainNode.AppendChild($FooBar) | Out-Null
# Adding multiple elements to the main node:
1..3 | % {
$e = $XMLDoc.CreateElement("Entry")
$e.InnerText = "E. #" + $_
$e.SetAttribute("Ticks", ((Get-Date).Ticks))
$MainNode.AppendChild($e) | Out-Null
}
# Save to a file (must be a fully qualified path!):
$FQP = Join-Path -Path (Resolve-Path -Path .).Path -ChildPath "file.xml"
$XMLDoc.Save($FQP)
Read an existing file and access its elements
Just a few simple command-line examples:
> [xml] $XMLDoc = Get-Content -Path ".\file.xml"
> $Root = $XMLDoc.'RootNode'
> $Root.'MainNode'
Language FooBar Entry
-------- ------ -----
PowerShell FooBar {Entry, Entry, Entry}
> $XMLDoc.'#comment'
Powershell Version: 7.5.3
Powershell Edition: Core
> $Root.MainNode.FooBar
Foo Bar
--- ---
ABC 123
> $Root.MainNode.Entry # or
> $XMLDoc.RootNode.MainNode.GetElementsByTagName("Entry")
Ticks #text
----- -----
638971946370073046 E. #1
638971946370074780 E. #2
638971946370075446 E. #3
> $Root.MainNode.Entry.InnerText
E. #1
E. #2
E. #3
> $XMLDoc.RootNode.MainNode.Entry.Get(1)
Ticks #text
----- -----
638971946370074780 E. #2
> $XMLDoc.RootNode.MainNode.Entry.GetValue(1).InnerText
E. #2
> $XMLDoc.RootNode.MainNode.Entry.GetValue(1).GetAttribute("Ticks")
638971946370074780
Modify an existing XML document and save it again
That is a combination of the previous steps:
[xml] $XMLDoc = Get-Content -Path ".\file.xml"
$XMLDoc.RootNode.MainNode.FooBar.InnerXml = "New"
$XMLDoc.RootNode.MainNode.FooBar.Bar = '456'
$XMLDoc.RootNode.MainNode.FooBar.Foo = 'XYZ'
$XMLDoc.Save((Resolve-Path ".\file.xml").Path)
Result (memory):
> $XMLDoc.RootNode.MainNode.FooBar
Foo Bar #text
--- --- -----
XYZ 456 New
Result (file):
<?xml version="1.0"?>
<!--
Powershell Version: 7.5.3
Powershell Edition: Core
-->
<RootNode>
<MainNode Language="Powershell">
<FooBar Foo="XYZ" Bar="456">New</FooBar>
<Entry Ticks="638971946370073046">E. #1</Entry>
<Entry Ticks="638971946370074780">E. #2</Entry>
<Entry Ticks="638971946370075446">E. #3</Entry>
</MainNode>
</RootNode>
Categories
Development (80)Film & Television (55)
How To (66)
Journal (18)
Miscellaneous (4)
News & Announcements (21)
On Software (12)
Projects (26)
Tags
ANSI Escape Code (1)
Bluetooth (1)
C++ (11)
Citrix (1)
Clang (1)
CMake (10)
Code (3)
DE (8)
Doxygen (1)
EN (180)
Excel (1)
Filezilla (1)
Firefox (1)
GeSHi (1)
Git (2)
Hugo (2)
JSON (2)
Lua (3)
Mercurial (5)
MTP (2)
Notepad++ (3)
Pico-8 (1)
Powershell (25)
PuTTY (1)
Python (5)
Qt (11)
RandFill (15)
RegEx (1)
Remi (2)
RSS (1)
SCons (1)
SIMInfo (7)
Site (2)
SSH (1)
TinyTinyRSS (1)
Using C++ With Lua (2)
Visual Studio (10)
Win32 (2)
Windows (22)
Windows Registry (1)
WordPress (3)
WPD (3)
WPDLib (2)
WPF (1)
XAML (1)
XML (1)
YouTube (1)