Windows Server 2012

Upgrading Server 2012 R2 to Server 2016 and Storage Spaces

Server 2016 has enhanced and added new features to Storage Spaces. Most notably is the introduction of Storage Spaces Direct, Storage Replica, and Storage QoS. This post explores upgrading a physical Server 2012 R2 that uses mirrored tiered storage space.

After installing Server 2016 (Desktop Experience), and choosing to keep ‘nothing’


In Server Manager, File and Storage Services\Volumes\Storage Pools, we see the old Storage Pool from the prior installation of Server 2012 R2


To recover the Storage Pool, its virtual disks, and all data follow these steps:

  1. Set Read-Write access server2016-19
  2. Upgrade the Storage Pool Version server2016-18Note that this step is irreversible
  3.  Right click on each virtual disk and attach it server2016-21
  4. Finally, in Disk Management, right click on each virtual disk and online it

The virtual disks retain the drive letters and volume labels assigned to them in the old 2012 R2 server. All data is intact.


Monitoring StorSimple Backups

Currently (10 November, 2015) StorSimple 8k provides email alerts regarding a range of error conditions. Email Alerts can be configured per device in the Azure Management Interface under the Device/Configure screen:


However, the Azure Interface does not currently provide for notification regarding successful backup jobs. Some clients have requested daily email notification of StorSimple backup jobs for both failed and successful jobs. This script does just that.

The top section of the script has the input region where you should enter the information specific to your environment:Monitor-StorSimple04

In the Azure Management Interface, under the StorSimple Manager/Dashboard page, you can see the Subscription Name, Subscription ID, and StorSimple Manager Name. Monitor-StorSimple05

On the same page, click Registration Key at the bottom center to copy it.Monitor-StorSimple06

The TargetDeviceName is your StorSimple Device Name as seen on the StorSimple Manager/Devices page:


‘Duration’ variable in the script is set to 7 (days) by default. This will report on backups that ran in the past 7 days from the script execution time.

‘LogFile’ and ‘HTMLFile’ variables should point to local or network paths. That’s where the script will create its log and HTML files (output). If/when this script is set to run as a scheduled job or task, you need to make sure that it runs under credentials that have read/write access to these 2 paths.

‘EmailSender’ is what the email notification would appear to come from. This may or may not be an existing email account.

‘EmailRecipients’ is where you can add the email addresses of who should receive this report. You can add more than one recipient, each on a line.

‘SMTPServer’ is your email relay server. You should configure your SMTP relay server to allow relay from the computer running the script. Details will depend on your environment specific email relay requirements.

You need to run this script in Powershell as Administrator NOT Powershell ISE.

Finally, setup a scheduled job or task to run this script daily or as frequently as needed.

Sample script output:


Sample email:


Get-VMMetering script to collect and reset VM Metering data, report to CSV

This script can be downloaded from the Microsoft Script Center Repository. It can be set as a scheduled task on one of the Hyper-V hosts in the environment, not all of them.

Set the schedule of the scheduled task to run as often as you’d like to have the VM metering data collected and reset.

Edit the top 3 lines to match your environment details:

  • $CSV = “d:\sandbox\MeteringReports”
    • Edit this line to enter the path to the folder to save CSV files. This can be a UNC path like “\\server\share\folder”
  • $HVHosts = @(“Host1″,”Host2”)
    • Edit this line to list Hyper-V hosts in your environment
  • $Sort = “AvgCPU”
    • Edit this line to change the report sort order. Options include: AvgCPU, AvgRAM, MaxRAM, MinRAM, TotalDisk, NetworkInbound, NetworkOutbound, VMName, ComputerName

Report data and output will look like:


Veeam Cloud Connect on Azure – take 2

2 Months ago in early September 2014, I tested setting up Veeam Cloud Connect on Azure. That was with Veeam version 8 beta 2. Now that Veeam version 8 general availability was November 6th, 2014, I’m revisiting some of the testing with Veeam v8. I’ve also been testing the same with a number of cloud providers who have their own infrastructure. This is helpful to compare performance, identify bottlenecks, and possible issues that may increase or reduce costs.

Summary of steps:

In Azure Management Portal:

  • Create a Cloud Service
  • Create a Storage Account
  • Create a VM: standard A2 with Windows 2012 R2 DC as the OS. Standard A2 is an Azure VM size that comes with 2 (hyperthreaded) processor cores, 3.5 GB of RAM, and up to 4x 1TB page blob disks @ 500 IOPS each. Prior testing with several providers have shown that cloud connect best features such as WAN accelerator need CPU and IOPS resources at the cloud connect provider end.
  • Added an endpoint for TCP 6180 VMcc01
  • Attached 4x disks to the VM, using max space possible of 1023 GB and RW cache VMcc02

On the VM:

  • I RDP’d to the VM at the port specified under Endpoints/Remote Desktop
  • I ran this small script to create a storage space out of the 4x 1TB disks available:

# Script to create simple disk using all available disks
# This is tailored to use 4 physical disks as a simple space
# Sam Boutros – 11/18/2014 – v1.0

$PoolName = "VeeamRepo1"
$vDiskName = "VeeamvDisk1"
$VolumeLabel = "VeeamRepo1"

New-StoragePool -FriendlyName $PoolName -StorageSubsystemFriendlyName “Storage Spaces*” -PhysicalDisks (Get-PhysicalDisk -CanPool $True) |
New-VirtualDisk -FriendlyName $vDiskName -UseMaximumSize -ProvisioningType Fixed -ResiliencySettingName Simple -NumberOfColumns 4 -Interleave 256KB |
Initialize-Disk -PassThru -PartitionStyle GPT |
New-Partition -AssignDriveLetter -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel $VolumeLabel -AllocationUnitSize 64KB -Confirm:$false

The GUI tools verified successful completion:


VMcc04This storage space was created to provide best possible performance for Veeam Cloud Connect:

  1. Fixed provisioning used instead of thin which is slightly faster
  2. Simple resiliency – no mirroring or parity, provides best performance. Fault Tolerance will be subject of future designs/tests
  3. Number of Columns and Interleave size: Interleave * Number Of Columns ==> the size of one stripe. The settings selected make the stripe size 1MB. This will help align the stripe size to the Block size used by Veeam.
  4. Allocation Unit 64KB for better performance
  • Installed Veeam Backup and Replication, using the default settings which installed SQL 2012 Express SP1, except that I changed default install location to drive f:\ which is the drive created above
  • I ran the SQL script to show the GUI interface as in the prior post (under 11. Initial Veeam Configuration)
  • The default backup Repository was already under f: VMcc05
  • Created a WAN Accelerator – cache size 400GB on drive f: created above
  • Installed the additional Cloud Connect License
  • Added a self-signed certificate similar to step 14 in the prior postVMcc07
  • Added a Cloud Gateway VMcc08 VMcc09
  • Added a user/tenant VMcc10 VMcc11

That’s it. Done setting up Veeam Cloud Connect on the provider side.

Powershell script to merge Hyper-V Virtual Machine disks

In some situations you might find a VM disk to be part of a series of differencing disks. Take this example:


If this was the result of VM Checkpoints, the fix would be easy: simply delete the checkpoints which merges the disks. But his is not the case. Hyper-V Manager shows no checkpoints:


Powershell confirms (notice no output):


This script shuts down the VM and merges its disks. It uses the Get-ParentPath function.

This script can be downloaded from the Microsoft Script Center Repository.

To use this script, download it, run it as administrator, then use the function.

To see help:


For example:
Merge-VMDisks -VMName ‘MyVM’
This may take some time depending on disk sizes and underlying storage system speed.
The script leaves a log file shows the same steps on the console.
This is the picture after the merge is done:
If the script is run on a VM that has no disks to be merged, no changes are made:
The script prompts for confirmation before shutting down the VM:
This can be bypassed by using the -Confirm parameter as shown above.
Script help output looks like:
    Function to merge VM disks
    Merge-VMDisks [-VMName]  [[-LogFile] ] [-WhatIf] [-Confirm] []
    Function/script to merge VM disks. The script will power down the VM in the process.

        Name of the VM whose VHD(x) disks are to be merged
        Required?                    true
        Position?                    1
        Default value                
        Accept pipeline input?       true (ByValue, ByPropertyName)
        Accept wildcard characters?  false
        Name and path of the file where the script will log its steps and progress
        Required?                    false
        Position?                    2
        Default value                ".\Merge-VMDisks_$(Get-Date -format yyyyMMdd_hhmmsstt).txt"
        Accept pipeline input?       false
        Accept wildcard characters?  false
    -WhatIf []
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
    -Confirm []
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer, PipelineVariable, and OutVariable. For more information, see 
        about_CommonParameters ( 
        Function by Sam Boutros
        v1.0 - 11/01/2014
    -------------------------- EXAMPLE 1 --------------------------
    C:\PS>Merge-VMDisks -VMName 'v-2012R2-VBR1'

Powershell script/function to expand system/boot disk on Windows XP/2003 VMs

In Windows 7 and Server 2008 virtual machines and above, expanding the boot/system disk is a simple matter of expanding it in the hypervisor, then expanding it in the guest OS in the Computer Management/Disk Management GUI. In Windows XP/Server 2003 guest VMs, expanding the boot/dystem disk is not available via native Windows tools.

This script leverages Server 2012 R2 hypervisor capabilities to expand boot/system disk on a guest VM running Windows XP/2003 OS. The script leaves a log file behind listing steps taken. The script can be downloaded from the Microsoft Script Center Repository.

To use it: Download the attached file, unblock it, adjust PS execution policy as needed, run the script to load the function in memory, then use this line to get detailed help and examples as shown below:


Note: The script will shutdown the VM during this process.

For example, if you down the VM, and expand the disk in Hyper-V Manager GUI:


In the VM, you cannot expand the boot/system partition with native Windows 2003/XP tools:


You can do that with this script. On the Hyper-V host where the VM is running, run:

Expand-C -VMName MyVM1 -Size 17GB -BackupPath "d:\save"

The script will

  • Backup the VHDX file before expanding it if the ‘BackupPath’ is used
  • Convert the file from VHD to VHDX format if it was a VHD file. In this case you’ll need to delete the old .vhd file manually.
  • Down the VM (gracefully)
  • Expand the VHDX file
  • Expand the partition
  • Re-attach the C: drive disk file to the VM
  • Start the VM Diskc8
  • Leave a log file listing the steps taken Diskc9



GUI or no GUI !?

The GUI (Graphical User Interface) is just a Windows feature in Server 2012. You can add it and remove it as needed. This also applies to Server 2012 R2 and Windows Server 10TP.

Server 2012 comes with 4 levels of GUI:

  1. No GUI = Core
  2. Minimal GUI = Server-Gui-Mgmt-Infra feature
  3. Regular GUI = minimal + Server-Gui-Shell (default if you install as GUI)
  4. Full GUI = regular + Desktop-Experience Core04

In Powershell the GUI options are displayed as:


If the server ever had the GUI installed, then the bits are there (under C:\Windows\WinSxS by default). If this a Core install and has never had a GUI before, then the bits are likely to be missing as well.

To check whether the bits are there or not:

$ComputerName = "MyCoreServer"
$Session = New-PSSession -ComputerName $ComputerName
Enter-PSSession -Session $Session
Get-WindowsFeature | Where { $_.Installed }

These commands will enter a remote PS session with the Core server, and list installed features.

This command will check for the 2 features we need to have the GUI:

Get-WindowsFeature | 
    where { $_.Name -eq "Server-Gui-Mgmt-Infra" -or 
            $_.Name -eq "Server-Gui-Shell" }

If the result looks like:


Removed = not installed AND the bits are missing.

We need the file from the WS 2012 media. Mount the install CD.

Next, identify which drive letter is your DVD drive, run:


Next, identify the index number of the installation media needed, run:

Get-WindowsImage -ImagePath D:\sources\install.wim

This should display:


The server version I’m working with in this example is DataCenter, so the media I need is index #4, run:

Install-WindowsFeature -Name "Server-Gui-Mgmt-Infra","Server-Gui-Shell" -source:wim:d:\sources\install.wim:4 

Core09Reboot, and you got GUI.


To remove the GUI later, run:

Remove-WindowsFeature -Name "Server-Gui-Mgmt-Infra","Server-Gui-Shell"


Create simultaneous checkpoints of a group of related Virtual Machines

In some cases you may need to checkpoint a group of related VMs at exactly the time, such as a SharePoint farm, or a multi-tiered application. The process includes pausing, saving the VMs, creating checkpoints, restrating, and eventually restoring back to original state. Powershell can help automate the process:

1. Pause and Save:

# Input
$HVHost = “xHost16”
$VMs = “SSTest1″,”V-2012R2-Test1″,”v-2012R2-TW01”

# Pause and Save
Stop-VM -Name $VMs -Save
# Confirm
Get-VM -ComputerName $HVHost -Name $VMs | Select VMName,State,ComputerName | FT -AutoSize


2. Checkpoint:

# Checkpoint
Checkpoint-VM -ComputerName $HVHost -Name $VMs
# Confirm
Get-VMSnapshot -ComputerName $HVHost -VMName $VMs | Select VMName, Name, ComputerName | FT -AutoSize


3. Restart:

# Restart
Start-VM -ComputerName $HVHost -Name $VMs
# Confirm
Get-VM -ComputerName $HVHost -Name $VMs | Select VMName, State, ComputerName | FT -AutoSize


Eventually, when it’s time to restore the group of VMs to their original state:

4. Remove all checkpoints:

# Later on, to remove all checkpoints:
Remove-VMSnapshot -ComputerName $HVHost -VMName $VMs -IncludeAllChildSnapshots
# Confirm
Get-VMSnapshot -ComputerName $HVHost -VMName $VMs | Select VMName, Name, ComputerName | FT -AutoSize

< no output>..


Hyper-V Virtual Machine checkpoints

In Windows Server 2012 R2 a VM checkpoint in Hyper-V captures a point in time state of a virtual machine’s memory, CPU, system state, and disk contents.

Checkpoints were called VM Snapshots in Server 2012 but that was confusing because it was too close to VSS volume snapshots for example, and it was also known as Checkpoint in VMM.

When a checkpoint is invoked, a .avhd file is created for each of the VM’s .vhd(x) files, and the .vhd(x) files becomes read-only. All changes are then written to the .avhd files preserving the state of the .vhd(x) files at the point of creating the checkpoint. If the VM attempts to access a file, Hyper-V will look for it in the .avhd file first, if not found, it will look for the parent .vhd file. This causes a performance degradation particularly if a number of nested checkpoints are created like:


In this example, The disk files can be observed in the VM folder:


where all the files are read-only except the latest .avhd file at the bottom. Only one checkpoint .avhd file is read-write at any given point in time. Each checkpoint has 1 parent check point. In Powershell, we can run the cmdlet:

Get-VMSnapshot -VMName vHost17

to identify each checkpoint’s parent checkpoint:


Removing a checkpoint merges its content (blocks) with its parent checkpoint. Checkpoints do not have to be removed in order. In this example, we can remove the 7:37:31 checkpoint using this Powershell cmdlet or from the Hyper-V Manager GUI:

Remove-VMSnapshot -VMName vHost17 -Name “vHost17 – (9/21/2014 – 7:37:31 PM)”

Hyper-V will merge the 7:37:31 checkpoint blocks with its parent RW checkpoint (7:37:43):



The entire tree of checkpoints can be deleted in one step by right clicking on the top checkpoint in Hyper-V Manager, and clicking ‘Delete Checkpoint Subtree’.

A checkpoint can be exported using the Export-VMSnapshot cmdlet. The resulting .vhd(x) file(s) can be used to create a clone of the original VM.

A checkpoint can be renamed in either Hyper-V Manager GUI or via Powershell cmdlet Rename-VMSnapshot.

A checkpoint can be applied (restored). This reverts the VM back to the point in time where the checkpoint was taken.



Configure Windows Updates on many computers with Powershell

This function can be used to configure Windows Updates on many computers. The script can be downloaded from the Microsoft Script Center Repository.

This Powershell function will change Windows Updates configuration on many computers to either disable updates, check only, download only, or download and automatically install updates.

To use it, download it, run it in Powershell_ISE for example, then run:


This will setup Windows Updates to ‘Install updates automatically’ on the local computer:


To set Windows Automatic Updates on computers listed in the file “.\Computers.txt” to ‘Download updates but let me choose whether to install them’:

Set-WindowsUpdates -ComputerName (Get-Content “.\Computers.txt”) -Options DownloadOnly -Verbose


To set Windows Automatic Updates on all computers in AD to ‘Install updates automatically’:

Set-WindowsUpdates -ComputerName ((Get-ADComputer -Filter * ).Name) -Options Install

To set Windows Automatic Updates on all running VMs on the Hyper-V Host “HVHost01” to ‘Check for updates but let me choose wether to download and install them’:

$VMs = (Get-VM -ComputerName “HVHost01” | Where { $_.State -eq “Running” }).VMName
Set-WindowsUpdates -ComputerName $VMs -Options CheckOnly

Powershell Script to report on VSS Writers on many computers

Backup of Windows machines uses VSS (Volume shadow Copy) to bring the files to a consistent state prior to performing the backup. VSS architecture is outlined in this diagram:


VSS call flow can be summarized in this chart:


Troubleshooting VSS often requires reporting on the status of VSS writers in the environment. This script can be used to report on VSS writers on many computers. The script is available in the Microsoft Script Center Repository.

For example:


This example gets VSS Writers on the list of $Computers, sort list by ComputerName:


and exports it to CSV file:

VssWriters05Another example:

$Computers = Get-Content “.\MyComputerList.txt”
$VssWriters = Get-VssWriters $Computers -Verbose |
    Where { $_.StateDesc -ne ‘Stable’ } | Sort “ComputerName”
$VssWriters | Out-GridView # Displays it in GridView
$VssWriters | Export-CSV “.\myReport.csv” -NoTypeInformation # Exports it to CSV

This reports any errors on VSS Writers on the computers listed in MyComputerList.txt, sorts list by ComputerName


The ever annoying DOT NET 3.5 on Server 2012, 2012 R2, Windows 8, and 8.1

High level summary:

  • In Server 2012 or 2012 R2:
  1. Find and remove these 3 hot-fixes in Control panel: KB2966826, KB2966827, KB2966828
  2. Pop in the Windows DVD media, and install DOT NET 3.5 from the Server Manager/Add Roles and Features
  • In Windows 8 or 8.1:
  1. Find and remove these 3 hot-fixes in Control panel: KB2966826, KB2966827, KB2966828
  2. Pop in the Windows DVD media, and run the command
    Dism.exe /online /enable-feature /featurename:netfx3 /source:d:\sources\sxs /all

Windows Server 2012, 2012 R2, Windows 8, and 8.1 come with DOT NET 4 or 4.5 but not 3.5. DOT NET 3.5 came with Server 2008, 2008 R2, and Windows 7. It was easily installable as a standalone executable. A lot of older applications need DOT NET 3.5 to run.

With Server 2012/Windows 8 and up, we cannot just install DOT NET 3.5 from the executable. That errors out.

In Server 2012 and up, we’re supposed to install roles and features from Server Manager/Add Roles and Features:


First, go to control panel/uninstall a program/View installed updated, and remove any of these updates if you find them:


or, use this Powershell script:

$RemoveMe = @('KB2966826','KB2966827','KB2966828')
$HotFixes = (Get-HotFix | Sort HotFixID).HotFixID

Write-Host 'Hotfixes installed on this system are:' -ForegroundColor Green

if ($HotFixes | Where { $RemoveMe -contains $_ }) {
 Write-Host 'Found matching Hotfixes:' -ForegroundColor Yellow
 $HotFixes | Where { $RemoveMe -contains $_ }
} else {
 Write-Host 'No matching Hotfixes Found' -ForegroundColor Green

# To remove:

$HotFixes | Where { $RemoveMe -contains $_ } | % {
 "Removing Hotfix: $_"
 & “wusa.exe /uninstall /kb:$($_.Replace(‘KB’,'')) /norestart”

Un-comment the lines at the bottom to remove.

Add DOT NET 3.5 as a feature:


That shows the warning that the media is missing:


Click “Specify an alternative source path”


I popped in the Windows DVD in my drive D: and typed in d:\sources\sxs

That’s all.

In Windows 8 and above, we can use the DISM command to do the same:

Dism.exe /online /enable-feature /featurename:netfx3 /source:d:\sources\sxs /all

Again d: is your DVD drive letter

This has been shown to work like this example..


DOT NET 3.5 on Windows 10 Technical Preview seems to work fine.


Cleaning up Boot Configuration Data store (BCD) using Powershell

You may have the misfortune of running into a situation where disks have been added and/or removed from a server a number of times. If these disks contain the system and/or boot partitions, invalid entries in the BCD store may be left behind. Here’s an example:


In this example, if we try to remove the mirror off the missing disk at the bottom:


We’ll get the following error:


Taking a look at the BCD using the command BCDEDIT /V shows:

Windows Boot Manager
identifier {9dea862c-5cdd-4e70-acc1-f32b344d4795}
device unknown
description Windows Boot Manager
locale en-US
inherit {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}
bootshutdowndisabled Yes
default {92a10962-be7e-11e3-8f5b-f7f89b276248}
resumeobject {92a10961-be7e-11e3-8f5b-f7f89b276248}
displayorder {92a10962-be7e-11e3-8f5b-f7f89b276248}
toolsdisplayorder {b2721d73-1db4-4c62-bf78-c548a880142d}
timeout 30

Windows Boot Loader
identifier {92a10962-be7e-11e3-8f5b-f7f89b276248}
device unknown
path \Windows\system32\winload.exe
description Windows Server 2012 R2
locale en-US
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
recoverysequence {92a10963-be7e-11e3-8f5b-f7f89b276248}
recoveryenabled Yes
allowedinmemorysettings 0x15000075
osdevice unknown
systemroot \Windows
resumeobject {92a10961-be7e-11e3-8f5b-f7f89b276248}
nx OptOut
hypervisorlaunchtype Auto
ems Yes

Windows Boot Loader
identifier {92a10969-be7e-11e3-8f5b-f7f89b276248}
device unknown
path \Windows\system32\winload.exe
description Windows Server 2012 R2 – secondary plex
locale en-US
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
recoverysequence {92a10963-be7e-11e3-8f5b-f7f89b276248}
recoveryenabled Yes
allowedinmemorysettings 0x15000075
osdevice unknown
systemroot \Windows
resumeobject {92a10961-be7e-11e3-8f5b-f7f89b276248}
nx OptOut
ems Yes

Windows Boot Loader
identifier {92a1096e-be7e-11e3-8f5b-f7f89b276248}
device partition=C:
path \Windows\system32\winload.exe
description Windows Server 2012 R2 – secondary plex
locale en-US
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
recoverysequence {92a10963-be7e-11e3-8f5b-f7f89b276248}
recoveryenabled Yes
allowedinmemorysettings 0x15000075
osdevice partition=C:
systemroot \Windows
resumeobject {92a10961-be7e-11e3-8f5b-f7f89b276248}
nx OptOut
hypervisorlaunchtype Auto
ems Yes

Notice the entries showing  device unknown. These are entries that belong to disks that are no longer physically present in this server, and need to be deleted.  The following script does just that:


The script can be downloaded from the Microsoft Script Center Repository.

After running the script, reboot the server. Going back into Computer Management, you now can remove the mirror off the missing disk.