Save to My DOJO
In today’s post, I’ll be introducing a very useful PowerCLI cmdlet which should be a great asset to your troubleshooting and automation quests.
The Invoke-VMScript cmdlet is used to remotely execute commands and scripts in the guest OS running on a VM. The cmdlet can be used to target both Windows and Linux operating systems. This functionality comes in handy in those instances where network connectivity to a VM has been lost or when you need to automate tasks on one or more virtual machines.
I’ll jump straight in and show you the basic syntax just to get you started. The minimal syntax required is as follows.
Invoke-VMScript -VM <VM> -ScriptText <commands> -GuestUser <administrator> -GuestPassword <password> -ScriptType <Bat, PowerShell, Bash>
The parameters to the cmdlet are mostly self-explanatory. Regardless, here’s an explanation for each:
- VM – This represents the vm you wish target. We use something like $vm = get-vm -name <virtual machine name> to populate it.
- ScriptText – This can represent a path to a script residing on the VM’s OS or simply a string of commands concatenated using the & operator.
- GuestUser – An account with administrative privileges on the vm’s guest OS such as the administrator account.
- GuestPassword – The password associated with the GuestUser administrative account.
- ScriptType – Defines the type of script or commands being executed. The supported types are Bat (for Batch file), PowerShell or Bash script.
A complete list of parameters is available here.
There are a number of prerequisites that must be met for the cmdlet to work properly. In no particular order, let’s go through them.
- PowerCLI has to be present on the machine off of which the cmdlet is run. I know this sounds obvious but you never know. The thing is that users new to VMware do tend to confuse PowerShell and PowerCLI.
- The vSphere user account with which the cmdlet is run must have read access to the folder containing the virtual machine and also be granted the VirtualMachine.Interaction.Console privilege. By vSphere account, I mean something like root if targeting a standalone ESX host or [email protected] in the case of vCenter Server.
- The target VM must be powered on with VMware Tools installed and running correctly.
- The machine from where the cmdlet is run must have unhindered access to TCP/UDP port 902 on the ESXi server hosting the VM being targeted.
In addition, different versions of vSphere must meet the following:
1) For vCenter Server and ESX(i) versions earlier than 5.0, you must:
- Run the cmdlet using the 32-bit version of PowerCLI.
- Ensure that TCP port 902 on the ESX server hosting the vm is accessible.
2) For vCenter Server and ESX(i) versions earlier than 4.1, you must also:
- Ensure that the user account used to connect to the ESXi server has the VirtualMachine.Interact.Console privilege. If you’re using root, know that the privilege is granted by way of the account’s default settings. If some other account is used, you can check the assigned privileges as per Fig. 1.
3) For vCenter Server and ESX(i) 4.1 and later, make sure the account used to connect to the ESX host has VirtualMachine.Interact.GuestControl privileges.
4) For vCenter Server and ESX(i) 5.0 and later, the ESX account in addition must also be granted VirtualMachine.GuestOperations.Modify and VirtualMachine.GuestOperations.Execute privileges.
Say you want to remotely display the contents of the root directory on C: for a VM called Windows 7. By remotely, I mean running the PowerCLI cmdlet inside a console on computer A whilst targeting computer B. The procedure I would use would be something like this:
Open a PowerCLI window and run this code:
Connect-VIServer <ESX IP address or FQDN> $vm = Get-vm -name 'Windows 7' Invoke-VMScript -vm $vm -ScriptText "dir c:\" -GuestUser 'jason' -GuestPassword '1qaz!QAZ' -ScriptType bat
Here’s the code explained:
- Line 1 – Establish a connection to the ESX host or vCenter Server.
- Line 2 – Use the $vm variable to hold a VM object representing the VM called ‘Windows 7’
- Line 3 – Call Invoke-VMScript to execute the command “dir c:\” on the target VM. The output is returned to the PowerCLI window from which the cmdlet is run.
You can also target Linux based operating systems. In the next example, I’m displaying the contents of the tmp folder off a VM set up as a VCSA. Notice that the ScriptType parameter is now set to Bash to reflect the fact that we’re targeting a Linux guest OS.
$vm = get-vm -Name 'vcsa-1.vsphere.local (16.51)' invoke-vmscript -VM $vm -ScriptText "ls /tmp" -GuestUser root -GuestPassword 1qaz!QAZ -scripttype Bash
Undoubtedly, these are very basic examples which serve little purpose other than to explore the cmdlet’s syntax and operation which is what I’ve tried to show here.
A more useful example is probably this one where netsh is used to set the IP settings for a newly deployed Windows virtual machine. In this case, I’d use something like this:
$cmd='netsh interface ip set address name="Local Area Connection" static 192.168.16.147 255.255.240.0 192.168.16.1 1' invoke-vmscript -VM $vm -ScriptText $cmd -GuestUser jason -GuestPassword 1qaz!QAZ -ScriptType bat
At this point, I must stress that on VMs running flavors of Windows, you will be limited in what you can execute by way of the User Account Control (UAC) settings. One example that comes to mind is one where slmgr.vbs is used to modify licensing on Windows. This method is often used to extend the evaluation period of a Windows operating system amongst other things.
In this example, we’ll pass the string ‘cscript c:\windows\system32\slmgr.vbs /rearm’ as the ScriptText parameter. Slmgr must be run using elevated privileges irrespective of it being run within an administrative context. Think of a UAC pop-up – Fig. 5 – that alerts you to a change about to occur. This happens irrespective of being logged in as an administrator or not.
The problem with this is that there is no way, as far as I know, to interact with UAC when the Invoke-VMScript cmdlet is used, meaning that UAC has to be disabled if some invoked tasks are to complete successfully. Figure 6 shows how to disable UAC under Windows 7.
As per Fig.7, The slmgr /rearm command works great when UAC is disabled.
Another gotcha to be aware of, is the requirement to be interactively logged in the VM’s guest OS for this to work. Failing this, you will end up with an Access Denied error. I’m pretty sure there’s a workaround but to be honest I haven’t tried looking for one.
Returning to UAC, if it is set to anything other than that shown in Fig.6, the error seen in Figure 8 will be returned. As mentioned, the only workaround I know of is to completely disable UAC. This compromise may be unacceptable to many out of security concerns and what have you, so you’ll need to get creative if this is the case. As always, experimentation and Google are your best friends!
As we have seen, the Invoke-VMScript cmdlet has the potential to automate mundane tasks that would otherwise have to be carried out manually. The cmdlet is thus a valuable tool in anyone’s arsenal of tricks. The ability to remotely reboot a virtual machine when network connectivity to it is lost, for instance, is a great thing to have if you ask me!
[the_ad id=”4738″][the_ad id=”4796″]
Not a DOJO Member yet?
Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!