VMware Cloud Community
golddiggie
Champion
Champion
Jump to solution

Script to attach VMware tools and HW version update baselines to a set of VMs (from csv file)?

This environment is large, alright it's downright HUGE (about 15k VMs on ~1200 hosts in four physical datacenters). We need to kick off a VMware tools and HW version update task on about half of the VMs. Looking to use csv files for the targets on this (since we have a short window to perform these updates).

So, I'm hoping that someone has a solid method to flip the switch in the settings to update tools on next power on, as well as the schedule HW update on reboot. Or, a way to pull said list into VUM to then push the updates to the targets (including taking snapshots of these VMs before executing the tasks).

If it wasn't for the high VM count we need to target, I'm sure we could do it a less automated way. But when you have this many and such a short amount of time, scripting/automation is required (for sanity sake).

I'm hoping to have something we can test out in the next few days in our sandbox (or on our canary set) to confirm it's going to work. This also needs to have many running concurrently. Since if they go in a serial fashion, we'll run out of time LONG before they are done (or even a set of them get completed). One of the people in the company had created a script, but it was set to run in a serial fashion, with it taking about one minute per VM. We have a few two hour windows to do half of the VM count. :smileyshocked:

Tags (1)
Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Sure, I used $global:defaultVIServer as the shortcut to the last connected vCenter.
This to avoid running over multiple vCenters, should you have multiple connections open.

For using a CSV it would require a small change.

Somehting like this, it assumes the CSV has column called Name, that holds all the VM displaynames.

$blNames = 'VM Hardware Upgrade to Match Host (Predefined)',

   'VMware Tools Upgrade to Match Host (Predefined)'

$root = Get-Folder -Name Datacenters -Server $global:defaultVIServer

$vmNames = Import-Csv -Path .\vmnames.csv -UseCulture

$vms = Get-VM -Name $vmNames.Name

$bl = Get-Baseline -Name $blNames

Add-EntityBaseline -Entity $root -Baseline $bl

Test-Compliance -Entity $vms -UpdateType VmHardwareUpgrade,VmToolsUpgrade -ErrorAction SilentlyContinue

$vms | ForEach-Object -Process {

   $vmsToUpdate = Get-Compliance -Entity $_ -ComplianceStatus NotCompliant

   $vmsToUpdate | Group-Object -Property {$_.Entity.Name} | ForEach-Object -Process {

   $sUpd = @{

   Entity = $_.Name

   Baseline = $_.Group.Baseline

   GuestCreateSnapshot = $true

   GuestSnapshotName = "Maintenance $(Get-Date -Format 'yyyy/MM/dd HH:mm')"

   Confirm = $false

   RunAsync = $true

   }

   Update-Entity @sUpd

   }

}

And yes, it will remediate multiple VMs at the same time, since the remediation step is started as background task.
There might be a limit imposed by the vCenter and/or Update Manager.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

Reply
0 Kudos
45 Replies
LucD
Leadership
Leadership
Jump to solution

A couple of questions:

  • what kind of guest OS do you have running on these VMs? All Windows or Linux or a mix?
  • what is the target HW version you want to upgrade to?
  • are there VMs that only need a HW version upgrade or a VMware Tools upgrade?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

Windows OS for the target. Mostly 2012r2 but there could be some 2016 and 2008r2 VMs in the mix.

Going to HW13 since this is for a 6.5u1 setup.

Pretty sure they all (or damned close to all) need both hardware and tools.

The script that just takes too long had a setting to check the tools and not do the update if they were current. We're thinking that if we can just settings flag for the tools (to upate on next reboot) and then schedule the HW update after that, we would be in a better position.

We want to leverage VUM as much as possible for this. I'm hoping to have Orchestrator setup before we need to do this again. I believe it would be easier with that part in the mix (unless I'm mistaken).

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

You could do something like this (it is completely based on Update Manager).

It will fire off all remediate steps in the background.

That way it will depend on the capacity of the system how many of the task are active.

You could also add a mechanism to limit the maximum number of background jobs, but that will require some additional code.

$blNames = 'VM Hardware Upgrade to Match Host (Predefined)',

           'VMware Tools Upgrade to Match Host (Predefined)'

$root = Get-Folder -Name Datacenters -Server $global:defaultVIServer

$vms = Get-VM -Location $root

$bl = Get-Baseline -Name $blNames

Add-EntityBaseline -Entity $root -Baseline $bl

Test-Compliance -Entity $vms -UpdateType VmHardwareUpgrade,VmToolsUpgrade -ErrorAction SilentlyContinue

$vms | ForEach-Object -Process {

    $vmsToUpdate = Get-Compliance -Entity $_ -ComplianceStatus NotCompliant

    $vmsToUpdate | Group-Object -Property {$_.Entity.Name} | ForEach-Object -Process {

        $sUpd = @{

            Entity = $_.Name

            Baseline = $_.Group.Baseline

            GuestCreateSnapshot = $true

            GuestSnapshotName = "Maintenance $(Get-Date -Format 'yyyy/MM/dd HH:mm')"

            Confirm = $false

            RunAsync = $true

        }

        Update-Entity @sUpd

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

This might be a stupid question, but does that use a list file (for the targets)?? Since we can only do this against half of the VMs in each cluster, at a time, we need to pick and choose which ones get the HW and tools updated.

BTW, already your script is about 1/20 the size of what the other person created.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

No, my sample code takes all the VMs in a vCenter, but you can easily change that.

This takes the VMs from the names in a text file for example.

$blNames = 'VM Hardware Upgrade to Match Host (Predefined)',

           'VMware Tools Upgrade to Match Host (Predefined)'

$root = Get-Folder -Name Datacenters -Server $global:defaultVIServer

$vmNames = Get-Content -Path .\vmnames.txt

$vms = Get-VM -Name $vmNames

$bl = Get-Baseline -Name $blNames

Add-EntityBaseline -Entity $root -Baseline $bl

Test-Compliance -Entity $vms -UpdateType VmHardwareUpgrade,VmToolsUpgrade -ErrorAction SilentlyContinue

$vms | ForEach-Object -Process {

    $vmsToUpdate = Get-Compliance -Entity $_ -ComplianceStatus NotCompliant

    $vmsToUpdate | Group-Object -Property {$_.Entity.Name} | ForEach-Object -Process {

        $sUpd = @{

            Entity = $_.Name

            Baseline = $_.Group.Baseline

            GuestCreateSnapshot = $true

            GuestSnapshotName = "Maintenance $(Get-Date -Format 'yyyy/MM/dd HH:mm')"

            Confirm = $false

            RunAsync = $true

        }

        Update-Entity @sUpd

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

Assuming we can edit "-Server $global:defaultVIServer" so that defaultVIServer is the actual vCenter Server we're going to target for the upgrade set.

Any reason to use a text file instead of a CSV?? Or can we just set that to use a CSV file instead, without issue?

With how this is currently written, it will do as many VMs (from the list) as it can at one shot. Right? One of the issues with the previous script (from someone else) was how it wouldn't do more than one at a time. So it was taking about a minute to kick off each VM's task set. So 60 VMs would take an hour to process. If we can get a bunch to execute at the same time, then that should allow us to complete the VMs we need to in the run we have coming up in a couple of weeks (around mid-month). We'll have the second half of the VMs to do next month. IIRC, we have a couple of days to get this done. BUT, only about a two hour window on each of those days. I'm just hoping we can get through all the VMs in that window of time. Mostly because the regular Windows patches are going to be executed after our window.

Thanks

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Sure, I used $global:defaultVIServer as the shortcut to the last connected vCenter.
This to avoid running over multiple vCenters, should you have multiple connections open.

For using a CSV it would require a small change.

Somehting like this, it assumes the CSV has column called Name, that holds all the VM displaynames.

$blNames = 'VM Hardware Upgrade to Match Host (Predefined)',

   'VMware Tools Upgrade to Match Host (Predefined)'

$root = Get-Folder -Name Datacenters -Server $global:defaultVIServer

$vmNames = Import-Csv -Path .\vmnames.csv -UseCulture

$vms = Get-VM -Name $vmNames.Name

$bl = Get-Baseline -Name $blNames

Add-EntityBaseline -Entity $root -Baseline $bl

Test-Compliance -Entity $vms -UpdateType VmHardwareUpgrade,VmToolsUpgrade -ErrorAction SilentlyContinue

$vms | ForEach-Object -Process {

   $vmsToUpdate = Get-Compliance -Entity $_ -ComplianceStatus NotCompliant

   $vmsToUpdate | Group-Object -Property {$_.Entity.Name} | ForEach-Object -Process {

   $sUpd = @{

   Entity = $_.Name

   Baseline = $_.Group.Baseline

   GuestCreateSnapshot = $true

   GuestSnapshotName = "Maintenance $(Get-Date -Format 'yyyy/MM/dd HH:mm')"

   Confirm = $false

   RunAsync = $true

   }

   Update-Entity @sUpd

   }

}

And yes, it will remediate multiple VMs at the same time, since the remediation step is started as background task.
There might be a limit imposed by the vCenter and/or Update Manager.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

Quick question... If we connect to the target vCenter in PowerCLI before running the script, will it just go to that vCenter for that run? Since we have a total of 12 vCenter Servers in place here, being able to easily target the correct one will be important. There are three of us in the US that will be running during one time frame with more people at another location running during our off hours. We all have logins to our 'jump host' systems that we use to connect to the environments (can't go direct from our systems).

We're looking to kick this off on Friday the 15th for the first round. So, we'll be testing against some 'canary' systems and/or some in our sandboxed lab setup.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

It depends how you configured PowerCLI.
If you have set the DefaultVIServer mode to Single with the Set-PowerCLIConfiguration cmdlet, only the vCenter specified on the last Connect-VIServer will be connected.

If you set that to Multiple, all vCenters for which you did a Connect-VIServer will be connected.

That is why I used the $global:defaultVIServer variable.

That one, independent of the mode you configured will always represent the last vCenter to which you connected.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

Connected through PowerCLI or from the vSphere Web Client??

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

PowerCLI, with the Connect-VIServer cmdlet.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

Got it... So if we just connect to the right vCenter before running the script it will go against that one by default...

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Correct, but I would still advise to use the $global:defaultVIserver variable.

That way you are independent of the DefaultVIServerMode


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

Hopefully this add will be an easy one.

There's a want to get a report once the file has been run (for each run/execution of it) with the status of the updates on the targets. Such as either success, or current levels of the VMs.

Right now I'm creating a bunch of target VMs in our sandboxed lab to test this with. We need to get the testing done by EOD Thursday (tomorrow). Due to issues in the lab, it's taken me the past couple of days to get it up to 6.5u1 since that's what our production environment is at. Including host hardware level (firmware) updates and getting the datastores worked out. It was a left a mess by a person that left just before I joined. Plus no one else had been maintaining the setup, so it was in a bad way.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Can this reporting script be a 2nd script that you run afterwards?

It would just need to report on the VMware Tools status/version and the HW version.
In fact, you could run the same report twice, before and after.

Something like this

Get-VM |

Select Name,HardwareVersion,

    @{N='ToolsStatus';E={$_.ExtensionData.Guest.ToolsStatus}},

    @{N='ToolsRunningStatus';E={$_.ExtensionData.Guest.ToolsRunningStatus}},

    @{N='ToolsVersion';E={$_.ExtensionData.Guest.ToolsVersion}},

    @{N='ToolsInstallType';E={$_.ExtensionData.Guest.ToolsInstallType}}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
golddiggie
Champion
Champion
Jump to solution

How about using the same VM target list for this one to run against??

Also, trying to find a script/command set to clone a VM 100 times (with a number after the name) for our test set. These won't have any live network since they're just to be used to see how long it will take to execute the script against that many VMs. Mostly so we have a solid idea of how long these runs will take. I found one script, but it failed (badly). It looks like I need to update the PowerShell and then PowerCLI versions (to be current since PowerShell is 4.0) first.

Also need this to export as a csv file for our records (dictated from higher up).

vSphere environment is still 6.5u1.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Ok, like this you mean?

$vmNames = Import-Csv -Path .\vmnames.csv -UseCulture

Get-VM -Name $vmNames.Name |

Select Name,HardwareVersion,

    @{N='ToolsStatus';E={$_.ExtensionData.Guest.ToolsStatus}},

    @{N='ToolsRunningStatus';E={$_.ExtensionData.Guest.ToolsRunningStatus}},

    @{N='ToolsVersion';E={$_.ExtensionData.Guest.ToolsVersion}},

    @{N='ToolsInstallType';E={$_.ExtensionData.Guest.ToolsInstallType}} |

Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture

On the cloning script, what are you using, and what goes wrong?

Otherwise any code I provide will be a shot in the dark.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

golddiggie
Champion
Champion
Jump to solution

Trying to use this

#

# PowerCLI to create VMs from existing vSphere VM

# Version 1.0

# Magnus Andersson RTS

#

# Specify vCenter Server, vCenter Server username and vCenter Server user password

#$vCenter="vcsa-dutt.arch.kronos.local"

#$vCenterUser="vcdx56@a_magnus"

#$vCenterUserPassword="notsecret"

#

# Specify number of VMs you want to create

$vm_count = "100"

#

# Specify the VM you want to clone

$clone = "2012r2_Template"

#

# Specify the Customization Specification to use

#$customspecification="VCDX56-customization"

#

# Specify the datastore or datastore cluster placement

$ds = "dutt-datastore-cluster"

#

# Specify vCenter Server Virtual Machine & Templates folder

$Folder = "Update_Targets"

#

# Specify the vSphere Cluster

$Cluster = "Salem02"

#

# Specify the VM name to the left of the - sign

$VM_prefix = "test-"

#

# End of user input parameters

#_______________________________________________________

#

write-host "Connecting to vCenter Server $vCenter" -foreground green

#Connect-viserver $vCenter -user $vCenterUser -password $vCenterUserPassword -WarningAction 0

1..$vm_count | foreach {

$y="{0:D2}" -f $_

$VM_name= $VM_prefix + $y

$ESXi=Get-Cluster $Cluster | Get-VMHost -state connected | Get-Random

write-host "Creation of VM $VM_name initiated" -foreground green

New-VM -Name $VM_Name -VM $clone -VMHost $ESXi -Datastore $ds -Location $Folder -RunAsync

}

Attached screenshot of the error... I'm also trying to get PowerShell up from 4.0 to 5.1 but that's fighting me.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Looks like the $ESXI variable is empty.

Does this actually return anything?

$Cluster = "Salem02"
Get-Cluster $Cluster | Get-VMHost -state connected | Get-Random


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos