PowerCLI

 View Only
Expand all | Collapse all

Disconnect-VIServer error wrapping/handling (might not working as expected?)

LucD

LucDJan 23, 2024 09:43 AM

  • 1.  Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Jan 22, 2024 05:05 PM

    Hi,

    Scratching my head right now about error wrapping/handling for "Disconnect-VIServer" while connecting/disconnecting to/from ESXi host (yes, yes, not vCenter but ESXi host).

    Basic command is as below:

     

     

    $disconnect = Disconnect-VIServer -Server <targetVMHost> -Confirm:$false

     

     

    So it seems that I'm able to get 2 types of error for now out of that above command.

    1. "Could not find any of the servers specified by name"

     

     

    Disconnect-VIServer: C:\Users\pp\Desktop\project\script.ps1:54:19
    Line |
      54 |  … isconnect = Disconnect-VIServer -Server "test" -Confirm:$false -Force …
         |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         | 1/22/2024 10:03:44 AM Disconnect-VIServer  Could not find any of the servers specified by name. 

     

     

    2. "Cannot validate argument on parameter 'Server (...)'."

     

     

    Disconnect-VIServer: C:\Users\pp\Desktop\project\script.ps1:54:47
    Line |
      54 |  … $disconnect = Disconnect-VIServer -Server $targetVmHost_DEBUG -Confir …
         |                                              ~~~~~~~~~~~~~~~~~~~
         | Cannot validate argument on parameter 'Server'. The argument is null or empty. Provide an argument that is not null or empty, and then try the
         | command again.

     

     

    As far as I can see adding "-WarningAction SilentlyContinue -ErrorAction SilentlyContinue" doesn't really change anything.

    Also $disconnect is $null in both cases and there is nothing inside "$Error[0]".

     

    Something is not working as expected? How should I handle this?

     


  • 2.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Jan 22, 2024 05:34 PM

    Did you try with a Try-Catch construct?
    If you also want to catch non-terminating exceptions you could add the -ErrorAction Stop parameter.



  • 3.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Jan 22, 2024 05:36 PM

    Haven't tried Try-Catch in this particular example, however just wondering why it's not working out of the box.



  • 4.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Jan 22, 2024 06:31 PM

    As far as I can tell, the error messages are clear.
    In one case the server can not be found, in the other case the value on the Server parameter seems to be empty.

    Since these are terminating errors the SilentlyContinue will not help.

    Not sure what behavior you would expect.



  • 5.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Jan 23, 2024 09:08 AM

    Right now, the error is displayed even with SilentlyContinue (but from what you have written it seems it is expected).

    Instead of having error displayed, I would prefer to contain/hide it somehow and display something a bit nicer.

     

    For Connect-VIServer I've used something like this:

     

    $connect = Connect-VIServer -Server $targetVmHost -User $username -Password $password -ErrorAction SilentlyContinue
    
    if ($null -eq $connect) {
        Write-Host -ForegroundColor Red "Failed"
        Write-Host ""
        Write-Host "Cannot connect to the ESXi host!"
        Write-Host ""
        if ($Error[0] -like "*No such host is known.*") {
            Write-Host "Error: (...) No such host is known (...)"
        }
        elseif ($Error[0] -like "*incorrect user name or password*") {
            Write-Host "Error: (...) incorrect user name or password (...)"
        } else {
            Write-Host "Error: Unknown error!"
        }
    } else {
        # CONTINUE WITH REST OF THE SCRIPT
        Write-Host -ForegroundColor Green "OK"
    }

     

    Above works perfectly and I was wondering how to do it for Disconnect-VIServer.

    Or is there more elegant/proper way of doing this?



  • 6.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Jan 23, 2024 09:43 AM

    Use a Try-Catch construct



  • 7.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 07, 2024 10:25 AM

    From try-catch idea point of view, embedding another try-catch inside try-catch is something normal?

    Is it valid to do it like this?

    $targetVmName = "testVm"
    
    try {
        $vm = Get-VM -Name $targetVmName -ErrorAction Stop
        try {
            Start-VM -VM $targetVmName -ErrorAction Stop
    
    
        }
        catch {
            <#Do this if a terminating exception happens#>
        }
    }
    catch {
        <#Do this if a terminating exception happens#>
    }


  • 8.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 07, 2024 10:46 AM

    Maybe I should expand a little more on this one.

    There is no point of doing Disconnect-VIServer if Connect-VIServer didn't work in first place.

    What's the best/proper way to do it with try-catch?



  • 9.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 07, 2024 12:00 PM

    You can include the COnnect-VIServer cmdlet in the Try block.



  • 10.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 08, 2024 03:59 PM

    What about placing try-catch in foreach loop?

    If we will place Get-VM -Name "vmName" -ErrorAction Stop inside try-catch inside foreach loop and VM will not be found, try-catch will actually stop the whole loop?



  • 11.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 08, 2024 04:08 PM

    Depends what you do in the Catch block



  • 12.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 08, 2024 05:03 PM

    Well, it does work, I have just rewritten few lines and clearly it does.

    Probably I made a typo and wasn't able to find it in the code



  • 13.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 12, 2024 10:40 AM

    Everything is fine until I try to display $report_targetObjects between Connect-VIServer and Disconnect-VIServer.

    # CONNECTING TO TARGET ESXi HOST
    if ($proceed -eq $true) {
        try {
            Write-Host "Connecting to ESXi host, please wait..."  
            $connect = $null
            $connect = Connect-VIServer -Server $targetVmHost -User $username -Password $password -ErrorAction Stop
            Write-Host "Connected to ESXi host: '$targetVmHost'!"
        }
        catch {
            if ($Error[0] -like "*No such host is known.*") {
                Write-Host "Error: (...) No such host is known (...)"
                Write-Host ""
            } elseif ($Error[0] -like "*incorrect user name or password*") {
                Write-Host "Error: (...) incorrect user name or password (...)"
                Write-Host ""
            } else {
                Write-Host "Error: Unknown error!"
                Write-Host ""
            }
        }
    }
    # CONNECTING TO TARGET ESXi HOST
    
    # CHECKING IF VM EXISTS
    if ($proceed -eq $true) {
        foreach ($virtualMachine in $report_targetObjects) {
            try {    
                Get-VM -Name $virtualMachine.vmName -ErrorAction Stop | Out-Null
                $virtualMachine.psobject.Properties.Add([PSNoteProperty]::new("found", "yes"))
            }
            catch {
                if ($Error[0] -like "*was not found using the specified filter(s).*") {
                    $virtualMachine.psobject.Properties.Add([PSNoteProperty]::new("found", "no"))
                } else {
                    Write-Host "Error: Unknown error!"
                }
            }
        }
    
        $report_targetObjects
    }
    # CHECKING IF VM EXISTS
    
    # DICONNECTING FROM TARGET ESXi HOST
    if ($proceed -eq $true) {
        try {
            Write-Host "Disconnecting from ESXi host, please wait..."    
            $disconnect = $null
            $disconnect = Disconnect-VIServer -Server $targetVmHost -Confirm:$false -ErrorAction Stop
            Write-Host "Disconnected from ESXi host: '$targetVmHost'!"
        }
        catch {
            Write-Host "Error occured!"
        }    
    }
    # DICONNECTING FROM TARGET ESXi HOST

    Result is that table is displayed AFTER disconnecting from ESXi hosts. Not sure if this is problem with displaying or I'm doing something wrong.

    Flag-1
    Connecting to ESXi host, please wait...
    Connected to ESXi host: 'vmHost.corp.domain.net'!
    
    Disconnecting from ESXi host, please wait...
    Disconnected from ESXi host: 'vmHost.corp.domain.net'!
    vmName        vmHost  powerState        found
    ------        ------  ----------        -----
    test1         vmHost1 desiredPowerState no
    test2         vmHost1 desiredPowerState no
    testVm_piotr  vmHost1 desiredPowerState yes
    testVm_piotr3 vmHost1 desiredPowerState no
    
    PS C:\Users\pp\Desktop\project>

     



  • 14.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 12, 2024 10:50 AM

    Hm... I've added Format-Table at the end of $report_targetObjects and it helped but I don't understand why.



  • 15.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 12, 2024 11:25 AM

    Now the output looks like this:

    Flag-1
    Connecting to ESXi host, please wait...
    Connected to ESXi host: 'vmHost.corp.domain.net'!
    
    vmName        vmHost  powerState        found
    ------        ------  ----------        -----
    test1         vmHost1 desiredPowerState no
    test2         vmHost1 desiredPowerState no
    testVm_piotr  vmHost1 desiredPowerState yes
    testVm_piotr3 vmHost1 desiredPowerState no
    
    Disconnecting from ESXi host, please wait...
    Disconnected from ESXi host: 'vmHost.corp.domain.net'!

    What's the difference between below two?

    #1

    $report_targetObjects

     

    #2

    $report_targetObjects | Format-Table

     



  • 16.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 12, 2024 12:38 PM

    That is a quirk of the PS output engine.
    It looks at the 1st output and then tries to look for similar output.
    Hence the order you expect is not always there.
    You can force output by sending that output to an output formatting cmdlet like Format-Table.
    A better option, imho, is to use the Out-Default cmdlet, which also forces the output but doesn't do any special formatting.



  • 17.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 14, 2024 09:47 AM

    Few days ago someone has posted here (and shortly after removed it), changed version of my code.

    In that post instead of using $Error[0] he recommended $_.Exception.Message while using try-catch.

    Is there any justification from practical/best practices point of view to use $_.Exception.Message or is it just a matter of preference?



  • 18.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)
    Best Answer

    Posted Feb 14, 2024 10:09 AM

    I removed that reply because it came from a spammer.
    The reply contained a link to a gambling site.

    In a Try-Catch, you can target specific exceptions in multiple Catch blocks.
    See for example Solved: Re: Needs to upgrade VMtools for all the outdated... - VMware Technology Network VMTN

    The $error[0] will just return a standard representation (on the console) of the last error, i.e. the exception.
    You can use any of the properties of the $error global variable to filter or display, but imho it is better to use the types of exceptions in multiple Catch blocks.



  • 19.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 15, 2024 10:30 AM

     

    Regarding script from that link you were kind to share. Below will not work right (it's not working at least in my PowerShell console)?

     

        } catch {
          Write-Host "`tException $($error[0].Message)" -ForegroundColor red
        }

     

    It works when I change it to $error[0].Exception.Message;



  • 20.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 15, 2024 10:36 AM

    Yes, that is a typo.
    But the idea behind that example was to show that you can have multiple catch blocks.
    Some with specific exceptions and a catch-all at the end.



  • 21.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 15, 2024 10:53 AM

    So we have:

     

    #
    try {
        Write-Host "Connecting to ESXi host: '$($targetVmHost)', please wait..."  
        $cmdlet_ConnectVIServer = $null
        $cmdlet_ConnectVIServer = Connect-VIServer -Server $targetVmHost -User $username -Password $password -ErrorAction Stop
        Write-Host "Connected to ESXi host: '$($targetVmHost)'!"
    }
    catch {
        if ($_.Exception.Message -match "No such host is known.") {
            Write-Host "Error: (...) No such host is known (...)"
        } elseif ($_.Exception.Message -like "*incorrect user name or password*") {
            Write-Host "Error: (...) incorrect user name or password (...)"
        } else {
            Write-Host "Error: Unknown error!"
        }
    }

     

    or

     

    try {
        Write-Host "Connecting to ESXi host: '$($targetVmHost)', please wait..."  
        $cmdlet_ConnectVIServer = $null
        $cmdlet_ConnectVIServer = Connect-VIServer -Server $targetVmHost -User $username -Password $password -ErrorAction Stop
        Write-Host "Connected to ESXi host: '$($targetVmHost)'!"
    }
    catch {
        "No such host is known."
        Write-Host "Error: (...) No such host is known (...)"
    }
    catch {
        "*incorrect user name or password*"
        Write-Host "Error: (...) incorrect user name or password (...)"
    }

     

    Well, maybe multiple catch blocks looks a bit more elegant in the end... and 'less code'. How would you code that Write-Host "Error: Unknown error!" with catch {} to catch any other errors than two above?



  • 22.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 15, 2024 11:03 AM

    You will have to provide the type of the exception in the 1st Catch block.
    The 2nd one, without an exception type, is the catch-all.

    It all depends on which exception from the Connect-VIServer cmdlet you want to capture in the 1st Catch block.

    I often use the following to find these types of exceptions.
    Start with only 1 Catch block in which you place

    $Error[0].exception.GetType().fullname

     Now you can use that type to create a specific Catch block.
    And add the catch-all at the end to handle all other types of exceptions.



  • 23.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 19, 2024 12:20 PM

    Hm...

    Something is not right.

     

    $targetVmName = "test"
    
    try {
        $virtualMachine = Get-VM -Name $targetVmName -ErrorAction Stop
    
        $virtualMachine
    }
    catch {
        $Error[0].Exception.GetType().FullName
    }

     

    Shows only:

     

    VMware.VimAutomation.Sdk.Types.V1.ErrorHandling.VimException.VimException

     

     

    However $Error[0] shows:

     

    Get-VM: C:\Users\piotrpierzchala\Desktop\project_threatModeling\try-catch_test.ps1:4:23
    Line |
       4 |      $virtualMachine = Get-VM -Name $targetVmName -ErrorAction Stop
         |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         | 2/19/2024 1:17:08 PM Get-VM  VM with name 'test' was not found using the specified filter(s). 

     

     

    Or is it actually correct output in this case? I would just expect a bit more specific.

    Anyone has already created like a list of exceptions that can occur or do I have to find it each time directly via PowerShell console?



  • 24.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 19, 2024 12:43 PM

    Not sure what you mean by "Something is not right."?

    And to answer your question, no there isn't a complete list with all the exceptions a cmdlet can generate.
    Since PS is built on .Net there can be exceptions coming from many layers.
    Not just PowerCLI in this case.
    Some module developers do provide a restricted list with the exceptions their cmdlet can generate, but that is unfortunately not the case with the PowerCLI modules.

    You will have to determine this for yourself when writing your code.
    That is btw one of the functions imho of the Pester tests you (should) write to validate your code.

    In your example, the 'VMware.VimAutomation.Sdk.Types.V1.ErrorHandling.VimException.VimException' is a rather general exception generated by some PowerCLI cmdlets.
    But you can use for example the ErrorCategory to find-tune your Catch block.
    Something like this

    $targetVmName = "test"
    
    try {
      $virtualMachine = Get-VM -Name $targetVmName -ErrorAction Stop
    
      $virtualMachine
    }
    catch [VMware.VimAutomation.Sdk.Types.V1.ErrorHandling.VimException.VimException] {
      switch($Error[0].Exception.ErrorCategory){
        'ObjectNotFound' {
          Write-Host "VM $($error[0].Exception.Data['ParameterValues']['Name']) not found"
        }
        Default {
          Write-Host "Another VIM exception"
        }
      }
    }
    catch {
      $Error[0].Exception.GetType().FullName
    }

    For me determining the list of exceptions your code can encounter, like I said before, is part of the development of the Pester tests for your code.



  • 25.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 19, 2024 01:18 PM

    After your post about trying to catch exceptions with specific error [(...).FullName] I just had a hope that there might be universal way to catch every type of error. I feel that still there is a need to make code more complicated for error where host (VM or VMHost) is not found by adding switch and using ErrorCategory property (which I don't mind. But it doesn't seems to be right - at least for me).

     

    • For Connect-VIServer if you provide wrong username/password you get specific $Error[0].Exception.GetType().FullName which is "VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.InvalidLogin".
    • For Connect-VIServer if you provide wrong ESXi host name (which doesn't exist) as -Server you get very generic exception which doesn't indicate what could be wrong - "VMware.VimAutomation.Sdk.Types.V1.ErrorHandling.VimException.ViError". The same applies when you try to look for a VM which doesn't exist via Get-VM -Name <targetVm> - it also shows very generic [(...).FullName].

     

    Anyway, try-catch is the way.

     

    You've mentioned there is no list of exceptions for every PowerCLI command. So everyone has the same problem? If they try to wrap certain error, they have to 1) run the command, 2) try to break it to find errors that might occur, 3) wrapp it around with for example try-catch?



  • 26.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Feb 19, 2024 01:32 PM

    Yes on all 3 questions



  • 27.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Apr 03, 2024 07:56 AM

    I've found a thing which I don't know how to explain...

    Below will give nothing in the output.

     

    $vCenterVmCloneName = "piotrTest_backup_63.03.2024"
    Get-VM -Name *$vCenterVmCloneName* -ErrorAction Stop

     

    But:

    $vCenterVmCloneName = "piotrTest_backup_63.03.2024"
    Get-VM -Name $vCenterVmCloneName -ErrorAction Stop

     

    Will give:

    Get-VM: 4/3/2024 9:49:58 AM Get-VM VM with name 'piotrTest_backup_64.03.2024' was not found using the specified filter(s).

     

    What's the difference? VM doesn't exist.

     



  • 28.  RE: Disconnect-VIServer error wrapping/handling (might not working as expected?)

    Posted Apr 03, 2024 09:06 AM

    This is a known discussion point, the difference between what a cmdlet should return when using a literal value and a wildcard/filtering value.
    See the reply from Steve in the discussion

    I quote

    the intent is for a literal to return a non-terminating error, but wildcards/filtering to return nothing"

    It might "feel" wrong, but it is working as designed.
    Btw, there are many Get- cmdlets that show the same.
    Play with for example the Get-Process cmdlet