---
title: "PowerShell to Parse XML: Read and Validate"
description: "Discover how to use PowerShell to parse XML, read XML files, and create and validate XML schemas in this handy tutorial."
canonical: "https://adamtheautomator.com/powershell-parse-xml/"
---

# PowerShell to Parse XML: Read and Validate

> Discover how to use PowerShell to parse XML, read XML files, and create and validate XML schemas in this handy tutorial.

Source: https://adamtheautomator.com/powershell-parse-xml/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![PowerShell to Parse XML: Read and Validate](https://adamtheautomator.com/wp-content/uploads/2020/12/How-to-Read-Parse-and-Validate-XML-with-PowerShell.jpg)

# PowerShell to Parse XML: Read and Validate

[![](https://secure.gravatar.com/avatar/3d789c8b517f2dac6b170f741b31b0658bd8e9dc5f272cf683b8e7b3a31e4005?s=192&d=mm&r=g)Tsvika Nahir](https://adamtheautomator.com/author/tsvika/)12 January 20219 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Prerequisites](#h-prerequisites)
*   [Parsing Powershell XML Elements with Select-Xml](#h-parsing-powershell-xml-elements-with-select-xml)
*   [Using PowerShell to Parse XML Attributes with Select-Xml](#h-parsing-powershell-xml-attributes-with-select-xml)
*   [Casting XML Strings to Objects](#h-casting-xml-strings-to-objects)
*   [Reading XML Object Elements](#h-reading-xml-object-elements)
*   [Reading XML Attributes](#h-reading-xml-attributes)
*   [Iterating Through XML Data](#h-iterating-through-xml-data)
*   [XML Schemas](#h-xml-schemas)
*   [Validating XML Data](#h-validating-xml-data)
*   [Possible Errors in XML Data](#h-possible-errors-in-xml-data)
*   [XML Metadata Errors](#h-xml-metadata-errors)
*   [Errors in the XML Data](#h-errors-in-the-xml-data)
*   [Creating an XML Schema](#h-creating-an-xml-schema)
*   [Using the Schema File to Validate Your Data](#h-using-the-schema-file-to-validate-your-data)
*   [Fine Tuning the Validation Schema](#fine-tuning-the-validation-schema)
*   [Adding setting to the default schema – examples](#h-adding-setting-to-the-default-schema-examples)
*   [String Length Validation with xs:restriction](#h-string-length-validation-with-xs-restriction)

XML is all over the place. Despite its annoying use of angle brackets, XML format is still widely used. Configuration files, RSS feeds, Office files (the ‘x’ in the .docx) are just a partial list. Using PowerShell to parse XML files is an essential step in your PowerShell journey.

This tutorial will show you how PowerShell parse XML files and validate them. This will walk you from zero to hero for all aspects of getting and evaluating XML data. You will be given tools that will help you validate XML data integrity and stop faulty data right at the gate of your scripts!

## Prerequisites

To follow along with the presented material, you should have:

*   [PowerShell version](https://adamtheautomator.com/powershell-version/ "PowerShell version") 3.0 and above. The examples were created on Windows PowerShell v5.1
*   [](https://notepad-plus-plus.org/)[_Notepad++_](https://notepad-plus-plus.org/downloads/), Visual Studio Code or another text editor that understands XML.

## Parsing Powershell XML Elements with `Select-Xml`

Let’s first cover one of the most popular and easiest ways to use PowerShell to parse XML and that’s with `Select-Xml`. The `Select-Xml` cmdlet allows you to provide an XML file or string along with a “filter” known as XPath to pull out specific information.

> _[XPath](https://www.w3schools.com/xml/xpath_intro.asp) is a chain of element names. It uses a “path like” syntax to identify and navigate nodes in an XML document._

Let’s say you have an XML file with a bunch of computers and would like to use PowerShell to parse this XML file. Each computer has various elements like name, IP address and an `Include` element for inclusion in a report.

> _An element is an XML portion with an opening tag and a closing tag, possibly with some text in-between, such as **`<Name>SRV-01</Name>`**_

```powershell
<Computers>
	<Computer>
		<Name>SRV-01</Name>
		<Ip>127.0.0.1</Ip>
		<Include>true</Include>
	</Computer>	
	<Computer>
		<Name>SRV-02</Name>
		<Ip>192.168.0.102</Ip>
		<Include>false</Include>
	</Computer>	
	<Computer>
		<Name>SRV-03</Name>
		<Ip>192.168.0.103</Ip>
		<Include>true</Include>
	</Computer>	
</Computers>
```

You’d like to use PowerShell to parse this XML file get the computer names. To do that, you could use the `Select-Xml` command.

In the file above, the computer names appear in the inner text (InnerXML) of the _Name_ element.

> _InnerXML is the text between the two element’s tags._

To find the computer names, you’d first provide the appropriate XPath (`/Computers/Computer/Name`). This XPath syntax would return only the `Name` nodes under the `Computer` elements. Then to only get the InnerXML of each `Name` element, reach the `Node.InnerXML` property on each element with a `[ForEach](https://adamtheautomator.com/powershell-foreach/ "ForEach")-Object` loop.

```powershell
Select-Xml -Path C:\Work\computers-elm.xml -XPath '/Computers/Computer/Name' | ForEach-Object { $_.Node.InnerXML }
```

## Using PowerShell to Parse XML Attributes with `Select-Xml`

Now let’s address this problem of finding computer names from a different angle. This time, instead of the computer descriptors represented with XML _elements_, they are represented with XML _attributes_.

> An a_ttribute is a key/value portion such as **`name="SRV-01"`** . Attributes always appear within the opening tag, right after the tag name._

Below is the XML file with computer descriptors represented with attributes. You can now see each descriptor as an attribute rather than an element.

```powershell
<Computers>
	<Computer name="SRV-01" ip="127.0.0.1" include="true" />
	<Computer name="SRV-02" ip="192.168.0.102" include="false" />
	<Computer name="SRV-03" ip="192.168.0.103" include="true" />
</Computers>
```

Since each descriptor is an attribute this time, tweak the XPath a little bit to only find the Computer elements. Then, using a `ForEach-Object` cmdlet again, find the value of the _name_ attribute.

```powershell
Select-Xml -Path C:\Work\computers-attr.xml -XPath '/Computers/Computer' | ForEach-Object { $_.Node.name }
```

And indeed, this also brings the same results: _SRV-01_, _SRV-02_ and _SRV-03 :_

![Reading data using Select-Xml](https://adamtheautomator.com/wp-content/uploads/2020/12/xml-1.png)

_Reading data using Select-Xml_

In both cases, whether you are reading elements or attributes, the syntax of `Select-Xml` is cumbersome: it forces you to use the `XPath` parameter, then to pipe the result to a loop, and finally to look for the data under the _Node_ property.

Luckily, PowerShell offers a more convenient and intuitive way to read XML files. PowerShell lets you read XML files and convert them to XML _objects_.

_**Related:** [Using PowerShell Data Types Accelerators to Speed up Coding](https://adamtheautomator.com/powershell-data-types/)_

## Casting XML Strings to Objects

Another way to use PowerShell to parse XML is to convert that XML to objects. The easiest way to do this is with the `[xml]` type accelerator.

By prefixing the variable names with `[xml]`, PowerShell converts the original plain text XML into objects you can then work with.

```powershell
[xml]$xmlElm = Get-Content -Path C:\Work\computers-elm.xml
[xml]$xmlAttr = Get-Content -Path C:\Work\computers-attr.xml
```

## Reading XML Object Elements

Now both the `$xmlElm` and `$xmlAttr` variables are XML objects allowing you to reference properties via dot notation. Perhaps you need to find the IP address of each computer element. Since the XML file is an object, you can so by simply referencing the IP element.

```powershell
$xmlElm.Computers.Computer.ip
```

> _Starting from PowerShell version 3.0, the XML object gets the attribute value with the same syntax used for reading the element’s inner text. Therefore, the IP addresses’ values are read from the attributes file with the exactly same syntax as the elements file._

## Reading XML Attributes

Using exactly the same dot notation, you can read XML attributes as well despite differences in the XML structure.

```powershell
$xmlElm.Computers.Computer.ip
$xmlAttr.Computers.Computer.ip
```

And the results below show that both got the same data, each one from its corresponding file:

![PowerShell to Parse XML : Reading XML Attributes](https://adamtheautomator.com/wp-content/uploads/2020/12/img-ip.png)

PowerShell to Parse XML : Reading XML Attributes

Moreover, with the object, once it is loaded to memory, you even get IntelliSense to tab-complete if you’re using the PowerShell ISE. For example as shown below.

![IntelliSense and tab completion for XML object](https://adamtheautomator.com/wp-content/uploads/2020/12/inteli.png)

_IntelliSense and tab completion for XML object_

## Iterating Through XML Data

Once you get around reading XML files directly to XML object (by taking advantage of the `[xml]` type accelerator), you have all the full power of PowerShell objects.

Say, for example, you are required to loop through all the computers that appear in the XML file with the _include=”true”_ attribute to check their connection status. The code below shows how it can be done.

This script is:

*   Reading the file and casting it to an XML object.
*   Iterating through the relevant computers to get their connection status.
*   Finally, sending the result output object to the pipeline.

```powershell
 ## casting the file text to an XML object
 [xml]$xmlAttr = Get-Content -Path C:\Work\computers-attr.xml

 ## looping through computers set with include="true"
 $xmlAttr.Computers.Computer | Where-Object include -eq 'true' |  ForEach-Object {
     ## see if the current computer is online
     if(Test-Connection -ComputerName $_.ip -Count 1 -Quiet)
     {
         $status = 'Connection OK'
     }
     else
     {
         $status = 'No Connection'
     }

     ## output the result object
     [pscustomobject]@{
         Name = $_.name
         Ip = $_.ip
         Status = $status
     }
 }
```

And the results of the script above are shown below:

![Connection status results](https://adamtheautomator.com/wp-content/uploads/2020/12/xml-3.png)

_Connection status results_

## XML Schemas

In the previous section, you saw two different XML files representing a data set in two different ways. Those ways are called XML schemas. An XML Schema defines the legal building blocks of a **_specific_** XML document:

*   The names of elements and attributes that can appear in that specific document.
*   The number and order of child elements.
*   The data types for elements and attributes.

The schema essentially defines the structure of the XML.

## Validating XML Data

An XML file may have the correct syntax (editors like Notepad++ will complain if not), yet its data might not match the project requirement. This is where the schema comes in to play. When you lean on XML data, you must ensure that _all_ the data is valid according to the defined schema.

The last thing you want is to discover data errors in runtime, 500 lines deep in the script’s middle. It might have already performed some irreversible operations on the file system and the registry, by that time.

So, how can you check in advance that the data is correct? Let’s see first some possible error types.

### Possible Errors in XML Data

Generally speaking, errors found on XML files belong to one of two categories; metadata errors and errors in the data itself.

#### XML Metadata Errors

This file _MorePeople.xml_ below, is perfectly valid syntax-wise. You can see below that the file has a single _People_ element (the root element) with three _Person_ elements inside. This structure is perfectly acceptable. Still, it contains one exception, can you see it?

```powershell
<People>
	<Person Name="Debra" County="Canada" IsAdmin="true" />
	<Person Name="Jacob" Country="Israel" IsAdmin="true" />
	<Person Name="Olivia" Country="Cyprus" IsAdmin="false" />
</People>
```

Do not worry if you didn’t, it is just hiding. The problem is found in the first inner element:

What should have been a _Country_ was misspelled, and Canada was degraded to a _County_.

#### Errors in the XML Data

After fixing the _Country_ issue on _MorePeople.xml_, another problem sneaked in:

```powershell
<People>
	<Person Name="Debra" Country="Canada" IsAdmin="yes" />
	<Person Name="Jacob" Country="Israel" IsAdmin="true" />
	<Person Name="Olivia" Country="Cyprus" IsAdmin="false" />
</People>
```

The metadata, i.e., the elements and attributes, are fine. So what is wrong? This time the problem, again on the first _Person_ line, is in one of the _values_. Someone decided that _yes_ is a good enough substitute for _true_ – but code like below will fail to get the first element as it is looking for _true_, not for _yes_:

```powershell
$peopleXml.People.Person | Where-Object IsAdmin -eq 'true'
```

### Creating an XML Schema

Now that you know the types of errors that may occur, it is time to show how a schema file helps. The first step is creating a sample data file. The sample can be the smallest example and contain nothing but a single inner element. For the above examples, let’s create a sample file like this _People.xml_ :

```powershell
<People>
	<Person Name="Jeff" Country="USA" IsAdmin="true" />
</People>
```

Now build a [PowerShell function](https://adamtheautomator.com/powershell-functions/ "PowerShell function") below and use it with the sample data to create the .xsd schema.

```powershell
function New-XmlSchema
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -Path $_ })]
        [ValidatePattern('\.xml')]
        [string]$XmlExample
    ) 

    $item = Get-Item $XmlExample
    $dir = $item.Directory
    $name = $item.Name
    $baseName = $item.BaseName

    ## build the schema path by replacing '.xml' with '.xsd'
    $SchemaPath = "$dir\$baseName.xsd"

    try
    {
        $dataSet = New-Object -TypeName System.Data.DataSet
        $dataSet.ReadXml($XmlExample) | Out-Null
        $dataSet.WriteXmlSchema($SchemaPath)
        
        ## show the resulted schema file
        Get-Item $SchemaPath
    }
    catch
    {
        $err = $_.Exception.Message
        Write-Host "Failed to create XML schema for $XmlExample`nDetails: $err" -ForegroundColor Red
    }
}
```

Copy the function to your ISE or your favorite Powershell editor, load it into memory and use it to create the schema. With the function loaded, the code to create the schema is this one-liner:

```powershell
New-XmlSchema -XmlExample 'C:\Work\People.xml'
```

The results will show the path to the newly created schema:

![Creating XML schema from a sample data file](https://adamtheautomator.com/wp-content/uploads/2020/12/01.png)

_Creating XML schema from a sample data file_

### Using the Schema File to Validate Your Data

Take a look at the location specified by the results above. If the .xsd is there, you are on the right way to see the validation in action. For the confirmation step, use the function below:

```powershell
function Test-XmlBySchema
{
    [CmdletBinding()]
    [OutputType([bool])]
    param
    (
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -Path $_ })]
        [ValidatePattern('\.xml')]
        [string]$XmlFile,
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -Path $_ })]
        [ValidatePattern('\.xsd')]
        [string]$SchemaPath
    )

    try
    {
        [xml]$xml = Get-Content $XmlFile
        $xml.Schemas.Add('', $SchemaPath) | Out-Null
        $xml.Validate($null)
        Write-Verbose "Successfully validated $XmlFile against schema ($SchemaPath)"
        $result = $true
    }
    catch
    {
        $err = $_.Exception.Message
        Write-Verbose "Failed to validate $XmlFile against schema ($SchemaPath)`nDetails: $err"
        $result = $false
    }
    finally
    {
        $result
    }
}
```

Load the function to memory, and use it to validate the _MorePeople.xml_ from the two error examples. To trigger the validation, use the command below:

```powershell
Test-XmlBySchema -XmlFile 'C:\Work\MorePeople.xml' -SchemaPath 'C:\Work\People.xsd' -Verbose
```

The actual results depend on the content of _MorePeople.xml._

Let’s see two examples. Notice that when _MorePeople.xml_ is error-free, the function above will return `True`.

![Validation success](https://adamtheautomator.com/wp-content/uploads/2020/12/02.png)

_Validation success_

When the _MorePeople.xml_ file contains wrong data (the _Country_ key misspelled as _County_), the function will return some failure details and return `False`.

![Validation failure - wrong attribute name detected](https://adamtheautomator.com/wp-content/uploads/2020/12/03.png)

_Validation failure – wrong attribute name detected_

As you can see, the error specified on the verbose output is very informative: It directs to the culprit file and points to the exact component in it where the problem occurred.

### Fine Tuning the Validation Schema

Let’s take a look at the schema file, then see how we can make it even better.

The schema created by the `New-XmlSchema` by default is below:

```powershell
<?xml version="1.0" standalone="yes"?>
<xs:schema id="People" xmlns="" xmlns:xs="<http://www.w3.org/2001/XMLSchema>" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="People" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Person">
          <xs:complexType>
            <xs:attribute name="Name" type="xs:string" />
            <xs:attribute name="Country" type="xs:string" />
            <xs:attribute name="IsAdmin" type="xs:string" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>
```

The default schema above is good, but not perfect. Indeed it has caught the typo with the _Country_ attribute. But, if you leave the schema as-is, in case other expectations you might have are not met – these issues will not be reported as errors by the `Test-XmlBySchema` validation. Let’s solve this.

The table below presents some cases that are not considered validation errors and will go unnoticed by `Test-XmlBySchema`. On each row, the right column shows how to manually change the schema to add support for the necessary protection.

> _A modified version of the schema file, with all protections added, is shown right after the table._

### Adding setting to the default schema – examples

<table><tbody><tr><td class="has-text-align-center" data-align="center"><strong>Required Behavior</strong></td><td class="has-text-align-center" data-align="center"><strong>Relevant setting on the schema file</strong></td></tr><tr><td class="has-text-align-center" data-align="center">At least one <em>Person </em>element</td><td class="has-text-align-center" data-align="center">Set the <em>minOccurs </em>value of the <em>Person </em>element to 1</td></tr><tr><td class="has-text-align-center" data-align="center">Make Name, Country and IsAdmin attributes mandatory</td><td class="has-text-align-center" data-align="center">Add <em>use=”required”</em> to each of these attributes declaration</td></tr><tr><td class="has-text-align-center" data-align="center">Allow only <em>true/false</em> values for <em>IsAdmin</em></td><td class="has-text-align-center" data-align="center">Set <em>type=”xs:boolean”</em> for the <em>IsAdmin </em>declaration</td></tr><tr><td class="has-text-align-center" data-align="center">Allow only <em>Country</em> names between<em> </em>3 and 40 characters</td><td class="has-text-align-center" data-align="center">Use the <em>xs:restriction</em> <em>(see detailed explanation after the schema text)</em></td></tr></tbody></table>

```powershell
<?xml version="1.0" standalone="yes"?>
<xs:schema id="People" xmlns="" xmlns:xs="<http://www.w3.org/2001/XMLSchema>" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="People" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Person">
          <xs:complexType>
            <xs:attribute name="Name" type="xs:string" use="required" />
	    <xs:attribute name="Country" use="required">
	      <xs:simpleType>
		<xs:restriction base="xs:string">
		  <xs:minLength value="3"/>
		  <xs:maxLength value="40"/>
		</xs:restriction>
	      </xs:simpleType>
	    </xs:attribute>	
            <xs:attribute name="IsAdmin" type="xs:boolean" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>
```

> _With the boolean restriction in place for the IsAdmin attribute in the example, its value must be a _**lower case**__ _true or false._

### String Length Validation with xs:restriction

The string length validation is a bit complex. So, even though it is shown above as part of the modified schema, it deserves a little more focus.

The original schema item for the _Country_ attribute (after having manually added the _use=”required”)_, is as below:

```powershell
<xs:attribute name="Country" type="xs:string" use="required" />
```

To add the length protection you should add the `<xs:simpleType>` element, and within it, the `<xs:restriction base="xs:string">`. This restriction in turn contains the required limits declared on `xs:minLength` and on `xs:minLength`.

Following all these changes the final `xs:attribute` declaration has grown from a single line to a giant 8 lines node:

```powershell
<xs:attribute name="Country">
  <xs:simpleType>
	<xs:restriction base="xs:string">
	  <xs:minLength value="3"/>
	  <xs:maxLength value="40"/>
	</xs:restriction>
  </xs:simpleType>
</xs:attribute>
```

If your head does not spin after the explanation above, you earned the right to see the validation in action. To do that let’s intentionally shorten the value _Canada_ to a two characters syllable: _Ca_

With the short country name in place, and _MorePeople.xml_ saved, you are ready to run the validation command below:

```powershell
Test-XmlBySchema -XmlFile 'C:\Work\MorePeople.xml' -SchemaPath 'C:\Work\People.xsd' -Verbose
```

and the results indeed show the complex schema has done its work:

![A string length error detected by the schema validation](https://adamtheautomator.com/wp-content/uploads/2020/12/04.png)

_A string length error detected by the schema validation_

> _XML schema validation can grow in complexity and validate just about any pattern you can think of, especially when combined with regular expressions._

Related:[Getting Started with PowerShell and Regex](https://adamtheautomator.com/powershell-regex/)

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-parse-xml%2F&text=PowerShell%20to%20Parse%20XML%3A%20Read%20and%20Validate)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-parse-xml%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-parse-xml%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
