Invoke-VMScriptPlus v2

The ability to execute scripts inside the guest OS of your VMs, is definitely one of the more useful cmdlets available in VMware PowerCLI. A year ago I published the first version of my Invoke-VMScriptPlus function to solve some of the issues the Invoke-VMScript cmdlet has in my opinion.
That function allowed you to run multi-line scripts in a Linux guest OS on your VMs. It also allowed you to use she-bang lines, to indicate which interpreter your script had to run in (bash, perl, python, nodejs, php…). Another handy feature was that you could use Linux here-documents in your scripts.

With the introduction of PowerShell Core (aka PowerShell v6), the lack of support for any Guest OS of the Windows family became obvious. Prompted by a recent thread in the VMTN PowerCLI Community, I decided it was time to publish a new version of my Invoke-VMScriptPlus function.


Update August 21st 2018

  • Added ScriptEnvironment


I defined some target features  for the new version of the Invoke-VMScriptPlus function:

  • Support the Windows family of Guest OS
  • Support using PowerShell Core scripts (Windows and Linux)
  • Fix the ScriptText length limitation

The Code



Line 1-35: The latest version of my OBN (Object By Name) class. It allows one to pass, or the actual .Net object, or the name of the object, as an argument to a parameter. See also Home Made OBN

Line 136: When the Invoke-VMScriptPlus  function cannot determine the Guest OS family, this parameter allows you to force a specific Guest OS family. Accepted values are Windows and Linux.

Line 133: The installation path of PowerShell Core on a Windows OS contains the version number. I could not find an easy way to determine the version number. This parameter allows to specify a specific PowerShell Core version. The default version is 6.0.2, and that is because that is the highest version VMware PowerCLI currently supports. Note that for the time being running VMware PowerCLI does not officially support running in PowerShell Core on a Windows Guest OS. Always consult the latest Compatibility Matrix to find out what is officially supported by VMware PowerCLI.

Line 134: This parameter allows you to pass a number of environment variables as an array of strings

Line 138: Most Linux OS return output with only a LF. This switch can be used to convert the LF to a CRLF, when the resulting output of the script is returned.

Line 147-155: A hard-coded table with the supported interpreters, and their corresponding SheBang line. This version of the Invoke-VMScriptPlus  function adds PowerShell Core to the table.

Line 160-167: If the VM is not powered on, or if the VMware Tools are not running, or if the Guest OS family can not be determined, the function will return with an error message.

Line 170-191: The Invoke-VMScriptPlus  function tests, based on the Guest OS family, if the requested ScriptType is valid.

Line 192-199: For a VM with a Guest OS in the Linux family, tests if there is a SheBang line in the ScriptText. If not, add a line based on the ScriptType value.

Line 202-213: Create the Authentication object for the GuestOperations methods. Note that in this release of the function, the GuestPassword requires a SecureString instead of a String.

Line 216-222: Depending on the ScriptType, the temporary file, see the following annotations, will have a filetype.

Line 223-237: The Invoke-VMScriptPlus  function uses two temporary files to store the script and the script’s output.

Line 239-241: If the target Guest OS family is Linux, the line endings in the ScriptText are converted from CRLF to LF

Line 242-252: The ScriptText is copied to the temporary file. This is done over HTTPS with the Invoke-WebRequest cmdlet. Note that the temporary filename returned earlier contains the IP address of the ESXi node on which the VM is running. This potentially causes problems with the Invoke-WebRequest and invalid certificates. In the URI for the file, the function replaces the IP address with FQDN.

Line 256: Fetch the current system environment variables

Line 263-272: On a Guest OS in the Linux family, the file containing the ScriptText needs to be made “executable”

Line 276: The function merges the system environment variables with the provided environment variables. The resulting array is passed to the StartProgramInGuest call.

Line 278-286: On a Guest OS in the Windows family, the path to the PowerShell Core EXE, contains the version number. This is where the $PSv6Version parameter comes into play. The default value is currently set to 6.0.2.

Line 280-286,308-314: Script execution is started

Line 318-328: Wait for the script execution to end

Line 330-335: The output is fetched, again with an Invoke-WebRequest.

Line 338-341: Clean up the temporary files

Line 343-364: Return an object containing the script output and further info about the script execution

Sample Use

The following snippet lists the content of the os-release file, a common method in Linux distros to obtain the name and version of the OS. We use the following simple bash script.

Note that in this new version of the Invoke-VMScriptPlus function you have to use a SecureString (instead of a String in the previous version) for the GuestPassword parameter. This is a breaking change, but was done to comply with the ScriptAnalyzer rules!

For an openSuse guest OS the result comes back as

For an Ubuntu guest OS

And for a CentOS guest OS as

One of the target goals of the Invoke-VMScriptPlus v2 was to be able to use the function to runs scripts in a Windows guest OS. The following sample uses the wmic command.

The result comes back as

And of course PowerShell scripts

Which returns

Note how this last invocation uses the GuestCredential parameter instead of GuestUser and GuestPassword. The Invoke-VMScriptPlus function supports both methods of passing the guest OS credentials.

This last sample is run under the “normal” PowerShell installed in the Windows guest OS, as we can easily see with

The output of that script

Another new feature of the Invoke-VMScriptPlus function is the ability to call PowerShell Core.

On Windows

which gives.
As you might have noted, we have both PowerShell version installed side-by-side on that station.

And also on Linux

Which results in

The final new feature I introduced in Invoke-VMScriptPlus v2 is the length limitation that exists in the regular Invoke-VMScript cmdlet. That limitation blocks you when you want to transfer scripts that surpass a specific length. Depending on the circumstances that limitation pops up in scripts that have a length somewhere in the neighbourhood of 2600 characters.

A new feature that was introduced is the ScriptEnvironment parameter. This allows the caller to pass environment variables. A simple example:

And we see our environment variables added to the execution environment.

If you encounter “issues” or have suggestions for additions and improvements, please let me know.





    Thanks for the improvised function LucD.
    The one thing lacking is that, even after all these years we still dont have a workaround for running invokevmscript in elevated privileges.
    Seen from many of the articles, all uses a user which has admin rights, but not the administrator user itself.
    Expecting a workaround from the master for running elevated (Runas) commands via invokevmscript


      I have been looking at that for quite some time, believe me.
      The issue is that due to security, and rightfully so, you can’t just elevate a user or a task.
      But I’ll give it another try.
      Don’t hold your breath though 🙂



    Resolve-DnsName : The term \'Resolve-DnsName\' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. Invoke-VMScriptPlus_v2.ps1:246 char:13
    + $hostName = Resolve-DnsName -Name $ip | Select-Object -ExpandProperty ...

    Seems, that Resolve-DNSName not exists in PowerShell in Linux, just Windows.


      No, it’s not I’m afraid

    Aaron R.

    Hey Luc,

    I haven’t had a chance to really dig through the meat of the code within the function yet, but I was wondering have you thought of incorporating (if you haven’t already) your Elevate process code into the Invoke-VMScriptPlus? Maybe as a Switch or an additional Parameter? Similar to how Start-Process allows a param -Verb RunAs to elevate the process action. I only ask because one of the biggest issues I run into is UAC being snarky and I know your elevate-Process to run as admin without the annoying access denied response.

    I have many situations, in my efforts for automation, where I am deploying scripted building of environments through vCenter and then automation in configuring resource platforms. One of my biggest hangups is trying to run things that require elevation through Invoke-VMScript that are key to get the systems I am automating deployment of, one of those things being enabling winrm through PS, that and Register-ScheduledTask both of which scream back with access denied. Just thought maybe your two scripts combined could help Admins/Engineers such as myself work through these various small hurdles.

    VMworld 2018 Roundup: Day 4 - T.B.D.

    […] operations are available via APIs, which in turn interact with vmware-tools. Luc created Invoke-VMScriptPlus, taking advantage of these APIs, to execute actions within the guest operating […]

    YVS Kumar

    hi luc,

    Getting below error while running invoke-vmscript. Guest OS is 2016 server.

    Invoke-VMScript The operation is not allowed in the current state

    Can you help ?


      Are the VMware Tools installed and running?
      Do you see any further info in the vmware.log file?

    Introducing the vSphere Migration Toolkit

    […] Set-IPInfo – Injects the network settings collected by Get-IPInfo into the target workload post-migration. The injection leverages VMware Tools, and no network connectivity is required on the target VM! (Shoutout to Luc Dekens for his work on Invoke-VMScriptPlus v2) […]

    Markus Kraus

    Hi Luc,

    thanks for this great Function.

    I ran into an issue where the Resolve-DnsName Cmdlet returns an Answer and the Authority. In my case this was fixed with this modification:

    $hostName = (Resolve-DnsName -Name $ip).where({$_.Section -eq “Answer”}) | Select-Object -ExpandProperty NameHost



      Thanks Markus

    Prabhu G

    Hi LucD,

    Im trying to run a command on remote VM’s powershell using Invoke-VmScript cmdlet.
    $dns_name = “Test-DNSVM”
    function dnsFeatureInstall {
    $scriptText = @”
    Install-WindowsFeature DNS -IncludeManagementTools
    $user = ‘administrator’
    $password = ‘password’
    write-host “installing DNS feature on $dns_name”
    Invoke-VMScript -Scripttype Powershell -ScriptText $scriptText -VM $dns_name -GuestUser “$user” -GuestPassword $password
    But it is not working. I know by default this cmdlet uses cmd.exe. so I changed the scripttype to powershell. Any helpl will be appreciated.

Leave a Reply

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.