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.
$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
For the Update-Tools you include a timeout.
Something like this for example.
$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
$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
For the Update-Tools you include a timeout.
Something like this for example.
$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
$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
I will give a try and update
while((New-TimeSpan -Start $start -End (Get-Data)).TotalSeconds -lt $timeoutSeconds -or
Its Get-Date right?
Yes, corrected.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks Its working