VMware Cloud Community
mazdajai
Contributor
Contributor
Jump to solution

for loop on vcenters - list skipping on fail

I have a for loop get-vm statement against a list of vcenters with try/catch. For some reason when one of the vcenter fails, the remaining will fail and will not run.

Sample list of vcenters.inputs:

BadVC1

GoodVC1 <---will not run if BadVC1 fails

GoodVC2<---will not run if BadVC1 fails

$pwd='d:\';

$vcenters=gc vcenters.input | sort;

$invuser='xxx';

$invpass='xxx';

$outlog="$(Get-Date -uformat %m%e%g)_run.log";

$errlog='error.log';

"Time :: host :: Runtime (seconds)" | Out-file -Encoding UTF8 $outlog

"$MyInvocation.MyCommand.Definition" | Out-file -Encoding UTF8 $errlog

foreach ($vcenter in $vcenters) {

    $startsec=Get-Date

    $outfile=$vcenter+"_inv.csv"

try

{

    connect-viserver $vcenter -User $vcenter\$invuser -Password $invpass

    $Report = @()

       

    Get-VM | % {

        $vmcls = $_ | Get-Cluster

        $vmnet = $_ | Get-NetworkAdapter

        $vmds = $_ | Get-Datastore

        $vms = "" | Select-Object Cluster, Host, Name, FQDN, State, OS, Network, Memory, CPU, ServerRole, `

        PatchGroup, DataStore, ProvisionedGB, ConsumedGB, Contact, PVU, Replicated, Notes

        $vms.Cluster = $vmcls.Name

        $vms.Host = $_.VMHost   

        $vms.Name = $_.Name

        $vms.FQDN = $_.Guest.HostName

        $vms.State = $_.PowerState

        $vms.OS = $_.Guest.OSFullName

        $vms.Network = $vmnet.NetworkName

        $vms.Memory = $_.MemoryMB

        $vms.CPU = $_.NumCpu

        $vms.ServerRole = $_.CustomFields.Item("ServerRole")

        $vms.PatchGroup = $_.CustomFields.Item("PatchGroup")

        $vms.DataStore = $vmds.Name

        $vms.ProvisionedGB = $_.ProvisionedSpaceGB

        $vms.ConsumedGB = $_.UsedSpaceGB

        $vms.Contact = $_.CustomFields.Item("System Contact")

        $vms.PVU = $_.CustomFields.Item("PVU")

        $vms.Replicated = $_.CustomFields.Item("Replicated")

        $vms.Notes = $_.Notes

        $Report += $vms

       }

    $Report | ConvertTo-csv | Out-file -Encoding UTF8 $pwd\data\$outfile

    Disconnect-VIServer $vcenter -confirm:$false

    $endsec=Get-Date;

    "$(Get-Date -uformat %H:%M:%S) :: $vcenter :: $((New-TimeSpan -Start $startsec -End $endsec).TotalSeconds)" | Out-file -Encoding UTF8 -Append $outlog

}

catch

{

"$(Get-Date -uformat %H:%M:%S) :: $vcenter :: EXCEPTION" | Out-file -Encoding UTF8 -Append $outlog

$error | Out-file -Encoding UTF8 -Append $errlog

}   

};

Reply
0 Kudos
1 Solution

Accepted Solutions
Craig_Baltzer
Expert
Expert
Jump to solution

I suspect that you're getting caught up in some Try/Catch stuff. For cmdlets its important that the error action is "stop" when you're using Try/Catch, and that's not the default for all cmdlets (you can try throwing an "-ErrorAction Stop" on all of the cmdlet calls).

Also the common coding pattern for controllable errors is to use -ErrorAction and -ErrorVariable to handle things gracefully rather than Try/Catch (try/catch also makes it hard to clean up after yourself (i.e. if "connect-viserver" fails then you don't need to do a "disconnect-viserver" in the catch, however if you ended up in the catch because Get-VM failed, then you should do a disconnect-viserver)). So as an alternative

Connect-VIServer $vcenter -User $vcenter\$invuser -Password $invpass -ErrorAction SilentlyContinue -ErrorVariable Err

If ($Err -ne $Null) {

     # Write logs to say connect failed or do whatever else you want to do. Since this is granular you can write something specific about the error in the log rather than just "Exception"

}

Else {

    # continue on with the rest of your processing. If you're worried about Get-VM or other cmdlets failing, then use the same coding pattern to check for errors

}

View solution in original post

Reply
0 Kudos
6 Replies
LucD
Leadership
Leadership
Jump to solution

Try adding a Continue statement to the end of the Catch block


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

Reply
0 Kudos
mazdajai
Contributor
Contributor
Jump to solution

No luck. Smiley Sad

I have attached an error.log that I send $error to.

catch

{

"$(Get-Date -uformat %H:%M:%S) :: $vcenter :: EXCEPTION" | Out-file -Encoding UTF8 -Append $outlog

$error | Out-file -Encoding UTF8 -Append $errlog

continue

}

Time :: host :: Runtime (seconds)

17:11:40 :: BADVC1:: EXCEPTION

17:18:50 :: GoodVC1:: EXCEPTION

Reply
0 Kudos
mazdajai
Contributor
Contributor
Jump to solution

Updated:

I closed the powercli prompt and re-run the script, it seems to be working (with or without the continue statement). It seems like it happens when it has previous connection to the VCs. If I open a new powercli prompt, I don't get the error. I have a line to disconnect-viserver, does it not working? Is there a way to cleanly clear all VC session?

Reply
0 Kudos
Craig_Baltzer
Expert
Expert
Jump to solution

Disconnect-VIServer * -Force -Confirm:$False

will kill your sessions to all connected servers.

One thing to keep in mind is if your code runs Connect-VIServer servername multiple times (or your code runs Connect-VIServer and stops before the matching Disconnect-VIServer and you run your script a bunch of times), then you have to run Disconnect-VIServer servername an equal number of times to get fully disconnected. Using * -Force disconnects everything.

$Global:DefaultVIServers | Where-Object {$_.RefCount -gt 1}

will show you which servers have been connected multiple times...

Reply
0 Kudos
mazdajai
Contributor
Contributor
Jump to solution

Thanks. I added 'Disconnect-VIServer * -Force -Confirm:$False' but there is an issue when one of them fail:

Time :: host :: Runtime (seconds)

12:06:49 :: bavc1 :: 1286.3862268

13:17:41 :: bvc1:: 4252.2041729

13:30:23 :: lvc1:: 761.6258825

13:30:30 :: lxdvc :: EXCEPTION!

13:34:00 :: lxvc1:: EXCEPTION!

13:37:28 :: nvc2:: EXCEPTION!

13:40:55 :: svc1:: EXCEPTION!

13:46:52 :: stavc1:: EXCEPTION!

13:53:28 :: zvc1:: EXCEPTION!

I restricted the get-vm to get-vm *abc* to speed up the troubleshooting and found the culprit - there was a global attribute missing one of the vc.

Time :: host :: Runtime (seconds)

21:01:56 :: bavc1 :: 54.4264154

21:02:23 :: bvc1 :: 27.2972137

21:02:29 :: lvc1 :: 5.9372769

21:02:36 :: lxdvc :: EXCEPTION!

21:02:51 :: lxvc1 :: EXCEPTION!

21:03:04 :: nvc2 :: EXCEPTION!

21:03:16 :: svc1 :: EXCEPTION!

21:03:32 :: stavc1 :: EXCEPTION!

21:03:50 :: zvc1 :: EXCEPTION!

By the question is 1) why it skip and HALT! the rest when it fail? 2) Is this new in powercli 6.0? it never happen in 5.5 or older.

21:06:38 :: bavc1 :: 30.5933593

21:06:52 :: bvc1 :: 13.7796256

21:06:57 :: lvc1 :: 5.4512553

21:07:09 :: lxvc1 :: 12.2495468

21:07:22 :: nvc2 :: 12.1385508

21:07:27 :: svc1 :: 5.1842234

21:07:31 :: stavc1 :: 4.1381707

21:07:37 :: zvc1 :: 5.6402636

Reply
0 Kudos
Craig_Baltzer
Expert
Expert
Jump to solution

I suspect that you're getting caught up in some Try/Catch stuff. For cmdlets its important that the error action is "stop" when you're using Try/Catch, and that's not the default for all cmdlets (you can try throwing an "-ErrorAction Stop" on all of the cmdlet calls).

Also the common coding pattern for controllable errors is to use -ErrorAction and -ErrorVariable to handle things gracefully rather than Try/Catch (try/catch also makes it hard to clean up after yourself (i.e. if "connect-viserver" fails then you don't need to do a "disconnect-viserver" in the catch, however if you ended up in the catch because Get-VM failed, then you should do a disconnect-viserver)). So as an alternative

Connect-VIServer $vcenter -User $vcenter\$invuser -Password $invpass -ErrorAction SilentlyContinue -ErrorVariable Err

If ($Err -ne $Null) {

     # Write logs to say connect failed or do whatever else you want to do. Since this is granular you can write something specific about the error in the log rather than just "Exception"

}

Else {

    # continue on with the rest of your processing. If you're worried about Get-VM or other cmdlets failing, then use the same coding pattern to check for errors

}

Reply
0 Kudos