Skip to content

Instantly share code, notes, and snippets.

@benpye
Created November 27, 2019 06:54
Show Gist options
  • Save benpye/4d011e65abc4d9c585b8a59f877a2d29 to your computer and use it in GitHub Desktop.
Save benpye/4d011e65abc4d9c585b8a59f877a2d29 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Options;
namespace VirtualMachineTray
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new VmTrayContext());
}
}
internal struct VirtualMachine
{
public string Name;
public string Guid;
public bool Running;
}
internal class VmTrayContext : ApplicationContext
{
private NotifyIcon trayIcon;
private System.Threading.Timer timer;
private CimSession session;
internal VmTrayContext()
{
var sessionOptions = new DComSessionOptions
{
Timeout = TimeSpan.FromSeconds(30)
};
session = CimSession.Create("localhost", sessionOptions);
trayIcon = new NotifyIcon()
{
Visible = false,
};
UpdateTrayIcon();
trayIcon.Visible = true;
timer = new System.Threading.Timer((object state) => UpdateTrayIcon(), null, 1000, 1000);
}
private void UpdateTrayIcon()
{
var vms = GetVirtualMachines();
var vmCount = vms.Count();
var runningCount = vms.Where(v => v.Running).Count();
trayIcon.Text = RunningString(runningCount);
trayIcon.Icon = GetTrayIcon(runningCount > 0);
trayIcon.ContextMenu = new ContextMenu();
if (vmCount > 0)
{
foreach (var vm in vms)
{
var state = vm.Running ? " [Running]" : "";
trayIcon.ContextMenu.MenuItems.Add(new MenuItem(
$"{vm.Name}{state}", (object s, EventArgs a) => OpenVmConnect(vm.Name, vm.Guid)
));
}
trayIcon.ContextMenu.MenuItems.Add(new MenuItem("-"));
}
trayIcon.ContextMenu.MenuItems.Add(new MenuItem("Open Hyper-V Manager", (object s, EventArgs a) => StartVmManager()));
}
private string RunningString(int count)
{
if (count == 0)
{
return "No virtual machines running";
}
else if (count == 1)
{
return "1 virtual machine running";
}
else
{
return $"{count} virtual machines running";
}
}
private void OpenVmConnect(string vmName, string vmGuid)
{
ProcessStartInfo psi = new ProcessStartInfo("vmconnect");
psi.ArgumentList.Add("localhost");
psi.ArgumentList.Add(vmName);
psi.UseShellExecute = true;
psi.Verb = "runas";
Process.Start(psi);
}
private void StartVmManager()
{
ProcessStartInfo psi = new ProcessStartInfo("mmc");
psi.ArgumentList.Add("virtmgmt.msc");
psi.UseShellExecute = true;
psi.Verb = "runas";
Process.Start(psi);
}
private Icon GetTrayIcon(bool running)
{
var font = new Font("Segoe MDL2 Assets", 12, FontStyle.Regular);
var iconBrush = new SolidBrush(Color.Black);
var indicatorBrush = new SolidBrush(running ? Color.Red : Color.Lime);
var bitmap = new Bitmap(16, 16);
var g = Graphics.FromImage(bitmap);
IntPtr icon;
g.Clear(Color.Transparent);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
g.DrawString("\uE977", font, iconBrush, -3, 0);
g.FillEllipse(indicatorBrush, 8, 8, 8, 8);
icon = bitmap.GetHicon();
return Icon.FromHandle(icon);
}
private IEnumerable<VirtualMachine> GetVirtualMachines()
{
var instances = session.EnumerateInstances(@"root\virtualization\v2", "Msvm_ComputerSystem");
return instances
.Where(i => (string)i.CimInstanceProperties["Caption"].Value != "Hosting Computer System")
.Select(i => new VirtualMachine()
{
Name = (string)i.CimInstanceProperties["ElementName"].Value,
Guid = (string)i.CimInstanceProperties["Name"].Value,
Running = (UInt16)i.CimInstanceProperties["EnabledState"].Value == 2
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment