Highlighted
Enthusiast
Enthusiast

Can a PowerCLI script display a prompt on a Guest OS?

So I'm writing a script to reboot all the VM's in a folder.  Very simple, no big deal.  What I'd like to know though is if there's a way in PowerCLI to put a prompt on the machines that they're being rebooted and somehow have a timer so a user can save any data if necessary and if perhaps they click ok it starts the reboot sooner and if not once the timer has counted down it reboots.  Is that possible using the Invoke-VM command or do I need to do something else?

0 Kudos
35 Replies
Highlighted
User Moderator
User Moderator

Published my solution, see Message To All Users, And Their Reply


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Hi LucD,

Thanks for the help on this.  I feel like an idiot asking this, but how do I import the Invoke-VMScriptPlus as a module in PowerShell or PowerCLI?  I thought I could save the code as a ps1 or pds1 but it definitely didn't like the pds1 when I tried to import it.  I just want to make sure I have everything setup right before I give it a shot and so I know how to show other users on my team in case they ever need to run this.

0 Kudos
Highlighted
User Moderator
User Moderator

At the moment I didn't place it in a module.
There a couple of ways to make the function known to your system:

  • place everything in 1 .ps1 file (the Invoke-VMScriptPlus function and the script that sends the Messagebox. Then just run the .sp1
  • place the Invoke-VMScriptPlus function in a .ps1 file. Place the MessageBox script in another .ps1 file. In that last .ps1 file you can dot-source the Invoke-VMScriptPlus .ps1 file. That way the function is "known" in your PowerShell session. Dot-sourcing is done like this ". .\Invoke-VMScriptPlus.ps1" (there is a space between the 2 dots at the beginning)
  • Create a module. Place the function in a .psm1 file, then create a manifest (.psd1) with the New-ModuleManifest cmdlet.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Hi LucD,

Ok when I try to get everything to run I wind up getting this issue:

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.
At C:\Users\emcclure\Desktop\GenScripts\Invoke-VMScriptPlus.ps1:237 char:13
+ $hostName = Resolve-DnsName -Name $ip | Select-Object -ExpandProperty ...
+             ~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Resolve-DnsName:String) [], Com
   mandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Invoke-WebRequest : Cannot bind parameter 'Uri'. Cannot convert value
"https://:443/guestFile?id=197&token=52e6ffc7-9002-4ea5-e2bd-33599ea10971197"
to type "System.Uri". Error: "Invalid URI: The hostname could not be parsed."
At C:\Users\emcclure\Desktop\GenScripts\Invoke-VMScriptPlus.ps1:239 char:38
+ $copyResult = Invoke-WebRequest -Uri $filePath -Method Put -Body $Scr ...
+                                      ~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-WebRequest], Parame
   terBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerSh
   ell.Commands.InvokeWebRequestCommand

ScripText copy failed!Status
At C:\Users\emcclure\Desktop\GenScripts\Invoke-VMScriptPlus.ps1:241 char:1
+ Throw "ScripText copy failed!`rStatus $($copyResult.StatusCode)`r$(($ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (ScripText copy failed!Status
    :String) [], RuntimeException
    + FullyQualifiedErrorId : ScripText copy failed!Status

What did I do wrong?

0 Kudos
Highlighted
Enthusiast
Enthusiast

Ok figured that out.  I was running from Windows 7 and that module isn't on there.  I went to a Windows 10 machine and didn't get that error, but now I get this:

Cannot find the type for custom attribute 'MyOBN'. Make sure that the assembly that contains this type is loaded.

At C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Invoke-VMScriptPlus\Invoke-VMScriptPlus.psm1:81 char:1

+ [MyOBN('VirtualMachine')]

+ ~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidOperation: ([MyOBN('VirtualMachine')]:AttributeAst) [], RuntimeException

    + FullyQualifiedErrorId : CustomAttributeTypeNotFound

0 Kudos
Highlighted
User Moderator
User Moderator

Did you copy the class MyOBN that I provided in the same post as the Invoke-VMScriptPlus V2 post?
The easiest way is to copy everything in one .ps1 file.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Ok so I copied the Invoke-VMScriptPlus v2 and Message to all users into one ps1 file and called it AllForOne.ps1.  I try running that, but I just get errors.  Initially if I just leave things the way they are I get this:

Invoke-VMScriptPlus : Cannot process argument transformation on parameter 'VM'. Index was out of range. Must be
non-negative and less than the size of the collection.
Parameter name: index
At C:\Users\emcclure\Desktop\GenScripts\AllForOne.ps1:436 char:31
+ $result = Invoke-VMScriptPlus @sInvP
+                               ~~~~~~
    + CategoryInfo          : InvalidData: (:) [Invoke-VMScriptPlus], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Invoke-VMScriptPlus

You cannot call a method on a null-valued expression.
At C:\Users\emcclure\Desktop\GenScripts\AllForOne.ps1:436 char:1
+ $result = Invoke-VMScriptPlus @sInvP
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Then if I change the VM name you have in there to something I want to reboot I get this:

ConvertTo-SecureString : Cannot bind argument to parameter 'String' because it is null.
At C:\Users\emcclure\Desktop\GenScripts\AllForOne.ps1:424 char:41
+ $sPswd = ConvertTo-SecureString -String $pswd -AsPlainText -Force
+                                         ~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertTo-SecureString], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertToSe
   cureStringCommand

Exception calling "GetNetworkCredential" with "0" argument(s): "Object reference not set to an instance of an object."
At C:\Users\emcclure\Desktop\GenScripts\AllForOne.ps1:196 char:1
+ $GuestUser = $GuestCredential.GetNetworkCredential().username
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NullReferenceException

Exception calling "GetNetworkCredential" with "0" argument(s): "Object reference not set to an instance of an object."
At C:\Users\emcclure\Desktop\GenScripts\AllForOne.ps1:197 char:1
+ $plainGuestPassword = $GuestCredential.GetNetworkCredential().passwor ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NullReferenceException

Exception calling "CreateTemporaryFileInGuest" with "5" argument(s): "A general system error occurred: vix error codes
= (3033, 0).
" Exception calling "GetNetworkCredential" with "0" argument(s): "Object reference not set to an instance of an
object." Exception calling "GetNetworkCredential" with "0" argument(s): "Object reference not set to an instance of an
object." Cannot bind argument to parameter 'String' because it is null. You cannot call a method on a null-valued
expression. Cannot process argument transformation on parameter 'VM'. Index was out of range. Must be non-negative and
less than the size of the collection.
Parameter name: index 8/6/2018 10:08:56 AM      Get-VM          VM with name 'vEng' was not found using the specified filter(s).
8/2/2018 2:17:09 PM     Set-NetworkAdapter              The network "@{Cluster=z610; Name=VLAN3653; VLanId=3653}" doesn't exist on the
host.    8/2/2018 1:58:55 PM    Get-VM          VM with name 'rsupdtest2' was not found using the specified filter(s).   Cannot
validate argument on parameter 'NetworkAdapter'. The argument is null. Provide a valid value for the argument, and
then try running the command again. 8/2/2018 1:58:54 PM Get-NetworkAdapter              Please specify at least one of the
following: VirtualMachine, Template or Snapshot.         8/2/2018 1:58:54 PM    Get-NetworkAdapter              Could not find
VirtualMachine with name 'rsupdtest2'.   8/2/2018 1:58:47 PM    Move-VM         Value cannot be found for the mandatory parameter
VM       8/2/2018 1:58:47 PM    Move-VM         Could not find VirtualMachine with name 'rsupdtest2'.    8/2/2018 1:55:20 PM
Import-VApp             The file item 'EN-W10ERS3x86_disk0.vmdk' does not match the hash from the manifest.      7/31/2018 2:08:02 PM
Set-NetworkAdapter              The network "@{Cluster=z610; Name=VLAN3653; VLanId=3653}" doesn't exist on the host.     7/30/2018
12:05:09 PM     Invoke-VMScript         The guest operations agent could not be contacted.      [0].Exception.Message
At C:\Users\emcclure\Desktop\GenScripts\AllForOne.ps1:220 char:1
+ Throw "$error[0].Exception.Message"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Exception calli...ception.Message:String) [], RuntimeException
    + FullyQualifiedErrorId : Exception calling "CreateTemporaryFileInGuest" with "5" argument(s): "A general system e
   rror occurred: vix error codes = (3033, 0).
    " Exception calling "GetNetworkCredential" with "0" argument(s): "Object reference not set to an instance of an ob
   ject." Exception calling "GetNetworkCredential" with "0" argument(s): "Object reference not set to an instance of
  an object." Cannot bind argument to parameter 'String' because it is null. You cannot call a method on a null-valu
ed expression. Cannot process argument transformation on parameter 'VM'. Index was out of range. Must be non-negat
ive and less than the size of the collection.
    Parameter name: index 8/6/2018 10:08:56 AM  Get-VM          VM with name 'vEng' was not found using the specified filter(s)
   .     8/2/2018 2:17:09 PM    Set-NetworkAdapter              The network "@{Cluster=z610; Name=VLAN3653; VLanId=3653}" doesn't exist
   on the host.  8/2/2018 1:58:55 PM    Get-VM          VM with name 'rsupdtest2' was not found using the specified filter(s).
  Cannot validate argument on parameter 'NetworkAdapter'. The argument is null. Provide a valid value for the argum
ent, and then try running the command again. 8/2/2018 1:58:54 PM        Get-NetworkAdapter              Please specify at least one o
f the following: VirtualMachine, Template or Snapshot.   8/2/2018 1:58:54 PM    Get-NetworkAdapter              Could not find Vir
tualMachine with name 'rsupdtest2'.      8/2/2018 1:58:47 PM    Move-VM         Value cannot be found for the mandatory paramete
r VM     8/2/2018 1:58:47 PM    Move-VM         Could not find VirtualMachine with name 'rsupdtest2'.    8/2/2018 1:55:20 PM    Impo
rt-VApp         The file item 'EN-W10ERS3x86_disk0.vmdk' does not match the hash from the manifest.      7/31/2018 2:08:02 PM
Set-NetworkAdapter              The network "@{Cluster=z610; Name=VLAN3653; VLanId=3653}" doesn't exist on the host.     7/30/20
18 12:05:09 PM  Invoke-VMScript         The guest operations agent could not be contacted.      [0].Exception.Message

So the machine names you see there, rsupdtest2 and EN-W10ERS3x86 are not machine names I specified in the script, so I don't know why it's pulling those.  All I just really want to do is take your scripts and put them into this one:

$GuestCredential = Get-Credential
$vmlocation = Get-VM -Location Domain2 | sort Name #Gets folder where VM's are located, if folder name is not unique in vCenter it will reboot VM's in all folders with same name
foreach ($vm in $vmlocation) {

#$script = '&C:\Users\emcclure\Desktop\GenScripts\RebootMessage.ps1'

Invoke-VMScriptPlus -vm $vm -ScriptText "C:\Users\emcclure\Desktop\GenScripts\RebootMessage.ps1" -ScriptType PowerShell -GuestCredential $GuestCredential | Format-List | Out-File reboot.txt -append

}

So that way all VM's in a folder I specify just get the prompt all at once.  I'd make it a scheduled task to happen on a certain day, but I'm still new to PowerShell and thinking I'm just not doing something right to make this all work.

0 Kudos
Highlighted
User Moderator
User Moderator

Looks like you didn't update all the required fields.
I do for example see my test VM with the name 'vEng' in your errors.
I would need to see the .ps1 file you created.
Can you attach it?
Mask away the sensitive fields you might have in there


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Hi LucD,

Here's the file.  Nothing sensitive in it.

0 Kudos
Highlighted
User Moderator
User Moderator

Try the attached .ps1 file.

You will have to update lines 424 & 425 with an account and password.

This account needs to be able to run scripts on the target station and access the DLL API


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Hi LucD,

So I ran the script from my desktop machine and get this:

Resolve-DnsName : ip.removed.in-addr.arpa : DNS name does not exist
At C:\Users\emcclure\Desktop\test.ps1:237 char:19
+       $hostName = Resolve-DnsName -Name $ip | Select-Object -ExpandPr ...
+                   ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (ip.removed.in-addr.arpa:String) [Resolve-DnsName], Win32Excepti
   on
    + FullyQualifiedErrorId : DNS_ERROR_RCODE_NAME_ERROR,Microsoft.DnsClient.Commands.ResolveDnsName

Invoke-WebRequest : Cannot bind parameter 'Uri'. Cannot convert value
"https://:443/guestFile?id=197&token=52cfa257-a30a-19ea-d060-af7c849421d1197" to type "System.Uri". Error: "Invalid
URI: The hostname could not be parsed."
At C:\Users\emcclure\Desktop\test.ps1:239 char:44
+       $copyResult = Invoke-WebRequest -Uri $filePath -Method Put -Bod ...
+                                            ~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-WebRequest], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

ScripText copy failed!Status
At C:\Users\emcclure\Desktop\test.ps1:241 char:9
+         Throw "ScripText copy failed!`rStatus $($copyResult.StatusCod ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (ScripText copy failed!Status  :String) [], RuntimeException
    + FullyQualifiedErrorId : ScripText copy failed!Status

I figured it's in a different location, so let's use a machine that's in the same location that's on the same vCenter server.  So I ran it from there (with the proper creds) and nothing.  It appears to run, doesn't give me any errors or any output, just goes to the next line in PowerCLI as if it's all good.  I figure I'll try running it in PowerShell on that same machine and all I get is this:

Unable to find type [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine].
At C:\Users\emcclure\Desktop\test.ps1:117 char:5
+     [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (VMware.VimAutom....VirtualMachine:TypeName) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

You cannot call a method on a null-valued expression.
At C:\Users\emcclure\Desktop\test.ps1:440 char:1
+ $result = Invoke-VMScriptPlus @sInvP
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

So what am I missing?  I should be able to run this from anywhere right and it should just work?  It should be able to find the machine in the vCenter and run the script?  For the creds I'm using the local administrator account, so that shouldn't be a problem as far as permissions go.

0 Kudos
Highlighted
User Moderator
User Moderator

Looks like DNS resolution doesn't work on the machine where you call the Invoke-VMScriptPlus function.

The function replaces the IP in the URI (for the script upload to the VM's guest OS) returned by Guest Operations.

This is done to avoid certificate errors on the HTTPS connection


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Ok, I'm not sure why DNS resolution would not work on the machine I'm typing this from as I can go anywhere on the internet, access internal resources by dns name, etc without issue.  When I run the script from a machine that's in the same subnet and location as the target machine though the script just runs, but that's it.  Nothing appears on the target machine.  I've even disabled AV to make sure that wasn't causing a problem.  Windows firewall is off as well, so this makes no sense to me as to why it's not working.  This is rather confusing and I was hoping this would work, but I just don't understand why it's working for you and not for me.

0 Kudos
Highlighted
User Moderator
User Moderator

The DNS name resolution is required to translate the IP address in the URI returned by the Guest Operations.
That URI is used to upload the script, via the ESXi node, to the VM.

In your output it looks like the name resolution of the IP address of the ESXi node on which the target VM is running, doesn't work.

All subsequent errors are a consequence of this 1st error.

You can check if this returns anything on your station

$ip = "<IP-addr-Of-ESXi-node-on-which VM-runs>"

Resolve-DnsName -Name $ip


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Highlighted
Enthusiast
Enthusiast

Hi LucD,

Looking at this page: Invoke-VMScriptPlus v2 - LucD notes  do I need to be using PowerShell v6.0.2?  I think I'm running 5.1 right now.  If so where did you download it exactly so I can use the same version?

Thanks.

0 Kudos
Highlighted
User Moderator
User Moderator

No, PS 5.1 is fine


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos