Prepare a VHDX image of Nano Server

Microsoft has recently announced a new version of Windows Server 2016 called Nano Server. The main advantage of this Windows Server version is the small footprint. For that, Microsoft has removed the Graphical User Interface stack, 32-bit support, local logins or Remote Desktop support. Nano Server can be managed only remotely by using PowerShell, WMI or WinRM. Nano Server has been designed for two kinds of usage:

  • Cloud infrastructure components as Hyper-V or Scale-Out File Server ;
  • Cloud apps built on runtime as Java, .Net and so on. Nano Server supports container through Hyper-V (and maybe via Docker later).

The Windows Server 2016 Technical Preview 2 has been released this week and brings the Nano Server through a WIM file. This kind of file is great to deploy by using DHCP/WDS but I wanted to build a VHDX image to deploy Virtual Machines without using PXE. This Microsoft guide describes how to build the VHDX file from the WIM included in the Windows Server Technical Preview 2 ISO.


First, we have to prepare our environment to do the job. So download the Windows Server TC2 ISO here. While the ISO is downloading, I create some folders by using this script (don’t forget to change the $ParentFolder variable):

$ParentFolder = "c:\temp\NanoPrep"
New-Item -ItemType Directory -Path $($ParentFolder + "\Dism")
New-Item -ItemType Directory -Path $($ParentFolder + "\VHDX")
New-Item -ItemType Directory -Path $($ParentFolder + "\Packages")
New-Item -ItemType Directory -Path $($ParentFolder + "\MountDir")
New-Item -ItemType Directory -Path $($ParentFolder + "\WIM")


My Work Folder looks like this:

Next I have downloaded the Convert-WindowsImage.ps1 script from this URL. I’ve downloaded this script in the $ParentFolder directory. Once your Windows Server TC2 ISO is downloaded, you can mount it and run the below script. This script will copy the WIM file and the package locally. Next, all files related to Dism are copied in the Dism folder. To finish it will make a VHDX image from the WIM file.

$ParentFolder = "c:\temp\NanoPrep"
$ISOPath = "C:\Temp\10074.0.150424-1350.fbl_impressive_SERVER_OEMRET_X64FRE_EN-US.ISO"
Mount-DiskImage $ISOPath
$DriveLetter = (Get-DiskImage $ISOPath | Get-Volume).DriveLetter
$ISONanoPath = $DriveLetter + ":\NanoServer"
$ISOSourcePath = $DriveLetter + ":\Sources"
Copy-Item -Path $($ISONanoPath + "\NanoServer.wim") -Destination $($ParentFolder + "\WIM")
Copy-Item -Path $($ISONanoPath + "\Packages\*") -Destination $($ParentFolder + "\Packages") -Recurse
Copy-Item -Path $($ISOSourcePath + "\api*downlevel*.dll") -Destination $($ParentFolder + "\Dism")
Copy-Item -Path $($ISOSourcePath + "\*dism*") -Destination $($ParentFolder + "\Dism")
Copy-Item -Path $($ISOSourcePath + "\*provider*") -Destination $($ParentFolder + "\Dism")
Dismount-DiskImage $ISOPath
Set-Location $ParentFolder
Convert-WindowsImage.ps1 -SourcePath $($ParentFolder + "\WIM\NanoServer.wim") `
                         -VHD $($ParentFolder + "\VHDX\NanoServer.vhdx") `
                         -VHDFormat VHDX `
                         -Edition 1 `
                         -VHDPartitionStyle GPT

Add packages to the VHDX image

Previously, we have copied some packages in our work folder. Below you have the description of each package.

Role or feature Package file
Hyper-V role Microsoft-NanoServer-Compute-Package.cab
Failover Clustering Microsoft-NanoServer-FailoverCluster-Package.cab
Drivers for hosting Nano Server as a virtual machine Microsoft-NanoServer-Guest-Package.cab
Basic drivers for a variety of network adapters and storage controllers Microsoft-NanoServer-OEM-Drivers-Package.cab
File Server role and other storage components Microsoft-NanoServer-Storage-Package.cab

Now it’s time to add this package to the NanoServer.vhdx image. For that the command dism will be used. The below script mount the image, add the packages and dismount the vhdx and commit the modification.

$ParentFolder = "c:\temp\NanoPrep"
Set-Location $ParentFolder
dism\dism /Mount-Image /ImageFile:$($ParentFolder + "\VHDX\NanoServer.vhdx") /index:1 /MountDir:$($ParentFolder + "\MountDir")
dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\Microsoft-NanoServer-Compute-Package.cab") /Image:$($ParentFolder + "\MountDir")
dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\en-us\Microsoft-NanoServer-Compute-Package.cab") /Image:$($ParentFolder + "\MountDir")

dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\Microsoft-NanoServer-OEM-Drivers-Package.cab") /Image:$($ParentFolder + "\MountDir")
dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\en-us\Microsoft-NanoServer-OEM-Drivers-Package.cab") /Image:$($ParentFolder + "\MountDir")

dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\Microsoft-NanoServer-FailoverCluster-Package.cab") /Image:$($ParentFolder + "\MountDir")
dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\en-us\Microsoft-NanoServer-FailoverCluster-Package.cab") /Image:$($ParentFolder + "\MountDir")

dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\Microsoft-NanoServer-Guest-Package.cab") /Image:$($ParentFolder + "\MountDir")
dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\en-us\Microsoft-NanoServer-Guest-Package.cab") /Image:$($ParentFolder + "\MountDir")

dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\Microsoft-NanoServer-Storage-Package.cab") /Image:$($ParentFolder + "\MountDir")
dism\dism /add-Package /PackagePath:$($ParentFolder + "\packages\en-us\Microsoft-NanoServer-Storage-Package.cab") /Image:$($ParentFolder + "\MountDir")

dism\dism /Unmount-Image /Mountdir:$($ParentFolder + "\MountDir") /commit

Configure Nano Server with a response file

It is possible to use a unattend.xml file to auto configure some settings in the server as the hostname, the time zone and so on. First, I prepare the machine to join my Active Directory Domain. So I run the below script:

$ParentFolder = "c:\temp\NanoPrep"
djoin.exe /provision /domain home.net /machine NanoServer01 /savefile $($ParentFolder + "\odjblob")

When this script is finished, a new computer account is created in Active Directory. I can move the object to apply a GPO and so manage Firewall for example J

Next I open the odjblob file and I copy the content. It looks like this:


Then I prepare my unattend.xml file and I copy it in my $ParentFolder (don’t forget to copy the content of the odjblob file):

<?xml version='1.0' encoding='utf-8'?>
<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <settings pass="offlineServicing">
        <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">

    <settings pass="oobeSystem">
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
            <TimeZone>Romance Standard Time</TimeZone>

    <settings pass="specialize">
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
            <RegisteredOwner>Romain Serre</RegisteredOwner>

To finish I integrate this unattend.xml file into my NanoServer.vhdx image by using this script:

$ParentFolder = "c:\temp\NanoPrep"
Set-Location $ParentFolder
dism\dism /Mount-Image /ImageFile:$($ParentFolder + "\VHDX\NanoServer.vhdx") /index:1 /MountDir:$($ParentFolder + "\MountDir")
dism\dism /image: $($ParentFolder + "\MountDir") /Apply-Unattend:$($ParentFolder + "\unattend.xml")
New-Item -Type Directory -Path $($ParentFolder + "\MountDir\windows\panther")
copy $($ParentFolder + "\unattend.xml") $($ParentFolder + "\MountDir\windows\panther")
dism\dism /Unmount-Image /Mountdir:$($ParentFolder + "\MountDir") /commit

Run commands on the first boot

It is possible to run some commands on the first boot of the Nano Server. It is very simple: just past all commands that you need in a SetupComplete.cmd file and next just copy it to the C:\Windows\Setup\Scripts folder of the image. Below you can find my SetupComplete.cmd:

netsh advfirewall set all state off
netsh interface ip set address "Ethernet" static
netsh interface ipv4 add dnsserver "Ethernet" address= index=1

This script disables the firewall (it’s for a lab J) and set the IP configuration on an Ethernet network interface. To finish the ipconfig is run to show me the good configuration of the Ethernet interface. Next I paste this file in $ParentFolder directory. To finish I run this script:

$ParentFolder = "c:\temp\NanoPrep"
Set-Location $ParentFolder
dism\dism /Mount-Image /ImageFile:$($ParentFolder + "\VHDX\NanoServer.vhdx") /index:1 /MountDir:$($ParentFolder + "\MountDir")
New-Item -Type Directory -Path $($ParentFolder + "\MountDir\windows\Setup\Scripts")
Copy-Item $($ParentFolder + "\SetupComplete.cmd") $($ParentFolder + "\MountDir\windows\Setup\Scripts")
dism\dism /Unmount-Image /Mountdir:$($ParentFolder + "\MountDir") /commit

Add drivers to the image

If your hardware is not recognized and you need specific drivers, you can use the below script to add drivers to the NanoServer.vhdx. Just set the $MyDriversPath variable by the path where are located your drivers.

dism\dism /Mount-Image /ImageFile:$($ParentFolder + "\VHDX\NanoServer.vhdx") /index:1 /MountDir:$($ParentFolder + "\MountDir")
dism\dism /Add-Driver /image:$($ParentFolder + "\MountDir") /driver: $MyDriversPath
dism\dism /Unmount-Image /Mountdir:$($ParentFolder + "\MountDir") /commit

Deploy NanoServer Virtual Machine

So I have created a Virtual Machine in Hyper-V and I have selected the NanoServer.vhdx disk.

Once the machine is deployed, just specify enter-pssesion –ComputerName NanoServer01

As you can see above, we are connected to the NanoServer remotely. You can also connect to the server by using Windows Explorer:

And you can use MMC as Event Viewer remotely:

Now that we have access to the server remotely, we can create cluster, configure Hyper-V and so on. But don’t expect to manage the server as before. There is no console installed locally and there is no local logins supportJ.

To finish, let’s talk about the footprint. As you can see below, the footprint of the Nano Server is really small. The VHDX file size is only 988 MB!

About Romain Serre

Romain Serre works in Lyon as a Senior Consultant. He is focused on Microsoft Technology, especially on Hyper-V, System Center, Storage, networking and Cloud OS technology as Microsoft Azure or Azure Stack. He is a MVP and he is certified Microsoft Certified Solution Expert (MCSE Server Infrastructure & Private Cloud), on Hyper-V and on Microsoft Azure (Implementing a Microsoft Azure Solution).

Leave a Reply


Check Also

Windows Server 2016 servicing model

Recently Microsoft announced that the official launch for Windows Server 2016 should be at the ...

Enable Data Deduplication on VMM Library

Data Deduplication is a storage method that eliminates redundant data to free storage space. The ...

Understand Microsoft licensing for Virtual Environments by Altaro

Altaro Software has released a new eBook to understand the Microsoft licensing for Virtual Environments. ...