Search code examples
powershellpowerclivcenter

How do I get the tasks associated with vCenter objects using PowerCLI?


We are using vSphere 6.7 in our environment.

I am writing a script to look for certain tasks associated with specific target resources in our vCenter environment. However, Get-Task only returns recent tasks that show up in the Recent Tasks view in the HTML5 client. I can get events associated with resources just fine, for example I can get the events associated with a given datastore folder like so:

Get-Folder FOLDER_NAME -Type Datastore | Get-VIEvent

But there doesn't seem to be an equivalent way to get tasks associated with those same resources. Get-Task doesn't accept pipeline input in the same way Get-VIEvent does, and results in an error:

Get-Folder FOLDER_NAME -Type Datastore | Get-Task

Output:

Get-Task: The input object cannot be bound to any parameters for the command either
because the command does not take pipeline input or the input and its properties
do not match any of the parameters that take pipeline input.

Get-Task also doesn't show any tasks that don't show in the Recent Tasks view of the HTML5 client.

Inspecting the object doesn't seem to offer any members that let me see tasks targeting these resources:

Get-Folder FOLDER_NAME -Type Datastore | Get-Member

Output:

   TypeName: VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreClusterImpl

Name                             MemberType Definition
----                             ---------- ----------
ConvertToVersion                 Method     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 VersionedObjectInterop.IsConvertableTo(type type)
LockUpdates                      Method     void ExtensionData.LockUpdates()
ToString                         Method     string ToString()
UnlockUpdates                    Method     void ExtensionData.UnlockUpdates()
CapacityGB                       Property   decimal CapacityGB {get;}
ExtensionData                    Property   System.Object ExtensionData {get;}
FreeSpaceGB                      Property   decimal FreeSpaceGB {get;}
Id                               Property   string Id {get;}
IOLatencyThresholdMillisecond    Property   System.Nullable[int] IOLatencyThresholdMillisecond {get;}
IOLoadBalanceEnabled             Property   bool IOLoadBalanceEnabled {get;}
Name                             Property   string Name {get;}
SdrsAutomationLevel              Property   VMware.VimAutomation.ViCore.Types.V1.Cluster.DrsAutomationLevel SdrsAutomationLevel {get;}
SpaceUtilizationThresholdPercent Property   System.Nullable[int] SpaceUtilizationThresholdPercent {get;}
Uid                              Property   string Uid {get;}

This isn't just for folder tasks, though, I can't seem to enumerate any tasks for a given resource at all if they aren't in the Recent Tasks view of the HTML5 client. Conversely, in the HTML5 client, I can easily enumerate tasks on a given resource using its Monitor tab, but this doesn't help with automation short of crawling through the UI programmatically (not happening):

Folder > Monitor > Tasks View

How do I use PowerCLI to see the tasks targeting specific resources using PowerCLI?


Solution

  • Luc Dekens wrote a scripted function to tackle your issue. Here's a copy of the function, you can target specific resources with the entity param.

    function Get-TaskPlus {
        <#  
        .SYNOPSIS  Returns vSphere Task information   
        .DESCRIPTION The function will return vSphere task info. The
        available parameters allow server-side filtering of the
        results
        .NOTES  Author:  Luc Dekens  
        .PARAMETER Alarm
        When specified the function returns tasks triggered by
        specified alarm
        .PARAMETER Entity
        When specified the function returns tasks for the
        specific vSphere entity
        .PARAMETER Recurse
        Is used with the Entity. The function returns tasks
        for the Entity and all it's children
        .PARAMETER State
        Specify the State of the tasks to be returned. Valid
        values are: error, queued, running and success
        .PARAMETER Start
        The start date of the tasks to retrieve
        .PARAMETER Finish
        The end date of the tasks to retrieve.
        .PARAMETER UserName
        Only return tasks that were started by a specific user
        .PARAMETER MaxSamples
        Specify the maximum number of tasks to return
        .PARAMETER Reverse
        When true, the tasks are returned newest to oldest. The
        default is oldest to newest
        .PARAMETER Server
        The vCenter instance(s) for which the tasks should
        be returned
        .PARAMETER Realtime
        A switch, when true the most recent tasks are also returned.
        .PARAMETER Details
        A switch, when true more task details are returned
        .PARAMETER Keys
        A switch, when true all the keys are returned
        .EXAMPLE
        PS> Get-TaskPlus -Start (Get-Date).AddDays(-1)
        .EXAMPLE
        PS> Get-TaskPlus -Alarm $alarm -Details
        #>
        param(
            [CmdletBinding()]
            [VMware.VimAutomation.ViCore.Impl.V1.Alarm.AlarmDefinitionImpl]$Alarm,
            [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]$Entity,
            [switch]$Recurse = $false,
            [VMware.Vim.TaskInfoState[]]$State,
            [DateTime]$Start,
            [DateTime]$Finish,
            [string]$UserName,
            [int]$MaxSamples = 100,
            [switch]$Reverse = $true,
            [VMware.VimAutomation.ViCore.Impl.V1.VIServerImpl[]]$Server = $global:DefaultVIServer,
            [switch]$Realtime,
            [switch]$Details,
            [switch]$Keys,
            [int]$WindowSize = 100
        )
        begin {
            function Get-TaskDetails {
                param(
                    [VMware.Vim.TaskInfo[]]$Tasks
                )
                begin {
                    $psV3 = $PSversionTable.PSVersion.Major -ge 3
                }
                process {
                    $tasks | ForEach-Object {
                        if ($psV3) {
                            $object = [ordered]@{ }
                        }
                        else {
                            $object = @{ }
                        }
                        $object.Add("Name", $_.Name)
                        $object.Add("Description", $_.Description.Message)
                        if ($Details) { $object.Add("DescriptionId", $_.DescriptionId) }
                        if ($Details) { $object.Add("Task Created", $_.QueueTime) }
                        $object.Add("Task Started", $_.StartTime)
                        if ($Details) { $object.Add("Task Ended", $_.CompleteTime) }
                        $object.Add("State", $_.State)
                        $object.Add("Result", $_.Result)
                        $object.Add("Entity", $_.EntityName)
                        $object.Add("VIServer", $VIObject.Name)
                        $object.Add("Error", $_.Error.ocalizedMessage)
                        if ($Details) {
                            $object.Add("Cancelled", (& { if ($_.Cancelled) { "Y" }else { "N" } }))
                            $object.Add("Reason", $_.Reason.GetType().Name.Replace("TaskReason", ""))
                            $object.Add("AlarmName", $_.Reason.AlarmName)
                            $object.Add("AlarmEntity", $_.Reason.EntityName)
                            $object.Add("ScheduleName", $_.Reason.Name)
                            $object.Add("User", $_.Reason.UserName)
                        }
                        if ($keys) {
                            $object.Add("Key", $_.Key)
                            $object.Add("ParentKey", $_.ParentTaskKey)
                            $object.Add("RootKey", $_.RootTaskKey)
                        }
                        New-Object PSObject -Property $object
                    }
                }
            }
            $filter = New-Object VMware.Vim.TaskFilterSpec
            if ($Alarm) {
                $filter.Alarm = $Alarm.ExtensionData.MoRef
            }
            if ($Entity) {
                $filter.Entity = New-Object VMware.Vim.TaskFilterSpecByEntity
                $filter.Entity.entity = $Entity.ExtensionData.MoRef
                if ($Recurse) {
                    $filter.Entity.Recursion = [VMware.Vim.TaskFilterSpecRecursionOption]::all
                }
                else {
                    $filter.Entity.Recursion = [VMware.Vim.TaskFilterSpecRecursionOption]::self
                }
            }
            if ($State) {
                $filter.State = $State
            }
            if ($Start -or $Finish) {
                $filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime
                $filter.Time.beginTime = $Start
                $filter.Time.endTime = $Finish
                $filter.Time.timeType = [vmware.vim.taskfilterspectimeoption]::startedTime
            }
            if ($UserName) {
                $userNameFilterSpec = New-Object VMware.Vim.TaskFilterSpecByUserName
                $userNameFilterSpec.UserList = $UserName
                $filter.UserName = $userNameFilterSpec
            }
            $nrTasks = 0
        }
        process {
            foreach ($viObject in $Server) {
                $si = Get-View ServiceInstance -Server $viObject
                $tskMgr = Get-View $si.Content.TaskManager -Server $viObject 
                if ($Realtime -and $tskMgr.recentTask) {
                    $tasks = Get-View $tskMgr.recentTask
                    $selectNr = [Math]::Min($tasks.Count, $MaxSamples - $nrTasks)
                    Get-TaskDetails -Tasks[0..($selectNr - 1)]
                    $nrTasks += $selectNr
                }
                $tCollector = Get-View ($tskMgr.CreateCollectorForTasks($filter))
                if ($Reverse) {
                    $tCollector.ResetCollector()
                    $taskReadOp = $tCollector.ReadPreviousTasks
                }
                else {
                    $taskReadOp = $tCollector.ReadNextTasks
                }
                do {
                    $tasks = $taskReadOp.Invoke($WindowSize)
                    if (!$tasks) { break }
                    $selectNr = [Math]::Min($tasks.Count, $MaxSamples - $nrTasks)
                    Get-TaskDetails -Tasks $tasks[0..($selectNr - 1)]
                    $nrTasks += $selectNr
                }while ($nrTasks -lt $MaxSamples)
                $tCollector.DestroyCollector()
            }
        }
    }
    

    More info at https://www.lucd.info/2013/06/01/task-data-mining-an-improved-get-task/#more-4464