VMware Cloud Community
Golden275
Contributor
Contributor
Jump to solution

shutdown bulk vms | failed to get-task status

Hello team

i'm unable to get task progress(e.g progress percentage, state, etc..) when shutdown bulk of vms and get a following error :

### Error output ###

Index operation failed; the array index evaluated to null.
At line:10 char:5
+ $taskTab[(Shutdown-VMGuest -vm $_ -Confirm:$false).id] = $_.name
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArrayIndex

### End of error output ###

 

 

### Findings ###

#1 there is no 'id' property for (Shutdown-VMGuest -vm $_ -Confirm:$false)

#2 Tried property (id, uid, vmid and VM) for (Shutdown-VMGuest -vm $_ -Confirm:$false),  but it does not return a  taskid so if/elseif never get evalutated

how to bind (Shutdown-VMGuest -vm $_ -Confirm:$false).property with taskid  ?

 

note: new-snapshot id property auto-bind with taskid, but id property not work for shutdown-vmguest and start-vm : either it not have ID property or return value like this : 3b51542f-69f3-4341-bf2e-a4508bdc2a5f rather than shutdown taskid: Task-task-29072

***

I think the issue is on this command but not sure how to fix it:

$vmlist | ForEach-Object -Process {
 
    $taskTab[(Shutdown-VMGuest -vm $_ -Confirm:$false).id] = $_.name
   
}

 

***
##member of variable (Shutdown-VMGuest -vm $_ -Confirm:$false):


ConvertToVersion       Method T ConvertToVersion[T](), T VersionedObjectInterop.ConvertToVersion[T]()
Equals                         Method bool Equals(System.Object obj)
GetClient                     Method VMware.VimAutomation.ViCore.Interop.V1.VIAutomation VIObjectCoreInterop.GetClient()
GetHashCode             Method int GetHashCode()
GetType                     Method type GetType()
IsConvertableTo        Method bool IsConvertableTo(type toType), bool VersionedObjectInterop.IsConvertableTo(type type)
LockUpdates             Method void ExtensionData.LockUpdates()
ToString                     Method string ToString()
UnlockUpdates          Method void ExtensionData.UnlockUpdates()
ConfiguredGuestId     Property string ConfiguredGuestId {get;}
Disks Property VMware.VimAutomation.ViCore.Types.V1.VM.Guest.DiskInfo[] Disks {get;}
ExtensionData             Property System.Object ExtensionData {get;}
GuestFamily                Property string GuestFamily {get;}
GuestId                       Property string GuestId {get;}
HostName                   Property string HostName {get;}
IPAddress                    Property string[] IPAddress {get;}
Nics Property VMware.VimAutomation.ViCore.Types.V1.VM.Guest.NicInfo[] Nics {get;}
OSFullName                 Property string OSFullName {get;}
RuntimeGuestId             Property string RuntimeGuestId {get;}
ScreenDimensions       Property System.Nullable[System.Drawing.Size] ScreenDimensions {get;}
State Property VMware.VimAutomation.ViCore.Types.V1.VM.Guest.GuestState State {get;}
ToolsVersion                Property string ToolsVersion {get;}
Uid                                Property string Uid {get;}
VM                                Property VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine VM {get;}
VmId                             Property string VmId {get;}
VmName                      Property string VmName {get;}
VmUid                          Property string VmUid {get;}

 

### shutdown Script###

$VMpath = get-content "C:\temp\vms.txt"

$vmlist = get-vm | where-object {$_.name -in $VMpath}

$taskTab = @{}

$vmlist | ForEach-Object -Process {
 
    $taskTab[(Shutdown-VMGuest -vm $_ -Confirm:$false).id] = $_.name
   
}


 
$runningTasks = $taskTab.Count
while($runningTasks -gt 0){
 


  Get-Task | % {
      if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){

 
          
           $timestamp = Get-Date
           $message = "$timestamp - shutdown VM ($($taskTab[$_.Id]))  : $($_.State)"
        

          Add-Content $logfile  $message

          $deletedSnaps += $message -join "`n"
          $VMSNapDelete +=  $n


          Write-host $message -ForegroundColor Black -backgroundColor Yellow

          $taskTab.Remove($_.Id)
          $runningTasks--
      }

      elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Running" -and  ($_.PercentComplete) -gt 70){
          #$p = "$($_.PercentComplete)%"
         
          $timestamp = Get-Date
         
          Write-Output "$timestamp -  VM ($($taskTab[$_.Id]))  progress at $($_.PercentComplete)%"
          Start-Sleep -Seconds 2


      }

      elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){
          $taskTab.Remove($_.Id)
          $runningTasks--
      }
  }
  Start-Sleep -Seconds 2
}


 



 

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

PowerCLI uses 2 types of Task objects, server-side and client-side.
In short, meaning where the background Task is executed.
Shutdown-VMGuest is one of those generating a client-side Task, hence no Id.

You should see the Task with a Get-Task cmdlet.


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

View solution in original post

0 Kudos
6 Replies
LucD
Leadership
Leadership
Jump to solution

PowerCLI uses 2 types of Task objects, server-side and client-side.
In short, meaning where the background Task is executed.
Shutdown-VMGuest is one of those generating a client-side Task, hence no Id.

You should see the Task with a Get-Task cmdlet.


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

0 Kudos
Golden275
Contributor
Contributor
Jump to solution

@LucD  thank you

since multiple VMs shutdown simultaneously , so how to make each shutdown process associate with its own task (get-task)?

 
$vmlist | ForEach-Object -Process {
 
    Shutdown-VMGuest -vm $_ -Confirm:$false
   
}

 

0 Kudos
Golden275
Contributor
Contributor
Jump to solution

@LucD 

I think I found a way to get the status for multiple VMs when shutdown them simultaneously  by following this article 

https://communities.vmware.com/t5/VMware-PowerCLI-Discussions/Import-VApp-RunAsync-task-Get-Task-mis...

 

I will run few more tests and update outcomes

0 Kudos
Golden275
Contributor
Contributor
Jump to solution

@LucD 

both Shutdown-VMGuest  and start-up work now

but Shutdown-VMGuest 'state' keeps showing in 'running' and even though VM already powered off.

 



PS C:\Windows\system32> $v3 | select state, vm

State VM
----- --
Running CASP-WS1
Running CASP-CV-VMwareVSA

 

 If run this command "$v3 | foreach { $_.vm }" and it shows VM PowerState: PoweredOff.

however state and $v3.extensiondata still show running, does this expected behavior ?

Golden275_4-1663473067601.png

 

 

 

 

 

 

####1 Shutdown-VMGuest script###

$VMpath = get-content "C:\temp\vms.txt"

$vmlist = get-vm | where {$_.name -in $VMpath}

$v3 = @()


$vmlist | ForEach-Object -Process {
$v3 += (Shutdown-VMGuest -vm $_ -Confirm:$false )

}

$runningTasks = $v3.Count

while($runningTasks -gt 0){
$v3 | foreach {
if ($_.vm.powerstate -eq "PoweredOff"){

$_.vm
$runningTasks--

}
}



}

 

### end of shutdown-vmguest script###

 


#2  start-up works now 
### Start-Up script ###

$VMpath = get-content "C:\temp\vms.txt"

$vmlist = get-vm | where-object {$_.name -in $VMpath}


$startVMs=@()
$vmlist | ForEach-Object -Process {
    $startVMs+= (Start-VM -vm $_ -Confirm:$false  -Runasync)
   
}

$runningTasks = $startVMs.Count

$temp = @()
while($runningTasks -ge 1){
   
    foreach($vmstate in $startVMs) {
                   
            $vmstate.id
            if($vmstate.State -eq "success" -and $vmstate.id -notin $temp){
               
                $vmstate | select id, state, starttime,finishtime,result | ft -AutoSize
                 
                $runningTasks--
               
                $temp += $vmstate.id
               
            }
            elseif($vmstate.State -eq "running"){
           
                $vmstate| select starttime,state,PercentComplete,id
                sleep 3

            }
  
 
      }
     
}



### End of Start-Up script ###

 

 

 

0 Kudos
LucD
Leadership
Leadership
Jump to solution

You could try to run an UpdateViewData() call before checking the values

$v3.extensiondata | %{ $_.UpdateViewData()}


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

0 Kudos
Golden275
Contributor
Contributor
Jump to solution

@LucD  thanks

$v3.extensiondata | %{ $_.UpdateViewData()}

$v3 doesn't has a method - updateviewdata()

 

I tried a different way and it works now

could you please take a look and let me know if there is anything need to be improved, thanks

###ShutDown Bulk VMs###

Function CreateLogfile($LogFile, $LogFolder) {


    if(![System.IO.Directory]::Exists($LogFolder)){

        Write-Output "Directory path doesn't exist and creating directory now"
        Try{

            New-Item -ItemType Directory -Path $LogFolder
       
               
            }
        Catch{
       
            Write-Host "Can't create directory and something went wrong!"
            Write-Output $_
        }


    }

    if(![System.IO.File]::Exists($LogFile)){

        Write-Output "File doesn't exist and creating file now"

        Try{

       
            New-Item -Path $LogFile -ItemType File
           
           
            }
        Catch{
       
            Write-Host "Can't create file and something went wrong!"
            Write-Output $_
        }

    }


}



$VMpath = get-content "C:\temp\vms.txt"
$VMWithToolsRunning = @()
$VMWithNoToolsRunning = @()
$temparray = @()

$vmlist = get-vm | where {$_.name -in $VMpath}

$vmlist | foreach{
   
     
    $VmProcess = get-vm -name $_.name

    if ($VmProcess.ExtensionData.Guest.toolsrunningstatus -eq "guestToolsRunning"){
        #Write-Output "Running vm tool"
        $VMWithToolsRunning += $VmProcess.name
        #$VMWithToolsRunning
    }
    else{
   
    #Write-Output "Not Running vm tool"
        $VMWithNoToolsRunning += $VmProcess.name
    #$VMWithNoToolsRunning
   
   
    }

}

$VMsProcessArray = @()

$logfile = "C:\vSpherePowerCli\VMShutDown.log"
$logPath = "C:\vSpherePowerCli\"
CreateLogfile $logfile $logPath



$VMWithToolsRunning| ForEach-Object -Process {
    $VMsProcessArray += (Shutdown-VMGuest -vm $_ -Confirm:$false )

}



$runningTasks = $VMsProcessArray.Count
$timestamp = Get-Date
Add-Content $logfile "#####################################################"
Add-Content $logfile "$timestamp VM ShutDown"

DO {


   
    $VMsProcessArray | foreach {

            $VmProcess = get-vm -name $_.vm.name
           
   
                if ($VmProcess.PowerState -eq "PoweredOff" -and $VmProcess.name -notin $temparray){
                   
                    $timestamp = Get-Date                
                    $vmpowerstate = $VmProcess.powerstate
                    $vmname = $VmProcess.name
                    $temparray += $vmname
                    $runningTasks--

                    $message = "$timestamp - VM($vmname) is $vmpowerstate -successful"
                    Add-Content $logfile  $message
                    Write-host $message -ForegroundColor red -backgroundColor Yellow

                }

                elseif($VmProcess.PowerState -eq "PoweredOn") {

                    $timestamp = Get-Date
                    $vmname = $VmProcess | % name
                    $messageElse = "$timestamp - VM($vmname) Poweroff in progress!"
                    Add-Content $logfile  $messageElse
                    Write-host $messageElse -ForegroundColor Black -backgroundColor Yellow
                               
                    sleep 5
           
                }
       
    }

 
           
} while($runningTasks -ge 1)

 

 

Golden275_2-1663538109371.png

 



0 Kudos