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.

Preparation

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:

ARAIAMzMzMwwAwAAAAAAAAAAAgABAAAAAQAAAAQAAgABAAAAAQAAAAgDAAAIAAIACAMAAAEQC ADMzMzM+AIAAAAAAADwZEKYcKZCmDCeQpigHUKYCAAKAGB6QpgQABIAcKtCmBAAEgCwp0KYPSW gj2mer06GzNIgAe4zfbClQpjA/kGYcKNCmAEAAAA9JaCPaZ6vTobM0iAB7jN9MKJCmLCdQpj88QDgsJ5Cm LCrQpgAAAAACQAAAAAAAAAJAAAAaABvAG0AZQAuAG4AZQB0AAAAAAANAAAAAAAAAA0AAABOAGE AbgBvAFMAZQByAHYAZQByADAAMQAAAAAAeQAAAAAAAAB5AAAAUwBfADUALgBdACAAZwAnAEYAL QB0AFQAOgAsADcAKgAlAEYANAAnADUAJwBPADgAdgBZACYAWAAqADoAJQAuAC4APAB3AEQAaABs AF4APwBEAGEAJQBIAHMAbgB5AEcAIQBVAEUATQBxACcATgByACEAMABbADsAUgA6AD8ARAAuAF8 AVwA5ACgAOABGADIAYAAkADYAdQA+AHIAdwAoACEAdQBeAEQANABuAFAAdwBaACEATQA6AE0AVg BOAGQAUwBkACcAYQBeACAAOABfAGYAIABhADIAeQA3AEcATQA0AFgAVgBFAFwAQwBrAHoAAAAAA AUAAAAAAAAABAAAAEgATwBNAEUACQAAAAAAAAAIAAAAaABvAG0AZQAuAG4AZQB0AAkAAAAAAAA ACAAAAGgAbwBtAGUALgBuAGUAdAAEAAAAAQQAAAAAAAUVAAAAV4rrGerLNjixfdBQEwAAAAAAAAAT AAAAXABcAFYATQBBAEQAUwAwADIALgBoAG8AbQBlAC4AbgBlAHQAAAAAAAwAAAAAAAAADAAAAFw AXAAxADAALgAxADAALgAwAC4ANAAAAAkAAAAAAAAACQAAAGgAbwBtAGUALgBuAGUAdAAAAAAAC QAAAAAAAAAJAAAAaABvAG0AZQAuAG4AZQB0AAAAAAAJAAAAAAAAAAkAAABUAG8AdQBsAG8AdQB zAGUAAAAAAAkAAAAAAAAACQAAAFQAbwB1AGwAbwB1AHMAZQAAAAAAAAAAAA==

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="https://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
    <settings pass="offlineServicing">
        <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
            <OfflineIdentification>
                <Provisioning>
                    <AccountData>ARAIAMzMzMwwAwAAAAAAAAAAAgABAAAAAQAAAAQAAgABAAAAAQAAAAgDAAAIAAIACAMAAAEQCADMzMzM+AIAAAAAAADwZEKYcKZCmDCeQpigHUKYCAAKAGB6QpgQABIAcKtCmBAAEgCwp0KYPSWgj2mer06GzNIgAe4zfbClQpjA/kGYcKNCmAEAAAA9JaCPaZ6vTobM0iAB7jN9MKJCmLCdQpj88QDgsJ5CmLCrQpgAAAAACQAAAAAAAAAJAAAAaABvAG0AZQAuAG4AZQB0AAAAAAANAAAAAAAAAA0AAABOAGEAbgBvAFMAZQByAHYAZQByADAAMQAAAAAAeQAAAAAAAAB5AAAAUwBfADUALgBdACAAZwAnAEYALQB0AFQAOgAsADcAKgAlAEYANAAnADUAJwBPADgAdgBZACYAWAAqADoAJQAuAC4APAB3AEQAaABsAF4APwBEAGEAJQBIAHMAbgB5AEcAIQBVAEUATQBxACcATgByACEAMABbADsAUgA6AD8ARAAuAF8AVwA5ACgAOABGADIAYAAkADYAdQA+AHIAdwAoACEAdQBeAEQANABuAFAAdwBaACEATQA6AE0AVgBOAGQAUwBkACcAYQBeACAAOABfAGYAIABhADIAeQA3AEcATQA0AFgAVgBFAFwAQwBrAHoAAAAAAAUAAAAAAAAABAAAAEgATwBNAEUACQAAAAAAAAAIAAAAaABvAG0AZQAuAG4AZQB0AAkAAAAAAAAACAAAAGgAbwBtAGUALgBuAGUAdAAEAAAAAQQAAAAAAAUVAAAAV4rrGerLNjixfdBQEwAAAAAAAAATAAAAXABcAFYATQBBAEQAUwAwADIALgBoAG8AbQBlAC4AbgBlAHQAAAAAAAwAAAAAAAAADAAAAFwAXAAxADAALgAxADAALgAwAC4ANAAAAAkAAAAAAAAACQAAAGgAbwBtAGUALgBuAGUAdAAAAAAACQAAAAAAAAAJAAAAaABvAG0AZQAuAG4AZQB0AAAAAAAJAAAAAAAAAAkAAABUAG8AdQBsAG8AdQBzAGUAAAAAAAkAAAAAAAAACQAAAFQAbwB1AGwAbwB1AHMAZQAAAAAAAAAAAA==</AccountData>
                </Provisioning>
            </OfflineIdentification>
        </component>
    </settings>

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

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

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 10.10.0.200 255.255.255.0 10.10.0.1
netsh interface ipv4 add dnsserver "Ethernet" address=10.10.0.5 index=1
ipconfig

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

x

Check Also

Deploy a Windows Server 2019 RDS farm with HTML5 client

These days I’m trying in depth Windows Server 2019. Today I chose to pay attention ...

Create a custom SUU to update Dell firmware

Dell provides a smart utility to update firmware and drivers in their servers. This utility ...

Next gen Microsoft management tool: Honolulu

Since the beginning of the year, Microsoft is working on a new management tool based ...