Solved

Powershell and XML question

Posted on 2014-01-14
2
379 Views
Last Modified: 2014-01-15
Hi - Powershell newbie. I have the following XML sample. I need to iterate through it via powershell and run some powershell code at each level. I am able to reach any one of the items but have not been successfull in looping through each one. I could use a sample of how to do this. For this example - just printing the text of each element to the console would be fine so long as I can replace that code with the actual code I need to accomplish the goal.

Here is the sample file. There are some elements that are nested as shown.

<?xml version="1.0" encoding="utf-8"?>
<Locations>
  <!-- There can be multiple locations -->
  <Location>
      <Name>Location A</Name>

	<!-- There can be multiple Drawers per location -->	  
  <Drawers>
      <Drawer>
        <Name>Drawer 1</Name>
		<!-- There can be multiple Files per Drawer -->	
        <Files>
          <File>
            <Name>File 1</Name>
			<!-- There can be multiple Custom Variables anywhere -->
			<Attributes>	
				<Attribute>ID</Attribute>
				<Attribute>User Name</Attribute>
				<Attribute>Another Variable</Attribute>
			</Attributes>	
			<!-- There can be multiple Folders per File -->
			<!-- Folders can be nested -->				
            <Folder>
              <Name>Folder 1</Name>
			  <!-- There can be multiple Custom Variables anywhere -->	
				<Attribute>ID</Attribute>
				<Attribute>User Name</Attribute>
			  <!-- There can be multiple Documents per Folder -->	
              <Document>
                <Name>Document 1</Name>
				<!-- There can be multiple Custom Variables anywhere -->	
				<Attribute>ID</Attribute>
				<Attribute>User Name</Attribute>
              </Document>
              <Document>
                <Name>Document 2</Name>
              </Document>
              <Document>
                <Name>Document 2</Name>
              </Document>
              <Folder>
                <Name>Folder 1.1</Name>
				<Repeatable>True</Repeatable>
				<Attribute>ID</Attribute>
				<Attribute>User Name</Attribute>
                <Document>
                  <Name>Document 1.1</Name>
                </Document>
                <Document>
                  <Name>Document 1.2</Name>
                </Document>
                <Document>
                  <Name>Document 1.2</Name>
                </Document>
					<Folder>
						<Name>Folder 1.1.1</Name>
						<Document>
						  <Name>Document 1.1.1</Name>
						</Document>
						<Document>
						  <Name>Document 1.1.2</Name>
						</Document>
						<Document>
						  <Name>Document 1.1.2</Name>
						</Document>
					</Folder>
				</Folder>
            </Folder>
          </File>
		  <File>
            <Name>File 2</Name>
            <Folder>
              <Name>Folder 1</Name>
              <Document>
                <Name>Document 1</Name>
              </Document>
              <Document>
                <Name>Document 2</Name>
              </Document>
              <Document>
                <Name>Document 2</Name>
              </Document>
              <Folder>
                <Name>Folder 1.1</Name>
                <Document>
                  <Name>Document 1.1</Name>
                </Document>
                <Document>
                  <Name>Document 1.2</Name>
                </Document>
                <Document>
                  <Name>Document 1.2</Name>
                </Document>
				</Folder>
            </Folder>
          </File>
        </Files>        
      </Drawer>
	  <!-- The next drawer with similar files, folders and documents as the first. -->	
      <Drawer>
      </Drawer>
    </Drawers>
  </Location>
</Locations>

Open in new window

0
Comment
Question by:ckelsoe
2 Comments
 
LVL 35

Accepted Solution

by:
Robert Schutt earned 500 total points
ID: 39782369
Hi, have a look at this. I've put comments in to make clear where to add/change code, maybe overkill but anyway...

Let me know if you have any questions.
# settings

$xmlFile = ’sample.xml’

# functions

Function ProcessXmlDoc
{
Param ([xml] $xmlDoc)

    foreach ($locationNode in $xmlDoc.Locations.Location) {
        # put code that needs to be performed for every <Location> node here.
        Write-Host (“* Location Name={0}” -f $locationNode.Name)
        foreach ($drawerNode in $locationNode.Drawers.Drawer) {
            # additional code for <Drawer> nodes here
            Write-Host (“** Location Name={0}, Drawer Name={1}” -f $locationNode.Name,$drawerNode.Name)
            foreach ($fileNode in $drawerNode.Files.File) {
                # additional code for <File> nodes here
                Write-Host (“*** Location Name={0}, Drawer Name={1}, File Name={2}” -f $locationNode.Name,$drawerNode.Name,$fileNode.Name)
                RecurseFolders $fileNode
            }
        }
    }
}

Function RecurseFolders
{
Param ([system.xml.xmlelement] $folderNodeParam,[string] $FolderPath = "") # <File> node or <Folder> node, both can contain <Folder> nodes

    # construct "path" to current file/folder tree in the xml document
    if ($FolderPath -ne "") {
        $FolderPath = $FolderPath + "/" + $folderNodeParam.Name
    } else {
        $FolderPath = $folderNodeParam.Name
    }

    # additional code for <Folder> nodes here

    if ($folderNodeParam.Document) {
        # additional code for <Folder> nodes which contain <Document> nodes here
        foreach ($documentNode in $folderNodeParam.Document) {
            # additional code for <Document> nodes here
            Write-Host (“**** Document Name={0}, Folder Path={1}” -f $documentNode.Name,$FolderPath) # $folderNodeParam.Name
        }
    }
    if ($folderNodeParam.Folder) {
        # additional code for <Folder> nodes which contain <Folder> nodes here
        foreach ($folderNode in $folderNodeParam.Folder) {
            RecurseFolders $folderNode $FolderPath
        }
    }
}

#main code

ProcessXmlDoc (Get-Content -Path $xmlFile)

Open in new window

PS: I'm not overly experienced in PowerShell myself but thought it would be a nice experience to try solving it, got this far, saw no reply yet and decided to post as this should get you started at least.
0
 

Author Comment

by:ckelsoe
ID: 39783548
Hi Robert,

I am impressed! Thank you for the excellent example.

I have more to figure out but this code example is a great start. Thanks.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Set OWA language and time zone in Exchange for individuals, all users or per database.
This article explains how to prepare an HTML email signature template file containing dynamic placeholders for users' Azure AD data. Furthermore, it explains how to use this file to remotely set up a department-wide email signature policy in Office …
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question