Get vCenter User Sessions and Idle times with PowerCLI

Today I was looking into a small “nice to have” notification system for users that had left their vSphere clients open and logged into vCenter. I found this great bit of script to list currently logged in users over at blog.vmpros.nl and thought I would expand on this in my own way to generate a handy list of logged in users and their current idle time – similar to the way the “Sessions” tab in the vSphere client displays user session information. When I got home this evening I expanded on the original script from vmpros.nl to create the following:

 

$Now = Get-Date
$Report = @()
$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){
   $time = $Now - $sess.LastActiveTime
   # Our time calculation returns a TimeSpan object instead of DateTime, therefore formatting needs to be done as follows:
   $SessionIdleTime = '{0:00}:{1:00}:{2:00}' -f $time.Hours, $time.Minutes, $time.Seconds
   $row = New-Object -Type PSObject -Property @{
   		Name = $sess.UserName
		LoginTime = $sess.LoginTime
		IdleTime = $SessionIdleTime
	} ## end New-Object
	$Report += $row
}
$Report

 

[download id=”6″]

 

Here is an example of the output of the script:

 

Using this bit of PowerCLI script, it should be easy for you to create your own notification system based on user session idle time, or some functionality that would disconnect idle users. Let me know if you do improve on the above, or if you have any other suggestions.

 

PowerCLI Advanced Configuration Settings – Setting Host Syslog options

 

This is a PowerCLI script that will script setting up your ESXi host syslogging in two places: A Shared Datastore (that all ESXi hosts have visibility of) and to a remote Syslog host on the network. Alternatively, you could set it to change the Syslog directory to a different local path on each ESXi host (rather than the default). The two advanced configuration settings we’ll be working with are:

 

  • Syslog.global.logDir
  • Syslog.global.logHost

 

Why did I do this? Well, tonight I got a little sidetracked after looking into a small warning on a new scripted ESXi host I deployed – it had not automatically set up logging during installation, my guess, was because it’s local datastore had failed to initialise during installation – I couldn’t see a local datastore after deploying it via a script and had received a warning during installation. I went ahead just to see what happened. This was a new test host in my home lab. So afterwards, I decided I would set it up a remote Syslog location to clear the warning off. Naturally, I wanted to do this in PowerCLI.

 

The following script will take a few options you specify like Shared Datastore name, Syslogging Folder Name, and a remote Syslog host, and go ahead and configure all the ESXi hosts in your specified DataCenter object to use these options you specify. If you have only one datacenter object the script will see this and use that one by default. Otherwise it will ask you for the name of the specific DataCenter you want to work with. It will then create a “ESXi-Syslogging” folder on the shared datastore you specified (if it doesn’t already exist) and under this, create a sub-folder for each ESXi host. It will then configure each ESXi host to send it’s Syslog info to this datastore. As far as I can tell, certain Sysl0g files are linked from /scratch/log on each ESXi host to the datastore specified. For example:

 

usb.log becomes:

usb.log -> /vmfs/volumes/1bec1487-1189988a/ESXi-Syslogging/esxi-04.noobs.local/usb.log

 

Naturally, this wouldn’t be a good idea if the ESXi host could potentially lose access to this datastore, so the script will also specify a remote Syslog host to log to. If you don’t have one, check out the Free “Kiwi Syslog Server”. Here is the resulting script (download via URL below or just copy the script out the block):

[download id=”4″]

 

# Remote Syslogging setup for ESXi Hosts in a particular datacenter object
# By Sean Duffy (http://www.shogan.co.uk)
# Version 1.0
# Get-Date = 15/12/2011

#region Set variables up
$SyslogDatastore = "SharedDatastore2" # The name of the Shared Datastore to use for logging folder location - must be accessible to all ESXi hosts
$SyslogFolderName = "ESXi-Syslogging" # The name of the folder you want to use for logging - must NOT already exist
$RemoteSyslogHost = "udp://192.168.0.85:514" #specify your own Remote Syslog host here in this format
$DataCenters = Get-Datacenter
$FoundMatch = $false
$SyslogDatastoreLogDir = "[" + $SyslogDatastore + "]"
#endregion

#region Determine DataCenter to work with
if (($DataCenters).Count -gt 1) {
	Write-Host "Found more than one DataCenter in your environment, please specify the exact name of the DC you want to work with..."
	$DataCenter = Read-Host
	foreach ($DC in $DataCenters) {
		if ($DC.Name -eq $DataCenter) {
			Write-Host "Found Match ($DataCenter). Proceeding..."
			$FoundMatch = $true
			break
			}
		else {
			$FoundMatch = $false
			}
	}
	if ($FoundMatch -eq $false) {
		Write-Host "That input did not match any valid DataCenters found in your environment. Please run script again, and try again."
		exit		
		}
	}
else {
	$DataCenter = ($DataCenters).Name
	Write-Host "Only one DC found, so using this one. ($DataCenter)"
	}
#endregion

#Enough of the error checking, lets get to the script!

$VMHosts = Get-Datacenter $DataCenter | Get-VMHost | Where {$_.ConnectionState -eq "Connected"}

cd vmstore:
cd ./$DataCenter
cd ./$SyslogDatastore
if (Test-Path $SyslogFolderName) {
	Write-Host "Folder already exists. Configure script with another folder SyslogFolderName & try again."
	exit
}
else {
	mkdir $SyslogFolderName
	cd ./$SyslogFolderName
}

# Crux of the script in here:
foreach ($VMHost in $VMHosts) {
	if (Test-Path $VMHost.Name) {
		Write-Host "Path for ESXi host log directory already exists. Aborting script."
		exit
	}
	else {
		mkdir $VMHost.Name
		Write-Host "Created folder: $VMHost.Name"
		$FullLogPath = $SyslogDatastoreLogDir + "/" + $SyslogFolderName + "/" + $VMHost.Name
		Set-VMHostAdvancedConfiguration -VMHost $VMHost -Name "Syslog.global.logHost" -Value $RemoteSyslogHost
		Set-VMHostAdvancedConfiguration -VMHost $VMHost -Name "Syslog.global.logDir" -Value $FullLogPath
		Write-Host "Paths set: HostLogs = $RemoteSyslogHost LogDir = $FullLogPath"
	}
}

 

Some results of running the above in my lab:

 

Script output after running against 3 x ESXi hosts

 

Advanced settings are showing as expected
Tasks completed by the PowerCLI script

 

Here is the structure of the Logging in my Datastore after the script had run.

 

 

Lastly, I have found that these values won’t update if they are already populated with anything other than the defaults (especially the LogDir advanced setting). You’ll get an error along the lines of:

 

Set-VMHostAdvancedConfiguration : 2011/12/15 11:37:01 PM    Set-VMHostAdvancedConfigurati
on        A general system error occurred: Internal error

 

If this happens, you could either set the value to an empty string, i.e. “” or you could use Set-VMHostAdvancedConfiguration [[-NameValue] <Hashtable>] (using a hashtable of the advanced config setting as the NameValue) to set things back to the way they were originally. The default value for Syslog.global.logDir is = [] /scratch/log for example. It might be a good idea to grab this value and pipe it out into a file somewhere safe before you run the script in case you need to revert back to the default Syslog local location – you would then know what the value should be. You could use something like this to grab the value and put it into a text file:

 

Get-VMHostAdvancedConfiguration -VMHost $VMHost -Name "Syslog.global.logDir" | Out-File C:\default-sysloglocation.txt

 

Also, remember to think this out carefully before changing in your own environment – it may not suit you at all to set your Syslog location to anywhere else other than the local disk of each host. However, you may find it useful to automatically set the remote syslog host advanced setting for each of your ESXi hosts – in that case, simply modify the script above to only apply the one setting instead of both. I hope this helps, and as always, if you have any suggestions, improvements or notice any bugs, please feel free to add your comments.

 

 

Adding a Percent Free Property to your Get-Datastore cmdlet results using Add-Member

 

Update:

 

Thanks to Alan Renouf  (@alanrenouf) for pointing out the New-VIProperty cmdlet to me, I was able to go back to the drawing board and really shorten up my original PowerCLI script by using the New-VIProperty cmdlet. @PowerCLI on twitter also pointed this out shortly afterwards. So after taking a quick look at the reference documentation for the cmdlet, here is my new VIProperty to get the “PercentFree” for each Datastore object returned from the Get-Datastore cmdlet!

 

New-VIProperty -Name PercentFree -ObjectType Datastore -Value {"{0:N2}" -f ($args[0].FreeSpaceMB/$args[0].CapacityMB*100)} -Force

 

To use it, simply run the above in your PowerCLI session, then use “Get-Datastore | Select Name,PercentFree”. A better option would be to load the above New-VIProperty script into your PowerCLI / PowerShell profile. Taking it one step further, @LucD has kindly offered to add this to his VIProperty Module, which means you could instead, just load this module in to your profile and benefit from all the other great VIProperty extensions! Example usage below:

 

New-VIProperty -Name PercentFree -ObjectType Datastore -Value {"{0:N2}" -f ($args[0].FreeSpaceMB/$args[0].CapacityMB*100)} -Force
Get-Datastore | Select Name,FreeSpaceMB,CapacityMB,PercentFree

 

You can find tons of other great VIProperties, or even download the entire module over at LucD’s blog.

 

Original Post:

 

I have been using the Get-Datastore cmdlet quite frequently at my workplace lately – mainly to gather information on various datastores which I export to CSV, then plug into Excel to perform further sorting and calculations on. To save myself a step in Excel each time (creating columns in spreadsheets to show and format the Percent Free figure of each Datastore), I decided to add this into my PowerCLI script.

 

Below, I’ll show you a fairly simple script that will add a member “NoteProperty” (A property with a static value) to your Datastore PS Objects. In the script, we’ll grab all the Datastores based on a search criteria (by default this will get all Datastores or Datastores with the word “Shared” in their name, but you can change it to match what you would like), then we’ll iterate through each, calculate the Percentage of free space from the two figures that we are given back already from Get-Datastore (CapacityMB and FreeSpaceMB), and finally add the member property to the current datastore object. Once this is done, we’ll output the results of  the $datastores object using “Select” to show the Name, Free Space in MB, Capacity in MB, and Percent Free of each object contained within to a CSV file (Remove the | Export-Csv part on the end if you just want the results output to console instead).

 

 

function CalcPercent {
	param(
	[parameter(Mandatory = $true)]
	[int]$InputNum1,
	[parameter(Mandatory = $true)]
	[int]$InputNum2)
	$InputNum1 / $InputNum2*100
}

$datastores = Get-Datastore | Sort Name
ForEach ($ds in $datastores)
{
	if (($ds.Name -match "Shared") -or ($ds.Name -match ""))
	{
		$PercentFree = CalcPercent $ds.FreeSpaceMB $ds.CapacityMB
		$PercentFree = "{0:N2}" -f $PercentFree
		$ds | Add-Member -type NoteProperty -name PercentFree -value $PercentFree
	}
}
$datastores | Select Name,FreeSpaceMB,CapacityMB,PercentFree | Export-Csv c:\testcsv.csv

 

Here’s an example of our output:

 

Note that you could simplify the script by removing the function called “CalcPercent” and adding it to your PowerShell or PowerCLI environment profile. Hope this helps!

 

How to create a PowerShell / PowerCLI profile & add Functions for later use

 

Ever wondered how to set yourself up a PowerShell or PowerCLI profile? Or how to go about saving useful Functions that you have created or picked up elsewhere to your profile for use in new sessions? Here I’ll detail the basics of PowerShell or PowerCLI session profiles and show you how to set one up, as well as how to save your first Function to this profile for use in future sessions.

 

Creating a PowerShell (or PowerCLI) profile is a great idea if you are considering spending any decent amount of time in the shell or executing scripts.  They allow you to customise your PowerShell / PowerCLI environment and apply useful functions or elements to every new PowerShell / PowerCLI session you start, without the need to reload these items yourself each time. A few examples of what you can add to your profile are functions, variables, cmdlets and snap-ins. This makes life so much easier when scripting or working on your latest bit of automation.

 

To begin with, you can see the currently set profile path in your session by typing $profile in the shell. If you would then like to edit your profile, try issuing the command “notepad $profile”. This will (if it exists) open your profile in notepad to edit. If it doesn’t exist, you’ll get an error when notepad tries to load indicating so. If this is the case, or you would like to create a new PowerShell profile for use in PowerShell or PowerCLI, use the last bit of script listed in the next section to create a profile and get started with customising your environment.

 

Show your profile path or open it up for editing in notepad:

$profile
notepad $profile

 

Create a new PowerShell profile for the current user if one does not already exist, then open it up for editing in notepad:

if (!(test-path $profile)) 
           {new-item -type file -path $profile -force}
notepad $profile

 

Once you have your profile created and ready for editing, try add a few useful Functions or variable declarations to get yourself going, then launch a new PowerShell or PowerCLI session to try them out. Here is a quick example of a function you can create to test your profile out in PowerCLI:

 

function VMInfo {
	param(
	[parameter(Mandatory = $true)]
    	[string[]]$VMName)
	Get-VM $VMName
}

 

Save your profile with the above function added, then start a new session of PowerCLI. Connect to your vCenter server using Connect-VIServer and then try type in “VMInfo aVMname” (where aVMname = the name of an actual VM in your environment). As you may have noticed, this function is just doing the same job that the Get-VM cmdlet already does for you, and will simply return the info about a VM specified. Here is a quick run down of the function above. The function is declared first of all (Name of the function). Then we open curly brackets to start the code. The param section then defines whether a parameter is mandatory (needed) or not, and what type of variable that parameter is (in our case we used a string), as well as giving the parameter a variable name ($VMName). The last bit does the actual work to run the Get-VM cmdlet on the parameter ($VMName) passed to the function. Here’s the output when running the new function against a VM called “SEAN-DC01” in my PowerCLI session:

 

 

You should now be able to see how useful this can become – you can quickly add new functions, variables, etc to your PowerShell profile for future use in new sessions. Try think of a few useful ones for cmdlets that you use often on a day to day basis and add these into your profile. You won’t regret it in the long run!

PowerCLI – Get HA Restart Priority and Memory Overhead for VMs

 

Another day, another PowerCLI automation script. Here is a handy cmdlet that will fetch you a list of VMs in your environment based on whether they are currently powered on.

 

The interesting bit of info retrieved is their current HA Restart Priority. This will be returned whether the VM itself has its own HA Restart Priority defined, or if the VM is getting this setting from the cluster it is running in. Another interesting bit of info we fetch is the VMs current Memory Overhead figure. Additionally, we also fetch some other useful information such as which Host the VM runs on and the RAM & vCPU assignments for the VM, sorting the whole list by the name of each VM. Remember that the Memory Overhead that is reported back is what the current overhead for the VM is. This can change and there is quite a bit involved in how it is worked out. Further reading on Memory Overhead for VMs can be done here. Read Table 3-2 on page 30 of the linked PDF for the specifics.

 

(Get-VM | Where {$_.PowerState -eq "PoweredOn"}) | Select Name,PowerState,NumCpu,MemoryMB,VMHost,@{N="MemoryOverhead";E={$_.ExtensionData.Runtime.MemoryOverhead/1MB}}, HARestartPriority | Sort Name | ft

 

If you don’t want a result formatted in a table, just remove the “| ft” at the end of the cmdlet, and remember if you want to push the results of this into a CSV file, you can also just replace the “ft” with a “Export-CSV C:\yourfile.csv”. If you have any improvements to the above script, suggestions or comments, please add do add them!

Get a list of VMs in a cluster and find their HA Restart Priority with PowerCLI

 

This is just a quick post today using one of the most common PowerCLI cmdlets, Get-VM.

 

I needed to find a list of VMs in a specific cluster, and grab their respective HA Restart Priority settings. PowerCLI makes this nice and simple. First of all, connect to your vCenter server, then find the name of your cluster you would like to search. You can use the Get-Cluster cmdlet on its own to list all clusters in a specific vCenter installation.

 

Connect-VIServer yourvcenterservername
Get-Cluster

 

Next, use this one liner to list all the VMs in your specified cluster along with their respective HARestartPriority settings. This will also sort the list in alphabetical order and export it into a CSV file in C:\temp. If you wish to rather just list the items in your shell instead, remove the Export-CSV bit at the end.

 

Get-Cluster "yourclustername" | Get-VM | Select Name,HARestartPriority | Sort Name | Export-CSV C:\temp\vmrestartpriorities.csv