Say your online store exports every order to an orders.xml file at night, and the finance team wants it in Excel by 8 AM.
To convert XML to Excel using PowerShell, load the file with [xml], turn each order into a [pscustomobject] row, and pipe the rows to Export-Excel or Export-Csv.
In this tutorial, I’ll show you three ways to do it with one sample order file from start to finish, plus the encoding and number traps I hit in PowerShell 7 and Windows PowerShell 5.1.
The sample XML file we’ll use
Here’s the orders.xml file the whole post works with, a nightly export from a made-up outdoor store with four October 2026 orders in USD. Two of them are shown:
<?xml version="1.0" encoding="utf-8"?>
<Orders store="Harbor & Pine Outfitters" exported="2026-10-16">
<Order id="SO-10422" status="Processing">
<Date>2026-10-03</Date>
<Customer>
<Name>Tom Baker</Name>
<City>Denver</City>
<State>CO</State>
</Customer>
<Items>
<Item sku="BTL-32" qty="3" price="18.00">Insulated Bottle 32 oz</Item>
</Items>
<Total currency="USD">54.00</Total>
</Order>
<Order id="SO-10423" status="Shipped">
<Date>2026-10-07</Date>
<Customer>
<Name>José Martínez</Name>
<City>San Antonio</City>
<State>TX</State>
</Customer>
<Items>
<Item sku="JKT-RN" qty="1" price="129.00">Rain Shell Jacket</Item>
<Item sku="SCK-WL" qty="4" price="12.75">Wool Hiking Socks</Item>
<Item sku="SPG-CK" qty="1" price="21.00">Salt & Pepper Camp Set</Item>
</Items>
<Total currency="USD">201.00</Total>
</Order>
<!-- SO-10421 and SO-10424 have the same shape -->
</Orders>
It’s small, but it has the parts that trip up most conversions:
- Attributes: the order
idandstatus, andcurrencyon<Total>. - Nested data: a
<Customer>block and one to three<Item>lines. - Non-ASCII text: José Martínez from San Antonio, and an ampersand in the store name.
A worksheet is flat, so the real job is deciding which XML parts become rows and columns. To just look at the data first, try viewing XML as a table in PowerShell.
Step 1: Load the XML file into PowerShell
The [xml] type accelerator is short for the .NET System.Xml.XmlDocument class. Once the file is an XmlDocument, you walk it with dot notation, like $xml.Orders.Order.
Most scripts load it with [xml](Get-Content ...). Here’s that next to the Load() method:
$file = Convert-Path .\xml2xlsx\orders.xml
$quick = [xml](Get-Content -Path $file -Raw)
$xml = [xml]::new()
$xml.Load($file)
'Get-Content + [xml] : ' + $quick.Orders.Order[2].Customer.Name
'XmlDocument.Load() : ' + $xml.Orders.Order[2].Customer.Name
'Orders in the file : ' + $xml.Orders.Order.Count
'Store attribute : ' + $xml.Orders.store
Output:
Get-Content + [xml] : José Martínez
XmlDocument.Load() : José Martínez
Orders in the file : 4
Store attribute : Harbor & Pine Outfitters
That’s PowerShell 7, where both lines are right. Windows PowerShell 5.1 prints José MartÃnez on the Get-Content line:
![Windows PowerShell 5.1 console where Get-Content plus [xml] garbles José Martínez but XmlDocument.Load reads it correctly](https://powershellfaqs.com/wp-content/uploads/2026/10/windows-powershell-5-1-xml-get-content-utf8-accents.png)
How does this code work?
Convert-Path makes the path absolute, because .NET methods like Load() resolve relative paths against the process folder, not your PowerShell location.
In 5.1, Get-Content reads UTF-8 without a byte order mark (BOM) as ANSI, so the accents break before the parser sees them. Load() reads the bytes itself and follows the file’s encoding declaration.
Attributes read like elements, so $xml.Orders.store returns the store name. The same BOM question shows up when