Parsing XML and filtering/sorting problem

by ledetekst at 2012-11-25 13:17:13

Hi.

My case is this. I have an XML-file that I am trying to parse output from and sort.
The XML is a file containing metadata of ESXi patches from VMware, downloaded using VMware Update Manager Download Service (UMDS) command line. It contains full KB-info of all patches released for the given ESXi version, also files not downloaded.

The logging that UMDS it self provides, lacks direct good and informative info of what is actually downloaded, other than the actual filename. But the metadata xml, that is later on imported to vCenter a long with the repository of files has this. This is done at a later step and location.

Here is the code so far:



[xml]$VmwXml = Get-Content .\vmware.xml

$VmwPatch = $VmwXml.metadataResponse

# Getting each object from the XML. The last part replaces the relative path from the URL, and changes it to local path. And also breaks, as some ID’s has multiple patches.

$VmwPatch.bulletin | ForEach {"Id : $($.Id)","Vendor : $($.vendor)","Summary : $($.summary)","Category : $($.category)","Urgency : $($.urgency)","ReleaseType : $($.releaseType)","Description : $($.description)","kbUrl : $($.kbUrl)","ReleaseDate : $($.releaseDate)","RebootRequired : $($.viblist.vib.postInstall.rebootRequired)","HostdRestart : $($.viblist.vib.postInstall.hostdRestart)","Path : $($.viblist.vib.vibfile.relativePath)"; $(Get-ChildItem ("D:\vmw-ESXi-4.1.0-metadata$($.viblist.vib.vibfile.relativePath -replace "/","&quot;)".Replace(" ","nD&#58;\vmw-ESXi-4&#46;1&#46;0-metadata\&quot;)) -ErrorAction SilentlyContinue | Select -ExpandProperty FullName);&quot;&quot;,&quot;&quot;,&quot;################&quot;&quot;&quot;}<br><br></code><br><br>What I would like is to extract a readable selected output of the KB info in the XML, after the download has finished. (That will be given to the proper people.) Have broken it down a bit, and the output so far using the above code, is like this:<br><br>####### CUT ########<br><br><code><br>Id &#58; ESXi410-201101224-UG<br>Vendor &#58; Neterion<br>Summary &#58; vxge&#58; net driver for VMware ESXi<br>Category &#58; general<br>Urgency &#58;<br>ReleaseType &#58; extension<br>Description &#58; Driver for X3100 10 GbE PCIe I/O Virtualized Server Adapter<br>kbUrl &#58; http&#58;//trac&#46;neterion&#46;com/cgi-bin/trac&#46;cgi/wiki/X3100VMware<br>ReleaseDate &#58; 2011-02-10T00&#58;00&#58;00-08&#58;00<br>RebootRequired &#58; true<br>HostdRestart &#58; false<br>Path &#58; embeddedEsx/4&#46;1&#46;0/ESXi-4&#46;1&#46;0-update01/cross_oem-vmware-esx-drivers-net-vxge_400&#46;2&#46;0&#46;28&#46;21239-1OEM&#46;vib<br>D&#58;\vmw-ESXi-4&#46;1&#46;0-metadata\embeddedEsx\4&#46;1&#46;0\ESXi-4&#46;1&#46;0-update01\cross_oem-vmware-esx-drivers-net-vxge_400&#46;2&#46;0&#46;28&#46;21239-1OEM&#46;vib<br><br><br>################&quot;<br>Id &#58; ESXi410-201110201-SG<br>Vendor &#58; VMware, Inc&#46;<br>Summary &#58; Updates ESXi 4&#46;1 Firmware<br>Category &#58; security<br>Urgency &#58; critical<br>ReleaseType &#58; update<br>Description &#58; For more information, see http&#58;//kb&#46;vmware&#46;com/kb/2002339&#46;<br>kbUrl &#58; http&#58;//kb&#46;vmware&#46;com/kb/2002339<br>ReleaseDate &#58; 2011-10-27T00&#58;00&#58;00-08&#58;00<br>RebootRequired &#58; true<br>HostdRestart &#58; false<br>Path &#58; embeddedEsx/4&#46;1&#46;0/ESXi-4&#46;1&#46;0-update02/vmware-esx-firmware-4&#46;1&#46;0-2&#46;11&#46;502767&#46;i386&#46;vib<br>D&#58;\vmw-ESXi-4&#46;1&#46;0-metadata\embeddedEsx\4&#46;1&#46;0\ESXi-4&#46;1&#46;0-update02\vmware-esx-firmware-4&#46;1&#46;0-2&#46;11&#46;502767&#46;i386&#46;vib<br><br><br>################&quot;<br>Id &#58; ESXi410-201101223-UG<br>Vendor &#58; AMCC<br>Summary &#58; 3w-9xxx&#58; scsi driver for VMware ESXi<br>Category &#58; general<br>Urgency &#58;<br>ReleaseType &#58; extension<br>Description &#58; 3ware SCSI driver for ESXi 4&#46;1<br>kbUrl &#58; http&#58;//www&#46;amcc&#46;com<br>ReleaseDate &#58; 2011-02-10T00&#58;00&#58;00-08&#58;00<br>RebootRequired &#58; true<br>HostdRestart &#58; false<br>Path &#58; embeddedEsx/4&#46;1&#46;0/ESXi-4&#46;1&#46;0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400&#46;2&#46;26&#46;08&#46;036vm40-1OEM&#46;vib<br>D&#58;\vmw-ESXi-4&#46;1&#46;0-metadata\embeddedEsx\4&#46;1&#46;0\ESXi-4&#46;1&#46;0-update01\cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400&#46;2&#46;26&#46;08&#46;036vm40-1OEM&#46;vib<br><br><br>################&quot;<br>Id &#58; ESXi410-201104402-BG<br>Vendor &#58; VMware, Inc&#46;<br>Summary &#58; Updates VMware Tools<br>Category &#58; bugfix<br>Urgency &#58; important<br>ReleaseType &#58; patch<br>Description &#58; For more information, see http&#58;//kb&#46;vmware&#46;com/kb/1035109&#46;<br>kbUrl &#58; http&#58;//kb&#46;vmware&#46;com/kb/1035109<br>ReleaseDate &#58; 2011-04-28T00&#58;00&#58;00-08&#58;00<br>RebootRequired &#58; false<br>HostdRestart &#58; false<br>Path &#58; embeddedEsx/4&#46;1&#46;0/ESXi-4&#46;1&#46;0-patch02/vmware-esx-tools-light-4&#46;1&#46;0-1&#46;6&#46;381591&#46;i386&#46;vib<br><br><br>################&quot;<br>Id &#58; ESXi410-201208202-UG<br>Vendor &#58; VMware, Inc&#46;<br>Summary &#58; Updates the ESXi 4&#46;1 Tools<br>Category &#58; bugfix<br>Urgency &#58; important<br>ReleaseType &#58; update<br>Description &#58; For more information, see http&#58;//kb&#46;vmware&#46;com/kb/2020375&#46;<br>kbUrl &#58; http&#58;//kb&#46;vmware&#46;com/kb/2020375<br>ReleaseDate &#58; 2012-08-30T00&#58;00&#58;00-08&#58;00<br>RebootRequired &#58; false<br>HostdRestart &#58; false<br>Path &#58; embeddedEsx/4&#46;1&#46;0/ESXi-4&#46;1&#46;0-update03/vmware-esx-tools-light-4&#46;1&#46;0-3&#46;26&#46;800380&#46;i386&#46;vib<br></code><br><br>####### SNIP ########<br><br>I wish to sort by the &quot;Local path&quot;, so that the files in &quot;vmware.xml&quot; that are actually downloaded come first. (The other objects are sortable..)<br>Do I need to create a new object, to be able to sort it? Any good pointers<br><br>Using VMware vSphere CLI is unfortunately not an option<br><br>Also provided the vmware.xml from VMware.com.</blockquote>by DonJ at 2012-11-26 09:19:31<blockquote>So, you've gotten a great start, but you're a bit down a bad path. I hope you don't mind me offering some advice, because it'll ultimately make everything easier.<br><br>Your ForEach is the problem. What you're outputting is raw text, and PowerShell sucks with raw text. It can't sort it or do anything else... and so, yes, you do need to create a new object. That's awfully simple, though.<br><br><code><br>$VmwPatch&#46;bulletin | ForEach {<br> $props = @{'ID'=$_&#46;id;'Vendor'=$_&#46;Vendor;'Summary'=$_&#46;Summary}<br> New-Object -Type PSObject -Prop $props<br>} | Sort -Property ID<br></code><br><br>I've only included three of your fields in that example, but you can obviously add them all. You'll see how easily that can then be sorted, piped to Format-List, and so forth. <br><br>Long-term, I'd probably build that logic into a function, so that you could just run something like...<br><br><code><br>Get-Content file&#46;xml | ConvertTo-VMWarePatchObject | Sort -Property Path | Format-List -Prop *<br></code><br><br>The &quot;ConvertTo-VMWarePatchObject&quot; being the custom function you set up to convert the XML into objects. Kinda encapsulates that particular task very nicely.</blockquote>by ledetekst at 2012-11-26 14:33:54<blockquote>Brilliant - thanks! That did the trick. Learning something new every day!<br>Tweaked it a bit, to only include where LocalPath exists.<br><br><code><br><br> $VmwPatch&#46;bulletin | ForEach {<br> $props = @{'IDs'=$_&#46;id;'Vendor'=$_&#46;Vendor;'Summary'=$_&#46;Summary;'Severity'=$_&#46;severity;'Category'=$_&#46;category;'Urgency'=$_&#46;urgency;'ReleaseType'=$_&#46;releaseType;'Description'=$_&#46;description;'kbUrl'=$_&#46;kbUrl;'ReleaseDate'=$_&#46;releaseDate;'RebootRequired'=$_&#46;viblist&#46;vib&#46;postInstall&#46;rebootRequired;'HostdRestart'=$_&#46;viblist&#46;vib&#46;postinstall&#46;hostdRestart;'Path'=$_&#46;viblist&#46;vib&#46;vibfile&#46;relativePath;'LocalPath'=$(Get-ChildItem (&quot;D&#58;\vmw-ESXi-4&#46;1&#46;0-metadata\$($_&#46;viblist&#46;vib&#46;vibfile&#46;relativePath -replace &quot;/&quot;,&quot;\&quot;)&quot;&#46;Replace(&quot; &quot;,&quot;nD:\vmw-ESXi-4.1.0-metadata&quot;)) -ErrorAction SilentlyContinue | Select -ExpandProperty FullName)}
New-Object -Type PSObject -Prop $props
} | Sort-Object -Property LocalPath | Where {$
.LocalPath -match ""} | Select IDs,Vendor,Summary,Severity,Category,Urgency,ReleaseType,Description,kbUrl,ReleaseDate,RebootRequired,hostdRestart,Path,LocalPath | Format-List


Toying with the function now, and working further on with the script.

:slight_smile:
by ledetekst at 2012-11-27 08:06:47
Hi again. Not sure if I should ask again here, since the topic is marked as "solved", but i stumbled upon a challenge in the XML again.

Some of the values in the XML, have multiple equally named subvalues (multiple "vib" under the "vibList"), and therefore will not be listed with the above command…


<bulletin>
<id>ESXi410-Update01</id>
<vendor>VMware, Inc.</vendor>
<summary>VMware ESXi 4.1 Complete Update 1</summary>
<severity>general</severity>
<category>general</category>
<urgency/>
<vendorProduct/>
<releaseType>update</releaseType>
<description>This bulletin includes all software updates required to install VMware ESXi 4.1 Update 1 on a host. A host will not be considered running Update 1 until it is compliant with this bulletin.</description>
<kbUrl>http://kb.vmware.com/kb/1029354</kbUrl>
<contact>http://www.vmware.com/support/contacts/</contact>
<releaseDate>2011-02-10T00:00:00-08:00</releaseDate>
<platforms>
<softwarePlatform locale="" version="4.1.0" productLineID="embeddedEsx"/>
</platforms>
<vibList>
<vib>
<vibVersion>1.4.5</vibVersion>
<vibID>deb_vmware-esx-tools-light_4.1.0-1.4.348481</vibID>
<name>vmware-esx-tools-light</name>
<vendor/>
<version>4.1.0-1.4.348481</version>
<buildDate>2011-01-13T01:47:55</buildDate>
<vibType>deb</vibType>
<systemReqs>
<swPlatform locale="" version="4.1.0" productLineID="embeddedEsx"/>
<swPlatform locale="" version="4.0.0" productLineID="embeddedEsx"/>
<maintenanceMode>false</maintenanceMode>
</systemReqs>
<postInstall>
<rebootRequired>false</rebootRequired>
<hostdRestart>false</hostdRestart>
</postInstall>
<visorDestination>locker</visorDestination>
<vibFile>
<sourceUrl/>
<relativePath>embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-tools-light-4.1.0-1.4.348481.i386.vib</relativePath>
<packedSize>124804976</packedSize>
<checksum>
<checksumType>sha-1</checksumType>
<checksum>055916d9381cbd6e22d3541e2167240b17767138</checksum>
</checksum>
</vibFile>
</vib>
<vib>
<vibVersion>1.4.5</vibVersion>
<vibID>cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM</vibID>
<name>oem-vmware-esx-drivers-scsi-3w-9xxx</name>
<vendor/>
<version>400.2.26.08.036vm40-1OEM</version>
<buildDate>2010-08-20T05:42:32</buildDate>
<vibType>cross</vibType>
<systemReqs>
<swPlatform locale="" version="4." productLineID="esx"/>
<swPlatform locale="" version="4.
" productLineID="embeddedEsx"/>
<maintenanceMode>true</maintenanceMode>
</systemReqs>
<postInstall>
<rebootRequired>true</rebootRequired>
<hostdRestart>false</hostdRestart>
</postInstall>
<visorDestination>oem</visorDestination>
<pkgfile>oem-vmware-esx-drivers-scsi-3w-9xxx-400.2.26.08.036vm40-1OEM.x86_64.rpm</pkgfile>
<softwareTags>
<tag>driver</tag>
<tag>module</tag>
</softwareTags>
<vibFile>
<sourceUrl/>
<relativePath>embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib</relativePath>
<packedSize>32318</packedSize>
<checksum>
<checksumType>sha-1</checksumType>
<checksum>abc0bd76404dca5aac607a9284f7370f5695c750</checksum>
</checksum>
</vibFile>
</vib>
<vib>
<vibVersion>1.4.5</vibVersion>
<vibID>deb_vmware-esx-firmware_4.1.0-1.4.348481</vibID>
<name>vmware-esx-firmware</name>
<vendor/>
<version>4.1.0-1.4.348481</version>
<buildDate>2011-01-13T01:47:44</buildDate>
<vibType>deb</vibType>
<systemReqs>
<swPlatform locale="" version="4.1.0" productLineID="embeddedEsx"/>
<swPlatform locale="" version="4.0.0" productLineID="embeddedEsx"/>
<maintenanceMode>true</maintenanceMode>
</systemReqs>
<postInstall>
<rebootRequired>true</rebootRequired>
<hostdRestart>false</hostdRestart>
</postInstall>
<visorDestination>stage</visorDestination>
<vibFile>
<sourceUrl/>
<relativePath>embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-firmware-4.1.0-1.4.348481.i386.vib</relativePath>
<packedSize>90059938</packedSize>
<checksum>
<checksumType>sha-1</checksumType>
<checksum>a147bc00556a04bc4d3c8216893f5d0d2a08263e</checksum>
</checksum>
</vibFile>
</vib>
<vib>
<vibVersion>1.4.5</vibVersion>
<vibID>cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM</vibID>
<name>oem-vmware-esx-drivers-net-vxge</name>
<vendor/>
<version>400.2.0.28.21239-1OEM</version>
<buildDate>2010-08-27T19:46:27</buildDate>
<vibType>cross</vibType>
<systemReqs>
<swPlatform locale="" version="4." productLineID="esx"/>
<swPlatform locale="" version="4.
" productLineID="embeddedEsx"/>
<maintenanceMode>true</maintenanceMode>
</systemReqs>
<postInstall>
<rebootRequired>true</rebootRequired>
<hostdRestart>false</hostdRestart>
</postInstall>
<visorDestination>oem</visorDestination>
<pkgfile>oem-vmware-esx-drivers-net-vxge-400.2.0.28.21239-1OEM.x86_64.rpm</pkgfile>
<softwareTags>
<tag>driver</tag>
<tag>module</tag>
</softwareTags>
<vibFile>
<sourceUrl/>
<relativePath>embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib</relativePath>
<packedSize>937268</packedSize>
<checksum>
<checksumType>sha-1</checksumType>
<checksum>87e7c20e6cafb49d579e88dc9a1132c85de6485a</checksum>
</checksum>
</vibFile>
</vib>
</vibList>
</bulletin>


And are instead listed like this, with no values in Path or LocalPath.


ID : ESXi410-Update02
Vendor : VMware, Inc.
Summary : VMware ESXi 4.1 Complete Update 2
Severity : general
Category : misc
Urgency : important
ReleaseType : rollup
Description : For more information, see http://kb.vmware.com/kb/2002338.
kbUrl : http://kb.vmware.com/kb/2002338
ReleaseDate : 2011-10-27T00:00:00-08:00
RebootRequired :
HostdRestart :
Path :
LocalPath : {D:\vmw-ESXi-4.1.0-metadata\embeddedESX, D:\vmw-ESXi-4.1.0-metadata\vmw-ESXi-4.0.0-metadata.zip, D:\vmw-ESXi-4.1.0-metadata\vmw-ESXi-4.1.0-metadata.zip, D:\vmw-ESXi-4.1.0-metadata_hostupdate20-consolidated-metadata-index_.xml}


Not sure have to solve this in the hash-table. Is another "ForEach" required?
by DonJ at 2012-11-27 08:31:50
Yup. That’s how PowerShell shows a collection or an array. And yes, if you wanted to enumerate them, you’d need another ForEach. How you do this depends a bit on what you want the final output to look like, but you’d need to enumerate each of those child objects in a nested loop.
by ledetekst at 2012-11-27 08:54:08
Ideally I’d like each separate child object (file), to have it’s own output. To keep it clean and tidy, but also because each separate file has different "rebootRequired" and "hostdRestart" values.

Like this:


ID : ESXi410-Update02
Vendor : VMware, Inc.
Summary : VMware ESXi 4.1 Complete Update 2
Severity : general
Category : misc
Urgency : important
ReleaseType : rollup
Description : For more information, see http://kb.vmware.com/kb/2002338.
kbUrl : http://kb.vmware.com/kb/2002338
ReleaseDate : 2011-10-27T00:00:00-08:00
RebootRequired : true
HostdRestart : true
Path : /path/to/folder1/file1
LocalPath : D:\path\to\folder1\file1

ID : ESXi410-Update02
Vendor : VMware, Inc.
Summary : VMware ESXi 4.1 Complete Update 2
Severity : general
Category : misc
Urgency : important
ReleaseType : rollup
Description : For more information, see http://kb.vmware.com/kb/2002338.
kbUrl : http://kb.vmware.com/kb/2002338
ReleaseDate : 2011-10-27T00:00:00-08:00
RebootRequired : false
HostdRestart : true
Path : /path/to/folder1/file2
LocalPath : D:\path\to\folder1\file2


A bit new to arrays and multiple loops, and fumbling around here. Any pointers?
by DonJ at 2012-11-27 09:10:56
Yeah, this can be a bit tricky. So, kinda pseudo-code:

In your main, outer ForEach, go ahead and create a complete custom object, but don’t output it. Make sure it has properties for localpath and whatnot - but don’t necessarily populate those.

Then create another inner ForEach loop to go through all the children. In there, you’re not actually going to create a new object, you’re just going to set the properties that were already created. Set the properties, output the object - do that for each child you’ve got. That way, you get a complete object for each of those children.

Another approach: At the parent-level, in your main ForEach loop, don’t create an object. Grab whatever common properties you need into variables, so you’ve got the information saved and accessible. Then, run an inner nested ForEach loop for each child element. Inside that, you’ll create a complete custom object. Much of the data will come from those variables, since it’s "shared" information, but some of the properties will be unique per child element.
by ledetekst at 2012-11-27 16:05:57
Guess I need a hint 2 , or most likely some working code, as I can’t seem to find out how to do this… :confused:
by DonJ at 2012-11-27 16:15:56
Well, show me what you’ve got, and a snippet of the relevant XML. Happy to give it a shot.
by ledetekst at 2012-11-28 03:20:40
Have also tried:

$VmwPatch | ForEach ($) {$.bulletin} | ForEach {$.vibList} | select vib | ForEach {$.vib} | Select vibFile | ForEach {$.vibFile} | Select relativePath | Sort relativePath


This outputs


embeddedEsx/4.1.0/ESXi-4.1.0-ep21/vmware-esx-firmware-4.1.0-2.22.702113.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-express-patch01/vmware-esx-firmware-4.1.0-0.2.320137.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-express-patch03/vmware-esx-firmware-4.1.0-2.23.721871.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch01/vmware-esx-firmware-4.1.0-0.1.320092.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch01/vmware-esx-tools-light-4.1.0-0.1.320092.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch02/vmware-esx-firmware-4.1.0-1.6.381591.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch02/vmware-esx-tools-light-4.1.0-1.6.381591.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch03/vmware-esx-firmware-4.1.0-1.8.433742.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch03/vmware-esx-tools-light-4.1.0-1.8.433742.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch04/vmware-esx-firmware-4.1.0-2.18.582267.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch04/vmware-esx-tools-light-4.1.0-2.18.582267.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch05/vmware-esx-firmware-4.1.0-2.21.659051.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-patch05/vmware-esx-tools-light-4.1.0-2.21.659051.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-firmware-4.1.0-1.4.348481.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-firmware-4.1.0-1.4.348481.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-tools-light-4.1.0-1.4.348481.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-tools-light-4.1.0-1.4.348481.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update02/vmware-esx-firmware-4.1.0-2.11.502767.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update02/vmware-esx-firmware-4.1.0-2.11.502767.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update02/vmware-esx-tools-light-4.1.0-2.11.502767.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update02/vmware-esx-tools-light-4.1.0-2.11.502767.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-firmware-4.1.0-2.25.811144.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-firmware-4.1.0-3.26.800380.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-firmware-4.1.0-3.26.800380.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-tools-light-4.1.0-2.25.811144.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-tools-light-4.1.0-3.26.800380.i386.vib
embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-tools-light-4.1.0-3.26.800380.i386.vib


What then, how to reuse that, to get to an upper level?

The complete XML file used, is the one in the first post.
http://powershell.org/discuss/download/file.php?id=16

The ID’s ESXi410-Update01, ESXi410-Update02, ESXi410-Update03, have multiple <vib> under <viblist> (at the same level as <id>) under it’s own <bulletin>.


<id>ESXi410-Update01</id>
<id>ESXi410-Update02</id>
<id>ESXi410-Update03</id>
by DonJ at 2012-11-28 07:30:13
Ok. Not sure I’m going to be able to sort all this today - got a full schedule - but will dig into this when I can.
by ledetekst at 2012-11-28 07:51:18
That’s quite ok, and thanks so much for helping out! Really appreciated.

The script will run against multiple VMware metadata .XML-files for 4.0.0, 5.0.0 and 5.1.0 versions also (built the same way).
And later on other software repositories, that lack good logging.
by DonJ at 2012-11-28 08:23:27
So, cramming this into a one-liner is part of the problem you’re having. It’s a lot trickier.


[xml]$vmXML = Get-Content c:\vmware.xml

ForEach ($bulletin in $vmXML.metadataResponse.bulletin) {
$props = @{‘IDs’=$bulletin.id;
‘Vendor’=$bulletin.vendor;
‘Summary’=$bulletin.summary;
‘Severity’=$bulletin.severity;
‘Category’=$bulletin.category;
‘Urgency’=$bulletin.urgency;
‘ReleaseType’=$bulletin.releaseType;
‘ReleaseDate’=$bulletin.releaseDate;
‘Description’=$bulletin.description;
‘kbUrl’=$bulletin.kbUrl}
ForEach ($vib in $bulletin.vibList.vib) {
$propcopy = $props
$propcopy += @{‘RebootRequired’=$vib.postInstall.rebootRequired;
‘HostdRestart’=$vib.postInstall.hostdRestart;
‘Path’=$vib.relativePath;
‘LocalPath’=$vib.vibFile.relativePath}
New-Object -TypeName PSObject -Property $propcopy
}
}


That seems to be working for me from the XML file you attached originally. You’re doing some manipulation with LocalPath that I can’t do, because I don’t have all the metadata files, but hopefully you can see where it would go. I’m not sure I’m doing Path correctly, but again - hopefully this will show you the logic, and you can fix up the individual details. I marked this as un-solved, so if this is fixing it for you, re-solve it ;).

I would probably wrap this in a function:


[xml]$vmXML = Get-Content c:\vmware.xml


function ConvertTo-VMObjects {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True)]
[xml]$inputXML
)
ForEach ($bulletin in $inputXML.metadataResponse.bulletin) {
$props = @{‘IDs’=$bulletin.id;
‘Vendor’=$bulletin.vendor;
‘Summary’=$bulletin.summary;
‘Severity’=$bulletin.severity;
‘Category’=$bulletin.category;
‘Urgency’=$bulletin.urgency;
‘ReleaseType’=$bulletin.releaseType;
‘ReleaseDate’=$bulletin.releaseDate;
‘Description’=$bulletin.description;
‘kbUrl’=$bulletin.kbUrl}
ForEach ($vib in $bulletin.vibList.vib) {
$propcopy = $props
$propcopy += @{‘RebootRequired’=$vib.postInstall.rebootRequired;
‘HostdRestart’=$vib.postInstall.hostdRestart;
‘Path’=$vib.relativePath;
‘LocalPath’=$vib.vibFile.relativePath}
New-Object -TypeName PSObject -Property $propcopy
}
}
}

$vmXML | ConvertTo-VMObjects | Sort Vendor


That kinda wraps the convert-from-XML-into-objects into a function, and you can pipe its output to sort, select, or whatever. Bit more modular that way. But this is how you do a nested ForEach when you’ve got multiple child objects to enumerate.
by ledetekst at 2012-11-30 06:41:56
Again brilliant! Code seems to be working nicely.
Will get back to you next week, when it has been adjusted with LocalPath and so on, and post full script.
by ledetekst at 2012-12-14 01:43:07
Everything ok here! Here’s (almost) the rest of the script
:slight_smile:


# Disk space check
Write-Host "# Checks E:\ disk space before download" -ForegroundColor YELLOW
$DiskCheck = Get-WmiObject Win32_LogicalDisk | Where {$
.DeviceID -eq "E:"} | Select -ExpandProperty FreeSpace
IF ($DiskCheck -lt "30000000000")
{Write-Host "Minimum 30GB on E:&quot; -ForeGroundColor RED ; EXIT}
ELSE {Write-Host "OK"}

# Script timer
$StopWatch = [System.Diagnostics.StopWatch]::StartNew()

# Adjust console
$pshost = Get-Host
$pswindow = $pshost.ui.rawui
$newsize = $pswindow.buffersize
$newsize.height = 5000
$newsize.width = 500
$pswindow.buffersize = $newsize
$newsize = $pswindow.windowsize
$newsize.height = 70
$newsize.width = 160
$pswindow.windowsize = $newsize

# Variables
$ProxyIP = "1.1.1.1:8888"
$VMwareUmdsProgram = "${env:ProgramFiles(x86)}\VMware\Infrastructure\Update Manager\vmware-umds.exe"
$ExportVMwareLogFile = ""
$Export = "E:\Export&quot;
$ExportVMware = "E:\Export\VMware&quot;
$ExportVMwareLog = "E:\Export\VMware\Log&quot;
$ExportVMwareLogFile = $ExportVMwareLog + "VMwarePatch.log"
$ExportVMwareLogFileSum = $ExportVMwareLog + "VMwarePatchSummary.log"
$ExportVMwarePatch = "E:\Export\VMware\Patch&quot;
$ExportVMwarePatchVersion = "E:\Export\VMware\Patch\version.txt"
$ExportVMwarePatchVersion1 = "E:\Export\VMware\Patch\version1.txt"
$ExportVMwarePatchVersionV4info = "Created with VMware Update Manager Download Service 4.1.0 Update 3"
$ExportVMwarePatchVersion1V4info1 = "Min=40"
$ExportVMwarePatchVersion1V4info2 = "Current=45"
$ExportVMwarePatchVersionV5info = "Created with VMware Update Manager Download Service 5.1.0"
$ExportVMwarePatchVersion1V5info1 = "Min=50"
$ExportVMwarePatchVersion1V5info2 = "Current=51"
$ExportTemp = "E:\ExportTemp&quot;
$ExportTempVMware = "E:\ExportTemp\VMware&quot;
$ExportTempVMwareESXiCsco400 = "E:\ExportTemp\VMware\csco-VEM-4.0.0-metadata&quot;
$ExportTempVMwareESXiCsco410 = "E:\ExportTemp\VMware\csco-VEM-4.1.0-metadata&quot;
$ExportTempVMwareESXiVmw400 = "E:\ExportTemp\VMware\vmw-ESXi-4.0.0-metadata&quot;
$ExportTempVMwareESXiVmw410 = "E:\ExportTemp\VMware\vmw-ESXi-4.1.0-metadata&quot;
$ExportDate = Get-Date -Format yyyy.MM.dd-HH.mm.ss
$ExportArchiveVMware = "E:\ExportArchive\VMware&quot;
$ExportArchiveVMwareLog = "E:\ExportArchive\VMware\Log&quot;
$ExportArchiveVMwareLogFile = $ExportArchiveVMwareLog + "VMwarePatch_" + $ExportDate + ".log"
$ExportArchiveVMwareLogFileSum = $ExportArchiveVMwareLog + "VMwarePatchSum_" + $ExportDate + ".log"
$ExportArchiveVMwareLogFileDown = "$env:appdata\VMware\VMware Update Manager Download Service\Logs\vmware-downloadService-log4cpp.log"
$ExportArchiveVMwareLogFileDownCopy = $ExportArchiveVMwareLog + "vmware-downloadService-log4cpp" + "" + $ExportDate + ".log"
$VMwareVmw = "E:\VMwareUpdateManager\Data\hostupdate\vmw&quot;
$VMwareCsco = "E:\VMwareUpdateManager\Data\hostupdate\csco&quot;
$VMwareESXiCsco400Metadata = "E:\VMwareUpdateManager\Data\hostupdate\csco\csco-VEM-4.0.0-metadata.zip"
$VMwareESXiCsco410Metadata = "E:\VMwareUpdateManager\Data\hostupdate\csco\csco-VEM-4.1.0-metadata.zip"
$VMwareESXiVmw400Metadata = "E:\VMwareUpdateManager\Data\hostupdate\vmw\vmw-ESXi-4.0.0-metadata.zip"
$VMwareESXiVmw410Metadata = "E:\VMwareUpdateManager\Data\hostupdate\vmw\vmw-ESXi-4.1.0-metadata.zip"


# Remove old VMware UMDS log.
Remove-Item -Path $ExportArchiveVMwareLogFileDown -Force -ErrorAction SilentlyContinue
Write-Host "# Set VMware UMDS config" -ForeGroundColor YELLOW
& $VMwareUmdsProgram -S --disable-host | Out-Null
& $VMwareUmdsProgram -S -e embeddedEsx-4.0.0 embeddedEsx-4.1.0 embeddedEsx-5.0.0 embeddedEsx-5.1.0| Out-Null
& $VMwareUmdsProgram -S --disable-va | Out-Null
& $VMwareUmdsProgram -S --proxy $ProxyIP | Out-Null
Write-Host "OK"

# Download patches
Write-Host "# Download patches froma VMware" -ForeGroundColor YELLOW
& $VMwareUmdsProgram --download
Write-Host "OK"

# Disk space check
Write-Host "# Checks E:\ disk space before export" -ForegroundColor YELLOW
$DiskCheck = Get-WmiObject Win32_LogicalDisk | Where {$
.DeviceID -eq "E:"} | Select -ExpandProperty FreeSpace
IF ($DiskCheck -lt "15000000000")
{Write-Host "Minimum 15GB on E:&quot; -ForeGroundColor RED ; EXIT}
ELSE {Write-Host "OK"}

# Create export folders.
IF ( -Not (Test-Path $ExportVMwarePatch))
{ New-Item -Path $ExportVMwarePatch -ItemType Directory | Out-Null }
IF ( -Not (Test-Path $ExportVMwareLog))
{ New-Item -Path $ExportVMwareLog -ItemType Directory | Out-Null }

# Create export archive folders.
IF ( -Not (Test-Path $ExportArchiveVMwareLog))
{ New-Item -Path $ExportArchiveVMwareLog -ItemType Directory | Out-Null }

# Remove old temp
Remove-Item $ExportTempVMware -Recurse -Force -ErrorAction SilentlyContinue

Write-Host "# Create log from XML-metadata" -ForegroundColor YELLOW


# Create temp folders
IF ( -Not (Test-Path $ExportTempVMwareESXiVmw400))
{ New-Item -Path $ExportTempVMwareESXiVmw400 -ItemType Directory | Out-Null}
IF ( -Not (Test-Path $ExportTempVMwareESXiVmw410))
{ New-Item -Path $ExportTempVMwareESXiVmw410 -ItemType Directory | Out-Null }
IF ( -Not (Test-Path $ExportTempVMwareESXiCsco400))
{ New-Item -Path $ExportTempVMwareESXiCsco400 -ItemType Directory | Out-Null }
IF ( -Not (Test-Path $ExportTempVMwareESXiCsco410))
{ New-Item -Path $ExportTempVMwareESXiCsco410 -ItemType Directory | Out-Null }

# Function to unzip using builtin Windows ZIP
Function Extract-Zip
{
param([string]$zipfilename, [string] $destination)

if(test-path($zipfilename))
{
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipfilename)
$destinationFolder = $shellApplication.NameSpace($destination)
$destinationFolder.CopyHere($zipPackage.Items())
}
}

# Unzip VMware metadata .ZIP-files
Extract-Zip -zipfilename $VMwareESXiCsco400Metadata -destination $ExportTempVMwareESXiCsco400
Extract-Zip -zipfilename $VMwareESXiCsco410Metadata -destination $ExportTempVMwareESXiCsco410
Extract-Zip -zipfilename $VMwareESXiVmw400Metadata -destination $ExportTempVMwareESXiVmw400
Extract-Zip -zipfilename $VMwareESXiVmw410Metadata -destination $ExportTempVMwareESXiVmw410

##############
# Function to VMware XML to objects
function ConvertTo-VMObjects {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True)]
[xml]$inputXML
)
ForEach ($bulletin in $inputXML.metadataResponse.bulletin) {
$props = @{‘ID’=$bulletin.id;
‘Vendor’=$bulletin.vendor;
‘Summary’=$bulletin.summary;
‘Severity’=$bulletin.severity;
‘Category’=$bulletin.category;
‘Urgency’=$bulletin.urgency;
‘ReleaseType’=$bulletin.releaseType;
‘ReleaseDate’=$bulletin.releaseDate;
‘Description’=$bulletin.description;
‘kbUrl’=$bulletin.kbUrl}
ForEach ($vib in $bulletin.vibList.vib) {
$propcopy = $props
$propcopy += @{‘RebootRequired’=$vib.postInstall.rebootRequired;
‘HostdRestart’=$vib.postInstall.hostdRestart;
‘Path’=$vib.vibfile.relativePath;
‘LocalPath’ = $(Get-ChildItem $VMwareVmw$($vib.vibfile.relativePath -replace "/","&quot;) -ErrorAction SilentlyContinue)
}
New-Object -TypeName PSObject -Property $propcopy
}
}
}

function ConvertTo-CscoObjects {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True)]
[xml]$inputXML
)
ForEach ($bulletin in $inputXML.metadataResponse.bulletin) {
$props = @{‘ID’=$bulletin.id;
‘Vendor’=$bulletin.vendor;
‘Summary’=$bulletin.summary;
‘Severity’=$bulletin.severity;
‘Category’=$bulletin.category;
‘Urgency’=$bulletin.urgency;
‘ReleaseType’=$bulletin.releaseType;
‘ReleaseDate’=$bulletin.releaseDate;
‘Description’=$bulletin.description;
‘kbUrl’=$bulletin.kbUrl}
ForEach ($vib in $bulletin.vibList.vib) {
$propcopy = $props
$propcopy += @{‘RebootRequired’=$vib.postInstall.rebootRequired;
‘HostdRestart’=$vib.postInstall.hostdRestart;
‘Path’=$vib.vibfile.relativePath;
‘LocalPath’ = $(Get-ChildItem $VMwareCsco$($vib.vibfile.relativePath -replace "/","&quot;) -ErrorAction SilentlyContinue)
}
New-Object -TypeName PSObject -Property $propcopy
}
}
}

# Remove old export log first
Remove-Item $ExportVMwareLogFile -Force -ErrorAction SilentlyContinue
Remove-Item $ExportVMwareLogFileSum -Force -ErrorAction SilentlyContinue

# Parse VMware metadata XML and log KB-info for downloaded patches only
[xml]$VmXml = Get-Content $ExportTempVMwareESXiVmw400\vmware.xml
$vmXML | ConvertTo-VMObjects | Sort-Object ReleaseDate -Descending | Where {$.LocalPath -match "E:\"} | Select ID,Vendor,Summary,Severity,Category,Urgency,ReleaseType,Description,kbUrl,ReleaseDate,RebootRequired,hostdRestart,Path,LocalPath | Out-File $ExportVMwareLogFile -Append
$vmXML | ConvertTo-VMObjects | Sort-Object ReleaseDate -Descending | Where {$
.LocalPath -match "E:\"} | Select ID,ReleaseDate,kbUrl,LocalPath | Format-List | Out-File $ExportVMwareLogFileSum -Append

[xml]$VmXml = Get-Content $ExportTempVMwareESXiVmw410\vmware.xml
$vmXML | ConvertTo-VMObjects | Sort-Object ReleaseDate -Descending | Where {$.LocalPath -match "E:\"} | Select ID,Vendor,Summary,Severity,Category,Urgency,ReleaseType,Description,kbUrl,ReleaseDate,RebootRequired,hostdRestart,Path,LocalPath | Out-File $ExportVMwareLogFile -Append
$vmXML | ConvertTo-VMObjects | Sort-Object ReleaseDate -Descending | Where {$
.LocalPath -match "E:\"} | Select ID,ReleaseDate,kbUrl,LocalPath | Format-List | Out-File $ExportVMwareLogFileSum -Append

[xml]$VmXml = Get-Content $ExportTempVMwareESXiCsco400\vmware.xml
$vmXML | ConvertTo-CscoObjects | Sort-Object ReleaseDate -Descending | Where {$.LocalPath -match "E:\"} | Select ID,Vendor,Summary,Severity,Category,Urgency,ReleaseType,Description,kbUrl,ReleaseDate,RebootRequired,hostdRestart,Path,LocalPath | Out-File $ExportVMwareLogFile -Append
$vmXML | ConvertTo-CscoObjects | Sort-Object ReleaseDate -Descending | Where {$
.LocalPath -match "E:\"} | Select ID,ReleaseDate,kbUrl,LocalPath | Format-List | Out-File $ExportVMwareLogFileSum -Append

[xml]$VmXml = Get-Content $ExportTempVMwareESXiCsco410\vmware.xml
$vmXML | ConvertTo-CscoObjects | Sort-Object ReleaseDate -Descending | Where {$.LocalPath -match "E:\"} | Select ID,Vendor,Summary,Severity,Category,Urgency,ReleaseType,Description,kbUrl,ReleaseDate,RebootRequired,hostdRestart,Path,LocalPath | Out-File $ExportVMwareLogFile -Append
$vmXML | ConvertTo-CscoObjects | Sort-Object ReleaseDate -Descending | Where {$
.LocalPath -match "E:\"} | Select ID,ReleaseDate,kbUrl,LocalPath | Format-List | Out-File $ExportVMwareLogFileSum -Append

# Archive export log
Copy-Item $ExportVMwareLogFile -Destination $ExportArchiveVMwareLogFile
Copy-Item $ExportVMwareLogFileSum -Destination $ExportArchiveVMwareLogFileSum

# Archive VMware download log
Copy-Item $ExportArchiveVMwareLogFileDown -Destination $ExportArchiveVMwareLogFileDownCopy -Force -ErrorAction SilentlyContinue

# Remove tepm
Remove-Item $ExportTemp -Recurse -Force
Write-Host "OK"

# Finish
Write-Host ""
Write-Host "Script done!" -ForeGroundColor GREEN
$StopWatch.Stop()
Write-Host "Time to run: " $StoppeKlokke.Elapsed
Write-Host ""
Write-Host "Export folder:" -ForeGroundColor YELLOW
Write-Host $ExportVMware -ForeGroundColor WHITE
Write-Host "Export archive:" -ForeGroundColor YELLOW
Write-Host $ExportArchiveVMware -ForeGroundColor WHITE
Write-Host ""