6 Replies Latest reply on Feb 6, 2019 1:22 PM by ScubaIT

    Automation of Windows Updates for Templates

    J_Kolkes Novice
    vExpertVMware Employees

      Hello Community,

       

      I wanted to share a script I've been working on hoping that other people find it useful and perhaps some PowerCLI specialists collaborate in making it better and more adequate as I’m not an expert PowerCLI scripter.

       

      I've decided to attempt scripting a solution that will keep many Windows Server Templates updated without user interaction.

      Disclaimer: I am not a PowerCLI expert; much of what I have scripted for this and other solutions was gathered from what others shared and learning as I go.

       

       

      The Tasks involved: Convert template to VM, Power On VM, run Windows Update remotely, reboot VMGuest, shut VM down and finally convert back to template.

       

      What's required on Templates:

      Note: This Windows Update Module includes the Get-WUInstall PowerShell command which is the one used to install patches remotely.

       

      Here's what is working for me:


      # Connect to vCenter

      Connect-VIServer "vCenterServer"

       

      # Convert template to VM

      Set-Template -Template W2K12Template -ToVM -Confirm:$false -RunAsync

      Start-sleep -s 15

       

      #Start VM - I've seen some converted templates that prompt with the VMQuestion, so adding the command to answer with the default option was my response to it.

      Start-VM -VM W2K12Template | Get-VMQuestion | Set-VMQuestion -DefaultOption -Confirm:$false

      Start-sleep -s 45

       

      #Create variables for Guest OS credentials - This is needed for the Invoke-VMScript cmdlet to be able to execute actions inside the Guest.

      #If you don't want to enter the Guest OS local administrator password as clear text in the script, follow the steps on following link to create a file and store it as an encrypted string: Using PowerShell credentials without being prompted for a password - Stack Overflow

       

      $Username = "administrator"

      $OSPwd = cat C:\Scripts\OSPwd.txt | convertto-securestring

      $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $OSPwd

       

      #The following is the cmdlet that will invoke the Get-WUInstall inside the GuestVM to install all available Windows updates; optionally results can be exported to a log file to see the patches installed and related results.

      Invoke-VMScript -ScriptType PowerShell -ScriptText "Get-WUInstall –WindowsUpdate –AcceptAll –AutoReboot" -VM W2K12Template -GuestCredential $Cred | Out-file -Filepath C:\WUResults.log -Append

       

      Start-sleep -s 45

       

      #Optionally restart VMGuest one more time in case Windows Update requires it and for whatever reason the –AutoReboot switch didn’t complete it.

      Restart-VMGuest -VM W2K12Template -Confirm:$false

       

      #On a separate scheduled script or after a desired wait period, Shutdown the server and convert it back to Template.

      Shutdown-VMGuest –VM W2K12Template -Confirm:$false –RunAsync

      Start-sleep -s 120

      Set-VM –VM W2K12Template -ToTemplate -Confirm:$false



      The script can be scheduled to run a couple of days after Patch Tuesdays or whenever you desire.

       

      I really hope PowerCLI leaders can take a look at this and suggest best practices, help improve or advance it with more capabilities.

      All feedback and questions are welcomed.

       

      --

      Jorge.

      @J_Kolkes

        • 1. Re: Automation of Windows Updates for Templates
          ruvreve Lurker

          This script still working well for you?

          • 2. Re: Automation of Windows Updates for Templates
            wreedctd Enthusiast

            I am curious also.

            • 3. Re: Automation of Windows Updates for Templates
              Nodnarb Novice

              Great Post! This was just what I needed to get going on the automation of updating our templates. Thanks!

               

              I customized the script a bit to add some additional waits/checks and parameters for the vCenter server and the template to update. I also added some lines to update VMware Tools, if needed. You would call it by specifying .\MyScript.ps1 VMtemplate vcenter.mydowmain.com. Once converted to a VM, your VM needs to be pingable via a DNS name that matches the name of the VM, so be sure to allow that through Windows Firewall. Note: I gave it a 2-hour window to settle down after rebooting so that the VM could be shut down and converted back into a template in the same script. Adjust this time for your own environment as-needed.

               

               

              [CmdletBinding()]
              
              Param(
              
                 [Parameter(Mandatory=$True,Position=1)]
              
                 [string]$TemplateVMName,
              
                  
              
                 [Parameter(Mandatory=$true,Position=2)]
              
                 [string]$VCenterServer
              
              )
              
              
              Write-Output "Script started $(Get-Date)"
              
              
              # Check for PowerCLI
              
              If ( (Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null) {
              
                  Add-PSSnapin VMware.VimAutomation.Core
              
              }
              
              
              Connect-VIServer $VCenterServer
              
              
              # Convert the template to a VM
              
              Set-Template -Template $TemplateVMName -ToVM -Confirm:$false
              
              Start-Sleep -Seconds 20
              
              
              # Start the VM. Answer any question with the default response
              
              Write-Output "Starting VM $TemplateVMName"
              
              Start-VM -VM $TemplateVMName | Get-VMQuestion | Set-VMQuestion -DefaultOption -Confirm:$false
              
              
              # Wait for the VM to become accessible after starting
              
              do 
              
              {
              
                Write-Output "Waiting for $TemplateVMName to respond...`r`n"
              
                Start-Sleep -Seconds 10      
              
              } until(Test-Connection $TemplateVMName -Quiet | ? { $True } )
              
              
              Write-Output "$TemplateVMName is up. Resting for 2 minutes to allow the VM to `"settle`"."
              
              Start-Sleep 120 # Wait additional time for the VM to "settle" after booting up
              
              
              # Update VMware tools if needed
              
              Write-Output “Checking VMware Tools on $TemplateVMName"
              
              do 
              
              { 
              
               $toolsStatus = (Get-VM $TemplateVMName | Get-View).Guest.ToolsStatus 
              
               Write-Output "Tools Status: " $toolsStatus 
              
               sleep 3 
              
               if ($toolsStatus -eq "toolsOld") 
              
               {
              
                   Write-Output "Updating VMware Tools on $TemplateVMName"
              
                   Update-Tools -VM $TemplateVMName -NoReboot
              
               } else { Write-Output "No VMware Tools update required" }
              
              } until ( $toolsStatus -eq ‘toolsOk’ ) 
              
              
              # Build guest OS credentials
              
              $username="$TemplateVMName\Administrator"
              
              $password=cat TemplatePass.txt | ConvertTo-SecureString
              
              $GuestOSCred=New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
              
              
              <#
              
              The following is the cmdlet that will invoke the Get-WUInstall inside the GuestVM to install all available Windows 
              
              updates; optionally results can be exported to a log file to see the patches installed and related results.
              
              #>
              
              
              Write-Output "Running PSWindowsUpdate script"
              
              
              Invoke-VMScript -ScriptType PowerShell -ScriptText "ipmo PSWindowsUpdate; Get-WUInstall –AcceptAll –AutoReboot -Verbose | Out-File C:\PSWindowsUpdate.log -Append" -VM $TemplateVMName -GuestCredential $GuestOSCred #| Out-file -Filepath C:\WUResults.log -Append
              
              
              Write-Output "Waiting 45 seconds for automatic reboot if updates were applied"
              
              Start-Sleep -Seconds 45
              
              
              do 
              
              {
              
                Write-Output "Waiting for $TemplateVMName to respond...`r`n"
              
                Start-Sleep -Seconds 10      
              
              } until(Test-Connection $TemplateVMName -Quiet | ? { $True } )
              
              
              Write-Output "$TemplateVMName is up. Waiting 2 hours for large updates to complete before final reboot."
              
              Start-Sleep -Seconds 7200
              
              
              #Restart VMGuest one more time in case Windows Update requires it and for whatever reason the –AutoReboot switch didn’t complete it.
              
              Write-Output "Performing final reboot of $TemplateVMName"
              
              Restart-VMGuest -VM $TemplateVMName -Confirm:$false
              
              
              do 
              
              {
              
                Write-Output "Waiting for $TemplateVMName to respond...`r`n"
              
                Start-Sleep -Seconds 10      
              
              } until(Test-Connection $TemplateVMName -Quiet | ? { $True } )
              
              Write-Output "$TemplateVMName is up. Resting for 2 minutes to allow the VM to `"settle`"."
              
              Start-Sleep 120 # Wait additional time for the VM to "settle" after booting up
              
              
              # Shut down the VM and convert it back to a template
              
              Write-Output "Shutting down $TemplateVMName and converting it back to a template"
              
              Shutdown-VMGuest –VM $TemplateVMName -Confirm:$false
              
              do 
              
              {
              
                Write-Output "Waiting for $TemplateVMName to shut down...`r`n"
              
                Start-Sleep -Seconds 10      
              
              } until(Get-VM -Name $TemplateVMName | Where-Object { $_.powerstate -eq "PoweredOff" } )
              
              
              Set-VM –VM $TemplateVMName -ToTemplate -Confirm:$false
              
              
              Write-Output "Finished updating $TemplateVMName"
              
              
              Write-Output "Script completed $(Get-Date)"
              
              • 4. Re: Automation of Windows Updates for Templates
                VirtuxpertsLLC Lurker

                J Kolekes. Very nice script. The only major problem that I am facing is that the Invoke-VMScript -ScriptType PowerShell -ScriptText "Get-WUInstall –WindowsUpdate –AcceptAll –AutoReboot" -VM MyTemplate -GuestCredential $Cred | Out-file -Filepath C:\WUResults.log -Append


                keeps throwing an error. I have investigated in depth and still can't figure why it doesn't work. If you can assist that would be fine. The rest of the script runs excellent!

                 

                Much Thanks!!!

                 

                James

                 

                 

                 

                • 5. Re: Automation of Windows Updates for Templates
                  chenerson Lurker

                  What kind of error did you get?

                  I've had issues trying to use these scripts too but the output file tells me nothing...

                   

                   

                  ScriptOutput

                  -------------------------------------------------------------------------------

                  -------------------------------------------------------------------------------

                  • 6. Re: Automation of Windows Updates for Templates
                    ScubaIT Lurker

                    Are you building your Guest OS credentials beforehand? I see where you're calling it Get-Content.

                     

                    Are you doing something like this before running the script? Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\TemplatePass.txt

                     

                    If so, could you just add that Read-Host string to the script to prompt to create the password variable? Then break it down at the end of the script.