vin01
Expert
Expert

automate template patching

Jump to solution

Hi LucD

With your help I have completed the below script. Thanks for support.

The script needs few improvements which I noticed when running on multiple vcenters separately.I am trying to reduce errors if I run on multiple environments.

1.On few vms Update-Tools will never completes and the whole script will struck on that line. However I can see vmware tools are in running state but still update will not succeed. Suspected issue inside the guest os but  if I do manually it installed without any issue.

So is there anyway to keep a wait time for 30mins and if still update-tools is not completed then stop that operation and Dismount-Tools the tools and proceed with next lines.

2.with few vms Stop-VMGuest is will not succeed with first attempt.(Not the same vms where Update-Tools failed)

For example in the below output for one vm. The Stop-VMGuest operation issued from script is failed but when I do a guest shutdown from the vcenter it succeeded.

So my thought is to include Stop-VMGuest  3 times with a wait time of 5mins. Like  Stop-VMGuest and wait for 5mins and if the 1st operation fails then try again stop-vmguest operation and if all 3 attempts failed then do stop-vm.

pastedImage_5.png

$CurrentDate = Get-Date -Format 'MM-dd-yyyy_hh-mm-ss'

Start-Transcript -Path "C:\My Data\Notepad++\$($CurrentDate)logfile.txt" -NoClobber -Force -Confirm:$false

$script = @'

$finalresult=@()

$ErrorActionPreference = "SilentlyContinue"

If ($Error) {

$Error.Clear()

}

$Today = Get-Date

$UpdateCollection = New-Object -ComObject Microsoft.Update.UpdateColl

$Searcher = New-Object -ComObject Microsoft.Update.Searcher

$Session = New-Object -ComObject Microsoft.Update.Session

$Result = $Searcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")

If ($Result.Updates.Count -EQ 0) {

$finalresult+= "There are no applicable updates for this computer."

}

Else {

For ($Counter = 0; $Counter -LT $Result.Updates.Count; $Counter++) {

$DisplayCount = $Counter + 1

    $Update = $Result.Updates.Item($Counter)

$UpdateTitle = $Update.Title

}

$Counter = 0

$DisplayCount = 0

$Downloader = $Session.CreateUpdateDownloader()

$UpdatesList = $Result.Updates

For ($Counter = 0; $Counter -LT $Result.Updates.Count; $Counter++) {

$UpdateCollection.Add($UpdatesList.Item($Counter)) | Out-Null

$ShowThis = $UpdatesList.Item($Counter).Title

$DisplayCount = $Counter + 1

$Downloader.Updates = $UpdateCollection

$Track = $Downloader.Download()

If (($Track.HResult -EQ 0) -AND ($Track.ResultCode -EQ 2)) {

$finalresult+="Download Status:SUCCESS"

}

Else {

$finalresult+="Download Status: FAILED With Error -- $Error()"

$Error.Clear()

}

}

$Counter = 0

$DisplayCount = 0

$Installer = New-Object -ComObject Microsoft.Update.Installer

For ($Counter = 0; $Counter -LT $UpdateCollection.Count; $Counter++) {

$Track = $Null

$DisplayCount = $Counter + 1

$WriteThis = $UpdateCollection.Item($Counter).Title

$Installer.Updates = $UpdateCollection

Try {

$Track = $Installer.Install()

$finalresult+="Update Installation Status:SUCCESS"

}

Catch {

[System.Exception]

$finalresult+= "Update Installation Status: FAILED With Error -- $Error()"

$Error.Clear()

}

}

}

$finalresult -join ','

'@

$tasks = @()

$alltemplates=Get-Datacenter WTR | Get-Template |?{$_.ExtensionData.Guest.GuestFullName -match 'windows' -and $_.ExtensionData.runtime.connectionstate -eq 'connected'} |select -First 5  |Select-Object @{N='Name';E={$_.Name}},@{N="Portgroup";E={((Get-View -Id $_.ExtensionData.Network).name)}},@{N="vCenter";E={([System.Net.Dns]::GetHostEntry($_.Uid.Split(“:”)[0].Split(“@”)[1])).HostName}}

$alltemplates|Export-Csv -Path "C:\My Data\CSV Output\$($CurrentDate)-first5templateswindows.csv" -NoTypeInformation -NoClobber

foreach($singletemplate in $alltemplates){

Set-Template -Template $singletemplate.Name -ToVM -Confirm:$false |fl

$templatevm= Get-VM $singletemplate.Name

$dhcpportgroup=Get-VirtualPortGroup -VMHost $templatevm.VMHost |?{$_.ExtensionData.config.DefaultPortConfig.Vlan.VlanId -eq '2067'}

Get-NetworkAdapter -VM $templatevm.Name |Set-NetworkAdapter -Portgroup $dhcpportgroup -Confirm:$false |fl

Start-VM -VM $templatevm.Name -Confirm:$false |fl

while($templatevm.ExtensionData.Guest.GuestOperationsReady -ne "True"){

Start-Sleep -Seconds 3

$templatevm.ExtensionData.UpdateViewData("Guest.GuestOperationsReady")

}

if($templatevm.ExtensionData.guest.toolsversionstatus -eq 'guestToolsNeedUpgrade'){

Update-Tools -VM $templatevm.Name -NoReboot

}

while($templatevm.ExtensionData.Guest.GuestOperationsReady -ne "True"){

Start-Sleep -Seconds 3

$templatevm.ExtensionData.UpdateViewData("Guest.GuestOperationsReady")

}

$sInvoke = @{

VM            = $templatevm.Name

GuestUser     = 'administrator'

GuestPassword = ''

ScriptText    = $script

ScriptType    = 'Powershell'

RunAsync      = $true

Confirm       = $false

    }

    $tasks += @{

        VM = $templatevm.Name

        Task = Invoke-VMScript @sInvoke

    }

}

while($tasks.Task.State -contains 'Running'){

    sleep 2

}

$report=@()

$csvFiles = @()

foreach ($task in $tasks) {

$vm=Get-VM -Name $task.VM

Stop-VMGuest -VM $vm.Name -Confirm:$false

while($vm.ExtensionData.Runtime.PowerState -ne 'poweredOff'){

    Start-Sleep -Seconds 1

    $vm.ExtensionData.UpdateViewData("Runtime.Powerstate")

}

Start-VM -VM $vm.Name -Confirm:$false

$vm.ExtensionData.UpdateViewData("Guest.GuestOperationsReady")

while($vm.ExtensionData.Guest.GuestOperationsReady -ne "True"){

    Start-Sleep -Seconds 1

    $vm.ExtensionData.UpdateViewData("Guest.GuestOperationsReady")

}

Stop-VMGuest -VM $vm.Name -Confirm:$false

$vm.ExtensionData.UpdateViewData("Runtime.PowerState")

while($vm.ExtensionData.Runtime.PowerState -eq 'poweredOn'){

    Start-Sleep -Seconds 1

    $vm.ExtensionData.UpdateViewData("Runtime.Powerstate")

}

$report+= $task | Select @{N='VM';E={$_.VM}},

@{N='State';E={$_.Task.State}},

@{N='Error';E={$_.Task.TerminatingError.Message}},

@{N ='Result'; E={$_.Task.Result.ScriptOutput.Split("`n") |Where-Object { $_ -ne '' } | %{$_.Trim("`r`n")}}}

}

$filename = "C:\AllTemplatepatchstatusreport.csv as on dated $($CurrentDate).csv"

$csvFiles += $filename

$report |Export-Csv -Path $filename -NoTypeInformation -NoClobber -UseCulture

Send-MailMessage -From "" -To "" -Subject "Script POC Template Patching" ` -Body "The attachment contains templates patching status" ` -Attachments $csvFiles -SmtpServer 'internalmail.sweng.ncr.com'

$alltemplates |ForEach-Object -Process {

Get-NetworkAdapter -VM $_.name |Set-NetworkAdapter -NetworkName $_.Portgroup -Confirm:$false

Set-VM -VM $_.Name -ToTemplate -Confirm:$false

}

Stop-Transcript

Regards Vineeth.K
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership

For the Update-Tools you include a timeout.

Something like this for example.

if($templatevm.ExtensionData.guest.toolsversionstatus -eq 'guestToolsNeedUpgrade'){

    $timeoutSeconds = 1800

    $start = Get-Date

    $task = Get-View -Id (Update-Tools -VM $templatevm.Name -NoReboot  -RunAsync).Id

    while((New-TimeSpan -Start $start -End (Get-Date)).TotalSeconds -lt $timeoutSeconds -or

            $task.Info.State -eq [VMware.Vim.TaskInfoState]::running -or

            $task.Info.State -eq [VMware.Vim.TaskInfoState]::queued){

        Sleep 5

        $task.UpdateViewData()

    }

    if($task.Info.State -eq [VMware.Vim.TaskInfoState]::running){

        $task.CancelTask()

    }

    elseif($task.Info.State -eq [VMware.Vim.TaskInfoState]::error){

        Write-Error "Update Tools failed"

    }

}

For stopping the VM, you could do something like this

$maxCount = 3

$count = 0

while($count -lt $maxCount -and $vm.PowerState -ne 'PoweredOff' ){

    Stop-VMGuest -VM $vm -Confirm:$false

    $count++

    Sleep 300

    $vm = Get-VM -Name $vm.Name

}

if($vm.PowerState -ne 'PoweredOff'){

    Stop-VM -VM $vm -Confirm:$false

}


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

View solution in original post

5 Replies
LucD
Leadership
Leadership

For the Update-Tools you include a timeout.

Something like this for example.

if($templatevm.ExtensionData.guest.toolsversionstatus -eq 'guestToolsNeedUpgrade'){

    $timeoutSeconds = 1800

    $start = Get-Date

    $task = Get-View -Id (Update-Tools -VM $templatevm.Name -NoReboot  -RunAsync).Id

    while((New-TimeSpan -Start $start -End (Get-Date)).TotalSeconds -lt $timeoutSeconds -or

            $task.Info.State -eq [VMware.Vim.TaskInfoState]::running -or

            $task.Info.State -eq [VMware.Vim.TaskInfoState]::queued){

        Sleep 5

        $task.UpdateViewData()

    }

    if($task.Info.State -eq [VMware.Vim.TaskInfoState]::running){

        $task.CancelTask()

    }

    elseif($task.Info.State -eq [VMware.Vim.TaskInfoState]::error){

        Write-Error "Update Tools failed"

    }

}

For stopping the VM, you could do something like this

$maxCount = 3

$count = 0

while($count -lt $maxCount -and $vm.PowerState -ne 'PoweredOff' ){

    Stop-VMGuest -VM $vm -Confirm:$false

    $count++

    Sleep 300

    $vm = Get-VM -Name $vm.Name

}

if($vm.PowerState -ne 'PoweredOff'){

    Stop-VM -VM $vm -Confirm:$false

}


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

View solution in original post

vin01
Expert
Expert

I will give a try and update

Regards Vineeth.K
0 Kudos
vin01
Expert
Expert

while((New-TimeSpan -Start $start -End (Get-Data)).TotalSeconds -lt $timeoutSeconds -or

Its Get-Date right?

Regards Vineeth.K
0 Kudos
LucD
Leadership
Leadership

Yes, corrected.


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

0 Kudos
vin01
Expert
Expert

Thanks Its working

Regards Vineeth.K
0 Kudos