PowerShell Script to build your Nano Server Image
This script is now retired! It has been replaced with the NanoServerImageGenerator.psm1 module on the latest Windows Server Technical Preview media. See Getting Started with Nano Server for instructions.
Update
We’ve modified the script to ask for a SecureString as a means of accepting a password, as opposed to plain-text input. Instead of specifying a password string in the parameter list, the script will now prompt for a password securely. This follows more closely the security guidelines for PowerShell scripts and secure handling of credentials. Having said that, it is important to keep in mind that the mechanism via which the Administrator account’s password is set is still an Unattend.xml file. This means that the password for the Administrator account is stored in it, in plain-text, in the %WINDIR%\Panther directory after the script is finished. The password will remain there, in plain-text, until the first boot, when Nano Server will process the Unattend.xml file and delete the password from it.
Nano Server Image Manipulation
For our next installment in this series, we’re happy to announce a script that automates the customization of Nano Server images. This new PowerShell script allows you to convert a Nano Sever WIM image into a VHD disk, add packages to it, drivers and set configuration options. In this post, we’ll explore the script and what you can do with it.
Getting Started
First and foremost, the script is available for download as an attachment to this blog post. You will also need a companion script, which is available here (TechNet). Place these two scripts in the same directory and fire up PowerShell as administrator. Next, change directory into the folder where you’ve placed the scripts and dot-source the NanoServer.ps1 script:
. .\NanoServer.ps1
This will instruct PowerShell to read the contents of NanoServer.ps1 and allow access to its functionality within the current session. You’re now all set! The script ships with its own help, which you may access at any time (you may omit the window, of course):
Get-Help New-NanoServerImage -ShowWindow
First Steps
Let’s begin with a simple example. Suppose you have your Nano Server installation media on a network share and would like to create an image with a given computer name, the Hyper-V guest drivers as well as have Nano Server print its IP configuration to the screen on every boot. Here is how you can achieve that using the script:
. .\Nano.ps1
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\FirstSteps
-ComputerName FirstStepsNano
-GuestDrivers
-EnableIPDisplayOnBoot
The script will proceed as follows:
Prompt for the Administrator password
Copy the installation media from \\Path\To\Media\en_us into .\Base
Convert the WIM image into a VHD
Copy that VHD into .\FirstSteps
Set that image’s administrator password as specified
Set that image’s computer name to FirstStepsNano
Install the Hyper-V guest drivers
Make that image display the output of ipconfig on every boot.
The resulting image will be .\FirstSteps\FirstSteps.vhd. In addition, the script generates a log every time it runs; the script will let you know where it has placed it when it finishes. Similarly, since the WIM to VHD conversion is performed by the companion script, its own log can be found in %TEMP%\Convert-WindowsImage\<GUID> (where GUID is a unique identifier per conversion session). Lastly, when you run the script, assuming you always use the same base path, the conversion from WIM to VHD will occur only once. Further invocations of the script make copies of that VHD, so you can create as many custom images as necessary without having to wait for the conversion each time (unless the source WIM changes). Also, if your media does not change from invocation to invocation, you may omit the media path; the script will automatically make use of the files already present in the base path.
Including Workloads
Nano Server ships with several packages that enable additional functionality, such as acting as a Hyper-V host or as a storage server. With the new PowerShell script, these packages are easy to install. For instance, let’s inject the Hyper-V guest drivers and the storage package into a Nano Server image:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\IncludingWorkloads
-GuestDrivers
-Storage
In this case, the script will include the two specified packages as well as their corresponding language packages. These ship in the installation media in a subfolder whose name corresponds to the locale of the image, such as en_us, tr_tr, etc. By default, the script will attempt to install the language packages corresponding to the locale of the administrator account. So if your locale is fr_fr but are operating on a Swedish image, sv_se, the script will exit reporting that the French France packages are not there. To tell the script to use a different language, all you need to do is:
New-NanoServerImage
<...>
-Language sv_se
Package Support
Here is a list of the switches and the corresponding workload packages:
-Storage |
File Server role and other storage components |
-Compute |
Hyper-V Role |
-Clustering |
Failover Clustering |
-OEMDrivers |
Variety of network and storage controller drivers. |
-GuestDrivers |
Drivers for running Nano Server as a Hyper-V virtual machine. |
-ReverseForwarders |
Reverse forwarders allow you to run some software on Nano Server that is not explicitly made for Nano Server. |
Extra Packages
If you happen to have additional packages that you would like to include in your Nano Server image, you may use the following syntax:
New-NanoServerImage
<...>
-ExtraPackages .\Extras\Pack1.cab, .\Extras\Pack2.cab, .\Extras\ru_ru\LangPack1.cab
In the case of extra packages, the script will not attempt to install corresponding language packages. Thus, if you have language packages, remember to include them explicitly in the list, too. Also, make sure that the extra language packages that you install are the same language as the workload packages; the script won’t check.
Joining Domains
The script provides two ways of joining a domain. Both of them rely on offline domain provisioning, but the difference lies in the collection of the domain join blob. Let’s try an example where you’d like to join a Nano Server machine to a domain and see what happens:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\JoiningDomainsHarvest
-ComputerName JoiningDomainsHarvest
-DomainName Contoso
For this command, the script will proceed as follows with regards to domain provisioning:
Harvest the domain join blob for the Contoso domain from the local machine (the local machine must be joined to the Contoso domain)
Perform an offline provisioning of the image using that blob.
At the end of this operation, you will see that a computer named JoiningDomainsHarvest has appeared in your Active Directory computer list.
If you want to run the script on a computer that is not joined to the Contoso domain, you may harvest the blob on a machine that is, and tell the script to use that blob instead:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\JoiningDomainsNoHarvest
-DomainBlobPath .\Path\To\Domain\Blob\JoiningDomainsNoHarvestContoso.djoin
To harvest a domain provisioning blob, you may use the following command:
djoin
/Provision
/Domain Contoso
/Machine JoiningDomainsNoHarvest
/SaveFile JoiningDomainsNoHarvest.djoin
Bear in mind that if you harvest a provisioning blob from another machine, you will have already included the computer name in it. Hence, if you try to add the computer name parameter to the script, it will report the error and exit.
Reusing Nodes
In the case that you already have a node with the same computer name as your future Nano Server image and don’t want to have to delete the name from Active Directory, you may have the script reuse it:
New-NanoServerImage
<...>
-ReuseDomainNode
Injecting Drivers
Since Nano Server has no local facility to install drivers, it would be horrible if your exotic network adapter wasn’t supported. In order to include drivers of your choosing into a Nano Server image, you may use the following syntax:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\InjectingDrivers
-DriversPath .\Extra\Drivers
The script will scout the directory for available drivers, recursively if necessary, and inject them into your image. In the folder where you keep your drivers, you will need the SYS files for the drivers as well as the corresponding INF files. You can have a look at an existing Windows installation under %WINDIR%\System32\DriverStore\FileRepository for inspiration. Note that Nano Server only supports 64-bit drivers, and they must be signed.
Connecting over WinRM
If you need to connect to your Nano Server computer over WinRM from a machine that is not in the same subnet, you will need to explicitly open port 5985 for inbound TCP traffic on the Nano Server image. The script helps you with that:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\ConnectingOverWinRM
-EnableRemoteManagementPort
Bring your own VHD
In the case that you already have a VHD image that you would like to customize, you may have the script use it with the following syntax:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\BYOVHD
-ExistingVHDPath .\MyImage.vhd
With this command, the script will behave the same way, but instead of converting the original WIM to a VHD, or using the VHD that it may have already converted in a previous invocation, it will use the VHD image that you specify.
Emergency Management Services
To enable EMS on a Nano Server image, all you need is:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\EnablingEMS
-EnableEMS
-EMSPort 3
-EMSBaudRate 9600
This command will enable EMS on serial port 3 with a baud rate of 9600 bps. The port and baud rate parameters are optional, so if you don’t include them, they will be port 1 and 115200 bps respectively.
Kernel Debugging
In the hopes that you will never have to debug a live kernel, this section goes last. If you ever find yourself needing to do so, however, the script allows you to configure that option, too. There are four ways to debug a live kernel remotely: via serial port, over the network, 1394 (FireWire) and USB. If you need more information, please refer to this page. Let’s now have a look at each option.
Debugging over Serial Port
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\KernelDebuggingSerial
-DebugMethod Serial
-DebugCOMPort 1
-DebugBaudRate 9600
As you’d expect, this command will enable serial debugging over port 2 with a baud rate of 9600 bps. As with EMS, the port and baud rate parameters are optional, and they are port 2 and 115200 bps by default. Bear in mind that if you enable both EMS and Kernel Debugging on the same image, you will need two different serial ports.
Debugging over the Network
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\KernelDebuggingNetwork
-DebugMethod Net
-DebugRemoteIP 192.168.1.100
-DebugPort 64000
This command will enable kernel debugging over the network and the only computer that can connect has 192.168.1.100 as its IP address. In addition, all communications will take place over port 64000. Both the IP and port parameters are mandatory, and the port number must be 49152 or higher. Moreover, since kernel debugging over the network is susceptible to interception, communication must be encrypted. When configuring kernel debugging on an image, the script automatically generates a key that you will need in order to connect. The script will place that key in a file next to the resulting VHD, and it will tell you about it when it finishes.
If you want to use your own key, you can use the -DebugKey parameter, as follows:
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\KernelDebuggingNetwork
-DebugMethod Net
-DebugRemoteIP 192.168.1.100
-DebugPort 64000
-DebugKey 1.2.3.4
Debugging over 1394 (FireWire)
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\KernelDebuggingFireWire
-DebugMethod 1394
-DebugChannel 3
This command will enable 1394 (FireWire) debugging and you will have to connect the remote debugger on channel 3. The channel parameter is mandatory.
Debugging over USB
New-NanoServerImage
-MediaPath \\Path\To\Media\en_us
-BasePath .\Base
-TargetPath .\KernelDebuggingUSB
-DebugMethod USB
-DebugTargetName KernelDebuggingUSBNano
This command will enable debugging over USB. When you attempt to connect the remote debugger to the computer running the resulting image, you will need to specify the target name as it appears in the command.
Conclusion
This time around, we’ve introduced a PowerShell script that allows you to easily convert and customize Nano Server images. This script offers a variety of options, such as adding workload and extra packages, joining a domain, injecting drivers, opening a port for WinRM connections, customizing your own VHD, enabling EMS and enabling and configuring kernel debugging. All of these options can be mixed and matched to create the required configuration. The resulting VHD may be used without further effort.
We hope that you will find this tool useful and look forward to your feedback!
Hernan Gatta
Microsoft Intern
Comments
- Anonymous
June 15, 2015
Great script. But please release the script on GitHub. - Anonymous
June 16, 2015
I'm curious why you are using the VHD format and not the newer VHDX. All my Hyper-V images now use this format. Or is there something specific to the VHD format with your script? - Anonymous
June 16, 2015
You should also point out that you must run this script on Windows 10 (or Server 2016) because it requires the newer version of DISM. Even better would be to add that requirement to the script. - Anonymous
June 16, 2015
Hi Jeff,
There's nothing preventing us from adding that option. For a first iteration, VHD seemed like the safest choice, given that VHDX images require Generation 2 VM's in Hyper-V. It's also possible to convert VHD images into VHDX ones using the Hyper-V VM Manager. Having said that, I'll have a look and see if we can add that.
For DISM, you make a good point; that's why the script uses the version of DISM that ships on the Nano Server installation media, not the one on your machine. That way, the script can also run on Windows 8.1. Are you having trouble with it though?
Thanks! - Anonymous
June 16, 2015
I would love for this to work from Windows 8.1. I was starting with the nano wim and packages already copied. But clearly I should try copying from source. And yes, having options for VHDX and a Gen2 VM would be ideal, but they should be separate parameters because I may want a GEN1 vm but a VHDX file. If you continue to develop this, I'd suggest turning it into a module. - Anonymous
June 16, 2015
Now that I am running the complete command including copying files from media, I have a better understanding of what is going on. And to clarify something, Gen2 VMs may require a VHDX format, but a Gen1 machine can also use a VHDX file which is why those should be two different parameters. - Anonymous
June 16, 2015
Guess I spoke too soon. Closer, but can't this to complete on Windows 8.1 running PowerShell 4.0.
$paramHash = @{
MediaPath = 'I:'
BasePath = 'C:NanoBase'
TargetPath = 'C:NanoImages'
AdministratorPassword = 'P@ssw0rd'
ComputerName = 'NANO-02'
EnableIPDisplayOnBoot = $True
Storage = $True
GuestDrivers = $True
}
New-NanoServerImage @paramHash
This is the log:
06/16/2015 14:27:21 & 'C:NanoBaseToolsdism' /Mount-Image /ImageFile:'C:NanoImagesNanoImages.vhd' /MountDir:'C:NanoImagesMount' -Index:1 /LogLevel:2 /LogPath:'C:UsersJeffAppDataLocalTempNew-NanoServerImage (DISM).log'
06/16/2015 14:27:25 & 'C:NanoBaseToolsdism' /Add-Package /PackagePath:'C:NanoBasePackagesMicrosoft-NanoServer-Storage-Package.cab' /Image:'C:NanoImagesMount' /LogLevel:2 /LogPath:'C:UsersJeffAppDataLocalTempNew-NanoServerImage (DISM).log'
06/16/2015 14:27:35 & 'C:NanoBaseToolsdism' /Add-Package /PackagePath:'C:NanoBasePackagesMicrosoft-NanoServer-Guest-Package.cab' /Image:'C:NanoImagesMount' /LogLevel:2 /LogPath:'C:UsersJeffAppDataLocalTempNew-NanoServerImage (DISM).log'
06/16/2015 14:27:39 & 'C:NanoBaseToolsdism' /Add-Package /PackagePath:'C:NanoBasePackagesen-usMicrosoft-NanoServer-Storage-Package.cab' /Image:'C:NanoImagesMount' /LogLevel:2 /LogPath:'C:UsersJeffAppDataLocalTempNew-NanoServerImage (DISM).log'
06/16/2015 14:27:44 & 'C:NanoBaseToolsdism' /Add-Package /PackagePath:'C:NanoBasePackagesen-usMicrosoft-NanoServer-Guest-Package.cab' /Image:'C:NanoImagesMount' /LogLevel:2 /LogPath:'C:UsersJeffAppDataLocalTempNew-NanoServerImage (DISM).log'
06/16/2015 14:27:48 Exception calling "GetFullPath" with "1" argument(s): "The given path's format is not supported."
06/16/2015 14:27:48 Terminating due to an error. See log file at:
C:UsersJeffAppDataLocalTempNew-NanoServerImage.log
06/16/2015 14:27:48 & 'C:NanoBaseToolsdism' /Unmount-Image /MountDir:'C:NanoImagesMount' /Discard /LogLevel:2 /LogPath:'C:UsersJeffAppDataLocalTempNew-NanoServerImage (DISM).log'
The target path gets deleted at the very end of the process, or something is deleting it and that causes the error. I can't tell which. - Anonymous
June 16, 2015
Hi Jeff,
Thank you for your comment. That is indeed a bug where one call inside the script is assuming a relative path for TargetPath. If you try something like TargetPath = .Target1, it should work.
I'll get on it.
Thanks again!
Hernan. - Anonymous
June 16, 2015
@Jeff: It's been fixed and a new copy uploaded. Give it a shot! - Anonymous
June 16, 2015
That did the trick. Eventually I hope we can configure things like IP address settings via an unattend.xml. I have not had much luck getting that to work yet.
And for anyone interested, here is a script to create the Nano server image, create the Hyper-V VM and start it.
cd c:scripts
. .NanoServer.ps1
cls
$pass = ConvertTo-SecureString -String 'P@ssw0rd' -AsPlainText -Force
$paramHash = @{
MediaPath = 'I:'
BasePath = 'F:NanoBase'
TargetPath = 'F:NanoImages'
AdministratorPassword = $pass
ComputerName = 'NANO-02'
EnableIPDisplayOnBoot = $True
Storage = $True
GuestDrivers = $True
EnableRemoteManagementPort = $True
}
New-NanoServerImage @paramHash
$original = Join-Path -Path $paramHash.TargetPath -ChildPath "$(Split-path $paramhash.TargetPath -leaf).vhd"
$destination = (Join-path -path D:VHD -child "$($paramHash.ComputerName).vhd")
Copy -Path $original -Destination $destination
$newVMHash = @{
Name = $paramHash.computername
Generation = 1
MemoryStartupBytes = 256MB
SwitchName = "Work Network"
VHDPath = $Destination
}
New-VM @NewVMHash | Set-VM -DynamicMemory -MemoryMaximumBytes 512MB -Notes "Test Nano Server"
Start-VM Nano-02 - Anonymous
June 17, 2015
that was great article ...i have few doubts regarding it ...i have followed all the steps.but when i booted the vhd..it shows windos logon and loading ,shows ip address also .but ,it stays till and becomes blank screen.does we can manage it through gui or remote desktop ...some tip we will be useful .thanx in advance. - Anonymous
June 17, 2015
Jeet, there is no interactive console. You will have to use PowerShell remoting or other remote management tools from your desktop. This is explained in the Technet documentation. You could also ask for help in the Nano forum.http://blogs.technet.com/b/nanoserver/archive/2015/05/18/nano-server-forum.aspx - Anonymous
June 17, 2015
Hi Jeet:
Have a look at this article:
https://msdn.microsoft.com/en-us/library/mt126167.aspx
While most of the steps in the guide are encapsulated in the script, the guide also explains how to manage Nano Server remotely.
Thanks and thank you Jeff for answering. - Anonymous
June 18, 2015
The comment has been removed - Anonymous
June 18, 2015
Hi Emin,
Thank you very much for pointing that out. It's been fixed. - Anonymous
June 30, 2015
This looks great! Pleaseo make a module out of it though and put it on the gallery :) I've also found the convert-image script a bit unreliable, sometimes I works and some times not, it would be great to see it get some official Microsoft quality stamp :) - Anonymous
August 10, 2015
Nano Server represents a great opportunity for applications to get the most of available resources and - Anonymous
August 11, 2015
Hi,
wouldn't it make sense to give the user the Chance to select between MBR and GPT Partition style; this would enable UEFI Installation (currently the scritp contains fix "-VHDPartitionStyle MBR" - Anonymous
October 12, 2015
Have you ever personally had to troubleshoot Nano Server but didn’t know where to start looking