From 14256a32a87ee2bb607feba0bed4e3d6da3f6d77 Mon Sep 17 00:00:00 2001 From: daoyuanw Date: Tue, 14 Nov 2017 14:43:47 +0800 Subject: [PATCH] Add VMToolsManagment for VMTools upgrade, guest info query .etc --- .../VMToolsManagement/VMToolsManagement.psm1 | 1149 +++++++++++++++++ 1 file changed, 1149 insertions(+) create mode 100644 Modules/VMToolsManagement/VMToolsManagement.psm1 diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 new file mode 100644 index 0000000..bbfdf5e --- /dev/null +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -0,0 +1,1149 @@ +# Script Module : VMToolsManagement +# Version : 1.0 + +# Copyright © 2017 VMware, Inc. All Rights Reserved. + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +New-VIProperty -Name ToolsBuildNumber -Object VirtualMachine -Value { + Param ($VM) + + foreach ($item in $VM.ExtensionData.Config.ExtraConfig.GetEnumerator()) { + if ($item.Key -eq "guestinfo.vmtools.buildNumber") { + $toolsBuildNumber = $item.value + break + } + } + + return $toolsBuildNumber +} -BasedOnExtensionProperty 'Config.ExtraConfig' -Force | Out-Null + +Function Get-VMToolsInfo { +<# +.SYNOPSIS + This cmdlet retrieves the VMTools info of specified virtual machines. + +.DESCRIPTION + This cmdlet retrieves the VMTools version and build number info of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the VMTools info of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsInfo + + Retrieves VMTools info of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*rhel*" | Get-VMToolsInfo + + Name ToolsVersion ToolsBuildNumber + ------ ------------ ---------------- + 111394-RHEL-6.8-0 10.2.0 6090153 + 111394-RHEL-6.8-1 9.0.15 + 111393-RHEL-Server-7.2 10.1.0 + + Retrieves VMTools info of virtual machines with name containing "rhel". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsInfo + + Retrieves VMTools info from virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsInfo + + Retrieves VMTools info of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + The tools build number is not supported in VMTools before 10.2.0 + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + Get-VM $VM | Select Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber + } +} + +Function Get-VMToolsInstallLastError { +<# +.SYNOPSIS + This cmdlet retrieves the error code of last VMTools installation. + +.DESCRIPTION + This cmdlet retrieves the error code of last VMTools installation on specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the error code of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Get-VMToolsInstallLastError + + Name LastToolsInstallErrCode + ------ ----------------------- + 111167-Win-7-Sp1-64-Enterprise-NoTools + 111323-Windows-8.1U3-32-Enterprise-Tools + 111305-Windows-Server2016 1641 + + Retrieves the last VMTools installation error code of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + $result = @() + foreach ($_ in $VM) { + $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | where {$_.Key -eq "guestinfo.toolsInstallErrCode"} + + $info = New-Object PSObject + $info | Add-Member -type NoteProperty -name VmName -value $_.Name + $info | Add-Member -type NoteProperty -name LastToolsInstallErrCode -value $errorCodeInfo.Value + + $result += $info + } + $result + } +} + +Function Get-VMToolsGuestInfo { +<# +.SYNOPSIS + This cmdlet retrieves the guest info of specified virtual machines. + +.DESCRIPTION + This cmdlet retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, + ToolsInstallType and GuestFamily of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the guest info of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsGuestInfo + + Retrieves guest info of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Get-VMToolsGuestInfo + + Name : 111323-Windows-8.1U3-32-Enterprise-Tools + HostName : win81u3 + IP : + ToolsStatus : toolsNotRunning + ToolsVersion : 10.2.0 + ToolsInstallType : guestToolsTypeMSI + GuestFamily : windowsGuest + VMPowerState : PoweredOff + + Name : 111305-Windows-Server2016 + HostName : WIN-ULETOOSSB7U + IP : 10.160.59.99 + ToolsStatus : toolsOk + ToolsVersion : 10.1.0 + ToolsInstallType : guestToolsTypeMSI + GuestFamily : windowsGuest + VMPowerState : PoweredOn + + Retrieves guest info of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsGuestInfo + + Retrieves guest info of virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsGuestInfo + + Retrieves guest info of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + Get-VM $VM | Select Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, + @{Name="IP"; Expression={$_.Guest.ExtensionData.IpAddress}}, + @{Name="ToolsStatus"; Expression={$_.Guest.ExtensionData.ToolsStatus}}, + @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, + @{Name="ToolsInstallType"; Expression={$_.Guest.ExtensionData.ToolsInstallType}}, + @{Name="GuestFamily"; Expression={$_.Guest.GuestFamily}}, + PowerState + } +} + +Function Get-VMByToolsInfo { +<# +.SYNOPSIS + This cmdlet retrieves the virtual machines with specified VMTools info. + +.DESCRIPTION + This cmdlet retrieves the virtual machines with specified VMTools version, + running status or version status. + +.PARAMETER VM + Specifies the virtual machines which you want to query VMTools status of. + +.PARAMETER ToolsVersion + Specifies the VMTools version. + +.PARAMETER ToolsRunningStatus + Specifies the VMTools running status. + +.PARAMETER ToolsVersionStatus + Specifies the VMTools version status. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMByToolsInfo + + Retrieves the virtual machines with VMTools not running in vCetner Server $VCServer. + +.EXAMPLE + C:\PS> Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsNotRunning + + Name PowerState Num CPUs MemoryGB + ---- ---------- -------- -------- + 111394-RHEL-6.8-1 PoweredOff 4 2.000 + + Retrieves all the virtual machines with VMTools not running. + +.EXAMPLE + C:\PS> Get-VM | Get-VMByToolsInfo -ToolsVersion '10.1.0' + + Name PowerState Num CPUs MemoryGB + ---- ---------- -------- -------- + 111394-RHEL-6.8-1 PoweredOff 4 2.000 + + Retrieves the virtual machines with VMTools version 10.1.0. + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMByToolsInfo -ToolsVersionStatus guestToolsNeedUpgrade + + Retrieves the virtual machines with VMTools that need to upgrade in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsRunning -ToolsVersionStatus guestToolsNeedUpgrade + + Retrieves the virtual machines with VMTools that need to upgrade on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587)(build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false)] + [String] $ToolsVersion, + + [Parameter(Mandatory=$false)] + [ValidateSet("guestToolsRunning", + "guestToolsNotRunning", + "guestToolsExecutingScripts")] + [String] $ToolsRunningStatus, + + [Parameter(Mandatory=$false)] + [ValidateSet("guestToolsNotInstalled", + "guestToolsNeedUpgrade", + "guestToolsCurrent", + "guestToolsUnmanaged")] + [String] $ToolsVersionStatus + ) + + Process { + $vmList = Get-VM $VM + + if ((-not $ToolsVersion) -and (-not $ToolsRunningStatus) -and (-not $ToolsVersionStatus)) { + Throw "Please specify at lease one parameter: ToolsVersion, ToolsRunningStatus or ToolsVersionStatus" + } + + if ($ToolsVersion) { + $vmList = $vmList | Where {$_.Guest.ToolsVersion -like $ToolsVersion} + } + + if ($ToolsRunningStatus) { + $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} + } + + if ($ToolsVersionStatus) { + $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} + } + + $vmList + } +} + +Function Set-VMToolsUpgradePolicy { +<# +.SYNOPSIS + This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle". + +.DESCRIPTION + This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle" of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of all virtual machines in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + Begin { + $UpgradePolicy = "upgradeAtPowerCycle" + $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo + $vmConfigSpec.Tools.ToolsUpgradePolicy = $UpgradePolicy + } + + Process { + foreach ($_ in $VM) { + # Get current setting + $vmView = Get-View $_ -Property Config.Tools.ToolsUpgradePolicy + # Change if VMTools upgrade policy is not "upgradeAtPowerCycle" + if ($vmView.Config.Tools.ToolsUpgradePolicy -ne $UpgradePolicy) { + Write-Verbose "Applying 'upgradeAtPowerCycle' setting to $($_.Name)..." + $vmView.ReconfigVM($vmConfigSpec) + } + } + } +} + +Function Invoke-VMToolsListProcessInVM { +<# +.Synopsis + This cmdlet lists the processes in the virtual machine. + +.Description + This cmdlet lists the running processes in the virtual machine. + +.PARAMETER VM + Specifies the virtual machine which you want to list the processes of. + +.Parameter GuestUser + Specifies the user name you want to use for authenticating with the guest OS. + +.Parameter GuestPassword + Specifies the password you want to use for authenticating with the guest OS. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleVM = get-vm "MyVMName" + C:\PS> Invoke-VMToolsListProcessInVM -VM $SampleVM -GuestUser -GuestPassword + + ScriptOutput + ----------------------------------------------------------------------------------------------------------------------- + | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + | root 1 0.0 0.0 19360 1556 ? Ss Jul20 0:02 /sbin/init + | root 2 0.0 0.0 0 0 ? S Jul20 0:00 [kthreadd] + | root 3 0.0 0.0 0 0 ? S Jul20 0:06 [migration/0] + | root 4 0.0 0.0 0 0 ? S Jul20 0:00 [ksoftirqd/0] + | root 5 0.0 0.0 0 0 ? S Jul20 0:00 [stopper/0] + ...... + + List the processes in the "MyVMName" VM. + +.NOTES + This cmdlet lists processes in the guest OS of virtual machine. + A VMTools should already be running in the guest OS. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 + Guest OS : RHEL6.8, Windows7 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [String] $GuestUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $GuestPassword + ) + + Process { + $vmView = Get-VM $VM | Get-View -Property Guest + if ($vmView.Guest.State -eq 'NotRunning') { + Write-Error "$VM is Not Running, unable to list the processes!" + return + } + + if ($vmView.Guest.GuestFamily -match 'windows') { + $command = 'Get-Process' + } elseif ($vmView.Guest.GuestFamily -match 'linux') { + $command = 'ps aux' + } else { + $command = 'ps' + } + + Invoke-VMScript -VM $VM -ScriptText $command -GuestUser $GuestUser -GuestPassword $GuestPassword + } +} + +Function Update-VMToolsImageLocation { +<# +.Synopsis + This cmdlet updates the link /productLocker in ESXi host. + +.Description + This cmdlet updates the link /productLocker in ESXi host directly to avoid host reboot. + +.Parameter VMHost + Specifies the ESXi host on which you want to update the /productLocker link. + +.Parameter HostUser + Specifies the user name you want to use for authenticating with the ESXi host. + +.Parameter HostPassword + Specifies the password you want to use for authenticating with the ESXi host. + +.Parameter ImageLocation + Specifies the new image location where you want /producterLocker to link. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleHost = get-vmhost + C:\PS> Update-VMToolsImageLocation -VmHost $SampleHost -HostUser 'root' -HostPassword -ImageLocation '/locker/packages/6.5.0/' + + Update link /productLocker successfully. + + Update the link /producterLocker on $SampleHost to point to '/locker/packages/6.5.0/'. + +.NOTES + This cmdlet connects to ESXi host to execute shell command directly. + Make sure the SSH service on ESXi host is enabled, and a SSH library(Posh-SSH or SSH-Sessions etc.) + for powershell is already installed on client where you call This cmdlet. + You can instal Posh-SSH by executing: + iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev") + For SSH-Sessions installation and usage, please refer to + http://www.powershelladmin.com/wiki/SSH_from_PowerShell_using_the_SSH.NET_library + + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost] $VMHost, + + [Parameter(Mandatory=$true)] + [String] $HostUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $HostPassword, + + [Parameter(Mandatory=$true)] + [String] $ImageLocation + ) + + Process { + if (-not (Get-Command New-SSHSession)) { + Throw "This cmdlet depends on SSH library. Please ensure a SSH library is already installed!" + } + + $password = new-object System.Security.SecureString + if ($HostPassword) { + $password = ConvertTo-SecureString -AsPlainText $HostPassword -Force + } + + $crendential = New-Object System.Management.Automation.PSCredential -ArgumentList $HostUser, $password + $sshSession = New-SSHSession -ComputerName $VMHost -Credential $crendential -Force + + $result = Invoke-SshCommand -SSHSession $sshSession -Command "readlink /productLocker" -EnsureConnection:$false + Write-Verbose "The link /productLocker before change: $($result.Output)" + + $command = "rm /productLocker && ln -s $ImageLocation /productLocker" + Write-Verbose "Updating /productLocker on $VMHost..." + $result = Invoke-SshCommand -SSHSession $sshSession -Command $command -EnsureConnection:$false + if ($result.ExitStatus -eq 0) { + Write-Host "Update link /productLocker successfully." -ForegroundColor Green + } else { + Write-Error "Failed to update link /productLocker: $($result.Error)" + } + + $result = Invoke-SshCommand -SSHSession $sshSession -Command "readlink /productLocker" -EnsureConnection:$false + Write-Verbose "The link /productLocker after change: $($result.Output)" + } +} + +Function Update-VMToolsConfInVM { +<# +.Synopsis + This cmdlet updates the tools.conf content in guest OS. + +.Description + This cmdlet copies the tools.conf in gueset OS of virtual machine to localhost, + then updates it locally by setting "vmtoolsd.level = info" and copies it back to the guest OS. + +.PARAMETER VM + Specifies the virtual machine to update. + +.Parameter GuestUser + Specifies the user name you want to use for authenticating with the guest OS. + +.Parameter GuestPassword + Specifies the password you want to use for authenticating with the guest OS. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleVM = get-vm "MyVMName" + C:\PS> Update-VMToolsConfInVM -VM $SampleVM -GuestUser -GuestPassword + + Update tools.conf of 111394-RHEL-6.8-0 successfully. + + Updates the tools.conf in $SampleVM, changes the vmtoolsd log level to info ("vmtoolsd.level = info") for example. + +.NOTES + This cmdlet updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + + [Parameter(Mandatory=$true)] + [String] $GuestUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $GuestPassword + ) + + Process { + $vmGuest = Get-VMGuest $VM + $OsName = $vmGuest.OSFullName + $guestToolsConfFile = "" + $localToolsConfFile = ".\tools.conf" + + # Determine the tools.conf path in guest OS + if (($OsName -match "Linux") ` + -or ($OsName -match "FreeBSD") ` + -or ($OsName -match "Solaris")) { + $guestToolsConfFile = '/etc/vmware-tools/tools.conf' + } elseif (($OsName -match "Windows Server 2003") ` + -or ($OsName -match "Windows Server 2000") ` + -or ($OsName -match "Windows XP")) { + $guestToolsConfFile = 'C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf' + } elseif ($OsName -match "Windows") { + $guestToolsConfFile = 'C:\ProgramData\VMware\VMware Tools\tools.conf' + } elseif ($OsName -match "Mac") { + $guestToolsConfFile = '/Library/Application Support/VMware Tools/tools.conf' + } else { + Throw "Unknown tools.conf path on OS: $OsName" + } + + # Get the tools.conf from guest OS to localhost, ignore the error if tools.conf was not found in guest OS + Write-Verbose "Copy tools.conf from $VM to localhost..." + $lastError = $Error[0] + Copy-VMGuestFile -Source $guestToolsConfFile -Destination $localToolsConfFile -VM $VM -GuestToLocal ` + -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:SilentlyContinue + + # The tools.conf doesn't exist in guest OS, create an empty one locally + if (($Error[0] -ne $lastError) -and ($Error[0] -notmatch 'tools.conf was not found')) { + Write-Error "Failed to copy tools.conf from $VM" + return + } elseif (-not (Test-Path $localToolsConfFile)) { + Set-Content $localToolsConfFile $null + } + + ############################################################################# + # Updates tools.conf by setting vmtoolsd.level = info, just for example. + ############################################################################# + $confContent = Get-Content $localToolsConfFile + $updatedContent = "vmtoolsd.level = info" + + Write-Verbose "Editing tools.conf (set 'vmtoolsd.level = info' for example)..." + if ($confContent -match "vmtoolsd\.level") { + $confContent -replace "vmtoolsd\.level.*", $updatedContent | Set-Content $localToolsConfFile + } elseif ($confContent -match "logging") { + Add-Content $localToolsConfFile $updatedContent + } else { + Add-Content $localToolsConfFile "[logging]`nlog=true" + Add-Content $localToolsConfFile $updatedContent + } + + # Upload the changed tools.conf to guest OS + try { + Write-Verbose "Copy local tools.conf to $VM..." + Copy-VMGuestFile -Source $localToolsConfFile -Destination $guestToolsConfFile -VM $VM -LocalToGuest ` + -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:Stop + } catch { + Write-Error "Failed to update tools.conf of $VM" + return + } + Write-Host "The tools.conf updated in $VM successfully." -ForegroundColor Green + } +} + +Function Invoke-VMToolsVIBInstall { +<# +.SYNOPSIS + This cmdlet installs VMTool VIB in ESXi hosts. + +.DESCRIPTION + This cmdlet installs VMTool VIB in specified ESXi hosts. + +.PARAMETER VMHost + Specifies the ESXi hosts which you want to install VMTool VIB in. + +.PARAMETER ToolsVibUrl + Specifies the URL of VMTools VIB package which you want to install in ESXi hosts. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password . + C:\PS> $viBurl = "http:///VMware_locker_tools-light_6.5.0-10.2.0.6085460.vib" + C:\PS> Get-VMHost -Server $VCServer | Invoke-VMToolsVIBInstall -ToolsVibUrl $viBurl + + Install VMTool VIB in $VCServer. + +.EXAMPLE + C:\PS> Invoke-VMToolsVIBInstall -VMHost "MyESXiHostName" -ToolsVibUrl $viBurl + + Installs VMTools VIB package successfully. + + Installs VMTool VIB in the "MyESXiHostName" ESXi host. + +.EXAMPLE + C:\PS> Get-VMHost -Location "MyClusterName" | Invoke-VMToolsVIBInstall -ToolsVibUrl $vib + + Installs VMTool VIB in ESXi host of the "MyClusterName" cluster. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost[]] $VMHost, + + [Parameter(Mandatory=$true)] + [String] $ToolsVibUrl + ) + + Process { + foreach ($_ in $VMHost) { + $esxcli = Get-EsxCLI -VMHost $_ -V2 + + $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + Write-Verbose "Existing tools VIB on $_ before installing: $($result.Name)_$($result.Version)" + + # Install VIBs + Write-Verbose "Installing $ToolsVibUrl on $($_.Name)..." + $Error.Clear() + $cliArgs = $esxcli.software.vib.install.CreateArgs() + $cliArgs.viburl = $ToolsVibUrl + $cliArgs.nosigcheck = $true + $cliArgs.force = $true + $result = $esxcli.software.vib.install.Invoke($cliArgs) + if ($Error) { + Write-Error "Failed to install VMTools VIB package!" + } else { + Write-Verbose $result.Message + $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + Write-Verbose "Tools VIB on $_ after installing: $($result.Name)_$($result.Version)" + Write-Host "VMTools VIB package installed on $_ successfully." -ForegroundColor Green + } + } + } +} + +Function Invoke-VMToolsUpgradeInVMs { +<# +.SYNOPSIS + This cmdlet upgrades VMTools to the version bundled by ESXi host. + +.DESCRIPTION + This cmdlet upgrades VMTools of specified virtual machines to the version + bundled by ESXi host. You can also specify the number of virtual machines + to upgrade in parallel. + +.PARAMETER VM + Specifies the virtual machines you want to upgrade VMTools of. + +.PARAMETER GuestOSType + Specifies the guest OS type of the virtual machines. + +.PARAMETER VersionToUpgrade + Specifies the current running VMTools version of virtual machines. + +.PARAMETER MaxParallelUpgrades + Specifies the max virtual machine numbers to upgrade in parallel. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 + + Upgrades VMTools of all virtual machines in the $VCServer vCetner Server, 5 at a time in parallel. + +.EXAMPLE + C:\PS> Get-VM | Invoke-VMToolsUpgradeInVMs -GuestOSType windows -MaxParallelUpgrades 1 | ft -Autosize + + Upgrade result: + + VmName UpgradeResult ToolsVersion ToolsVersionStatus TotalSeconds Message + ------ ------------- ------------ ------------------ ------------ ------- + 111167-Win-7-Sp1-64-Enterprise-NoTools-2 Completed 10.1.0 guestToolsCurrent 102 Upgrade VMTools successfully + 111393-RHEL-Server-7.2 Skipped 10.0.0 guestToolsNeedUpgrade 0 Guest OS type does not meet condtion 'windows' + 111305-Windows-Server2016 Completed 10.1.0 guestToolsCurrent 144 Upgrade VMTools successfully + + Upgrades VMTools of windows virtual machines one by one. + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 2 | ft -Autosize + + Upgrade result: + + VmName UpgradeResult ToolsVersion ToolsVersionStatus TotalSeconds Message + ------ ------------- ------------ ------------------ ------------ ------- + 111167-Win-7-Sp1-64-Enterprise-NoTools-2 Failed 10.0.0 guestToolsNeedUpgrade 0 The required VMware Tools ISO image does not exist or is inaccessible. + 111393-RHEL-Server-7.2 Completed 10.1.0 guestToolsCurrent 100 Upgrade VMTools successfully + + Upgrades VMTools of virtual machines in the "MyClusterName" cluster, 2 at a time. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 + + Upgrades VMTools of virtual machines on the "MyESXiHostName" ESXi host, 5 at a time. + +.NOTES + This cmdlet assumes an old VMTools is already running in the virtual machine. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false)] + [ValidateSet("linux", "windows")] + [String] $GuestOSType, + + [Parameter(Mandatory=$false)] + [String] $VersionToUpgrade, + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 5)] + [Int] $MaxParallelUpgrades = 1 + ) + + Begin { + $RunspacePool = [runspacefactory]::CreateRunspacePool( + 1, #Min Runspaces + $MaxParallelUpgrades #Max Runspaces + ) + + $RunspacePool.Open() + + $jobs = New-Object System.Collections.ArrayList + $result = @() + } + + Process { + foreach ($_ in $VM) { + $vmView = Get-View $_ -Property Guest + $toolsVersion = $_.Guest.ToolsVersion + $toolsVersionStatus = $vmView.Guest.ToolsVersionStatus + + # Skip if VMTools doesn't need to upgrade + if ($toolsVersionStatus -ne "guestToolsNeedUpgrade") { + Write-Host "No VMTools need to upgrade!`nVM: '$_', ToolsVersionStatus: '$toolsVersionStatus'" + $result += [pscustomobject]@{ + VmName = $_.Name + UpgradeResult = "Skipped" + ToolsVersion = $toolsVersion + ToolsVersionStatus = $toolsVersionStatus + TotalSeconds = 0 + Message = "No VMTools need to upgrade!" + } + continue + } + + # Skip if current VMTools doesn't meet to specified version + if ($VersionToUpgrade -and ($toolsVersion -notmatch $VersionToUpgrade)) { + Write-Host "Current ToolsVersion in $_ is: $toolsVersion,"` + "does not meet condtion `'$VersionToUpgrade`', skipping it..." -ForegroundColor Yellow + $result += [pscustomobject]@{ + VmName = $_.Name + UpgradeResult = "Skipped" + ToolsVersion = $toolsVersion + ToolsVersionStatus = $toolsVersionStatus + TotalSeconds = 0 + Message = "Current VMTools version does not meet condtion `'$VersionToUpgrade`'" + } + continue + } + + # Create a thread to upgrade VMTools for each virtual machine + $PSThread = [powershell]::Create() + $PSThread.RunspacePool = $RunspacePool + + # Script content to upgrade VMTools + $PSThread.AddScript({ + Param ( + $vcServer, + $session, + $vmId, + $GuestOSType + ) + # Load PowerCLI module and connect to VCServer, as child thread environment is independent with parent + if(-not $global:DefaultVIServer) { + $moduleName = "vmware.vimautomation.core" + if(-not (Get-Module | Where {$_.name -eq $moduleName})) { + try { + Import-Module $moduleName -ErrorAction SilentlyContinue | Out-Null + } + catch { + Throw "Failed to load PowerCLI module('$moduleName')" + } + } + try { + $server = Connect-VIServer -Server $vcserver -session $session -Force + } + catch { + Throw "Failed to connect to VI server: $vcserver" + } + } + + # Retrieves VM + $vm = Get-VM -Id $vmId + + $ThreadID = [appdomain]::GetCurrentThreadId() + Write-Verbose “Thread[$ThreadID]: Beginning Update-Tools for $vm” + + if ($vm.PowerState -ne 'PoweredOn') { + Write-Host "Powering on VM: $vm..." + Start-VM $vm | Out-Null + $vm = Get-VM $vm + } + + # Wait for OS and VMTools starting up + $timeOut = 60*10 #seconds + $refreshInterval = 5 #seconds + $count = $timeOut/$refreshInterval + while (($vm.Guest.ExtensionData.ToolsRunningStatus -ne "guestToolsRunning") ` + -or (-not $vm.Guest.GuestFamily)) { + $count -= 1 + if ($count -lt 0) { + Write-Error "VMTools doesn't start up in $timeOut seconds, please check if $vm is hung!" + break + } + Write-Verbose "Waiting for VMTools running in $vm before upgrading..." + Start-Sleep -Seconds $refreshInterval + } + + # Skip if virtual machine doesn't meet specified guest OS type + if ($GuestOSType -and ($vm.Guest.GuestFamily -notmatch $GuestOSType)) { + Write-Host "GuestFamily of $vm is: $($vm.Guest.GuestFamily),"` + "does not meet condition `'$GuestOSType`', skipping it..." -ForegroundColor Yellow + # upgrade result + [pscustomobject]@{ + VmName = $vm.Name + UpgradeResult = "Skipped" + ToolsVersion = $vm.Guest.ToolsVersion + ToolsVersionStatus = $vm.Guest.ExtensionData.ToolsVersionStatus + TotalSeconds = 0 + Message = "Guest OS type does not meet condtion `'$GuestOSType`'" + } + Disconnect-VIServer $server -Confirm:$false + return + } + + # Upgrade VMTools and check the tools version status + Write-Host "Upgrading VMTools for VM: $vm..." + $task = Update-Tools -VM $vm -RunAsync + $task | Wait-Task + $task = Get-Task -Id $task.Id + + if ($task.State -eq "Success") { + $upgradeResult = "Completed" + $message = "Upgrade VMTools successfully" + Write-Host "Upgrade VMTools successfully for VM: $vm" -ForegroundColor Green + } else { + $upgradeResult = "Failed" + $message = $task.ExtensionData.Info.Error.LocalizedMessage + Write-Error "Failed to upgrade VMTools for VM: $vm" + } + $vm = Get-VM $vm + # Upgrade result to return + [pscustomobject]@{ + VmName = $vm.Name + UpgradeResult = $upgradeResult + ToolsVersion = $vm.Guest.ToolsVersion + ToolsVersionStatus = $vm.Guest.ExtensionData.ToolsVersionStatus + TotalSeconds = [math]::Floor(($task.FinishTime).Subtract($task.StartTime).TotalSeconds) + Message = $message + } + Write-Verbose “Thread[$ThreadID]: Ending Update-Tools for $vm” + }) | Out-Null + $vc = $Global:DefaultVIServer.ServiceUri.Host + $vcSession = $Global:DefaultVIServer.SessionSecret + $PSThread.AddArgument($vc).AddArgument($vcSession).AddArgument($_.Id).AddArgument($GuestOSType) | Out-Null + + # Start thread + $Handle = $PSThread.BeginInvoke() + $job = New-Object System.Object + $job | Add-Member -type NoteProperty -name Thread -value $PSThread + $job | Add-Member -type NoteProperty -name Handle -value $Handle + $jobs.Add($job) | Out-Null + + Write-Verbose (“Available Runspaces in RunspacePool: {0}” -f $RunspacePool.GetAvailableRunspaces()) + } + } + + End { + #Verify all threads completed + while (($jobs | Where {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + Start-Sleep -Seconds 5 + } + + $upgradeResult = $jobs | foreach { + $_.Thread.EndInvoke($_.Handle) + $_.Thread.Dispose() + } + $result += $upgradeResult + $result + + $RunspacePool.Close() + $RunspacePool.Dispose() + } +} + +Export-ModuleMember *-* \ No newline at end of file