Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Adding Some Power to Hyper-V VM Notes

Posted on December 15, 2015January 11, 2016

Since I work at home, I rely a great deal on my Hyper-V environment. I'm assuming if you are using Hyper-V at work the same is true for you.  Because I do a lot of testing, it is difficult sometimes to remember what is running on a given VM. Did I update that box to PowerShell v5? Is that VM running Windows Server 2016 TP 3 or TP4?

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

Hyper-V virtual machines have a setting where you can keep notes which seems like the ideal place to store system information.  Since most of my Windows machines are on my public network and the virtual machine name is the same as the computer name, I can easily use PowerShell remoting to connect to each virtual machine, get some system information, and update the corresponding note.

I can run a command like this to get the system information I need.

Get-WmiObject win32_Operatingsystem | 
Select @{Name="OperatingSystem";Expression={$_.Caption}},
@{Name="ServicePack";Expression={$_.CSDVersion}},
@{Name="PSVersion";Expression= {$psversiontable.PSVersion}},
@{Name="Hostname";Expression={
    If (Get-Command Resolve-DNSName -ErrorAction SilentlyContinue) {
    (Resolve-DnsName -Name $env:computername -Type A).Name
    }
    else {
[system.net.dns]::Resolve($env:computername).hostname
}
}}

I get back a result like this:

System Information
system information

In my code, I want to include the computer name just in case it is different. If the server has the Resolve-DNSName cmdlet, I invoke it otherwise I use the .NET Framework to resolve the name.

To set the the Notes property , I can use Set-VM.

$VM = get-vm chi-dc02
Set-VM $VM -Notes $newNote

Be aware that this behavior will replace any existing notes. In my final code, I take that into account and by default I append the system information. But there is a parameter to replace the note contents if you wish.

My final code also includes a parameter to use the VM's IP address instead of it's name. I have a few VMs that are not part of my test domain, but I register their names in my DNS.

Here's the complete script.

#requires -version 4.0
#requires -module Hyper-V


<#
Update the Hyper-V VM Note with system information

The script will make a PowerShell remoting connection to each virtual machine using the 
VM name as the computer name. If that is not the case, you can use the detected IP address
and then connect to the resolved host name. Alternate credentials are supported for 
the remoting connection.

The default behavior is to append the information unless you use -Replace.

The default is all virtual machines on a given server, but you can specify an
individual VM or use a wild card.

You can only update virtual machines that are currently running.

Usage:
c:\scripts\Update-VMNote chi* -computername chi-hvr2 -credential globomantics\administrator -replace
#>

[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Position=0)]
[ValidateNotNullorEmpty()]
[Alias("name")]
[string]$VMName = "*",
[Alias("CN")]
[string]$Computername = $env:COMPUTERNAME,
[Alias("RunAs")]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
[Switch]$ResolveIP,
[Switch]$Replace
)


Write-Verbose "Starting: $($MyInvocation.Mycommand)"

Write-Verbose "Getting running VMs from $($Computername.ToUpper())"

$VMs = (Get-VM -Name $VMName -computername $computername).Where({$_.state -eq 'running'})

if ($VMs) {
    foreach ($VM in $VMs) {
    Write-Host "Processing $($VM.Name)" -ForegroundColor Green
    if ($ResolveIP) {
        #get IP Address
        $IP = (Get-VMNetworkAdapter $VM).IPAddresses | where {$_ -match "\d{1,3}\." } | select -first 1

        #resolve IP address to name
        $named = (Resolve-DnsName -Name $IP).NameHost
    }
    else {
        #use VMname
        $named = $VM.name
    }
    
    #get PSVersion
    #get Operating System and service pack
    #resolving hostname locally using .NET because not all machines
    #may have proper cmdlets
    $sb = { 
        Get-WmiObject win32_Operatingsystem | 
        Select @{Name="OperatingSystem";Expression={$_.Caption}},
        @{Name="ServicePack";Expression={$_.CSDVersion}},
        @{Name="PSVersion";Expression= {$psversiontable.PSVersion}},
        @{Name="Hostname";Expression={
            If (Get-Command Resolve-DNSName -ErrorAction SilentlyContinue) {
            (Resolve-DnsName -Name $env:computername -Type A).Name
            }
            else {
        [system.net.dns]::Resolve($env:computername).hostname
        }
        }}
      } #close scriptblock
    
    #create a hashtable of parameters to splat to Invoke-Command
    $icmHash = @{
        ErrorAction = "Stop"
        Computername = $Named
        Scriptblock = $sb
    }
    
    #add credential if specified
    if ($Credential.username) {
        $icmHash.Add("Credential",$Credential)
    }
    Try {
        #run remoting command
        Write-Verbose "Getting remote information"
        $Info = Invoke-Command @icmHash  | Select * -ExcludeProperty RunspaceID
        #update Note
        Write-Verbose "`n$(($info | out-string).Trim())"
        if ($Replace) {
            Write-Verbose "Replacing VM Note"
            $newNote = ($info | out-string).Trim()
        }
        else {
            Write-Verbose "Appending VM Note"
            $current = $VM.Notes
            $newNote = $Current + "`n" + ($info | out-string).Trim()    
        }
        Set-VM $VM -Notes $newNote
        #reset variable
        Remove-Variable Info
    } #try

    Catch {
        Write-Warning "[$($VM.Name)] Failed to get guest information. $($_.exception.message)"
    } #catch

    } #foreach VM
} #if running VMs found
else {
    Write-Warning "Failed to find any matching running virtual machines on $Computername"
}

Write-Verbose "Ending: $($MyInvocation.Mycommand)"

Note that this is a script and not a function.  I can now easily update my virtual machines.

C:\scripts\Update-VMNote.ps1 chi* -Computername chi-hvr2 -Credential globomantics\administrator -replace
setting VM note
getting system information for the VM note

And here's the result:

viewing the note
The new note

Of course you can modify the script to include any information you want in the note.

If you find this useful I hope you'll let me know.

Enjoy!

UPDATE JANUARY 11, 2016

I have updated the script and turned it into a function. You can now pipe virtual machines into the function. I also included a Passthru parameter so you can see the Note information. The function is hosted on GitHub at https://gist.github.com/jdhitsolutions/6f17c1d901ff870ff7a3.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

2 thoughts on “Adding Some Power to Hyper-V VM Notes”

  1. Dalmiro says:
    December 15, 2015 at 9:20 am

    Found it useful! I use the notes to put numbers on the VM’s to specify their priority.

    Then I use a function that wakes up an entire environment on VMs at once. Lets say “All the machines whose name starts with NY, which means they are from the NY domain”

    Priority 1 – Its a domain controller/dns/dhcp. I start it up and wait 20 secs before moving on to Priority 2 machines. Just to make sure the DCs are running when the rest of the servers wake up.

    Priority 2 – Databases (I have services that depend on them). Wait 10 secs before moving to Priority 3

    Priority 3 – The rest

    If you know a better way to do this, please let me know 🙂

    1. Jeffery Hicks says:
      December 15, 2015 at 9:28 am

      There is a setting for Automatic Startup Delay which is probably the best option. You would set delays starting from the beginning. Priority 1 would have a 0 second delay. P2 = 20 seconds, P3 = 30 seconds.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d