Hello team
i'm trying to validate local admin credential for all vms
#1 Able to submit validation for all vms without waiting for other to complete by command : 'Invoke-VMScript RunAsync'
#2 but try...catch doesn't work for some reason, the 'Catch part never get evaluated, even though tasks.state show some vms failed to login
Question :
the interesting thing is foreach loop work fine for try...catch, and try..catch doesnot work when use 'foreach-object -process'
if there is a way to catch error when Invoke-VMScript RunAsync ?
#################
' $result : output shows all good. But the real result are item 1 - 5 : 'error for login' and item6 'login successfully' if compare with below "tasks.state output "
tasks.state output :
###script####
$VMName=Get-VM | Where-Object {$_.PowerState -eq "PoweredOn" -and $_.ExtensionData.Config.GuestFullName -like "*Microsoft*" }
$tasks = @()
$result = @()
$tasks += $VMName | ForEach-Object -process {
try{
(Invoke-VMScript -vm $_ -GuestUser ".\XXX" -GuestPassword "XXX" -ScriptText " " -ErrorAction Stop -ScriptType Powershell -RunAsync -confirm:$false)
$Loginstate= "Login Sucessfully"
write-host "$($_.name) successful guest login"
}
catch [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.InvalidGuestLogin]{
$Loginstate= "Invalid guest logon"
Write-Host "$($_.name) invalid guest login"
Write-Output $_
}
catch{
$Loginstate= "something went wrong !"
Write-Host "$($_.name) other error"
Write-Output $_
}
###
$result += $_ | Select Name,
@{N='Output';E={$Loginstate}},
@{N='IP';E={(Get-VMGuest -VM $_ | Select -ExpandProperty IPAddress) -join '|'}}
}
}
The Try-Catch construct will intercept a terminating exception.
With -ErrorAction Stop you specify that every error will be a terminating exception.
So far so good, your logic is correct.
But with the RunAsync option you tell the Invoke-VMScript cmdlet to start the script and then return to continue execution of the rest of the code.
In your case the Try-Catch will only handle any errors that are caused by the start of the Invoke-VMScript cmdlet.
Not any errors that the actual script started with Invoke-VMScript triggers.
Leave out the RunAsync and you should see the difference.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
The Try-Catch construct will intercept a terminating exception.
With -ErrorAction Stop you specify that every error will be a terminating exception.
So far so good, your logic is correct.
But with the RunAsync option you tell the Invoke-VMScript cmdlet to start the script and then return to continue execution of the rest of the code.
In your case the Try-Catch will only handle any errors that are caused by the start of the Invoke-VMScript cmdlet.
Not any errors that the actual script started with Invoke-VMScript triggers.
Leave out the RunAsync and you should see the difference.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thank you @LucD
You're right, get ride of -RunAsync, and initiated by a cmdlet do not run in parallel, run it in a loop and try-catch handles the error properly.
Because there are more than hundred machines need to check so I would like to run in parallel.
For Invoke-VMScript, to refresh the task status, pass the task object to the Get-Task cmdlet will not work rather have to call tasks.state directly(client side task)
Question:
I'm looking to see if there is a way to get the vm name along with tasks.state, coz the regular tasks.task output doesn't has vm properties.
When you use Start-Job for parallelism ou don't need that RunAsync switch.
Just make sure that limit the maximum number of background jobs you run with Start-Job.
Client-side tasks are not visible through Get-Task I'm afraid.
You could use the Get-Job cmdlet to check on the status of the background jobs.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
thank you @LucD
I will try your recommendation 'start-job' and report back
Right, client-side task doesn't avail via get-task so I modified my code, and as a workaround I'm able to bind state with VM name by adding a new temp hash table
####Script to validate local admin cred###
while ($tasks.State -contains 'running') {
Start-Sleep 1
}