Invoke-VMScriptPlus v3

My InvokeVMScriptPlus function serves me well while interacting with the guest OS on a VM. And I’m apparently not the only one that uses the function. This post introduces Invoke-VMScriptPlus v3.

The original Invoke-VMScriptPlus post, and the addition of PS Core support, described in the Invoke-VMScriptPlus v2 post, keep being some of my most read posts. Time for another update.

In this v3 version, I introduce some new features to the function.

  • PSv6 and PSv7 support
  • Use files (input and output) from within your scripts
  • improved sudo support

Update April 15th 2020

  • Added SkipCertificateCheck switch

Update January 16th 2020

  • Bug fix which occured when connected to an ESXi node

Update November 18th 2019

  • Added NoIPinCert switch

The Code


The following annotations will only document the additions to the v2 version of the function. Refer to the blog posts mentioned in the introduction to see the annotations of the previous versions of the function.

Line 191-192: Addition/change of the script types. Now includes powershellv6 and powershellv7.

Line 201: A switch that allows the caller to ask for sudo support. In practice the function will pipe, via an echo command, the guest credential’s password to each sudo command in the script.

Line 206-207: New parameters InFile and OutFile. They permit files to be copied to/from the script environment.

Line 208: The NoIPforCert switch

Line 209: The SkipCertificateCheck switch

Line 214-262: Internal helper function to send files from the caller’s environment to the guest OS.

Line 248-255,286-293: The SkipCertificateCheck switch calls Invoke-WebRequest with the option to not check the certificate. In pre-V6 that is done through the CertificatePolicy class, in PS v6 and higher, the SkipCertificateCheck switch on Invoke-WebRequest is used.

Line 264-307: Internal helper function to receive files from the guest OS into the caller’s environment.

Line 237-242,276-281: If the NoIPforCert switch is $true, the IP address in the URI returned by the ESXi node (where the VM is running) will be converted to the FQDN of the ESXi node.

Line 248-255,286-293: If the SkipCertificateCheck switch is used, the following Invoke-WebRequest is called with the setting to check checking certificates.

Line 325-326: New she-bang entries for PowerShell v6 and v7. Note that at the time this post was published, that v7 was still in preview.

Line 331-345: When the SkipCertificateCheck is used and the PS version is pre-V6 and the type hasn’t been declared yet, the TrustAllCertsPolicy class is defined.

Line 365-369: Additional ‘ready’ test. If this property is not $true, the VMware Tools inside the guest OS are not ready to accept any GuestOperations related calls.

Line 400: For any Windows guest OS, the function currently only accepts BAT, PS, PSv6 and PSv7 scripts.

Line 411: For any Linux (this includes MacOS) guest OS, the function accepts all scripttypes, except BAT and PowerShell (meaning PS pre-v6).

Line 438-444: sudo support. Each line of the user’s script containg the sudo command, will be prefixed with an echo command, which will provide the password to the sudo prompt.

Line 465: In this version of the function, all files will be stored in a temporary directory in the guest OS.

Line 510-517: The function allows the caller to copy one or more files, from the caller’s environment to the temporary folder in the guest OS. Since these files will be in the same folder as the actual script, the script can reference these files.

Line 581-595: The function supports for a Windows guest OS, the use of PSv5.*, PSV6 and PSv7.

Line 651-658: The function allows the caller to copy one or more files, from the folder, where the script ran in the guest OS, to the caller’s environment. This allows an alternative method to send data back to caller besides the stdin channel.

Line 663-667: When the KeepFiles switch is not used, the function will remove the temporary directory in the guest OS, where all the script related files are stored.


The following section will show some examples of how to use the new features introduced in the v3 of the Invoke-VMScriptPlus function.


One of security measure on many Linux systems is that you need to use sudo to run commands with elevated privileges.

This is a typical example of such a case.

The OS returns the following error.

Elevated privileges required

Ok, let’s place sudo in front of that.

But that just makes the next issue obvious. How to answer to a prompt in a script. The method to solve this quite simple. Echo the password and then pipe it to the sudo command.

But this not always a practical solution, and probably not very safe either. To avoid having to handle this in the code you sent to the guest OS, the Invoke-VMScriptPlus function has the Sudo switch.

It will extract the password from the GuestCredential parameter value, and insert the echo with the password on each line in your code that starts with sudo.

PowerShell v7

At the moment, of this writing, PowerShell v7 is still a preview.
Since you can install PSv6 and PSv7 side-by-side, you can run your scripts in either version.

This is a handy way to test your scripts for readiness for PSv7.

With the ScriptType parameter, you easily define against which PowerShell version your script should run. First we use powershellv6.

This results in.


And then the same, but with powershellv7.

And now we get.


The Invoke-VMScriptPlus function captures the output of your script on the stdin stream. But sometimes you would like to produce multiple outputs, or output in a specific format.

The same goes for your input to your script. You can pass input along to your script, for example with a here-string, but this at least requires extra steps to run your script.

For that reason, this v3 version of Invoke-VMScriptPlus, added two new parameters, Infile and OutFile.

Each of these parameters allow you to specify one or more files in your local environment that will be passed and/or retrieved to the environment where your script runs in the guest OS of the target VM.

A somewhat contrived example on what this allows you to do.

In short, the script creates an input file, then runs a script on the target VM, passing along the input file.
The script on the target VM creates a number of files, which are returned to the caller when the script completes.

This is the output from the above code.

This is a handy feature when your script requires an existing file as input and produces multiple output files.


When the function needs to retrieve files from the guest OS, the ESXi node on which the VM is running, provides a URI. This URI normally contains the IP address of the ESXi node.

This can cause an issue when using certificates, and not bypassing the certificate check. The reason is sometimes that the IP address of the ESXi node is not included as a Subject Alternate Address (SAN) in the certificate. This is visible through the following error message. Note that the following output also shows some verbose output to demonstrate when this is happening, and also to show that the error occurs when doing a GET with an URI that contains the IP address.

No IP SAN in certificate

To avoid this error, the Invoke-VMScriptPlus function, by default, translates this IP address into the FQDN of the ESXi node. The following verbose output shows the adapted URI for the GET

In some environments these automatic conversion of the IP address to the FQDN might cause an issue. One reason for this to happen might be that the ESXi node is added with it’s IP address. Another might be that the DNS query to get the FQDN of the ESXi node fails.
Especially for those occasion, the function now has this NoIPforCert switch. This switch, when set, instructs the function to NOT translate the IP address in the URI to the FQDN.

A sample call that uses this switch can look like this.


Version: 3.1
24.4 KiB


    Hi Luc,

    Really cool script, thank you for it!
    I never had the need to use classes in my PS scripts, I forced myself into learning classes (which is a good thing) so I understand your script, luckily the syntax is the same as in C#, only the ‘grammar’ looks different, so thankfully it was not as harder than learning totally new concepts.
    Additionally, thank you, your script made me learn something completely new: Transformation Attributes
    I found a small bug in your code, line 18 “$($inputData)” if the VM has a space in its name, your script will fail – I had a machine named like his ‘VM -Test01’ – which caused the script to try to execute ‘Get-VM VM -Test01’, the ‘-Test01’ was treated like a cmdlet parameter, what I did on my end to fix this was to change it from:
    $cmdParam = “-$(if($this.Type -eq ‘VIServer’){‘Server’}else{‘Name’}) $($inputData)”
    $cmdParam = “-$(if($this.Type -eq ‘VIServer’){‘Server’}else{‘Name’}) ‘$inputData'”
    I put single quotation marks around it – BTW I got rid of the ‘$()’ – out of habit.
    Line 34 which is for array input objects, I guess would have to go through the same process – I have not checked/tested this as it did not apply to my case.


      Thanks for finding that “feature” 😉

      I’ll update the code.


    Hi Luc,
    thanks for the new version.

    However, I hit some issue when running your script against vcenter 6.5 to 6.7 u3.
    I installed the latest powercli
    powershell version 5.1 on machine executing the script.
    Your script is located on a file share, target machine tested are windows 2016-2019

    Error message is the following :

    VERBOSE: 10/16/2020 10:59:37 AM Get-View Finished execution
    Exception calling “CreateTemporaryDirectoryInGuest” with “5” argument(s): “The object ‘vim.VirtualMachine:vm-48032’ has already been deleted or has not been completely created”
    At \\..\Invoke-VMScriptPlus.ps1:382 char:104
    + … oraryDirectoryInGuest($moref, $auth, “$($env:USERNAME)_$($PID)”, $nul …
    + ~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : VimException

    VERBOSE: Created temp folder in guest OS
    VERBOSE: Encountered a problem creating the script file in the guest OS
    At \\..\Invoke-VMScriptPlus.ps1:404 char:17
    + Throw “$error[0].Exception.Message”
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: ([0].Exception.Message:String) [], RuntimeException
    + FullyQualifiedErrorId : [0].Exception.Message

    Advice is welcome, thank you for your help !


      The error message seems to indicate the issue might be with that specific VM.
      Do you get the same error for other VMs?


        Yes, and for the same machine, original invoke-vmscript works properly


          Do you have some further info on the Guest OS?
          And is that the same or different for the other VMs where you encounter the issue?
          Is the temporary folder created in the Guest OS?
          You should see the path in the verbose message.
          If the folder is there, can you create a file in there?
          Logon with the same account as you use for the GuestCredential


            Guest OS is windows 2019-build 1809,
            executionPolicy set to unrestricted,
            uac disabled,
            machine joined to the domain,
            account used is in admin group,
            Temp folder and file created but file is empty.
            By the way, I was connected to 3 different vcenter, by dropping 2 of them, I get now another error :

            VERBOSE: Copying Data to C:\Users\xx\AppData\Local\Temp\xx_8840vmware248\xx_8840vmware209.ps1
            VERBOSE: PUT with -1-byte payload
            Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
            At \\..\Invoke-VMScriptPlus_new.ps1:223 char:27
            + … copyResult = Invoke-WebRequest -Uri $fileInfo -Method Put -Body $Data
            + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
            + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

            ScripText copy failed!Status
            At \\..\Invoke-VMScriptPlus_new.ps1:226 char:17
            + … Throw “ScripText copy failed!`rStatus $($copyResult.Statu …
            + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            + CategoryInfo : OperationStopped: (ScripText copy failed!Status :String) [], RuntimeException
            + FullyQualifiedErrorId : ScripText copy failed!Status

            Find the powercliConfiguration :

            Scope ProxyPolicy DefaultVIServerMode InvalidCertificateAction DisplayDeprecationWarnings WebOperationTimeout
            —– ———– ——————- ———————— ————————– ——————-
            Session NoProxy Multiple Ignore False -1
            User NoProxy Multiple Ignore False -1
            AllUsers NoProxy Multiple Ignore False -1

            by forcing to trust all certificates with the following command :

            [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } | out-null
            [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 | out-null
            if(-not(“TrustAllCertsPolicy” -as [type])){
            add-type @”
            using System.Net;
            using System.Security.Cryptography.X509Certificates;
            public class TrustAllCertsPolicy : ICertificatePolicy {
            public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
            [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy;

            I get another new error :

            VERBOSE: Copied scipttext to temp script file
            VERBOSE: Encountered a problem running the script file in the guest OS
            At \\..\Invoke-VMScriptPlus_new.ps1:528 char:25
            + Throw “$error[0].Exception.Message”
            + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            + CategoryInfo : OperationStopped: ([0].Exception.Message:String) [], RuntimeException
            + FullyQualifiedErrorId : [0].Exception.Message

            ps1 file contains now the command, but output is empty


              Did you use the NoIPinCert switch?


                tried both, same behavior

                by looking more closely at the exception, I can see the follownig :

                for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException))
                { “$i” * 80
                $Exception | Format-List * -Force

                ErrorRecord : Exception calling “StartProgramInGuest” with “3” argument(s): “A specified parameter was not correct: ”
                WasThrownFromThrowStatement : True
                Message : Exception calling “StartProgramInGuest” with “3” argument(s): “A specified parameter was not correct: ”
                Data : {}
                InnerException :
                TargetSite :
                StackTrace :
                HelpLink :
                Source :
                HResult : -2146233087


                  Ok, I’ll have to do some further debugging on that.

                  Can you share the Invoke-VMScriptPlus line you used?
                  And the script you were trying to run?

                  If you don’t want to post it here, you can send it to me via the Contact Form on the website.


                    Well no problem.

                    The call :
                    Invoke-VMScriptPlus -vm (get-vm -name “vmdc*” -Server $sgdcvc) -scriptText “get-service” -server $sgdcvc -ScriptType powershell -GuestCredential $cred -Verbose -scriptenvironment “Windows” -GuestOSType Windows


                    Hi Luc,
                    Were you able to find something new about that behavior ?
                    Thank you for your feedback




                    Hey Luc,
                    Quick update, your function works fine with powercli 10.1 against vcenter 6.7u3 even if this powercli version is not officially supported with that vcenter version


                Sorry stacktrace shows more thing


                Server stack trace:
                at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
                at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
                at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
                at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

                Exception rethrown at [0]:
                at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
                at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
                at VimApi_70.VimPortType.StartProgramInGuest(StartProgramInGuestRequest request)
                at VMware.Vim.GuestProcessManager.StartProgramInGuest(ManagedObjectReference vm, GuestAuthentication auth, GuestProgramSpec spec)


    Hi LucD, first thanks for sharing your work. I had some trouble using your function:
    – we have vms with execution policy remote signed. I would like to see a switch for powershell to start the scripts with policy unrestricted or bypass
    – using in and out file has some problems since you use “/” in concatenation of path and files. This does not work. In windows you have to use “\”. Problem exists for in and for out-
    – the outfile option only works with filenames without path. This should be documented.
    – where is the console output saved to – in verbose mode I can see the download of the outlogfile, but I can not find the file.
    – for problems with SSL/TLS there should be a switch to ignore them (I use a scriptblock from someone else to completly ignore certificate problems). The parameter noipincert is nice but not allways enough.
    Greetings, Spex


      Thanks for that valuable feedback.
      I will see if I can implement some of those suggestions and observations.


    the invoke-vmscriptplusv3 download url is still 2019, would you put the latest file? Thanks


      That is correct, there have been some minor updates (see notes at the start of the article).
      But the URL is still the same one.


    Hi Lucd,

    I have tried to run TLS reconfig script (python) using invoke-vmscriptplus but I am getting invalid syntax error. Am I doing any thing wrong ? Could you please advice what colud be the issue here
    Invoke-VMScriptPlus -VM “VMNAME” -ScriptText ‘/usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan’ -GuestUser “xx”” -ScriptType python3 -SkipCertificateCheck -GuestOSType linux

    Here is the output
    ScriptType : python3
    ScriptText : #!/usr/bin/env python3
    /usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan
    GuestOS : linux
    Start : 8/12/2020 2:57:42 AM
    ScriptSize : 102
    Finish : 8/12/2020 2:57:43 AM
    ExitCode : 1
    Pid : 41709
    ScriptOutput : File “/tmp/vmware-root_1374-2689143812/xxx_10928vmware52/xxx_10928vmware79”, line 2
    /usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan
    SyntaxError: invalid syntax


      I’m not sure what is causing this I’m afraid.
      Could you add the Verbose switch to the call, that might provide some more information.

      Another option is to use the KeepFiles switch.
      That way the files, script & output, will not be removed in the Guest OS.
      The Verbose switch should tell you which are those files.

      Then you could login to the Guest OS and try to run the script file from the prompt.
      That sometimes provides more feedback on what goes wrong.


        Hi Lucd,
        Thanks for your reply. I missed to check this as I got work around to fix this. Here is the Verbose output with invoke-vmscriptplus

        $stext = “/usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan”
        Invoke-VMScriptPlus -VM $VM -ScriptText $stext -GuestCredential $cred -ScriptType python3 -GuestOSType Linux -SkipCertificateCheck -Verbose
        VERBOSE: 9/4/2020 7:57:09 PM Get-View Finished execution
        VERBOSE: 9/4/2020 7:57:09 PM Get-View Finished execution
        VERBOSE: 9/4/2020 7:57:09 PM Get-View Finished execution
        VERBOSE: 9/4/2020 7:57:09 PM Get-View Finished execution
        VERBOSE: Seems to be a Linux guest OS
        VERBOSE: Add SheBang #!/usr/bin/env python3
        VERBOSE: Created temp folder in guest OS /tmp/vmware-root_1376-2689143845/padvmengnp02_10756vmware52
        VERBOSE: Created temp script file in guest OS /tmp/vmware-root_1376-2689143845/padvmengnp02_10756vmware52/user02_10756vmware105
        VERBOSE: Created temp output file in guest OS /tmp/vmware-root_1376-2689143845/user02_10756vmware52/user02_10756_outputvmware189
        VERBOSE: Copying Data to /tmp/vmware-root_1376-2689143845/user02_10756vmware52/user02_10756vmware105
        VERBOSE: PUT with 102-byte payload
        VERBOSE: received 33-byte response of content type
        VERBOSE: Copied scripttext to temp script file
        VERBOSE: Make script file executable
        VERBOSE: Run script with ‘/tmp/vmware-root_1376-2689143845/user02_10756vmware52/user02_10756vmware105 > /tmp/vmware-root_1376-2689143845/user02_10756vmware52/user02_10756_outputvmware189’
        VERBOSE: Wait for process to end
        VERBOSE: Get output from /tmp/vmware-root_1376-2689143845/user02_10756vmware52/user02_10756_outputvmware189
        VERBOSE: GET with 0-byte payload
        VERBOSE: received 223-byte response of content type
        VERBOSE: Removed folder /tmp/vmware-root_1376-2689143845/user02_10756vmware52

        ScriptText : #!/usr/bin/env python3
        /usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan
        ExitCode : 1
        Start : 9/4/2020 11:57:09 PM
        Pid : 46761
        ScriptOutput : File “/tmp/vmware-root_1376-2689143845/user02_10756vmware52/user02_10756vmware105”, line 2
        /usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan
        SyntaxError: invalid syntax

        GuestOS : Linux
        PidOwner : root
        ScriptType : python3
        ScriptSize : 102
        OutFiles :
        VM : VMNAMe
        Finish : 9/4/2020 11:57:10 PM

        This code works for me, I followed some steps mentioned in this article

        Code Working

        foreach ($vc in $vcs){
        Write-Output “Scanning TLS Versions on $vc”
        Invoke-VMScript -ScriptText “export VMWARE_VAPI_HOME=/usr/lib/vmware-vapi
        export VMWARE_RUN_FIRSTBOOTS=/bin/run-firstboot-scripts
        export VMWARE_DATA_DIR=/storage
        export VMWARE_INSTALL_PARAMETER=/bin/install-parameter
        export VMWARE_LOG_DIR=/var/log
        export VMWARE_OPENSSL_BIN=/usr/bin/openssl
        export VMWARE_TOMCAT=/opt/vmware/vfabric-tc-server-standard/tomcat-7.0.55.A.RELEASE
        export VMWARE_RUNTIME_DATA_DIR=/var
        export VMWARE_PYTHON_PATH=/usr/lib/vmware/site-packages
        export VMWARE_TMP_DIR=/var/tmp/vmware
        export VMWARE_PERFCHARTS_COMPONENT=perfcharts
        export VMWARE_PYTHON_MODULES_HOME=/usr/lib/vmware/site-packages/cis
        export VMWARE_JAVA_WRAPPER=/bin/
        export VMWARE_COMMON_JARS=/usr/lib/vmware/common-jars
        export VMWARE_TCROOT=/opt/vmware/vfabric-tc-server-standard
        export VMWARE_PYTHON_BIN=/opt/vmware/bin/python
        export VMWARE_CLOUDVM_RAM_SIZE=/usr/sbin/cloudvm-ram-size
        export VMWARE_VAPI_CFG_DIR=/etc/vmware/vmware-vapi
        export VMWARE_CFG_DIR=/etc/vmware
        /usr/lib/vmware-vSphereTlsReconfigurator/VcTlsReconfigurator/reconfigureVc scan
        ” -vm $vc -Guestcredential $gcred


          I suspect the issue might be caused by line breaks in your ScriptText.
          You could try to define the ScriptText in a here-string.


    Lucd Hi, I have some problems converting my scripts into workflow architecture. I’ve solved many of them but except the ones that I use your Invoke-VMScriptPlus function/script.
    I have added your function into my script and I can call it from anywhere inside the script. But in the same script I I have a workflow and inside that workflow I have a inlinescript part. When I use invoke-vmscriptplus inside that inlinescript I receive error that invoke-vmscriptplus is not recognized as commandlet or function. I’ve read many articles that says inside the workflow any function can be called in workflow scope or parent scope (which has invoke-vmscriptplus function) but I cannot make it work. Do you have any suggestion?


    Any suggestions on how to utilize your Invoke-VMScriptPlus v3 with Start-Job? Specifically how to pass the function including the class into Start-Job. I’ve tried to tie it together with another one of your posts without any success.


      Hi Todd,
      I’m not exactly sure what you are trying to do.
      Is it the intention to call Invoke-VMScriptPlus from within a background job (started with Start-Job)?

      You can just pass the class + function in the code you run via Start-Job.
      Or save it in a file that you could dot-source from within the code you run via Start-Job.

      If that is not what you want to do, can you provide some more details?

      If you want, use the Contact Form to keep your information more private.


        Hi Luc!!

        Just tried the contact form from two separate systems. I get this message: There was an error trying to send your message. Please try again later.

        Anyways…Exactly right, call Invoke-VMScriptPlus within the Start-Job. I have a long running process I’m performing on multiple systems by utilizing your AWESOME function Invoke-VMScriptPlus that I’d like to run in parallel. Basically, I have a main script I want to run SDelete.exe on several template VMs in parallel as jobs. When the jobs are completed the main script will continue with the additional items I want to complete on the templates.

        This runs great:

        $VMname = “W2019-Temp”
        $code = @’
        C:\Admin\SDelete\sdelete64.exe -z C:

        $sInvP = @{
        VM = $VMname
        ScriptType = ‘bat’
        ScriptText = $code
        GuestCredential = $LocalAdminCreds
        GuestOSType = ‘Windows’
        NoIPinCert = $true
        SkipCertificateCheck = $true
        Invoke-VMScriptPlusV3 @sInvP -Verbose

        However trying to figure out what the syntax would look like to pass the class + function into the Start-Job using InitializationScript

        I thought about dot sourcing it (Invoke-VMScriptPlus) from a file, which I may just end up with that but really wanted it all to be self-contained into one script.

        Anyways, THANK YOU SO MUCH for all you do for the PowerCLI community. I’ve re-used your code to accomplish so much over the years. You are a treasure to the community!


          Thanks for notifying me, there is indeed an issue with the Contact Form.

          On your question; it is just a matter of packing all the required code in a scriptblock that you pass to Start-Job.
          For example

          # The scriptblock you pass to Start-Job
          $scriptBlock = {

          # <== Insert lines with class and Invoke-VMScriptPlus function # As an alternative dot-source a .ps1 file holding those lines Set-PowerCLIConfiguration -DisplayDeprecationWarnings $false -Confirm:$false | Out-Null Connect-VIServer -Server $Server -Session $SessionId # Your script $code = @’ C:\Admin\SDelete\sdelete64.exe -z C: ‘@ # !!! Inline string terminator has to start in column 1 # Set up $LocalAdminCreds (you could pass user/pswd as arguments to Start-Job) $LocalAdminCreds = ''

          $sInvP = @{
          VM = $VMname
          ScriptType = ‘bat’
          ScriptText = $code
          GuestCredential = $LocalAdminCreds
          GuestOSType = ‘Windows’
          NoIPinCert = $true
          SkipCertificateCheck = $true
          Invoke-VMScriptPlusV3 @sInvP -Verbose

          $vmName = 'W2019-Temp'
          $sJOb = @{
          ScriptBlock = $scriptBlock
          ArgumentList = $global:DefaultVIServer.Name, $global:DefaultVIServer.SessionId, $vmName

          Start-Job @sJob


    When I run it through Windows 2016 host with PowerCLI 11.5, got following error:

    Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or Internet
    Explorer’s first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again.
    At C:\Users\maverick\Documents\Invoke-VMScriptPlus.ps1:223 char:27
    + … copyResult = Invoke-WebRequest -Uri $fileInfo -Method Put -Body $Data
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotImplemented: (:) [Invoke-WebRequest], NotSupportedException
    + FullyQualifiedErrorId : WebCmdletIEDomNotSupportedException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

    ScripText copy failed!Status
    At C:\Users\maverick\Documents\Invoke-VMScriptPlus.ps1:226 char:17
    + … Throw “ScripText copy failed!`rStatus $($copyResult.Statu …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (ScripText copy failed!Status :String) [], RuntimeException
    + FullyQualifiedErrorId : ScripText copy failed!Status


      Sorry to hear that.

      This seems to be a known issue with Invoke-WebRequest.
      Can you try changing lines 243-247 to

      $sWeb = @{
      Uri = $fileInfo
      Method = 'Put'
      Body = $Data


      $sWeb = @{
      Uri = $fileInfo
      Method = 'Put'
      Body = $Data
      UseBasicParsing = $true

      and lines 282-285

      $sWeb = @{
      Uri = $fileInfo.Url
      Method = 'Get'


      $sWeb = @{
      Uri = $fileInfo.Url
      Method = 'Get'
      UseBasicParsing = $true

      If that solves the issue, I will update the post accordingly.


    I was getting errors with line 297,
    “VERBOSE: received 295-byte response of content type
    Set-Content: C:\Users\dave.moreland\invoke-vmscriptplus.ps1:297
    Line |
    297 | $fileContent.Content | Set-Content -Path $File -Encoding byte -Confir …
    | ~~~~
    | Cannot process argument transformation on parameter ‘Encoding’. ‘byte’ is not a supported encoding
    | name. For information on defining a custom encoding, see the documentation for the
    | Encoding.RegisterProvider method. (Parameter ‘name’)”

    I had to change mine to look like this:
    “$fileContent.Content | Set-Content -Path $File -Encoding oem -asbytestream -Confirm:$false”

    I’m running scripts on centos 7, have not tested elsewhere,

    Thank you for the script,


      Thanks Dave.
      With the multitude of available platforms the function will probably need to determine the encoding or offer an option to specify one.

      I’ll look into it.


    Thanks for v3

    Have you been able to get this to work in powershell Core for Linux? I have been trying to get it working on Core 6.x and 7.0 preview and get these errors:

    ERROR The remote certificate is invalid according to the validation procedure.

    7.x preview:
    Exception calling “CreateTemporaryDirectoryInGuest” with “5” argument(s): “Failed to authenticate with the guest operating system using the supplied credentials.”

    I tried adding
    Set-PowerCLIConfiguration -InvalidCertificateAction ignore -confirm:$false
    but still receiving same issue.


      Yes, I am trying to do PS Core in Linux and am receiving the same thing. Please update accordingly!


        Which Linux version do you have as the Guest OS?
        And which vSphere version (ESXi & VCSA)?

    Dave Benayoun

    Hey Luc love your scripts! Quick question though any chance of adding something similar to invoke-command $using: so that I can pass my local variables to the session?



      Hi Dave,
      There is, unfortunately, no ‘connection’ between the station where you run Invoke-VMScriptPlus and the script running on the target station.
      Unlike the PS remote sessions where that kind of connection is present.

      The best substitute, imho, is to substitute your local variables in the code you sent, before calling Invoke-VMScriptPlus.
      Have a look at my Here string and variable substitution and Here strings and the ExpandString method posts.

      Hope this helps,

    Cloud-init - Part 4 - Running Scripts - LucD notes

    […] avoid those issues I have written my Invoke-VMScriptPlus function. Besides fixing the above-mentioned issues, it also adds some extra features that come in […]

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.