Hyper-V Compact VHD(X) Disk Task Taking Hours to Complete in GUI

The Scenario

I have a VM on my Windows Server 2012 R2 Standard with Hyper-V role. It has a dynamically expanding disk which I need to compact to reclaim disk space on the host.

The Problem

I used the Hyper-V Management console to compact the disk, but after several hours it’s still running. And because you can only compact a disk on a powered-off VM my business critical VM remains offline.

The Solution

In my case the compact process actually completed successfully within 30 minutes, it’s just the GUI had crashed even though it looked like it was still running normally (the green progress bar hadn’t quite reached the end). I found this out by look in the Event Logs:

Event Viewer > Applications and Services Logs > Microsoft > Windows > Hyper-V-VMMS > Operational log

Search for event ID 27301

“The system successfully compacted ‘:\Virtual Hard Disks\.vhdx’.”

Once I saw this I pressed cancel on the GUI compact window and restarted the Hyper-V management console. I was then able to successfully power-on my VM and the space had been successfully reclaimed.

I also noticed that the high disk activity that had been seen during the early stages of the disk compaction had completely stopped, however the above event log gave me the confidence to cancel the GUI.

NB To enable disk performance counter in Server 2012 R2 open an elevated command prompt and enter the following command “diskperf -y” then close/reopen the task manager window.

Disclaimer: provided “AS IS” with no warranties and confer no rights

WSUS Console Fails to Start: SQL server may not be running

The Scenario

I have WSUS installed on a Windows Server 2012 Standard instance. At the weekend I have installed various updates, including KB3159706.

The Problem

Once KB3159706 installed the WSUS console will not run despite both the WSUS Service and Windows Internal Database services running. It keeps reporting the error that the SQL server may not be running, which is not the case.

The Solution

The fault lies with update KB3159706, and there are two options

Solution 1 (Preferred):

Open an elevated command prompt and type

“C:\Program Files\Update Services\Tools\wsusutil.exe” postinstall /servicing


Wait 1-2 minutes for it to complete…


Enable HTTP Activation under .NET Framework 4.5 Features (I did this in PowerShell or use the Server Manager GUI)

Install-WindowsFeature AS-HTTP-Activation


Finally, restart the WSUS Service

get-service WsusService | Restart-Service

The WSUS console should now launch successfully.


Solution 2 (less secure):

You can simply uninstall this update from the Control Panel (Control Panel > All Control Panel Items > Programs and Features > Installed Updates and search for this update, right-click and select uninstall).


Disclaimer: provided “AS IS” with no warranties and confer no rights

Ubuntu 14 Server – Change hostname

The Scenario

I have copied a virtualised Ubuntu 14.04 LTS server to expand my estate.

The Problem

The server still has the same name of the original server, this needs to be changed.

The Solution

Amend the hostname in the following files:



Then, to apply the changes, you either have to reboot the server or restart the hostname service:

sudo service hostname restart


Disclaimer: provided “AS IS” with no warranties and confer no rights

PS Script: Form to get MAC Address (v1.0)

Description: Enter the name of a computer and get it’s MAC address. The form is still a work in progress, with some of the functions and results needing tightened up and the form is ugly. Remember if you copy and paste this text I often find the format of the quotation marks gets changed so the script becomes corrupt.


#region start declare .NET FUNCTIONALITY
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”)
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
Add-Type -AssemblyName System.Windows.Forms
[System.Reflection.Assembly]::LoadWithPartialName(‘Microsoft.VisualBasic’) | Out-Null
$psexec = ‘\\<computer name>\share$\PSTools\PsExec.exe’
#endregion end declare .NET FUNCTIONALITY


#region FUNCTION #0 Get computer MAC from ARP table – not used in this script
Function arpcheck () {
$IP = [System.Net.Dns]::GetHostByName($computer).AddressList[0].IpAddressToString #the IP of the computer I need to get the MAC for.
$mac = arp -a
($mac | ? { $_ -match $ip } ) -match “([0-9A-F]{2}([:-][0-9A-F]{2}){5})” | out-null;

if ( $matches ) {


} else {

“Not Found”

#endregion FUNCTION #0 Get computer MAC from ARP table

#region FUNCTION #1 Display Form
Function showform () {
[void] $Form.ShowDialog()
#endregion FUNCTION #1 Display Form

#region FUNCTION #2 Conversion and Display

function get-mac2 ()
$computer = $ECN.text

#test if WinRM is enabled on the remote computer, this script requires WinRM is enabled.
$winrm = test-wsman -ComputerName $computer -ErrorAction SilentlyContinue
if ($winrm)

$VPNTC = Test-Connection $computer -Count 1 -ErrorAction SilentlyContinue
$VPNIP = ($VPNTC.IPV4Address).IPAddressToString
If ($VPNIP -match “92.*”){$MAC.text=”ERROR:VPN Reply”} #a test/result if I’m on my VPN and the computer is offline, an active ping response is still returned by the VPN starting with 92.
$TC = Test-Connection -count 1 $computer -Quiet
# If the PC is online then get the InterfaceIndex ID of the active NIC
If ($TC -eq “True”){
$result1 = Invoke-Command -ComputerName $computer {(get-wmiobject win32_networkadapter -filter “netconnectionstatus = 2″).InterfaceIndex | out-string}
$result1 = $result1.Trim()
# If multiple NICs are active then this script won’t work – it still a work in progress 🙂
If ($result1.length -lt 3) {
$result2 = Invoke-Command -ComputerName $computer {(gwmi Win32_NetworkAdapter | where {$_.InterfaceIndex -eq $using:result1}).MACAddress}
Else {$MAC.text=”ERROR:Multi MACs”}
Else {$MAC.text=”ERROR:PC Offline”}
Else {$MAC.text= “WinRM Disabled”}
#endregion FUNCTION #2 Conversion and Display

#region FUNCTION #3 Copy to clipboard
Function ClipMe() {
#endregion FUNCTION Copy to clipboard

#endregion FUNCTIONS

#region FORM

$Form = New-Object System.Windows.Forms.Form
$form.text = “MAC Address Finder”
$Form.Size = New-Object System.Drawing.Size(400,300)
$Form.Font = “Segoe UI,12”
$Form.ForeColor = [System.Drawing.Color]::White
$Form.BackColor = [System.Drawing.Color]::LightSteelBlue
#endregion FORM ELEMENT #1 The basic form


$groupConvert = New-Object System.Windows.Forms.GroupBox
$groupConvert.Location = New-Object System.Drawing.Size(10,20)
$groupConvert.size = New-Object System.Drawing.Size(360,170)
$groupConvert.text = “Enter Computer Name:”
#endregion FORM ELEMENT #2 group boxes


$cnlabel = New-Object System.Windows.Forms.Label
$cnlabel.Text = “Enter Computer Name:”
$cnlabel.AutoSize = $True
$cnlabel.Font = “Segoe UI,16”
$cnlabel.Location = “20,20”

$ECN = New-Object System.Windows.Forms.Textbox
$ECN.Size = New-Object System.Drawing.Size(135,100)
$ECN.Font = “Segoe UI,16”
$ECN.Location = “20,60”
$ECN.TextAlign = “Center”

$malabel = New-Object System.Windows.Forms.Label
$malabel.Text = “MAC Address:”
$malabel.AutoSize = $True
$malabel.Font = “Segoe UI,16”
$malabel.Location = “20,120”

$MAC = New-Object System.Windows.Forms.Textbox
$MAC.Size = New-Object System.Drawing.Size(185,100)
$MAC.ReadOnly = $true
$MAC.Font = “Segoe UI,16”
$MAC.Location = “170,120”
$MAC.TextAlign = “Center”

#endregion LABELS and TEXTBOXES


#region BUTTON #1 Create Convert button
$ConvertButton = New-Object System.Windows.Forms.Button
$ConvertButton.Location = New-Object System.Drawing.Size(20,200)
$ConvertButton.Size = New-Object System.Drawing.Size(80,40)
$ConvertButton.Text = “Get MAC”
$ConvertButton.Font = “Segoe UI,12″
$ConvertButton.BackColor = [System.Drawing.Color]::Green
$ConvertButton.Enabled = $True
$Closebutton.Text = “Exit”
$buttonCopyToClipboard.Enabled = $true
#endregion BUTTON #1 Create Convert button

#region BUTTON #2 Create CANCEL button
$Closebutton = New-Object System.Windows.Forms.button
$Closebutton.Location = New-Object System.Drawing.Size(280,200)
$Closebutton.Size = New-Object System.Drawing.Size(80,40)
$Closebutton.Text = “Cancel”
#endregion BUTTON #2 Create CANCEL button

#region BUTTON #3 Create CLIPBOARD button
$buttonCopyToClipboard = New-Object System.Windows.Forms.Button
$buttonCopyToClipboard.Location = New-Object System.Drawing.Size(110,200)
$buttonCopyToClipboard.Size = New-Object System.Drawing.Size(160,40)
$buttonCopyToClipboard.Text = “Copy to clipboard”
#$buttonCopyToClipboard.Font = “Segoe UI,12”
$buttonCopyToClipboard.Enabled = $False
#call the function Clipme to copy the MAC address to the system clipboard
#endregion BUTTON #3 Create CLIPBOARD button

#region BUTTON #4 Create Clear button
$Clearbutton = New-Object System.Windows.Forms.button
$Clearbutton.Location = New-Object System.Drawing.Size(180,59)
$Clearbutton.Size = New-Object System.Drawing.Size(80,40)
$Clearbutton.Text = “Clear”
$buttonCopyToClipboard.Enabled = $False
#clears the text from both fields
#endregion BUTTON #4 Create CLEAR button

#endregion BUTTONS

#endregion FORM

#region SHOW FORM
#endregion SHOW FORM

PS Tip – Use local variable in Invoke-Command (remote computer)

I have a locally declared variable $var1

Using it directly doesn’t work, the value of the variable is not carried over within the invoke-command scriptblock.

$result2 = Invoke-Command -ComputerName $computer {(gwmi Win32_NetworkAdapter | where {$_.InterfaceIndex -eq $var1}).MACAddress}

Instead you have to use the “Using” scope modifier followed by a colon, thus $var1 becomes $using:var1

$result2 = Invoke-Command -ComputerName $computer {(gwmi Win32_NetworkAdapter | where {$_.InterfaceIndex -eq $using:var1}).MACAddress}