Welcome to my first Azure Stack blog.
Recently I have been exploring the Azure Stack POC TP1 which is available for everyone at https://azure.microsoft.com/en-us/overview/azure-stack/
So far I am very impressed, of cause always bear in mind that this is the first technical preview POC.
Today I made a small tool for helping me to have a good overview of my Azure Stack tenant VMs.
In Azure Stack the VMs are named by their GUID in Hyper-V.
This makes perfect sense, since multiple tenants could easily name their VMs the same name.
But when administrating your hyper-v host, It can be a bit hard to recognize which machine is which.
Therefore I have create a small GUI tool in PowerShell to help list the machines on a host, and to be able to trigger some basic actions.
This is the first beta and the following actions have been added:
- Connect to Console
- Stop VMs
- Start VMs
You can download the PowerShell based tool here:
https://gallery.technet.microsoft.com/Azure-Stack-VM-GUI-Beta-1-9e55aa80
Here is the current script content (the gallery item might be updated since this blog post was published):
# //********************************************************************************************* # // Solution: # // Author: Jakob Gottlieb Svendsen, Coretech A/S. https://blog.ctglobalservices.com / www.runbook.guru # // Purpose: List Azure Stack VMs from hyper-v host in a friendly layout. # // Trigger actions on a number of VMs # // Connects to localhost by default. Please send suggestions to [email protected] # // # // Usage: MAS-VM-Admin.ps1 # // MAS-VM-Admin.ps1 -Computer <hyper-v host" # // # // History: # // 1.0.0 JGS 02/22/2016 Created initial version. # // # //******************************************************************************************** # //---------------------------------------------------------------------------- #// #// Global constant and variable declarations #/ #//---------------------------------------------------------------------------- param($ComputerName = "localhost") #//---------------------------------------------------------------------------- #// Procedures #//---------------------------------------------------------------------------- Function UpdateVMList($ComputerName) { $VMInfos = @() $VMs = get-vm -ComputerName $ComputerName foreach ($VM in $VMs) { if(!$vm.Notes.StartsWith("Region:")) { continue } #Skip non MAS VMs $VMInfo = New-Object -TypeName PSObject $VMInfo | Add-Member -MemberType NoteProperty -Name Name -Value $VM.Name #MAS Attributes $NotesSplit = $VM.Notes.Split(",") foreach ($pair in $NotesSplit) { $pairsplit = $pair.Split(":") $VMInfo | Add-Member -MemberType NoteProperty -Name $pairsplit[0].Trim() -Value $pairsplit[1].Trim() } $VMInfo | Add-Member -MemberType NoteProperty -Name VM -Value $VM $VMInfos += $VMInfo } $ListViewMain.ItemsSource= $VMInfos } #//---------------------------------------------------------------------------- #// Main routines #//---------------------------------------------------------------------------- #Check hyper-v module installed if(!(get-module -ListAvailable -Name "hyper-v")) { throw "Hyper-V module not found. Please run this tool on a server that has the Hyper-V management tools installed" } Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName PresentationCore [XML]$MainWindow = @' <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Runbook.Guru - Azure Stack VM Manager" Height="700" Width="1000"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1000*"></ColumnDefinition> <ColumnDefinition Width="150"></ColumnDefinition> </Grid.ColumnDefinitions> <ListView x:Name="ListViewMain" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > <ListView.View> <GridView > <GridViewColumn Header="VMName" DisplayMemberBinding="{Binding VMName}" /> <GridViewColumn Header="State" DisplayMemberBinding="{Binding VM.State}" /> <GridViewColumn Header="CPU Usage" DisplayMemberBinding="{Binding VM.CPUUsage}" /> <GridViewColumn Header="Assigned Memory" DisplayMemberBinding="{Binding VM.MemoryAssigned}" /> <GridViewColumn Header="Uptime" DisplayMemberBinding="{Binding VM.Uptime}" /> <GridViewColumn Header="ResourceGroup" DisplayMemberBinding="{Binding ResourceGroup}" /> <GridViewColumn Header="Subscription" DisplayMemberBinding="{Binding Subscription}" /> <GridViewColumn Header="Region" DisplayMemberBinding="{Binding Region}" /> <GridViewColumn Header="Hyper-V VM Name" DisplayMemberBinding="{Binding Name}" /> <!--<GridViewColumn Header="VM" DisplayMemberBinding="{Binding VM}" />--> </GridView> </ListView.View> </ListView> <StackPanel Grid.Column="1"> <Label Name="LabelAction" Content="Action" /> <ComboBox Name="ComboBoxAction" /> <Button Name="ButtonGo" Content="Go" /> <Button Name="ButtonRefresh" Content="Refresh VMs" /> </StackPanel> </Grid> </Window> '@ $Reader = (New-Object System.XML.XMLNodeReader $MainWindow) $Window = [Windows.Markup.XAMLReader]::Load($Reader) $ButtonGo = $Window.FindName('ButtonGo') #$ButtonAdd = $Window.FindName('ButtonAdd') $ButtonRefresh = $Window.FindName('ButtonRefresh') $ComboBoxAction = $Window.FindName('ComboBoxAction') $ListViewMain = $Window.FindName('ListViewMain') #Set sorting events UpdateVMList -ComputerName $ComputerName $Actions = @("Connect to Console","Stop VMs", "Start VMs") $ComboBoxAction.ItemsSource = $Actions $ComboBoxAction.SelectedIndex = 0 #Event Handlers $Window.Add_Loaded({ }) #Sort event handler $Window.Add_SourceInitialized({ [System.Windows.RoutedEventHandler]$ColumnSortHandler = { If ($_.OriginalSource -is [System.Windows.Controls.GridViewColumnHeader]) { If ($_.OriginalSource -AND $_.OriginalSource.Role -ne 'Padding') { $Column = $_.Originalsource.Column.DisplayMemberBinding.Path.Path # And now we actually apply the sort to the View $ListViewMain_DefaultView = [System.Windows.Data.CollectionViewSource]::GetDefaultView($ListViewMain.ItemsSource) # Change the sort direction each time they sort Switch($ListViewMain_DefaultView.SortDescriptions[0].Direction) { "Decending" { $Direction = "Ascending" } "Ascending" { $Direction = "Descending" } Default { $Direction = "Ascending" } } $ListViewMain_DefaultView.SortDescriptions.Clear() $ListViewMain_DefaultView.SortDescriptions.Add((New-Object System.ComponentModel.SortDescription $Column, $Direction)) $ListViewMain_DefaultView.Refresh() } } } #Attach the Event Handler $ListViewMain.AddHandler([System.Windows.Controls.GridViewColumnHeader]::ClickEvent, $ColumnSortHandler) }) $ButtonGo.Add_Click({ switch ($ComboBoxAction.SelectedValue) { "Stop VMs" { Stop-VMs -VM $ListViewMain.SelectedItems } "Start VMs" { Start-VMs -VM $ListViewMain.SelectedItems } "Connect to Console" { #. "$env:windir\system32\vmconnect.exe" "$computername $($ListViewMain.SelectedItem.Name)" Start-Process -FilePath "$env:windir\system32\vmconnect.exe" -ArgumentList $computername,$ListViewMain.SelectedItem.Name } } }) $ButtonRefresh.Add_Click({ UpdateVMList }) #Actions function Stop-VMs { [CmdletBinding()] [Alias()] [OutputType([int])] Param ( # Param1 help description [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [Object] $VM ) Process { write-warning "Shutting down VM: $($VM.VMName) ($($VM.Name))" Stop-VM -Name $VM.Name } } function Start-VMs { [CmdletBinding()] [Alias()] [OutputType([int])] Param ( # Param1 help description [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [Object] $VM ) Process { write-warning "Starting VM: $($VM.VMName) ($($VM.Name))" Start-VM -Name $VM.Name } } $Window.ShowDialog() #//---------------------------------------------------------------------------- #// End Script #//----------------------------------------------------------------------------