Wednesday, August 20, 2014

Update VMtools and virtual hardware using PowerCLI (UPDATED)

Original content credit to: http://www.getshifting.com/wiki/powerclivmupgrade
================================================================
what this does is:
1) check the VMtool level, if it's not current, upgrade the VMtool.
2) check virtual hardware level, if it is not current, and VMtool is current, upgrade vm hardware
3) else, break

- made some changes to process the vmtool upgrade with runasync switch, and do the poweroff for all VMs at once. this could save some time if you have many VMs in the list

- link to the .ps1 file - CLICK HERE

=========BEGIN CODE============================================

# HOW TO RUN:
# save the list of vm to be updated in text file, and run this script. Enter the filename when requested.
#

$timestamp = Get-Date -format "yyyyMMdd-HH.mm"
$csvfile = ".\$timestamp-vminfo.csv"

Function VM-Selection{
  
      $sourcename = Read-Host "Give the name of the object or inputfile (full path) you want to upgrade"
      if($sourcename){
         $abort = Read-Host "You've chosen $sourcetype with this file: $sourcename, this is your last chance to abort by pressing <CTRL>+C. Press <ENTER> to continue selecting old hardware VMs"
         #$list = Get-Content $sourcename | Foreach-Object {Get-VM $_ | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-04" } | Select Name }
         $list = Get-Content $sourcename | Foreach-Object {Get-VM $_ | Get-View | Where-Object {-not $_.config.template} | Select Name }
             $vms = $list
      }
      else{
         Write-Host "$sourcetype file does not exist. Exit the script by pressing <CTRL>+C and try again."
      }
  
   return $vms
}

Function PowerOn-VM($vm){
   Start-VM -VM $vm -Confirm:$false -RunAsync | Out-Null
   Write-Host "$vm is starting!" -ForegroundColor Yellow
   sleep 10

   do {
      $vmview = get-VM $vm | Get-View
        $getvm = Get-VM $vm
        $powerstate = $getvm.PowerState
      $toolsstatus = $vmview.Guest.ToolsStatus

      Write-Host "$vm is starting, powerstate is $powerstate and toolsstatus is $toolsstatus!" -ForegroundColor Yellow
      sleep 5
        #NOTE that if the tools in the VM get the state toolsNotRunning this loop will never end. There needs to be a timekeeper variable to make sure the loop ends

      }until(($powerstate -match "PoweredOn") -and (($toolsstatus -match "toolsOld") -or ($toolsstatus -match "toolsOk") -or ($toolsstatus -match "toolsNotInstalled")))

      if (($toolsstatus -match "toolsOk") -or ($toolsstatus -match "toolsOld")){
       $Startup = "OK"
         Write-Host "$vm is started and has ToolsStatus $toolsstatus"
      }
      else{
       $Startup = "ERROR"
         [console]::ForegroundColor = "Red"
         Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
         [console]::ResetColor()
      }
    return $Startup
}

Function PowerOff-VM($vm){
   Shutdown-VMGuest -VM $vm -Confirm:$false | Out-Null
   Write-Host "$vm is stopping!" -ForegroundColor Yellow
   sleep 10

   do {
      $vmview = Get-VM $vm | Get-View
      $getvm = Get-VM $vm
        $powerstate = $getvm.PowerState
        $toolsstatus = $vmview.Guest.ToolsStatus

      Write-Host "$vm is stopping with powerstate $powerstate and toolsStatus $toolsstatus!" -ForegroundColor Yellow
      sleep 5

   }until($powerstate -match "PoweredOff")

   if (($powerstate -match "PoweredOff") -and (($toolsstatus -match "toolsNotRunning") -or ($toolsstatus -match "toolsNotInstalled"))){
      $Shutdown = "OK"
        Write-Host "$vm is powered-off"
   }
   else{
      $Shutdown = "ERROR"
        [console]::ForegroundColor = "Red"
        Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
        [console]::ResetColor()
   }
   return $Shutdown
}

Function Check-ToolsStatus($vm){
   $vmview = get-VM $vm | Get-View
   $status = $vmview.Guest.ToolsStatus

   if ($status -match "toolsOld"){
      $vmTools = "Old"}
   elseif($status -match "toolsNotRunning"){
      $vmTools = "NotRunning"}
   elseif($status -match "toolsNotInstalled"){
      $vmTools = "NotInstalled"}
   elseif($status -match "toolsOK"){
      $vmTools = "OK"}
   else{
      $vmTools = "ERROR"
        Read-Host "The ToolsStatus of $vm is $vmTools. Press <CTRL>+C to quit the script or press <ENTER> to continue"
        }
   return $vmTools
}

Function Check-VMHardwareVersion($vm){
   $vmView = get-VM $vm | Get-View
   $vmVersion = $vmView.Config.Version
   $v9 = "vmx-09"
   $v10 = "vmx-10"

   if (($vmVersion -ne $v9) -or ($vmVersion -ne $v10)){
      $vmHardware = "Old"}
   elseif(($vmVersion -eq $v9) -or ($vmVersion -eq $v10)){
      $vmHardware = "OK"}
   else{
      $vmHardware = "ERROR"
        [console]::ForegroundColor = "Red"
        Read-Host "The Hardware version of $vm is not set to $v4 or $v9. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
        [console]::ResetColor()
   }
   return $vmHardware
}

Function Upgrade-VMHardware($vm){
   $vmview = Get-VM $vm | Get-View
   $vmVersion = $vmView.Config.Version
   $v9 = "vmx-09"

   if ($vmVersion -ne $v9){
      Write-Host "Old Version detected" -ForegroundColor Red

# Update Hardware
      Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow
      Get-View ($vmView.UpgradeVM_Task($v9)) | Out-Null
   }
}

Function CheckAndUpgradeTools($vm){

   $vmview = Get-VM $VM | Get-View
   $family = $vmview.Guest.GuestFamily
   $vmToolsStatus = Check-ToolsStatus $vm

   if($vmToolsStatus -eq "OK"){
      Write-Host "The VM tools are $vmToolsStatus on $vm"}
   elseif(($family -eq "windowsGuest") -and ($vmToolsStatus -ne "NotInstalled")){
      Write-Host "The VM tools are $vmToolsStatus on $vm. Starting update/install now! This will take at few minutes." -ForegroundColor Red
        Get-Date

      Get-VMGuest $vm | Update-Tools -NoReboot -RunAsync
      ###############changes###########################
#       do{
#       sleep 10
#       Write-Host "Checking ToolsStatus $vm now"
#       $vmToolsStatus = Check-ToolsStatus $vm
#       }until($vmToolsStatus -eq "OK")
#       sleep 60
#     PowerOff-VM $vm
#       PowerOn-VM $vm
        #############end changes#######################
   }
   else{
        # We're skipping all non-windows guest since automated installs are not supported
        Write-Host "$vm is a $family with tools status $vmToolsStatus. Therefore we're skipping this VM" -ForegroundColor Red
   }
}

Function CheckAndUpgrade($vm){

   $vmHardware = Check-VMHardwareVersion $vm
   $vmToolsStatus = Check-ToolsStatus $vm

   if($vmHardware -eq "OK"){
      Write-Host "The hardware level is $vmHardware on $vm"}
   elseif($vmToolsStatus -eq "OK"){
      Write-Host "The hardware level is $vmHardware on $vm." -ForegroundColor Red
      $PowerOffVM = PowerOff-VM $vm
        if($PowerOffVM -eq "OK"){
           Write-Host "Starting upgrade hardware level on $vm."
             Upgrade-VMHardware $vm
           sleep 5
             PowerOn-VM $vm
           Write-Host $vm "is up to date" -ForegroundColor Green
        }
        else{
        Write-Host "There is something wrong with the hardware level or the tools of $vm. Skipping $vm."
        }
   }  
}

Function CreateHWList($vms, $csvfile){
# The setup for this hwlist comes from http://www.warmetal.nl/powerclicsvvminfo
   Write-Host "Creating a CSV File with VM info" -ForegroundColor Yellow

   $MyCol = @()
      ForEach ($item in $vms){
         $vm = $item.Name
             # Variable getvm is required, for some reason the $vm cannot be used to query the host and the IP-address
             $getvm = Get-VM $vm
             $vmview = Get-VM $vm | Get-View

             # VM has to be turned on to make sure all information can be recorded
             $powerstate = $getvm.PowerState
             if ($powerstate -ne "PoweredOn"){
                PowerOn-VM $vm}

             $vmnic = Get-NetworkAdapter -VM $vm
         $nicmac = Get-NetworkAdapter -VM $vm | ForEach-Object {$_.MacAddress}
         $nictype = Get-NetworkAdapter -VM $vm | ForEach-Object {$_.Type}
         $nicname = Get-NetworkAdapter -VM $vm | ForEach-Object {$_.NetworkName}

         $VMInfo = "" | Select VMName,NICCount,IPAddress,MacAddress,NICType,NetworkName,GuestRunningOS,PowerState,ToolsVersion,ToolsStatus,ToolsRunningStatus,HWLevel,VMHost
         $VMInfo.VMName = $vmview.Name
         $VMInfo.NICCount = $vmview.Guest.Net.Count
         $VMInfo.IPAddress = [String]$getvm.Guest.IPAddress
         $VMInfo.MacAddress = [String]$nicmac
         $VMInfo.NICType = [String]$nictype
         $VMInfo.NetworkName = [String]$nicname
         $VMInfo.GuestRunningOS = $vmview.Guest.GuestFullname
         $VMInfo.PowerState = $getvm.PowerState
         $VMInfo.ToolsVersion = $vmview.Guest.ToolsVersion
         $VMInfo.ToolsStatus = $vmview.Guest.ToolsStatus
         $VMInfo.ToolsRunningStatus = $vmview.Guest.ToolsRunningStatus
         $VMInfo.HWLevel = $vmview.Config.Version
         $VMInfo.VMHost = $getvm.VMHost

         $myCol += $VMInfo
        }

   if ((Test-Path -path $csvfile) -ne $True){
      $myCol |Export-csv -NoTypeInformation $csvfile
   }
   else{
      $myCol |Export-csv -NoTypeInformation $csvfile-after.csv
   }
}

function PowerOffAll-VM($vm){
      shutdown-vmguest -VM $vm -Confirm:$false | out-null
}

function PowerOff-vm-check($vm){

            $vmview = get-vm $vm | get-view
            $getvm = get-vm $vm
            $powerstate = $getvm.PowerState
            $toolsstatus = $vmview.Guest.ToolsStatus
           
            #write-host "$vm is stopping with powerstate $powerstate and toolsStatus $toolsstatus!" -foregroundcolor yellow
            if (($powerstate -match "PoweredOff") -and (($toolsstatus -match "toolsNotRunning") -or ($toolsstatus -match "toolsNotInstalled"))){
                        $Shutdown = "OK"
            #     Write-Host "$vm is powered-off"
            }
            else{
                        $Shutdown = "ERROR"
                  [console]::ForegroundColor = "Red"
                  Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
                  [console]::ResetColor()
            }
           
            return $shutdown
           
}


##################################
# main function
##################################
$vms = VM-Selection

#CreateHWList $vms $csvfile
$vmupgraded = "NO"
foreach($item in $vms){
   $vm = $item.Name
   Write-Host "Working on $vm"
   CheckAndUpgradeTools $vm
}

do{
            sleep 20
            $count = 0
            foreach($vmname in $vms){
                  $vm = $vmname.Name
                  #write-host "checking status for $vm"
                  $vmToolsStatus = Check-ToolsStatus $vm
                  if($vmToolsStatus -ne "OK"){
                        $count += 1
                        $vmupgraded = "yes"
                  }
            }
            write-host "$count VM still in progress"
      }until($count -eq 0)
      write-host "All VM has vmtools upgraded"

write-host "VMtool upgraded status = $vmupgraded"    
Read-Host "Continue to virtual hardware upgrade. Press <CTRL>+C to quit the script or press <ENTER> to continue"

     

if($vmupgraded -eq "yes"){
      foreach($vmname in $vms){
            $vm = $vmname.Name
            PowerOffAll-VM $vm
      }

      do{
            sleep 10
            $count = 0
            write-host "checking power state for all VMs"
            foreach($vmname in $vms){
                  $vm = $vmname.Name
                  $powerState = PowerOff-vm-check $vm
                  if($powerState -ne "OK"){
                        $count += 1
                  }
            }
            write-host "$count VM still powering off" -foregroundcolor yellow
      }until($count -eq 0)
      write-host "All VMs powered off"

      foreach($vmname in $vms){
            $vm = $vmname.Name
            PowerOn-VM $vm
      }
}
     
foreach($item in $vms){
      $vm = $item.Name
      Write-Host "Working on $vm"
      CheckAndUpgrade $vm
}
#CreateHWList $vms $csvfile
###################################
# end main
###################################