Deploy Azure Resource Using Bicep template and PowerShell

In a previous post we went through deploying resource using ARM templates. I have been recently working on creating some new templates to be used for additional deployment and decided to use Bicep templates instead as it seem to an easier and more straight forward way of writing template files to deploy resources in Azure.

Bicep uses a simpler syntax than creating templates using JSON, the syntax is declarative and specifies which resources and resource properties you want to deploy.

Below is a comparison of a JSON and Bicep template file to create a storage account.

We can see that the bicep file is an easier format to read and create.

JSON Template
Bicep Template

To get started with Bicep we will first be installing the Bicep extension to Visual Studio Code so we can edit and modify Bicep templates.

The extension adds intellisense which makes it easier than looking up the full syntax for each resource.

To create a new template click on new file in VS code and select bicep as the language.

To create a template using intellisense either start typing the res-resource type or the resource type itself.

Click on the resource to pre populate the template.

The values can be hard code in the template file but this would require manual change each time the template is run.

We can add parameters to the template to make it more reusable. There are a few different types of parameters that can be used.

Below is a brief description of each type.

ParameterDescription
stringSingle line value
arrayAllow multiple values
intInteger value
boolRequired true or false
objectsAllows property types

Microsoft have a more in depth document on the different data types.

https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/data-types

The below is an example of a template with parameters set.

Once we have the template we need to install Azure PowerShell if not already installed and to install the Bicep tools, below is the document to install.

https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install#install-manually

To connect to Azure PowerShell use

Connect-AzAccount

Once connected we can use the New-AzResourceGroupDeployment to deploy the template and specify the parameters values. To test the deployment for errors without running an actual deployment we can use the -whatif parameter.

New-AzResourceGroupDeployment -ResourceGroupName ResourceGroup -TemplateFile pathtotempaltefile\BicepStorageTest.bicep -location regsion -storagename storageaccountname -storagetype Standard_LRS -WhatIf

Run the command and it should return any error if there is an issue or green if there is no issue.

Once the template comes back with no issues we can remove the -whatif and the storage account will be created.

To confirm the storage account has been created use the Get-AzStorageAccount

Using parameters in the Bicep template is fine when there are only a few that need to be called but for more complex deployment it will be better to use a parameters file and pre fill each value.

In the next post we will go through the process of using a template to create a VM and its network interface and will call a parameters files instead of call the parameters in PowerShell directly.

Azure VM Snapshot Backup: UserErrorRequestDisallowedByPolicy

During a recent project I have been deploying new VM to Azure, when trying to configure the Azure VM backup I was getting a failure at taking snapshot.

The error that showed in the reason was UserErrorRequestDisallowedByPolicy.

This was being caused by a policy that one of the Azure Admins had setup to require tags be configure on resource groups. When a initial backup is run it creates a resource group to save the restore point collection to and it is this resource group that is getting blocked by the Azure tag policy.

To view the policy details we can go to Policy > assignments

Click on the policy to view the parameter’s.

There are two option to work around this issue, either changing the policy from a Deny effect to a Modify effect, or create the resource group manually.

I will be creating a manual resource group as I am not that familiar with creating custom policy yet and this was the quicker workaround.

Below is the link to the Microsoft document on creating a manual resource group for restore collection point.

https://docs.microsoft.com/en-us/azure/backup/backup-during-vm-creation#azure-backup-resource-group-for-virtual-machines

Here are the steps that I did to get around this, by manually creating the resource group that will be used for the backup.

This needs to be RG name with 1 as this starting number in my case I used TheSleepyAdmin_Backup_RG1.

In the backup policy we specify the new resource group. Go to Azure Backup center > Backup policies.

Put in the name of the resource group we create manually without the number. In my case this was TheSleepyAdmin_Backup_RG

Wait for the policy update to complete.

Now try the backup again and it should complete.

If we check the resource group we can see that the restore point collection has been created.

Any addtional backup should now also be successfully, if the resource group becomes full it will try to create a new RG so there maybe a need to create another RG in the future. I will be having a look at creating or updating the tag policy to apply a modify instead of a deny but that will be in a different post as this seems like it would be a better longer term solution.

Enable Accelerated Networking on existing Azure VM’s

In this post we will go over the different methods to enabled accelerated networking in an existing Azure VM.

Accelerated networking improves performance as it allows the network interfaces of Azure VM to bypass the host.

Screen shot from Microsoft documentation

Below are some of the benefits of using accelerated network.

Lower Latency / Higher packets per second

Reduced jitter,

Decreased CPU utilization

Accelerated networking is only supported on VM that have 2 or more CPU’s. If the VM’s are in a availability set all VM’s in the set need to be powered off before updating.

There are three way’s to enabled accelerated networking on existing VMs use either AZ PowerShell Module or the AZ CLI and directly in the Azure portal.

To enable in the Azure portal go to Virtual machines > Networking and select the required network interface.

To enable first Power off the VM,

Select the network interface and click on the name. This will bring you to the network interface configuration page.

Click on enable accelerated networking

You will have to confirm you have validate that your operating system is supported.

Once completed the network interface should now show have accelerated networking enabled.

Enabling in the console is fine for one or two interfaces but if there are a few to update doing PowerShell or AZ CLI will be a quicker method.

To update using the AZ PowerShell Module, first we need to install the module.

To install run the below command

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force

Once installed use the below to connect, you will be prompted to put in Azure account details.

Connect-AzAccount

Once connected, we can check if the network interfaces have accelerated networking using the below command.

Get-AzNetworkInterface -ResourceGroupName RGName | Select-Object Name,EnableAcceleratedNetworking

To enabled accelerated networking the VM needs to be stopped and deallocated so either power off from the Azure console or use stop-azvm

Stop-AzVM  -Name VMName -ResourceGroupName RGName

To enable we need to get the network adapter information into a variable and then set the enabledacceleratednetworking property to true.

$networkacc = Get-AzNetworkInterface -ResourceGroupName RGName-Name nicname
$networkacc.EnableAcceleratedNetworking = $true
$networkacc | Set-AzNetworkInterface

Once the command completes, we can run the command to check the network interfaces again and one should now have enabledaccleratednetworking set to true.

If there were multiple network interfaces in the resource group to enable, we could get the list and loop through each, but each VM would need to be supported or they would error out.

$networkaccs = Get-AzNetworkInterface -ResourceGroupName RGName
foreach ($networkacc in $networkaccs){

$networkacc.EnableAcceleratedNetworking = $true
$networkacc | Set-AzNetworkInterface

}

Last step is to power back on the VM either from the Azure portal or using AZ PowerShell.

Start-AzVM  -Name VMName -ResourceGroupName RGName

That is the process for setting using AZ Powershell.

To set using the Azure CLI, first we need to install the go to the below and download the MSI installer.

https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli

Once installed launch PowerShell.

to logon either use az login for an interactive logon process

or use with username and password parameter. (This method will not work with MFA so we will be using the interactive method.)

az login -u <username> -p <password>

When running the az login command you will be brought to the standard login.microsoft.com page.

Once signed in, we can query the resource group for network interfaces to see what has acceleratednetworking enabled

az network nic list --resource-group RGName --query [].[name,enableAcceleratedNetworking] --output table

To update the interfaces the VM needs to be powered off either in the Azure console or using AZ Cli

To use AZ Cli

az vm deallocate --resource-group RGName --name VMName
az network nic update --name NicName --resource-group RGName --accelerated-networking true

Once the command completes run the list command again to confirm that acceleratednetworking is set to true.

last step is to start the VM using either Azure port or Az Cli

az vm start --resource-group RGName --name VMName

The network interfaces should now have accelerated networking enabled.

Allow External Access to vCenter Using Azure Application Proxy

With some of the recent critical vulnerability’s for both VMware and Log4j vulnerability this is has shown again that having vCenter open on the internet is not a good idea as it leave a big target for hackers to try exploit.

There are several ways to avoid having vCenter directly available on the internet, in this post we will be going through publishing using the Microsoft Azure Application Proxy. This will be using Azure AD as an authentication source and we can add addtional security like MFA.

First before we can use the Azure Application Proxy we need to make sure we have an Azure subscription and the appropriate license types. The application proxy is available for users that have either a Azure AD P1 or P2 license.

Once all the pre requisite are meet we can install the Azure Application Proxy, we will be using a Windows Server 2019 VM.

For Windows Server 2019 we need to disable http2 protocol, to disable run the below command from PowerShell.

Set-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp\' -Name EnableDefaultHTTP2 -Value 0

To download the installer, logon to the Azure portal > Azure Active Directory > Application proxy.

Once downloaded run the installer on the server that will be used for the app proxy. To register the connector the minimum rights is to be part of the application administrator role in Azure.

During the install we will be prompted to enter details for an account that has the correct permissions.

The install can take a minute or two to finish.

Once the install has completed the Azure Application proxy connector should show in Azure.

Now that we have the proxy connected to Azure, we will need to register the enterprise application.

Go to Azure AD > Enterprise applications > create your own application

Give the application a name and click create.

Next

  • Give the app a name
  • Add in the internal URL for vCenter
  • Set external URL this can either be an msappproxy.net address or custom domain named
  • Set the pre authentication to either Azure AD or passthrough (to use MFA or conditional access policy set to Azure AD)
  • Set the connector group

I left the addtional settings as the defaults. If the internal and external URL are different (its recommend from Microsoft to use the same DNS address), then to allow the redirect set the translate URLs in > Application Body to yes so allow link translation from the external to internal URL.

Click create, the app can take a few minutes provision.

We can restrict access to the app by using security groups or induvial users access.

Once we have setup the access group we can now connect to the external URL.

If the internal application is using an self singed cert or un trusted certificate authority, then the cert will need to be add to the trusted root cert store on the application proxy server.

This is the TLS error:

There should also be event log 13001 log under Applications and Services Logs/Microsoft- AAD Application Proxy Connector/Admin.

Download the root CA cert from vCenter and install to the trusted root on the server that has the Azure Application Proxy connector installed.

The second option is to use a custom SSL cert for vCenter, I have done a previous post on how to install a custom cert.

Set Custom SSL Certificate on VMware vCenter 6.7 Appliance using Windows CA

After this has been completed the page should now load without issue using the external Azure msapproxy address.

If the application proxy is set to use pre authentication then users will be redirected to the sign in page for Azure and be subject to any conditional access policies.

When connecting from an account that has not been give access rights they will not be able to connect.

The VMware remote console does not work using the Azure Application proxy as it requires both port 443 and 902, the application proxy can’t connect on 902 so the connection fails.

Deploying Infrastructure in Azure Using ARM Templates

I have recently been looking at using Azure Resource Manager templates (ARM) to deploy and redeploy resources in Azure. I haven’t really done a lot with ARM templates so I though it might be helpful to do a few test runs and try figure out how to deploy resource in Azure using ARM templates.

In this post we will be going to through creating a ARM template from an existing resource group and what we need to do to redeploy to a new resources group.

ARM Templates are JSON files that define the infrastructure and configuration that will be deploy.

https://azure.microsoft.com/en-gb/services/arm-templates/

First we are going to export the template from Azure resource group that we want to redeploy to another resource group.

Logon to the Azure portal and go to resource groups.

Select the resource group that we want to export the template from.

Go to Automation and select export template.

This will bring up the ARM template for the resource group. We can then download the template to modify, I will be using visual studio code with the Azure Resource Manager (ARM) Tools extension added to edit the template.

Once the zip file is download and extracted there will be two JSON files, parameters’ and template.

When we look at the template file itself there will be a set of parameters. There are default values for each parameters which are the names of each resource in the resource group. I remove the default values.

The parameters are what is used to define the name of the resources that are created.

When I first started to look at the ARM templates they did seem very confusing but if you break them up in to each part instead of looking at it as a whole it made a lot easier for me to understand how the template worked.

If we take the below as a example this part of the JSON defines the virtual network and subnet to be created. It sets the location, subnet prefixes and one subnet for 10.0.0.0/24.

If there are IP address assigned or the subnet need to be changed this can be updated in the JSON file.

Once the JSON file has been modified we can then use this to deploy to Azure. The two way we will be going through in this post is using Azure portal Deploy from a custom template and second we will be going through adding the parameters to the parameters JSON and deploy using PowerShell.

First we will go through the portal deployment.

Logon to the Azure portal and go to deploy from a custom template.

We could search for template using the quick start template if we don’t have a existing template

but we will be using build your own template so we will be selecting build your own template.

This image has an empty alt attribute; its file name is image-10.png

Once the blade opens click load file and select the JSON template file this will then load the template.

Click save this should then a view like the below that we can manually in put the details we want to use for the deployment.

Click next and the arm template will be validated.

Click create to start the deployment.

When I deployed the template I had some issues with the VM creation.

This was caused by a few different issue. The first was the managed disk which returned the below error.

“Parameter ‘osDisk.managedDisk.id’ is not allowed.”

I found this article on Github https://github.com/Azure/azure-quickstart-templates/issues/3290 that explained the fix was to change the manageddisk from

to the below storage account type

The second issue was to do with requireGuestProvisionSignal property. I found the below forum post that said to remove the line.

https://docs.microsoft.com/en-us/answers/questions/332816/the-property-39requireguestprovisionsignal39-is-no.html

I removed this from the JSON.

The last issue was due to the admin password not being set. To fix this I added a new parameter at the start of the template

and set it under below under os profile

Once this was done I went back to deploy a custom template and readd the details which should now have the addtional admin password field.

The deployment now completed without issue.

The resources now be deployed to the resource group.

The second method we will be going through to deploy the ARM template is to use PowerShell.

We will be using the New-AzResourceGroupDeployment command to deploy the template.

We first will be modifying the parameters file to set the names that will be used.

For the adminpassword I will be adding the password to the parameter’s file but in production this should not be done and instead use something like Azure key vault to store the password.

First we need to install the Azure module

Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force

Next we run

Connect-AzAccount

Next we run the New-AzResourceGroupDeployment I used the verbose parameter to get more details on the deployment. We will be calling the template and parameter JSON files.

New-AzResourceGroupDeployment -ResourceGroupName "resource group"  -TemplateFile "path to template json" -TemplateParameterFile "path to parameters json" 

Below is the command running and provisioning the resources in the template.

Once the deployment completes all the resources will show under the resource group.

We can also use the ARM template to redeploy a resource that has been removed.

If we run the New-AzResourceGroupDeployment again after a resource has been deleted the deployment picks up that the missing resources and redeploys.

This was my first attempt at doing ARM and it not as complicated as I first thought I will probable do a few more post in the future after I have some more time working with ARM templates.

Microsoft Graph Report on Azure Role Assignments

In this post we will be going through creating an automate report to list all assigned Azure roles and user/group assignments using Microsoft Graph SDK.

This can be useful for environments that haven’t implemented Microsoft privileged identity management for roles management. This can be used to keep track of roles assignments in Azure.

I will be using Microsoft Graph SDK, if you haven’t used this before I have done a previous post on installing and getting start with the Graph SDK.

I will be using a app registration in Azure AD with certificate authentication (I covered this in one of my previous posts) so I don’t have to use any username or password with the script. We will need to add the required API permission.

To find the specific commands that I needed to use, I generally search for them on the Graph module reference document link below as there are a lot of commands in the Graph SDK module.

https://docs.microsoft.com/en-us/powershell/module/microsoft.graph.applications/?view=graph-powershell-beta

To add the API permission logon to Azure portal

https://portal.azure.com

Open Azure Active Directory > App registrations

Select the Graph registration that was previously created. Under the API permissions select add permissions and add the the required application permissions to run the command.

In this case we will be using the rolemanagment.read.all

Once the API permission is added we can start to create the script.

To get the list of directory roles that are currently in use use

Get-MgDirectoryRole

Then to get the assigned objects use the below command and copy the ID to view details.

Get-MgDirectoryRoleMember -DirectoryRoleId IDValue

To view addtional values for the returned object use

(Get-MgDirectoryRoleMember -DirectoryRoleId IDValue).AdditionalProperties

The full script can be downloaded from the below github link and

https://github.com/TheSleepyAdmin/Scripts/blob/master/MSGraph/RoleAssigment/Get-AdminRolesAssigment.ps1

Below is what the export will look like.

VMware List All Port Groups and Associated VM’s Using PowerCLI

During a recent project we have been starting to use network segregation to give more security and control instead of using a flat network.

This has lead to VM’s being broken up in to there own VMware port groups and segregated VLAN’s.

There are now old port groups that have had all VM’s removed, so we wanted to report on any port groups that have no VM’s associated so that they can be removed as we will hit a issue with max VLAN limit per physical interface.

The quickest way I could think of to create the report was to use PowerCLI, in this post we will go through the process and commands used to create the report.

First we need to connect to vCenter using PowerCLI

We will be using a few different commands in the script.

First we will need to get list of port groups will only be getting distributed port groups as we don’t use standard port groups.

Get-VDPortgroup

Second part of the script is to get the port group view using get-view

Get-View -ViewType Network -Property Name -Filter @{"Name" = "portgroup name"}

We will be using UpdateViewData to add some addtional values to the view to make the script quicker and easier to read see below link for more details on UpdateViewData.

https://blogs.vmware.com/PowerCLI/2011/08/optimize-the-performance-of-powerclis-views.html

To find the properties we wanted to report on we used

Get-VM -Name VMName | Get-View

Use Get-VIObjectByVIView to get the host information.

$vm = Get-VM -name VMName | get-view
(Get-VIObjectByVIView $vm.runtime.host).name

I want to report on the VM name, Host, Cluster and PowerState.

Below we will get the view for the port group and update the view with the additional details that I want in the report.

$networks = Get-View -ViewType Network -Property Name -Filter @{"Name" = "portgroup name"}

$networks | ForEach-Object{($_.UpdateViewData("Vm.Name","Vm.Runtime.Host.Name","Vm.Runtime.Host.Parent.Name","vm.Runtime.PowerState"))}

We can run the below to check if the addtional information has been added to the veiw

$networks.LinkedView.vm.name

Once we have the view working and adding the properties we want we can start to create the full script.

The full script can be copied from the below github link.

https://github.com/TheSleepyAdmin/Scripts/blob/master/VMware/Network/VMware_PortGroupReport.ps1

There are two parameters in the script.

To just output to the console screen use -ConsoleOnly parameter.

To export to csv use the -ReportExport parameter.

Below is a example of the exported csv.

VMware PowerCLI Module 12.4 Update Error

With the release of VMware PowerCLI 12.4 I was updating the module on my LAB servers so I could check out the new command.

When upgrading I was getting the below error which is due to VMware changing the certificate authority used to publish the new module.

Authenticode issuer ‘E=noreply@vmware.com, CN=”VMware, Inc.”, O=”VMware, Inc.”, L=Palo Alto, S=California, C=US’ of the new module ‘VMware.VimAutomation.Sdk’ with version ‘12.4.0.18627054’ from root
certificate authority.

In the release notes from VMware there is a know issue with the certificate. The fix is to remove and re-install the module.

https://blogs.vmware.com/PowerCLI/2021/09/powercli-12-4-whats-new.html

I though I would do a quick post on this incase anyone doesn’t know the process.

To check where the module is installed run the below command.

Get-Module -ListAvailable VMware.PowerCLI
This image has an empty alt attribute; its file name is image-21.png

In my case the module was installed in C:\Program Files\WindowsPowerShell\Modules.

Next we need to remove the old modules, below is a list of the folders that make up the VMware PowerCLI 12.0 module.

After removing the folder we now have to install the new module using Install-Module

Install-Module VMware.PowerCLI

Once completed we should now have PowerCLI version 12.4

Using VMware PowerCLI Get-EsxCli

In this post we will be going through using the PowerCLI Get-EsxCli commandlet, which is used to call EsxCli command from PowerShell instead of having to SSH directly to the the ESXi host.

This can be useful when trying to gather information from multiple hosts instead of connecting on to each host with SSH or updating configuration settings.

First step is to connect to vCenter, once connected we can run the Get-EsxCli command and this will return the list of namespaces that can be use to gather information or set configuration settings.

We will be using -V2 as this sets Get-EsxCli to use version 2 interface as version 1 is being deprecated and will be removed in a later version.

Get-EsxCli -VMHost esxihost -V2

We can set the Get-EsxCli command to a variable so that we can call the namespaces, below will call the network namespace, once called there will be a list of addtiaonl namespaces that can be called.

$vmhostesxcli = Get-EsxCli -VMHost esxihost -V2
$vmhostesxcli.network

Once we select a namespace there should also be a list of methods that can be called these can be used to run specific actions like list or get to return information.

To list all nic’s we can call the nic and then list namespace

$vmhostesxcli.network.nic.list.invoke()

To gather info on details like driver version we can use the get method, in v1 you use to be able to call the nic name directly but if you try this in v2 the below error will be returned.

If specified, the arguments parameter must contain a single value of type Hashtable.

This is due to the method requiring a hash table parameter. If we call the help method it should return the valid parameters. If the parameter has a hyphens remove this or the command wont work.

For the nic namespace the parameter is nicname and needs to be called as a hash table.

$vmhostesxcli.network.nic.get.invoke(@{nicname="vmnic1"})

There might be some namespaces that have multiple properties like driverinfo under nic, these can be called by adding the property like below.

$vmhostesxcli.network.nic.get.invoke(@{nicname="vmnic1"}).DriverInfo

Now that we have the command we can start to build out a script to export information.

In this case we will be getting all hosts, listing all NIC’s and getting the drivers info.

The above shows that Get-EsxCli can be very good for retrieving information, if we wanted to set a configuration we can use similar command syntax but use the set method.

In this case we will update the Power policy settings on all host, we could do this manually by going to the Configure > Hardware > Overview > Power Management one each host and update the power policy settings

but doing this on a larger cluster is a lot of effort. To update using PowerCli we can first create the script to report on the current host power policy.

To update the policy settings we will use the set method like the below.

$vmhostesxcli.hardware.Power.policy.set.Invoke(@{id="1")})

Below are the 4 different power policy’s.

IDPower Policy
1High Performance
2Balanced
3Lower Power
4Custom

We can then take the above and create a re-usable script to report or set the power policy on all host in one go.

To download a copy of the either of the above script use the below link to my Github these can be used as reference if you want to create your own scripts for other settings.

https://github.com/TheSleepyAdmin/Scripts/tree/master/VMware/EsxCli

Upgrading VMware Tools Different Methods

Keeping VMware tools updated is an import task to improve performance and keep up with security / bug fixes. VMware tools are not required for a VM to run but are used to enable VMware features.

VMware tools can be upgrade in a few different methods. In this post we will go through some of these different methods these range from completely manual by upgrading to fully automated using VM options, scripting or application deployment.

First method is to manually mount the tools on the VM by right clicking and then install in the guest OS, this is the slowest method and is fine if there is a few VM to upgrade but not really great at scale.

Second method is to set the VMware tools to check for upgrades during power on. This method can be good when doing OS patching as when patching a VM the tools will also be upgraded.

To enabled this either edit the VM setting and go to VM Options > VMware tools > Tools Upgrade

To enabled on multiple VM’s we can use PowerCli to bulk update the VM options.

To view the current upgrade policy we can use

(Get-VM VMName  | Get-View).config.Tools

To update the VM Option using PowerCli we can create a new VM configuration and then apply to a list of VMs in a text file using a loop. To set the upgrade policy back to manual just update tools upgrade policy from upgradeAtPowerCycle to manual.

$VMs = Get-Content C:\Temp\VMs\VMware_Tools_Upgrade.txt
$Toolsconfig = New-Object VMware.Vim.VirtualMachineConfigSpec
$Toolsconfig.tools = New-Object VMware.Vim.ToolsConfigInfo
$Toolsconfig.tools.toolsUpgradePolicy = "upgradeAtPowerCycle"

foreach ($VM in $VMs) {
Write-Warning "Setting VM Tools to Upgrade on PowerOn for $VM"
(Get-VM -Name $VM | Get-View).ReconfigVM($Toolsconfig)

 }

vCenter should show the tasks that where run to update the VM option.

Now when the VM’s reboot they should auto upgrade to the newest version.

Third method is to use a script to update the tools. This can be used when we want to have more control over when VMware tools are upgrade.

This can be done by using the VMware PowerCli Update-Tools command

For one VM we could use

Update-Tools VMName

Below is an example of using a text file with VMs names. I used the no reboot parameter to stop the VM from rebooting after the tools are updated.



$VMs = Get-Content C:\Temp\VMs\VMware_Tools_Upgrade.txt
foreach ($VM in $VMs) {
Get-VM -Name $VM  | Update-Tools -NoReboot
}

If we check vCenter we should see the upgrade task start

The last method I would use would be an application deployment tool to push out the latest VMware tools.

I use Microsoft Endpoint Configuration Manager for most of my deployment so this will be where I will be creating the deployment package.

Mount the VMware tools on on of the VMs and copy the install files.

Open the ConfigMgr console > Software Library > Application Management > Application

Create a new application and set to manual specify.

Add in the application details.

Add a new Deployment Type

Set type to manual specify.

Give the deployment a name

I used the document for the command line switches for the tools upgrade its for version 5.5 but the same switches worked.

https://docs.vmware.com/en/VMware-vSphere/5.5/com.vmware.vmtools.install.doc/GUID-CD6ED7DD-E2E2-48BC-A6B0-E0BB81E05FA3.html

Add the path to the copied install files, install command line switches and the uninstall command line (not required)

Command line: setup.exe  /S /v “/qn REBOOT=R

Next set a detection method this can be either MSI install code if available but I used file version for the vmtoolsd.exe.

below is what the detection clause should look like.

Set the install behavior to Install for system and logon requirement to Whether or not a user is logged on.

I didn’t set any requirements or dependencies. Review the summary page and then complete the application wizard.

Once completed the wizard will go back to the create application wizard.

Follow the wizard and complete.

Now that the application is create we can deploy out to the required VM’s.

Right click and go to deploy.

Select the device collection that will be used to put VMs that will have there tools upgraded.

Add the application to the required distribution points so that content is transferred.

There are two install type available or required. To force the install use required.

For scheduling I setup as soon as possible but this can be set to what ever time the application should start to install.

I left user experience and alerts as default and completed the deployment wizard.

Once the application deployment has been assigned to the client the app should now show in software center on the client and start the upgrade.

After the upgrade completes the version of VMware tools should be 11.3 and will prompt for reboot if required.

These are the main way I manage VM tools upgrades, I usually try to use VM options for most severs as it works well and requires the least manual intervention to keep VMware tools up to date.