VMware Cloud Community
J_Kolkes
VMware Employee
VMware Employee

Automation of Windows Updates for Templates

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

8 Replies
ruvreve
Contributor
Contributor

This script still working well for you?

Reply
0 Kudos
wreedctd
Enthusiast
Enthusiast

I am curious also.

Reply
0 Kudos
Nodnarb
Enthusiast
Enthusiast

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)"

Reply
0 Kudos
VirtuxpertsLLC
Contributor
Contributor

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

Reply
0 Kudos
chenerson
Contributor
Contributor

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

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

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

Reply
0 Kudos
ScubaIT
Contributor
Contributor

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.

Reply
0 Kudos
MKUMAR2
Contributor
Contributor

Hello 

DO you have any updated script that can automate windows template patching in vCenter 7.xx ?

Reply
0 Kudos
Xenophon1
Contributor
Contributor

Am I the only one that I got stuck a lot earlier?

When getting to: "Set-Template -Template W2K12Template -ToVM -Confirm:$false -RunAsync"

I get the below error:

 

Set-Template : 7/19/2022 5:25:52 PM Set-Template Object reference not set to an instance of an object.
At line:1 char:1
+ Set-Template -Template $TeplateVMName -ToVM -Confirm:$false –RunAsync
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (W10-tmpl-test:TemplateImpl) [Set-Template], ViError
+ FullyQualifiedErrorId : Client20_VMServiceImpl_ConvertTemplateToVm_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.SetTemplate

 

or

 

PS C:\Scripts> Set-Template -Template W10-tmpl-test -ToVM -Confirm:$false -RunAsync
Set-Template : 7/19/2022 5:29:52 PM Set-Template Object reference not set to an instance of an object.
At line:1 char:1
+ Set-Template -Template W10-tmpl-test -ToVM -Confirm:$false -RunAsync
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (W10-tmpl-test:TemplateImpl) [Set-Template], ViError
+ FullyQualifiedErrorId : Client20_VMServiceImpl_ConvertTemplateToVm_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.SetTemplate

==============================

Any idea on this?

Reply
0 Kudos