Parsing XML and filtering/sorting problem

This topic contains 0 replies, has 1 voice, and was last updated by  Forums Archives 5 years, 11 months ago.

  • Author
    Posts
  • #5967

    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 "/","\")".Replace(" ","`nD:\vmw-ESXi-4.1.0-metadata\")) -ErrorAction SilentlyContinue | Select -ExpandProperty FullName);"","","################"""}

    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:

    ####### CUT ########


    Id : ESXi410-201101224-UG
    Vendor : Neterion
    Summary : vxge: net driver for VMware ESXi
    Category : general
    Urgency :
    ReleaseType : extension
    Description : Driver for X3100 10 GbE PCIe I/O Virtualized Server Adapter
    kbUrl : http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100VMware
    ReleaseDate : 2011-02-10T00:00:00-08:00
    RebootRequired : true
    HostdRestart : false
    Path : embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib
    D:\vmw-ESXi-4.1.0-metadata\embeddedEsx\4.1.0\ESXi-4.1.0-update01\cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib

    ################"
    Id : ESXi410-201110201-SG
    Vendor : VMware, Inc.
    Summary : Updates ESXi 4.1 Firmware
    Category : security
    Urgency : critical
    ReleaseType : update
    Description : For more information, see http://kb.vmware.com/kb/2002339.
    kbUrl : http://kb.vmware.com/kb/2002339
    ReleaseDate : 2011-10-27T00:00:00-08:00
    RebootRequired : true
    HostdRestart : false
    Path : embeddedEsx/4.1.0/ESXi-4.1.0-update02/vmware-esx-firmware-4.1.0-2.11.502767.i386.vib
    D:\vmw-ESXi-4.1.0-metadata\embeddedEsx\4.1.0\ESXi-4.1.0-update02\vmware-esx-firmware-4.1.0-2.11.502767.i386.vib

    ################"
    Id : ESXi410-201101223-UG
    Vendor : AMCC
    Summary : 3w-9xxx: scsi driver for VMware ESXi
    Category : general
    Urgency :
    ReleaseType : extension
    Description : 3ware SCSI driver for ESXi 4.1
    kbUrl : http://www.amcc.com
    ReleaseDate : 2011-02-10T00:00:00-08:00
    RebootRequired : true
    HostdRestart : false
    Path : embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib
    D:\vmw-ESXi-4.1.0-metadata\embeddedEsx\4.1.0\ESXi-4.1.0-update01\cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib

    ################"
    Id : ESXi410-201104402-BG
    Vendor : VMware, Inc.
    Summary : Updates VMware Tools
    Category : bugfix
    Urgency : important
    ReleaseType : patch
    Description : For more information, see http://kb.vmware.com/kb/1035109.
    kbUrl : http://kb.vmware.com/kb/1035109
    ReleaseDate : 2011-04-28T00:00:00-08:00
    RebootRequired : false
    HostdRestart : false
    Path : embeddedEsx/4.1.0/ESXi-4.1.0-patch02/vmware-esx-tools-light-4.1.0-1.6.381591.i386.vib

    ################"
    Id : ESXi410-201208202-UG
    Vendor : VMware, Inc.
    Summary : Updates the ESXi 4.1 Tools
    Category : bugfix
    Urgency : important
    ReleaseType : update
    Description : For more information, see http://kb.vmware.com/kb/2020375.
    kbUrl : http://kb.vmware.com/kb/2020375
    ReleaseDate : 2012-08-30T00:00:00-08:00
    RebootRequired : false
    HostdRestart : false
    Path : embeddedEsx/4.1.0/ESXi-4.1.0-update03/vmware-esx-tools-light-4.1.0-3.26.800380.i386.vib

    ####### SNIP ########

    I wish to sort by the "Local path", so that the files in "vmware.xml" that are actually downloaded come first. (The other objects are sortable..)
    Do I need to create a new object, to be able to sort it? Any good pointers

    Using VMware vSphere CLI is unfortunately not an option

    Also provided the vmware.xml from VMware.com.

    by DonJ at 2012-11-26 09:19:31

    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.

    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.


    $VmwPatch.bulletin | ForEach {
    $props = @{'ID'=$_.id;'Vendor'=$_.Vendor;'Summary'=$_.Summary}
    New-Object -Type PSObject -Prop $props
    } | Sort -Property ID

    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.

    Long-term, I'd probably build that logic into a function, so that you could just run something like...


    Get-Content file.xml | ConvertTo-VMWarePatchObject | Sort -Property Path | Format-List -Prop *

    The "ConvertTo-VMWarePatchObject" being the custom function you set up to convert the XML into objects. Kinda encapsulates that particular task very nicely.

    by ledetekst at 2012-11-26 14:33:54

    Brilliant – thanks! That did the trick. Learning something new every day!
    Tweaked it a bit, to only include where LocalPath exists.

    $VmwPatch.bulletin | ForEach {
    $props = @{'IDs'=$_.id;'Vendor'=$_.Vendor;'Summary'=$_.Summary;'Severity'=$_.severity;'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;'LocalPath'=$(Get-ChildItem ("D:\vmw-ESXi-4.1.0-metadata\$($_.viblist.vib.vibfile.relativePath -replace "/","\")".Replace(" ","`nD:\vmw-ESXi-4.1.0-metadata\")) -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.

    🙂

    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..



    ESXi410-Update01
    VMware, Inc.

    VMware ESXi 4.1 Complete Update 1

    general
    general


    update
    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.
    http://kb.vmware.com/kb/1029354
    http://www.vmware.com/support/contacts/
    2011-02-10T00:00:00-08:00

    1.4.5
    deb_vmware-esx-tools-light_4.1.0-1.4.348481
    vmware-esx-tools-light

    4.1.0-1.4.348481
    2011-01-13T01:47:55
    deb



    false
    false
    false
    locker


    embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-tools-light-4.1.0-1.4.348481.i386.vib 124804976
    sha-1
    055916d9381cbd6e22d3541e2167240b17767138




    1.4.5
    cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM
    oem-vmware-esx-drivers-scsi-3w-9xxx

    400.2.26.08.036vm40-1OEM
    2010-08-20T05:42:32
    cross



    true
    true
    false
    oem oem-vmware-esx-drivers-scsi-3w-9xxx-400.2.26.08.036vm40-1OEM.x86_64.rpm
    driver
    module



    embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-scsi-3w-9xxx_400.2.26.08.036vm40-1OEM.vib 32318
    sha-1
    abc0bd76404dca5aac607a9284f7370f5695c750




    1.4.5
    deb_vmware-esx-firmware_4.1.0-1.4.348481
    vmware-esx-firmware

    4.1.0-1.4.348481
    2011-01-13T01:47:44
    deb



    true
    true
    false
    stage


    embeddedEsx/4.1.0/ESXi-4.1.0-update01/vmware-esx-firmware-4.1.0-1.4.348481.i386.vib 90059938
    sha-1
    a147bc00556a04bc4d3c8216893f5d0d2a08263e




    1.4.5
    cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM
    oem-vmware-esx-drivers-net-vxge

    400.2.0.28.21239-1OEM
    2010-08-27T19:46:27
    cross



    true
    true
    false
    oem oem-vmware-esx-drivers-net-vxge-400.2.0.28.21239-1OEM.x86_64.rpm
    driver
    module



    embeddedEsx/4.1.0/ESXi-4.1.0-update01/cross_oem-vmware-esx-drivers-net-vxge_400.2.0.28.21239-1OEM.vib 937268
    sha-1
    87e7c20e6cafb49d579e88dc9a1132c85de6485a





    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.. :/

    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 under (at the same level as ) under it's own .


    ESXi410-Update01
    ESXi410-Update02
    ESXi410-Update03

    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
    🙂


    # 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:\" -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\"
    $ExportVMware = "E:\Export\VMware\"
    $ExportVMwareLog = "E:\Export\VMware\Log\"
    $ExportVMwareLogFile = $ExportVMwareLog + "VMwarePatch.log"
    $ExportVMwareLogFileSum = $ExportVMwareLog + "VMwarePatchSummary.log"
    $ExportVMwarePatch = "E:\Export\VMware\Patch\"
    $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\"
    $ExportTempVMware = "E:\ExportTemp\VMware\"
    $ExportTempVMwareESXiCsco400 = "E:\ExportTemp\VMware\csco-VEM-4.0.0-metadata\"
    $ExportTempVMwareESXiCsco410 = "E:\ExportTemp\VMware\csco-VEM-4.1.0-metadata\"
    $ExportTempVMwareESXiVmw400 = "E:\ExportTemp\VMware\vmw-ESXi-4.0.0-metadata\"
    $ExportTempVMwareESXiVmw410 = "E:\ExportTemp\VMware\vmw-ESXi-4.1.0-metadata\"
    $ExportDate = Get-Date -Format yyyy.MM.dd-HH.mm.ss
    $ExportArchiveVMware = "E:\ExportArchive\VMware\"
    $ExportArchiveVMwareLog = "E:\ExportArchive\VMware\Log\"
    $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\"
    $VMwareCsco = "E:\VMwareUpdateManager\Data\hostupdate\csco\"
    $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:\" -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 "/","\") -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 "/","\") -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 ""

You must be logged in to reply to this topic.