Get Virtual Machine Inventory from a Hyper-V Failover Cluster using PowerShell

A colleague was asking around for a PowerShell script that would fetch some inventory data for VMs on a Hyper-V cluster the other day. Not knowing too much about Hyper-V and having only ever briefly looked at what was out there in terms of PowerShell cmdlets for managing Hyper-V, I decided to dive in tonight after I got home.

 

Here is a function that will fetch Inventory data for all VMs in a specified Failover Cluster. This is what it fetches:

  • VM Name
  • VM CPU Count
  • VM CPU Socket Count
  • VM Memory configuration
  • VM State (Up or Down)
  • Cluster Name the VM resides on
  • Hyper-V Host name the VM resides on
  • Network Virtual Switch Name
  • NIC Mac Address
  • Total VHD file size in MB
  • Total VHD Count

 

Being a function, you can pipe in the name of the cluster you want, for example Get-Cluster | Get-HyperVInventory. Or you could do Get-HyperVInventory -ClusterName “ExampleClusterName”. You could also send it to an HTML Report by piping it to “ConvertTo-HTML | Out-File example.html”

Download here, or copy it out from the script block below:
[download id=”15″]
 

# Requires: Imported HyperV PowerShell module (http://pshyperv.codeplex.com/releases/view/62842)
# Requires: Import-Module FailoverClusters
# Requires: Running PowerShell as Administrator in order to properly import the above modules

function Get-HyperVInventory {
<#
.SYNOPSIS
Fetches Hyper-V VM Inventory from a specified Hyper-V Failover cluster

.DESCRIPTION
Fetches Hyper-V VM Inventory from a specified Hyper-V Failover cluster

.PARAMETER ClusterName
The Name of the Hyper-V Failover Cluster to inspect

.EXAMPLE
PS F:\> Get-HyperVInventory -ClusterName "dev-cluster1"

.EXAMPLE
PS F:\> Get-Cluster | Get-HyperVInventory

.LINK
http://www.shogan.co.uk

.NOTES
Created by: Sean Duffy
Date: 09/07/2012
#>

[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=$true,HelpMessage="Name of the Cluster to fetch inventory from",
ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[System.String]
$ClusterName
)

process {

$Report = @()

$Cluster = Get-Cluster -Name $ClusterName
$HVHosts = $Cluster | Get-ClusterNode

foreach ($HVHost in $HVHosts) {
$VMs = Get-VM -Server $HVHost
foreach ($VM in $VMs) {
[long]$TotalVHDSize = 0
$VHDCount = 0
$VMName = $VM.VMElementName
$VMMemory = $VM | Get-VMMemory
$CPUCount = $VM | Get-VMCPUCount
$NetSwitch = $VM | Get-VMNIC
$NetMacAdd = $VM | Get-VMNIC
# VM Disk Info
$VHDDisks = $VM | Get-VMDisk | Where { $_.DiskName -like "Hard Disk Image" }
foreach ($disk in $VHDDisks) {
$VHDInfo = Get-VHDInfo -VHDPaths $disk.DiskImage
$TotalVHDSize = $TotalVHDSize + $VHDInfo.FileSize
$VHDCount += 1
}
$TotalVHDSize = $TotalVHDSize/1024/1024
$row = New-Object -Type PSObject -Property @{
Cluster = $Cluster.Name
VMName = $VMName
VMMemory = $VMMemory.VirtualQuantity
CPUCount = $CPUCount.VirtualQuantity
CPUSocketCount = $CPUCount.SocketCount
NetSwitch = $NetSwitch.SwitchName
NetMACAdd = $NetMacAdd.Address
HostName = $HVHost.Name
VMState = $HVHost.State
TotalVMDiskSizeMB = $TotalVHDSize
TotalVMDiskCount = $VHDCount
} ## end New-Object
$Report += $row
}
}
return $Report

}
}

 

Example use cases – load the function into your PowerShell session, or place it in your $profile for easy access in future, and run the following:

# Example 1
Get-HyperVInventory -ClusterName "mycluster1"
# Example 2
Get-Cluster | Get-HyperVInventory
# Example 3
Get-HyperVInventory -ClusterName "mycluster1" | ConvertTo-HTML | Out-File C:\Report.html

 

The function includes help text and examples, so you can also issue the normal “Get-Help Get-HyperVInventory” or “Get-Help Get-HyperVInventory -Examples”. It is by no means perfect and could do with some improvements, for example if there is more than one Virtual Switch Network associated with a VM these would be listed in a row multiple times for each. Feel free to suggest any improvements or changes in the comments.

 

Changing Registry entries on multiple systems with PowerShell and Remoting

 

A few weeks ago, a colleague asked if I knew of a way to script the change or modification of the Registered Owner / Organization information on a Windows Server system (2003 or 2008). I knew that this could be achieved with PowerShell and had some initial ideas, so I spent a few minutes whipping up the script below.

For this to work, you should ideally have all systems on the same Windows Domain and have enabled PowerShell remoting on each system that needs to be changed. Of course you could also just run the script on a single workstation/server on its own without the need for PSRemoting.

 

# On all remote machines that need their info changed
Set-ExecutionPolicy RemoteSigned
Enable-PSRemoting # Say yes to all prompts
#region This part only needed if machines do not belong to the same domain...
# Note: This can be a security risk, only use if you are sure you want to allow any host as a trusted host. (e.g. fine for lab environments)
cd wsman::localhost\client
Set-Item .\TrustedHosts * # Say yes to all prompts
#endregion
# Run on your management machine/machine you are using to update all others...
$computers = @("SERVER1","SERVER2","SERVER3")

foreach ($computer in $computers) {
    Enter-PSSession $computer
    cd 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion'
    Set-ItemProperty -Path . -Name "RegisteredOwner" -Value "Auth User"
    Set-ItemProperty -Path . -Name "RegisteredOrganization" -Value "Lab"
    Exit-PSSession
}

 

So the above should update your registered owner and organization details for each server listed in the $computers array. (Specify your own host names here). The above script should be easy enough to modify if you are looking to change other registry entries. Finally, don’t forget that you should always be careful when updating registry, especially via script – make sure you have backups!

 

How to use PoSH or PowerCLI to SSH into network devices – wodSSH [Part 2]

 

In [part 1] of this series of posts, I explored SharpSSH, and how to use this to SSH into network devices via PowerShell or PowerCLI. I found this extremely useful, and managed to automate a process of retrieving some SHA1 SSL fingerprints from a few clusters of ESX hosts in the process. I did however find that loading the dll and functions necessary to get this bit of automation done was a little tedious. I had heard about wodSSH via the get-scripting podcast and decided I would need to take a look at this.

 

If you are planning on using wodSSH, you should start by downloading it here. Note that you should definitely buy a license if you are going to be using this for your job or day to day automation – the license is not to expensive if you consider the kinds of automation you could achieve with this! For this blog post I am just using the trial version in my lab environment at home to try out – the trial pops up a “nag screen” every now and then to indicate you are unlicensed. Once downloaded, install wodSSH and the libraries will now be available for use on your machine.

 

Download the script below, or take a look at it in the Syntax Highlighted area below – this is an example of how I was able to SSH into a cluster of ESXi hosts and run a remote command via SSH through PowerCLI. In this example, a table is returned with Host names, along with their SHA1 fingerprint information. It is possible to retrieve this info (as of ESXi 5 I believe) in PowerCLI, but for this example I just wanted to demonstrate the use of SSH and PowerShell / PowerCLI.

 

[download id=”14″]

 

$login = "root"
$password = "yourrootpassword" 

$Report = @()
$VMHosts = Get-VMHost | Where {$_.ConnectionState -eq "Connected"} | Sort Name

foreach ($vmhost in $VMHosts) {
	$hostname = $vmhost
	$ssh = New-Object -ComObject "weOnlyDo.wodSSHCom.1"
	$ssh.Hostname = $hostname
	$ssh.Login = $login
	$ssh.Password = $password
	$ssh.Blocking = 1
	$ssh.Protocol = 4
	$ssh.Timeout = 25
	$ssh.Connect($hostname)
	$ssh.WaitFor("regex:[$%#>] $")
	$cmdresult = $ssh.Execute("openssl x509 -sha1 -in /etc/vmware/ssl/rui.crt -noout -fingerprint`r`n","regex:[~#]")
	$ssh.Disconnect()
	$temp = $cmdresult | select-string -pattern "SHA1 Fingerprint="
	Write-Host $cmdresult -ForegroundColor Green
	$row = New-Object -TypeName PSObject -Property @{
		SHA1 = $cmdresult
		HostName = $vmhost
	}
	$Report += $row
}
$Report

 

You will notice that on line 09, we load the wodSSH library using the New-Object cmdlet. After this we continue to setup some properties for our $ssh connection object. A regex check is used to determine when are connected to a host and have an SSH shell prompt ($ssh.WaitFor(“regex:[$%>;] $”).  We then use $cmdresult to capture the result of running an SSH command via our connection to our current ESXi host. To finish capturing the output of the command on our remote host, we use a regex check again (“regex:[~#]”). You’ll notice that the actual command is also on this line, i.e. line 18 (openssl). After the result is captured, we disconnect our SSH session, then proceed to build our small report array. At the end of the script, we output the $Report array to the screen.

 

Results of the above script in PowerCLI

 

As far as I can see, the wodSSH library can open up a whole new world of automation for you in the data centre. Think of the possibilities – you could automate just about everything, from switches, routers, Linux/Unix hosts / ESXi Hosts to iLO / DRAC and other management cards. Essentially, anything that accepts commands via SSH! If you have any automation stories using wodSSH, or just PowerShell or PowerCLI in general, I would love to hear about them – so feel free to drop a comment or two on this post.

 

 

How to use PoSH or PowerCLI to SSH into Devices & retrieve information (Gathering SHA1 Fingerprints)

 

I was listening to GetScripting podcast #29 the other day. The guest was Pete Rossi (PoSH Pete), and in the discussion he discussed data centre automation. Part of the automation he has set up involves wrapping SSH with PowerShell, and by doing so he is able to automate various functions on devices that can be SSH’d onto. This got me thinking of potential use cases. Soon enough I already had a couple of use case scenarios that could do with automating using SSH and PowerCLI. Pete mentioned he mainly uses an SSH component by a company called “WeOnlyDo Software”, however Alan Renouf also mentioned having heard of “SharpSSH”. I decided I wanted to try both out and figure out how to use both, so with that I set out figuring out how to get them working with PowerShell and PowerCLI. In this post (Part 1) I will cover using the SharpSSH DLL. In Part 2 I will go into the (easier in my opinion) wodSSH component (also paid for) method.

 

SharpSSH (based on Tamir Gal’s .NET library)

 

I believe Tamir Gal originally created this library, however it seems to now be maintained by others.

 

First of all, for SharpSSH to work with PowerShell or PowerCLI, you’ll need to get the relevant DLL that will be loaded by your script. I found a version of SharpSSH being actively worked on and improved by Matt Wagner on Bitbucket. I downloaded this version (called SharpSSH.a7de40d119c7.dll) to get started. To load the functions that we’ll be using to SSH in to devices, I used the following PowerShell function. Just be sure to reference in the correct path of the SharpSSH DLL that you downloaded above in this function. Download the function below:

 

[download id=”13″]

 

Then as long as the functions are loaded in your PoSH session, you should be able to run the example below.

 

How to SSH into ESXi hosts and retrieve SHA1 Fingerprints using PowerCLI and SharpSSH

 

Example output after running the script detailed below against multiple ESX hosts

 

 

Now, first off I’ll say that this isn’t necessarily the best way of retrieving SSL Fingerprints from your ESXi hosts in terms of security – you’d want to do this from the DCUI of the ESXi hosts to confirm the identity of each host is as you expect. (See this blog post and comments over at Scott Lowe’s blog for more detail on the security considerations). With that being said, here is my implementation of SharpSSH, used to SSH into each ESXi host (from a Get-VMHost call) and retrieve the SHA1 Fingerprints. The script will create and output a table report, listing each ESX/ESXi host as well as their SHA1 Fingerprint signatures.

 

Background for the Script

 

I believe this is actually quite an easy bit of info to collect using PowerCLI and the ExtensionData.Config properties on newer hosts / vSphere 5, but in my environment I was working with, all my ESX 4.0 update 4 hosts did not contain this Fingerprint info in their ExtensionData sections when queried with PowerCLI. Therefore I automated the process using SSH as I could use the command “openssl x509 -sha1 -in /etc/vmware/ssl/rui.crt -noout -fingerprint” to generate the Fingerprint remotely on each host via SSH. So with that in mind, here is the script that fetches this info. Note it will prompt for root credentials on each host that is connected to – this could probably be easily changed in the Function (downloaded from above). So here is the final script which will list all ESXi hosts and their SHA1 Fingerprints:

 

$Report = @()
$VMHosts = Get-VMHost | Sort Name

foreach ($vmhost in $VMHosts) {
	New-SshSession root $vmhost
	if (Receive-SSH '#')
	{
		Write-Host "Logged in as root." -ForegroundColor Green
		$a = Invoke-SSH "openssl x509 -sha1 -in /etc/vmware/ssl/rui.crt -noout -fingerprint" 'SHA1'
		$temp = $a | select-string -pattern "SHA1 Fingerprint="
		$row = New-Object -TypeName PSObject -Property @{
			SHA1 = $temp
			HostName = $vmhost
		}
		$Report += $row
		$rootlogin = $true
		Write-Host "Output complete." -ForegroundColor Green
	}
	if ($rootlogin -eq $true)
	{
		Write-Host "Exiting SSH session."
		Send-SSH exit
	}
	Write-Host "Terminating Session."
	Remove-SshSession
}

$Report

 

Well, I hope this helps you out with a way to automate SSH access to devices to retrieve information or change settings. This could easily be adapted to send SSH commands to any other kind of device that accepts SSH as a method of login. Switches, Routers, linux servers, you name it! In my next blog post I will be showing you how to use the wodSSH library (We Only Do Software) to do SSH in PowerShell or PowerCLI – I have found this method to be a bit easier to use when compared with SharpSSH! So look out for my next post coming soon!

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.