# Reading XML

**URL:** <https://forums.powershell.org/t/reading-xml/11931>\
**Category:** PowerShell Help\
**Created:** [January 19, 2019, 2:36pm UTC](https://forums.powershell.org/t/reading-xml/11931 "2019-01-19T14:36:13Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![turtle9270](https://avatars.discourse-cdn.com/v4/letter/t/838e76/32.png) [@turtle9270](https://forums.powershell.org/u/turtle9270)\
**Post date:** [January 19, 2019, 2:36pm UTC](https://forums.powershell.org/t/reading-xml/11931/1 "2019-01-19T14:36:13Z")

</div>

Hi all,

I’ve recently started using PowerShell to make my life easier in my job.

I often have to check Web.Config files on different servers and want to do this using PS as there can be 10 different App’s running on the same server all with their own Web.Config. Rather then just search for a string I would like to use the actual key and print out the value.

The XML files have multiple levels of nested elements, and after googling there seems to be so many different opinions on how to do this.

Can someone help point me in the right direction, maybe an e-book or video that covers how to get started.

Thanks

Paul

&nbsp;

&nbsp;

---

<div class="post-metadata">

**Author:** ![js2010](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@js2010](https://forums.powershell.org/u/js2010)\
**Post date:** [January 19, 2019, 2:50pm UTC](https://forums.powershell.org/t/reading-xml/11931/2 "2019-01-19T14:50:11Z")

</div>

There’s isn’t a cmdlet to do it, but with a cast:

```
PS /Users/js> [xml]$xml = get-content test.xml                                   
PS /Users/js> $xml                                                               

Objs
----
Objs

PS /Users/js> $xml.objs                                                          

Version xmlns Obj
------- ----- ---
1.1.0.1 http://schemas.microsoft.com/powershell/2004/04 {Obj, Obj, Obj, Obj}

# if you want to save changes
PS /Users/js> $xml.save('test.xml')
```

---

<div class="post-metadata">

**Author:** ![turtle9270](https://avatars.discourse-cdn.com/v4/letter/t/838e76/32.png) [@turtle9270](https://forums.powershell.org/u/turtle9270)\
**Post date:** [January 19, 2019, 3:37pm UTC](https://forums.powershell.org/t/reading-xml/11931/3 "2019-01-19T15:37:17Z")

</div>

> [@](#):
>
> There’s isn’t a cmdlet to do it, but with a cast:

Thanks for the reply, when I try your code it just opens the XML in IE.

Would I then be able to do something like

```
Write-Host $xml.object.value
```

---

<div class="post-metadata">

**Author:** ![js2010](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@js2010](https://forums.powershell.org/u/js2010)\
**Post date:** [January 19, 2019, 3:38pm UTC](https://forums.powershell.org/t/reading-xml/11931/4 "2019-01-19T15:38:53Z")

</div>

It should work. What are you running? It sounds like you’re just running ‘test.xml’.

---

<div class="post-metadata">

**Author:** ![postanote](https://avatars.discourse-cdn.com/v4/letter/p/ebca7d/32.png) [@postanote](https://forums.powershell.org/u/postanote)\
**Post date:** [January 19, 2019, 8:10pm UTC](https://forums.powershell.org/t/reading-xml/11931/5 "2019-01-19T20:10:19Z")

</div>

No matter what you read, you are going to have to decide what works for you. Meaning, what you can grasp, understand and internalize for future needs.

There are lots of articles all over the web regarding using PS to create, read, update and delete XML files and or their content. As you’ve obviously already found, but don’t let that overwhelm you. Be specific in the task you are after, and attack it one step at a time. PS is natively XML heavy in many respects.

There are cmdlets specifically for dealing XML as well as leveraging the .Net namespace for it.

```
Get-Command -Name '*xml*'

CommandType Name Version Source
----------- ---- ------- ------
Cmdlet ConvertTo-Xml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Convert-XMLtoJSON 5.0.0.1 Sorlov.PowerShell
Cmdlet Export-Clixml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Import-Clixml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Merge-XMLFile 5.0.0.1 Sorlov.PowerShell
Cmdlet New-XSDfromXML 5.0.0.1 Sorlov.PowerShell
Cmdlet Select-Xml 3.1.0.0 Microsoft.PowerShell.Utility
```

**Of course using any of what is hear requires you know what you are after and use the correct resource.**

 

_Here are few examples I’ve passed on._

 

_> PowerShell Data Basics: XML - Simple Talk
> 
> •Accessing XML data in PowerShell ◦Accessing XML with XPath.  
> ◦Accessing XML as Objects.  
> ◦Comparison of XPath and Object Approaches
> 
> •Modifying or Creating XML Data ◦Adding XML Data  
> ◦Using XML for Object Serialization
> 
> > **[PowerShell Data Basics: XML - Simple Talk](https://www.red-gate.com/simple-talk/sysadmin/powershell/powershell-data-basics-xml/)**
> >
> > To master PowerShell, you must know how to use XML. XML is an essential data interchange format because it remains the most reliable way of ensuring that an object's data is preserved. Fortunately, PowerShell makes it all easy, as Michael Sorens..._

 

_> Mastering everyday XML tasks in PowerShell https://www.powershellmagazine.com/2013/08/19/mastering-everyday-xml-tasks-in-powershell_

 

_> The Scripting Wife Learns to Use PowerShell to Work with XML https://blogs.technet.microsoft.com/heyscriptingguy/2012/03/25/the-scripting-wife-learns-to-use-powershell-to-work-with-xml_

 

_As for videos, YouTube is there for that as well…  
[https://www.youtube.com/results?search\_query=PowerShell+xml](https://www.youtube.com/results?search_query=PowerShell+xml)_

 

_There are also free and fee-oriented modules you can acquire:_

 

_> PowerShell Gallery | Power-XML 1.0.0.4 https://www.powershellgallery.com/packages/Power-XML/1.0.0.4
> 
> PowerShell Gallery | Xml 7.0
> 
> > **[Xml 7.0](https://www.powershellgallery.com/packages/Xml/7.0)**
> >
> > A module providing converters for HTML to XML, various core XML commands and a DSL for generating XML documents._

 

_> XML PowerShell Cmdlets An easy-to-use set of PowerShell Cmdlets offering real-time access to XML data. https://www.cdata.com/drivers/xml/powershell_

---

<div class="post-metadata">

**Author:** ![js2010](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@js2010](https://forums.powershell.org/u/js2010)\
**Post date:** [January 19, 2019, 11:48pm UTC](https://forums.powershell.org/t/reading-xml/11931/6 "2019-01-19T23:48:09Z")

</div>

I don’t know of any cmdlet that would work like an “import-xml”. Import-clixml won’t work with a typical xml file.

---

<div class="post-metadata">

**Author:** ![turtle9270](https://avatars.discourse-cdn.com/v4/letter/t/838e76/32.png) [@turtle9270](https://forums.powershell.org/u/turtle9270)\
**Post date:** [January 20, 2019, 2:38am UTC](https://forums.powershell.org/t/reading-xml/11931/7 "2019-01-20T02:38:43Z")

</div>

> [@](#):
>
> It should work. What are you running? It sounds like you’re just running ‘test.xml’.

You were correct, I totally forgot the Get-Content.

&nbsp;

@postanote

Thank you very much for the links, I’ve not had a chance to go through all of them yet but that ‘Scripting Wife’ blog was a great starting point and exactly what I needed to get me going.

Following through the blog I’ve hit a bit of a snag. If i’m understanding this correctly from the online stuff I’ve read, the end result is being put into a hash table…I think, I’m looking for the value of DataPortalServer, so when I do $xml.configuration.appsettings.add.value[6] this gives me the information that I’m looking for. However, the index may not always be the same, so I want to address it by the name of the key.

I’ve tried .ContainsKey(‘DataPortalServer’), I’ve tried $xml.configuration.appsettings.add.value[‘DataPortalServer’] as well as several other things that I’ve googled but I just can’t get it to work.

Thank’s so much for what you’ve already provided.

&nbsp;

```
Function QPConfigFiles{
[xml]$xml=get-content C:\test.xml
$xml.configuration.appsettings.add ('CslaDataPortalUrl')
}
QPConfigFiles
```

```
<configuration>
<appSettings>
<!-- Dataportal -->
<add key="SystemUser" value="" />
<add key="SystemPW" value="" />
<add key="Authentication" value="CSLA" />
<add key="Location" value="Client" />
<add key="ChangeMonitorIntervalMins" value="2" />
<add key="CslaDataPortalProxy" value="Csla.DataPortalClient.GenuineChannelsProxy, Csla3" />
<add key="CslaDataPortalUrl" value="ghttp://localhost:8753/Rawr/RemotingPortal.rem" />
<add key="DataPortalServer" value="ghttp://localhost:8753/Rawr/DataPortal.rem" />

</appSettings>
```

Paulie

---

<div class="post-metadata">

**Author:** ![js2010](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@js2010](https://forums.powershell.org/u/js2010)\
**Post date:** [January 20, 2019, 9:59am UTC](https://forums.powershell.org/t/reading-xml/11931/8 "2019-01-20T09:59:31Z")

</div>

Hi, I don’t see your latest reply. Unfortunately this forum can’t handle xml. You can make a gist of the xml and link to it here. (Maybe this forum should use the technet system?) Actually select-xml has some potential. But I don’t know xpath. Xpath runs deep. Xpath filters can be used with get-winevent as well.

xpath info: [XML and XPath](https://www.w3schools.com/xml/xml_xpath.asp)

I was trying this. Both $a.node and $xml.objs are XmlElement types.

```
# Selects the first book element that is the child 
# of the bookstore element
$a = select-xml /bookstore/book[1] xpath.xml
$a
$a.node
$a.node.gettype()

# Selects all the title elements (anywhere) that have a "lang" attribute 
# with a value of "en"
(select-xml "//title[@lang='en']" xpath.xml).node

lang #text
---- -----
en Everyday Italian
en Harry Potter
en XQuery Kick Start
en Learning XML

[xml]$xml = get-content xpath.xml
$xml.gettype()
$xml.Objs
$xml.Objs.gettype()

# same thing
$xml = (select-xml / xpath.xml).node
```

---

<div class="post-metadata">

**Author:** ![turtle9270](https://avatars.discourse-cdn.com/v4/letter/t/838e76/32.png) [@turtle9270](https://forums.powershell.org/u/turtle9270)\
**Post date:** [January 20, 2019, 10:28pm UTC](https://forums.powershell.org/t/reading-xml/11931/9 "2019-01-20T22:28:24Z")

</div>

It’s a shame that I can’t see my own post to edit it ☹

> <https://gist.github.com/turtle9270/464c9687c705a0aa5cba3f2272db8638#file-gistfile1-txt>

I’ve linked the gist above.

The links posted have been great, especially the scripting wife blog. From what I can see, im at a stage where it’s put the detail into a hast table.

```
$xml.configuration.appsettings.add.value[6]
```

This line works, but I want to address it by a name not by index number, $xml.configuration.appsettings.add.value[‘DataPortalServer’]

&nbsp;

Something like that, but I can’t for the life of me get it to work.

Paulie

---

<div class="post-metadata">

**Author:** ![js2010](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@js2010](https://forums.powershell.org/u/js2010)\
**Post date:** [January 21, 2019, 12:38am UTC](https://forums.powershell.org/t/reading-xml/11931/10 "2019-01-21T00:38:00Z")

</div>

It’s not a hash table. You can do it this way:

```
$xml.configuration.appsettings.add | where key -eq DataPortalServer | 
  select -expand value 

ghttp://localhost:8753/Rawr/DataPortal.rem
```

Or using xpath, which is case sensitive. With select-xml, the node property has the resulting object.

```
(Select-Xml "/configuration/appSettings/add[@key='DataPortalServer']" example.xml).node.value  

ghttp://localhost:8753/Rawr/DataPortal.rem
```

---

<div class="post-metadata">

**Author:** ![turtle9270](https://avatars.discourse-cdn.com/v4/letter/t/838e76/32.png) [@turtle9270](https://forums.powershell.org/u/turtle9270)\
**Post date:** [January 22, 2019, 4:28pm UTC](https://forums.powershell.org/t/reading-xml/11931/11 "2019-01-22T16:28:14Z")

</div>

That’s great. I’ve almost got what I’m looking for!

```
Function QPConfigFilesxpath{
$configfiles=@( 
@{
Name='QP'
cfgpath = 'C:\inetpub\Qp\Web.Config'
param1 = 'ApiURL'
param2='ApiUrl'
},
@{
Name='IdentServer'
cfgpath ='C:\inetpub\IdentityServer\Web.Config'
param1='CslaDataPortalUrl'
param2='CslaDataPortalUrl'
param3='CslaDataPortalUrl'
}
)

for($i=0; $i -lt $configfiles.Length; $i++)
{
#$b=$file.param2
#write-output $configfiles[$i].param2
$a=$xml.selectNodes("//add[@key=`"$configfiles[$i].param2`"]")
$a.value
write-host `n
}

#$configfiles[0].cfgpath
#[xml]$xml=get-content $configfiles[0].cfgpath

#$b=$configfiles[0].param1
#Write-Output $b
#$xml.SelectNodes("//add[@key='IdentityServerURL']")
#$a=$xml.selectNodes("//add[@key='$b']")
#$a.value
}
QPConfigFilesxpath
```

This issue seems to be with [pre]$a=$xml.selectNodes(“//add[@key=`”$configfiles[$i].param2`"]")[pre]

The write-out line above it prints the right then when I uncomment it but it doesnt work on the selectnodes.

&nbsp;

Paulie

---

<div class="post-metadata">

**Author:** ![js2010](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@js2010](https://forums.powershell.org/u/js2010)\
**Post date:** [January 25, 2019, 10:20am UTC](https://forums.powershell.org/t/reading-xml/11931/12 "2019-01-25T10:20:33Z")

</div>

That’s a difficult quoting situation. How about:

```
$key = $configfiles[$i].param2
# selectnodes() takes an xpath string
# '//add' means search for an add node anywhere
$a = $xml.selectNodes("//add[@key='$key']")
```

But I don’t see an ‘ApiUrl’ key in your xml. I guess it’s in a different xml. Also the bottom closing ‘\< /configuration \>’ tag is missing in the xml.

Unless you want to use the “$( )” method, but it gets more complex and less readable. “$object[$index]” or “$object.property” doesn’t work inside a string the way you would want.

```
$a = $xml.selectNodes("//add[@key=`"$($configfiles[$i].param2)`"]")
```

---

<div class="post-metadata">

**Author:** ![dotnVo](https://avatars.discourse-cdn.com/v4/letter/d/4af34b/32.png) [@dotnVo](https://forums.powershell.org/u/dotnVo)\
**Post date:** [May 16, 2024, 8:33pm UTC](https://forums.powershell.org/t/reading-xml/11931/13 "2024-05-16T20:33:24Z")

</div>


