VMware Cloud Community
Brucky
Contributor
Contributor

Monitoring DRS VMotion via Powershell

Hi all,

Is there any way to monitor whether a VM has been ( or is being ) migrated by DRS via a PowerShell script?

The reason I ask is that I would like to use the Automatic DRS facility within a cluster but have any movements monitored and the VM, its Source and its Destination reported or alerted upon. In this manner I could keep our company Configuration Database up to date and thus keep the pencil pushers off my back.

I appreciate it may be simpler to run a script on a regular basis rather than have it perpetually loop waiting for a migration and thus wasting resources.

I assume that the Recent Task list needs to be searched but if anyone has any brighter ideas I would be very appreciative.

Apologies if this has been asked before and already has an answer only I have Googled this request and have yet to find any pointers.

Thanks

Brucky

Reply
0 Kudos
52 Replies
halr9000
Commander
Commander

Anything you see in the VI Client tasks pane will show up when you use the Get-Task cmdlet. And you can use Wait-Task to wait for completion.

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
Reply
0 Kudos
Brucky
Contributor
Contributor

Thanks Hal,

Does this mean I have to keep cycling around with a Get-Task ?

Also how do I only filter on Migration tasks?

I have run Get-Task on a Migration task and got the following

</p></p>
<p><p>PS C:\WINDOWS&gt; get-task Success</p></p>
<p><p>Name                           State      % Complete Start Time   Finish Time<br/><br/>
----                           -----      ---------- ----------   -----------<br/><br/>
                               Success           100 05:00:02     05:01:30</p></p>
<p><p>

</p>

Any help would be gratefully accepted.

- Brucky

PS Love your PowerScripting Podcast ! I only found it 2 months ago but have downloaded all 33 episodes and have had a marathon catch-up - Worse than watching 24 on DVD !

Reply
0 Kudos
halr9000
Commander
Commander

Does this mean I have to keep cycling around with a Get-Task ?

Also how do I only filter on Migration tasks?

Hmm. Yeah, the task objects by themselves are next to useless. I believe you can get more data on the tasks by delving into the SDK. I don't have time to elaborate right now, but there's a buncha smart ppl in this forum.

PS Love your PowerScripting Podcast ! I only found it 2 months ago but have downloaded all 33 episodes and have had a marathon catch-up - Worse than watching 24 on DVD !

Hey, thanks! I'll let Jonathan know as well. We love getting feedback.

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
Reply
0 Kudos
LucD
Leadership
Leadership

And into the SDK we go... Smiley Wink

With the HistoryCollector we can get a list of all tasks for a defined period.

In the list of tasks we have to get the tasks that have a DescriptionId that starts with Drm.

Note1: the number of days to look back is defined in the variable $days

Note2: I couldn't find a way to get all the tasks without specifying a number to the ReadNextTasks method.

I took 999 since this is normally enough for our environment but your millage can vary...

$days = 1
$tasknumber = 999

[http://Reflection.Assembly|http://Reflection.Assembly]::LoadWithPartialName("vmware.vim")

$svcRef = new-object VMware.Vim.ManagedObjectReference 
$svcRef.Type = "ServiceInstance" 
$svcRef.Value = "ServiceInstance" 
$serviceInstance = get-view $svcRef
$taskMgr = $serviceInstance.Content.TaskManager

$filter = New-Object VMware.Vim.TaskFilterSpec
$filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime
$filter.Time.beginTime = (Get-Date).AddDays(-$days)
$filter.Time.timeType = "startedTime"

$collectionImpl = ([http://VMware.Vim.TaskManager|http://VMware.Vim.TaskManager]$taskMgr).CreateCollectorForTasks($filter)

([http://VMware.Vim.TaskHistoryCollector|http://VMware.Vim.TaskHistoryCollector]$collectionImpl).RewindCollector
$collection = ([http://VMware.Vim.TaskHistoryCollector|http://VMware.Vim.TaskHistoryCollector]$collectionImpl).ReadNextTasks($tasknumber)

$collection | Where-Object {$_.DescriptionId -like "Drm*"} | Sort-Object StartTime | %{
  write-host $_.StartTime $_.EntityName $_.State
}

PS: I attached the script since the forum SW tends to change certain characters (i.e. square brackets)


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

Reply
0 Kudos
Brucky
Contributor
Contributor

Luc,

Thanks for this. It works like a charm.

Is there anyway of seeing the contents of the message so I could see which ESX hosts were the source and the targets for the migrations?

Sorry if I'm asking the earth but I am still trying to get my head around using the SDK in PowerShell.

Your help is gratefuly accepted.

- Brucky

Reply
0 Kudos
LucD
Leadership
Leadership

That is possible but with a catch.

The from and to ESX hosts are not contained in the task history but in the event history.

Luckily the TaskInfo object contains the EventChainId property that points to the related events.

In any case, a good suggestion for extending the script.

Let me have a look and I'll get back to you.


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

Reply
0 Kudos
LucD
Leadership
Leadership

This should do the trick.

$days = 1
$tasknumber = 999
$eventnumber = 100

[http://Reflection.Assembly|http://Reflection.Assembly]::LoadWithPartialName("vmware.vim")

$svcRef = new-object VMware.Vim.ManagedObjectReference 
$svcRef.Type = "ServiceInstance" 
$svcRef.Value = "ServiceInstance" 
$serviceInstance = get-view $svcRef
$taskMgr = $serviceInstance.Content.TaskManager
$eventMgr = $serviceInstance.Content.eventManager

$filter = New-Object VMware.Vim.TaskFilterSpec
$filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime
$filter.Time.beginTime = (Get-Date).AddDays(-$days)
$filter.Time.timeType = "startedTime"

$collectionImpl = ([http://VMware.Vim.TaskManager|http://VMware.Vim.TaskManager]$taskMgr).CreateCollectorForTasks($filter)

([http://VMware.Vim.TaskHistoryCollector|http://VMware.Vim.TaskHistoryCollector]$collectionImpl).RewindCollector
$collection = ([http://VMware.Vim.TaskHistoryCollector|http://VMware.Vim.TaskHistoryCollector]$collectionImpl).ReadNextTasks($tasknumber)

$collection | Where-Object {$_.DescriptionId -like "Drm*"} | Sort-Object StartTime | %{
  write-host $_.StartTime $_.EntityName $_.State
  $efilter = New-Object VMware.Vim.EventFilterSpec
  $efilter.eventChainId = $_.EventChainId
  
  $ecollectionImpl = ([http://VMware.Vim.EventManager|http://VMware.Vim.EventManager]$eventMgr).CreateCollectorForEvents($efilter)
  $ecollection = ([http://VMware.Vim.EventHistoryCollector|http://VMware.Vim.EventHistoryCollector]$ecollectionImpl).ReadNextEvents($eventnumber)
  foreach($event in $ecollection){
    switch($event.GetType()){
	  "VMware.Vim.DrsVmMigratedEvent" {
	    $from = $event.SourceHost.Name
	  }
	  "VMware.Vim.VmBeingHotMigratedEvent"{
	    $to = $event.DestHost.Name
	  }
	}
  }
  Write-Host "  From : " $from
  Write-Host "  To   : " $to
}


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

Reply
0 Kudos
Brucky
Contributor
Contributor

Luc, You Beauty !!!!

Thank you for this. It is exactly what I needed.

I was starting to get my head around what you had done and was experimenting with the EventTaskManager but you beat me to it. I will be able to combine this script with my own emailing script to auto-update our Configuration Management Database.

Thanks again for your time and patience.

I owe you one !

- Brucky

Reply
0 Kudos
houghtp
Contributor
Contributor

Hi Luc,

I was looking for something along these lines when i came across your script. but i'm having a problem running it i get an error:

Cannot convert "VMware.Vim.ManagedObjectReference" to "VMware.Vim.TaskManager".

At C:\scripts\ESX-collect-tasks.ps1:17 char:52

+ $collectionImpl = (http://VMware.Vim.TaskManager$taskMgr <<<< ).CreateCollectorForTasks($filter)

You cannot call a method on a null-valued expression.

At C:\scripts\ESX-collect-tasks.ps1:20 char:79

+ $collection = (http://VMware.Vim.TaskHistoryCollector$collectionImpl).ReadNextTasks <<<< ($tasknumber)

i'm using the script in your attachment?

Reply
0 Kudos
houghtp
Contributor
Contributor

can this now be replaced with get-vievent and get-task?

Reply
0 Kudos
houghtp
Contributor
Contributor

answered my own question..

Reply
0 Kudos
houghtp
Contributor
Contributor

I'm having problems accessing old events. If i use

Get-VIEvent -Start (get-date).AddDays(-7) | Format-Table CreatedTime, FullFormattedMessage -AutoSize

i still only get same number of events as if i run

Get-VIEvent | Format-Table CreatedTime, FullFormattedMessage -AutoSize

i take it this si because this is the view VC shows us. is there a way to get older events?

Reply
0 Kudos
LucD
Leadership
Leadership

Well with the new VITK build the script needed some changes.

Attached one that should work with the current build.

The Get-VIEvent cmdlet returns by default 100 events.

If you need more, use the -MaxSamples parameter.


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

Reply
0 Kudos
astrolab
Contributor
Contributor

How do I export the output to CSV. I used the Export-CSV cmdlet but it's not populating the file, I assume that script produces an output incompatible to CSV?

Reply
0 Kudos
LucD
Leadership
Leadership

This should do the trick.


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

Reply
0 Kudos
astrolab
Contributor
Contributor

Thank you LucD.

Reply
0 Kudos
hugop
Hot Shot
Hot Shot

Lucd,

Is it possible to amend the 3rd version of the script to restrict it to only on a per VM basis? I assume by doing so we will not need to increase the number of events variable??

Thanks,

Hugo

Reply
0 Kudos
LucD
Leadership
Leadership

Yes, the CreateCollectorForTasks method can be limited to a specific entity via the TaskFilterSpec object.

That would allow us to lower the $tasknumber variable (unless there are a lot of DRS initiated vMotion in the environment).

But that won't really allow us to lower the number in $eventnumber.

The $eventnumber variable is just my stupid way of making sure that I have (on average and not foolproof) enough events to correlate with the task that was found.

Note that I only look for events that are chained via the EventChainId in the TaskInfo object.

This can be done more correctly in a loop where the script tests the number of returned events till it equals 0 (zero). Something like I did in .

That way we are sure we see all the events related to the task.

The $eventnumber variable in this case defines the size of the "window" you scroll over all the events.

If it is lowered, we could have more loops through the "while"-loop.

The script then becomes something like this

$days = 10
$tasknumber = 999
$eventnumber = 100
$vmName = <VM-name>

$vm = Get-VM $vmName | Get-View 

$serviceInstance = get-view ServiceInstance
$taskMgr = Get-View TaskManager
$eventMgr = Get-View eventManager

$report = @()

$filter = New-Object VMware.Vim.TaskFilterSpec
$filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime
$filter.Time.beginTime = (Get-Date).AddDays(-$days)
$filter.Time.timeType = "startedTime"
$filter.entity = New-Object VMware.Vim.TaskFilterSpecByEntity
$filter.entity.entity = $vm.MoRef

$collectionImpl = Get-View ($taskMgr.CreateCollectorForTasks($filter))

$dummy = $collectionImpl.RewindCollector
$collection = $collectionImpl.ReadNextTasks($tasknumber)

$collection | Where-Object {$_.DescriptionId -like "Drm*"} | Sort-Object StartTime | % {
	$efilter = New-Object VMware.Vim.EventFilterSpec
	$efilter.eventChainId = $_.EventChainId

	$ecollectionImpl = Get-View ($eventMgr.CreateCollectorForEvents($efilter))
	$ecollection = $ecollectionImpl.ReadNextEvents($eventnumber)
	while($ecollection -ne $null){
		foreach($event in $ecollection){
			switch($event.GetType()){
				"VMware.Vim.DrsVmMigratedEvent" {
					$from = $event.SourceHost.Name
				}
				"VMware.Vim.VmBeingHotMigratedEvent"{
					$to = $event.DestHost.Name
				}
				Default {}
			}
		}
		$ecollection = $ecollectionImpl.ReadNextEvents($eventnumber)
	}
	$row = "" | Select StartTime, Entity, State, Description, From, To
	$row.StartTime = $_.StartTime
	$row.Entity = $_.EntityName
	$row.State = $_.State
	$row.Description = $_.DescriptionId
	$row.From = $from
	$row.To = $to
	$report += $row
	$ecollectionImpl.DestroyCollector()
}

$report | Export-Csv "C:\DRS-events.csv" -noTypeInformation


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

Reply
0 Kudos
hugop
Hot Shot
Hot Shot

LucD,

Works like a dream... need quotes around the VM-name to work.. e.g.,

$vmName = "MyServer01"

Many thanks,

Hugo

Reply
0 Kudos