Get complete vCenter session info

There was an interesting thread in the PowerCLI Community today. It raised the question how one could report on the current vCenter sessions, including the IP address or hostname from where the session was started.

Unfortunately the SessionManager doesn’t hold any information from where the session was started.

But there are other ways of finding that information. The UserLoginSessionEvent object has a property, called ipAddress, that has the information we’re after.

Btw if you are only interested in looking for idle sessions, independent from which host they were started, there is a great post, called List and Disconnect vCenter Sessions on the PowerCLI blog.

Update May 4th 2012: function updated to handle multiple vCenter connections.

The script

function Get-VISessionInfo{
<#
.SYNOPSIS  Retrieve vCenter session information
.DESCRIPTION The function will retrieve the open vCenter
  session, including the IP address and hostname from where
  the session was started
.NOTES  Author:  Luc Dekens
.PARAMETER AllowedDifference
  The timestamps from the Session Manager entries and the
  event objects can sometimes differ, depending on the vCenter
  activity. The default is 1 second, but this can be changed
  with this parameter. The unit for this parameter is seconds.
.EXAMPLE
  PS> Get-VISessionInfo
#>

  param(
  [CmdletBinding()]
  [int]$AllowedDifference = 1
  )

  process{
    if((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple"){
      $vcenter = $defaultVIServers
    }
    else{
      $vcenter = $defaultVIServers[0]
    }

    foreach($vc in $vcenter){
      $sessMgr = Get-View SessionManager -Server $vc
      $oldest = ($sessMgr.SessionList | Sort-Object -Property LoginTime | Select -First 1).LoginTime
      $users = $sessMgr.SessionList | %{$_.UserName}
      $events = Get-VIEvent -MaxSamples ([int]::MaxValue) -Start $oldest.AddHours(-1) -Server $vc |
      where {$_ -is [VMware.Vim.UserLoginSessionEvent] -and $users -contains $_.UserName} |
      Sort-Object -Property CreatedTime

      $allowedDiffTS = New-TimeSpan -Seconds $AllowedDifference

      foreach($session in $sessMgr.SessionList){
        $events |
        where {[math]::Abs(($session.LoginTime.ToLocalTime() - $_.CreatedTime).Ticks) -lt $allowedDiffTS.Ticks -and
          $users -contains $_.UserName} | %{
          New-Object PSObject -Property @{
            vCenter = $vc.Name
            "Session login" = $session.LoginTime
            UserName = $_.UserName
            IPAddress = $_.IPAddress
            Hostname = [System.Net.Dns]::GetHostEntry($_.IPAddress).HostName
          }
        }
      }
    }
  }
}

Annotations

Line 23-28: If the PowerCLI session is configured in “Multiple” mode, the function will loop through all connected vCenters. The Get-PowerCLIConfiguration cmdlet is used to retrieve the active mode.

Line 32: The script will look for the session with the oldest login time. This will allow us to limit the number of events that need to be retrieved.

Line 33: Besides the timestamps, the script will also check if the username that appears in an user session login event, is one of the users that has an open vCenter session.

Line 34-36: We retrieve the UserLoginSessionEvent for users that have an open vCenter session.

Line 38: The time difference we allow between the timestamp in the session and the corresponding UserLoginSessionEvent is converted to a TimeSpan object.

Line 42: To link a vCenter session to a UserLoginSessionEvent the script calculates the time difference between the timestamps in the UserLoginSessionEvent and the session object from the SessionManager. If the absolute time difference falls below the accepted time difference ($AllowedDifference), the event is linked to the session.

Line 44-49: The result is placed in the pipeline

Line 45: The output contains the name of the vCenter where the session was found.

Line 49: The script converts the IP address to the hostname with the GetHostEntry method.

Sample usage

The function is rather simple in use.


Get-VISessionInfo

And the result looks something like this.

Enjoy!

20 thoughts on “Get complete vCenter session info

  1. Hi

    The idea of this script is simple awesome!
    But it doesn’t work for me :/
    Im running that script but there’s no any output (nor error). I don’t have problem with running other cmdlets. For example I run this and got some users output without any problems:
    ——-code——
    $svcRef = new-object VMware.Vim.ManagedObjectReference
    $svcRef.Type = “ServiceInstance”
    $svcRef.Value = “ServiceInstance”
    $serviceInstance = get-view $svcRef
    $sessMgr = get-view $serviceInstance.Content.sessionManager
    foreach ($sess in $sessMgr.SessionList){if (($sess.LastActiveTime).addminutes(60) -lt (Get-Date)){write “$($sess.UserName)”}
    }
    ——-code——

  2. Hi Luc

    Great function, very usefull
    Do you think you could add the block Jonathan Medd added in the comments ?
    i just don’t understand where to put it.

    thanks in advance

  3. Is it possible to get the vcenter version and build number when connecting to multiple vcenters?

  4. hey Luc,

    I am trying to get the history of Vcenter users login/logouts from January2013 to till date & when i execute the below script it returns nothing.

    will be helpful if you could find the mistake in the below script

    Get-VIEvent -start 03/06/2013 -finish 02/07/2013 | ?{($_ -is [VMware.Vim.UserLoginSessionEvent]) -or ($_ -is [VMware.Vim.UserLogoutSessionEvent])} | %{
    if ($_ -is [VMware.Vim.UserLoginSessionEvent]) {$strLoginOrLogout = “logged in”; $strSourceIP = $_.IpAddress} ## end if
    else {$strLoginOrLogout = “logged out”; $strSourceIP = $null}
    New-Object -TypeName PSObject -Property @{
    UserName = $_.UserName
    SourceIP = $strSourceIP
    Time = $_.CreatedTime
    Action = $strLoginOrLogout
    } ## end new-object
    } | Select UserName,SourceIP,Time,Action

    • Hi Arvinth,
      Can you try changing that 1st line into

      Get-VIEvent -start (Get-Date 03/06/2013) -finish (Get-Date 02/07/2013)

      The function expects DateTime objects on the Start and Finish parameters, and I think it sees [string] objects when called the way you did it.

  5. Thanks for this, very useful :-)

    If you add the following, then you also get the type of client connection, e.g. vSphere Client, PowerCLI etc….

    $PowerShell2EscapeString = [regex]::Escape(“Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0″)
    $PowerShell3EscapeString = [regex]::Escape(“Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0″)

    switch -regex ($_.UserAgent)
    {
    “VMware VI Client” {$Agent = “vSphere Client”; break}
    “VMware vim-java 1.0″ {$Agent = “vSphere WebClient”; break}
    $PowerShell2EscapeString {$Agent = “PowerCLI (PS2)” ;break}
    $PowerShell3EscapeString {$Agent = “PowerCLI (PS3)” ;break}
    “Java/1.6.0_20″ {$Agent = “VI Java”; break}
    “VI Perl” {$Agent = “vSphere SDK for Perl”; break}
    Default {$Agent = “Unable to determine the agent type”}
    }

    New-Object PSObject -Property @{

    vCenter = $vc.Name
    “Session login” = $session.LoginTime
    UserName = $_.UserName
    IPAddress = $_.IPAddress
    Hostname = [System.Net.Dns]::GetHostEntry($_.IPAddress).HostName
    Agent = $Agent
    }

    Note: the webclient IP is that of the server running the WebClient service, not the IP of the user running the webclient

    Thanks to the below for helping to decode them:

    http://www.virtuallyghetto.com/2010/12/how-to-identify-origin-of-vsphere-login.html

  6. I’m getting similar errors to Wayne:

    You cannot call a method on a null-valued expression.
    At H:\Scripts\VMware PowerCLI\Get-VISessionInfo.ps1:34 char:82
    + $events = Get-VIEvent -MaxSamples ([int]::MaxValue) -Start $oldest.AddHours <<<< (-1) -Server $vc |
    + CategoryInfo : InvalidOperation: (AddHours:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At H:\Scripts\VMware PowerCLI\Get-VISessionInfo.ps1:42 char:59
    + where {[math]::Abs(($session.LoginTime.ToLocalTime <<<< () – $_.CreatedTime).Ticks) -lt $allowedDiffTS.Ticks -and
    + CategoryInfo : InvalidOperation: (ToLocalTime:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    I don't know why $oldest and $session.LoginTime are NULL. LucD, can you please help ?

    PS: If this is a duplicate post, sorry, my last post appeared to fail.

  7. 45 lines of code to get an IP address – really? This looks like a great script but having to write 45 lines of code to get to this tells me something was left out in the design process.

    • Hi Chris, there are 14 lines of comments in there as well.
      But seriously, I agree with you, the script uses another source (Events) to find the IP addresses which should have been there in the first place.
      There is definitely room for improvement :-)

  8. Tried running the script I received a couple of errors….

    You cannot call a method on a null-valued expression.
    At P:\Powershell\Vmware\Get-vcenter-sessions\get-VISessionInfo.ps1:26 char:80
    + $events = Get-VIEvent -MaxSamples ([int]::MaxValue) -Start $oldest.AddHours <<<< (-1) |
    + CategoryInfo : InvalidOperation: (AddHours:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At P:\Powershell\Vmware\Get-vcenter-sessions\get-VISessionInfo.ps1:34 char:57
    + where {[math]::Abs(($session.LoginTime.ToLocalTime <<<< () – $_.CreatedTime).Ticks) -lt $allowedDiffTS.Ticks -and
    + CategoryInfo : InvalidOperation: (ToLocalTime:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

  9. Nice script. :)

    Good to have a script like this ready for troubleshooting connection issues.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>