Windows Server How-To

Windows Nano Server Deployment 101, Part 2: The Execution

Navigate the uncharted Nano Server deployment waters with this step-by-step guide.

Read "Windows Nano Server Deployment 101, Part 1: The Setup," here.

In the first part of this series, I explained that I had created a proof of concept, graphical installer for Nano Server. If you haven't yet read that post, I strongly recommend going back and checking it out before delving into this one, because that post discusses some critical path variables that must be set. It is also worth noting that although this script works, I have not tested every possible combination of inputs.

Getting Started
Before you will be able to use my graphical tool to deploy Nano Server, there is a bit of prep work that needs to be done. I may build this prep work into a future version of the tool if there is enough interest from the Windows Server community.

The first thing that you will need to do is to set three variables within the code. I discussed these variables in Part 1, and the code is provided at the end of this blog post.

The second thing that you will need to open an elevated PowerShell session and adjust the server's execution policy if necessary. For the sake of simplicity, I am using an execution policy of Unrestricted, as shown in Figure 1.

[Click on image for larger view.] Figure 1. Be sure to set the server's execution policy if necessary.

Now, insert the Windows Server 2016 installation media, and copy the contents of the Nano folder to a folder on your hard disk. Be sure to keep the installation media mounted, as it will be required throughout the Nano Server installation process. You will also need to copy my PowerShell script to the folder that you have created. I used a folder called C:\Nano to store the necessary files, as shown in Figure 2.

[Click on image for larger view.] Figure 2. Copy the contents of the Windows Server 2016 installation media's Nano folder to your hard disk.

You will now need to import the Nano Server Image Generator Module into PowerShell. Assuming that the required files reside in C:\Nano, you can do so by entering these commands:

C:
CD\
CD Nano
Import-Module C:\Nano\NanoServerImageGenerator.psm1 –Verbose

Notice that I included the full path to the module in the command. If you omit the path, then the command will fail, even if you are in the correct folder. You can see what this process looks like in Figure 3.

[Click on image for larger view.] Figure 3. Import the Nano Server Image Generator Module

Now it's time to run the graphical installer. To do so, just type ./PoseyNano.ps1. Of course this assumes that you have used the same filename that I did.

As you can see in Figure 4, the installer prompts you for the installation type (host or guest), Windows Server edition, computer name, The type of media that you want to create (WIM or VHD), the administrator password, and the maximum size of the VHD. As you look at the figure, you will also notice that a PowerShell window remains open in the background. This is going to be important later on.

[Click on image for larger view.] Figure 4. Populate the wizard with your desired values.

Click OK, and you will be prompted to choose which package you want to include with the Nano Server deployment, as shown in Figure 5. One of this script's limitations is that you can only choose a single package, although I might change that later. There are also a number of rules that are not currently represented. For example, the script cannot currently create a failover cluster node or a Hyper-V server. Such capabilities may be added in the next version.

[Click on image for larger view.] Figure 5. Select a package to include in the Nano Server.

Click the Create Nano Server button to generate a Nano Server. Upon doing so, the GUI will display a message saying that your Nano Server is being created. Although the GUI contains an Exit button, as shown in Figure 6, the button should not be clicked until the Nano Server has been created.

[Click on image for larger view.] Figure 6. PowerShell begins creating the Nano Server.

As previously mentioned, the GUI holds open a background PowerShell window. You can use this window to monitor the deployment process, as shown in Figure 7.

[Click on image for larger view.] Figure 7. You can watch the deployment process in the background.

When all is said and done, the Nano Server components will be created in the path specified within the script. You can see what this looks like in Figure 8.

[Click on image for larger view.] Figure 8. The Nano Server resources are created at the base path.

My hope is that you will find this script to be useful. If so, please let me know. If I get enough of a response, I plan to build a much more elaborate version of the tool.

So with that said, I think that I have made you wait long enough for the source code. Just copy the code below into Notepad, and save it as a PowerShell script named PoseyNano.ps1 (Don't forget that Notepad appends a hidden .TXT extension to files, and that extension will need to be removed in order for the file to be recognized as a PowerShell script.

#Load Assemblies
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
$net = New-Object -ComObject Wscript.Network

# Functions and Button Click Actions

# Display the Initial Screen
Function Acquire-NanoInfo
{

$Form.Controls.Add($Button1)
$Form.Controls.Add($Button2)
$Form.Controls.Add($Label1)
$Form.Controls.Add($Label3)
$GroupBox1.Controls.Add($RadioButton1)
$GroupBox1.Controls.Add($RadioButton2)
$Form.Controls.Add($GroupBox1)
$Form.Controls.Add($Label4)
$GroupBox2.Controls.Add($RadioButton3)
$GroupBox2.Controls.Add($RadioButton4)
$Form.Controls.Add($GroupBox2)
$Form.Controls.Add($Label5)
$Form.Controls.Add($TextBox1)
$Form.Controls.Add($Label6)
$GroupBox3.Controls.Add($RadioButton5)
$GroupBox3.Controls.Add($RadioButton6)
$Form.Controls.Add($GroupBox3)
$Form.Controls.Add($TextBox1)
$Form.Controls.Add($Label7)
$Form.Controls.Add($TextBox2)
$Form.Controls.Add($Label9)
$Form.Controls.Add($TextBox3)

}

#This function controls what happens when someone clicks the Back button
Function Return-MainScreen
{

$Form.Controls.Remove($Label2)
$Form.Controls.Remove($ListBox1)
$Form.Controls.Remove($Button3)
$Form.Controls.Remove($Button4)
$Form.Refresh()

Acquire-NanoInfo
}

 

#Define OK Button Click Function
Function Acquire-ServerPackage
{

<------------- Process Selections ---------------
If ($RadioButton1.Checked){$Global:Type='Host'}
If ($RadioButton2.Checked){$Global:Type='Guest'}
If ($RadioButton3.Checked){$Global:Edition='Standard'}
If ($RadioButton4.Checked){$Global:Edition='Datacenter'}
If ($RadioButton5.Checked){$Global:MediaType='WIM'}
If ($RadioButton6.Checked){$Global:MediaType='VHD'}
$Global:ComputerName=$TextBox1.text
$Global:MyPassword=$TextBox2.text
$Global:MaxSize=$TextBox3.text

 

#Clear the window
$Form.Controls.Remove($Button1)
$Form.Controls.Remove($Button2)
$Form.Controls.Remove($Label1)
$Form.Controls.Remove($Label3)
$Form.Controls.Remove($GroupBox1)
$Form.Controls.Remove($Label4)
$Form.Controls.Remove($GroupBox2)
$Form.Controls.Remove($Label5)
$Form.Controls.Remove($TextBox1)
$Form.Controls.Remove($Label6)
$Form.Controls.Remove($GroupBox3)
$Form.Controls.Remove($TextBox1)
$Form.Controls.Remove($Label7)
$Form.Controls.Remove($TextBox2)
$Form.Controls.Remove($Label9)
$Form.Controls.Remove($TextBox3)
#$Form.Refresh()

 

#Create Output
Add-Type -AssemblyName System.Windows.Forms

#Populate window
$Form.Controls.Add($Label2)
$Form.Controls.Add($ListBox1)
$Form.Controls.Add($Button3)
$Form.Controls.Add($Button4)
}

 

#Define Create Button Click Function
Function Create-NanoServer($SelectedPackage)
{

#Clear the window
$Form.Controls.Remove($Label2)
$Form.Controls.Remove($ListBox1)
$Form.Controls.Remove($Button3)
$Form.Controls.Remove($Button4)
$Form.Refresh()

#Create Output
Add-Type -AssemblyName System.Windows.Forms

#Create text

$Form.Controls.Add($Label8)
$Form.Controls.Add($Button5)

 

<----------Display Summary on the text screen----------------
cls
Write-Host 'Nano Server Type: ' $Type
Write-Host 'Windows Server Edition: ' $Edition
Write-Host 'Computer name assigned to Nano Server: ' $ComputerName
Write-Host 'Media Type: ' $MediaType
Write-Host 'Maximum Nano Server Size (in GB): ' $MaxSize
Write-Host 'Selected Package: ' $SelectedPackage

<-----------Convert Maximum Size to GB------------------------

$MaxSize = $MaxSize + 'GB'

<-----------Form Package String-----------------
If ($SelectedPackage -eq 'DNS Server'){$SelectedPackage = '-Packages Microsoft-NanoServer-DNS-Package'}
If ($SelectedPackage -eq 'Desired State Configuration (DSC)'){$SelectedPackage = '-Packages Microsoft-NanoServer-DSC-Package'}
If ($SelectedPackage -eq 'Internet Information Server (IIS)'){$SelectedPackage = '-Packages Microsoft-NanoServer-IIS-Package'}
If ($SelectedPackage -eq 'Network Performance Diagnostics Service (NPDS)'){$SelectedPackage = '-Packages Microsoft-NanoServer-SCVMM-Package'}
If ($SelectedPackage -eq 'Datacenter Bridging'){$SelectedPackage = '-Packages Microsoft-NanoServer-DCB-Package'}
If ($SelectedPackage -eq 'Secure Startup'){$SelectedPackage = '-Packages Microsoft-NanoServer-SecureStartup-Package'}
If ($SelectedPackage -eq 'Shielded VM'){$SelectedPackage = '-Packages Microsoft-NanoServer-ShieldedVM-Package'}
If ($SelectedPackage -eq 'None'){$SelectedPackage = ''}
If ($SelectedPackage -eq ''){$SelectedPackage = ''}

<----------Form Paths-----------------------------------------

$BasePath = 'C:\VMs\' + $ComputerName
$TargetPath = 'C:\VMs\' + $ComputerName + '\' + $ComputerName + '.' + $MediaType
Write-Host 'Your Nano Server will be created at: ' $TargetPath
$MediaPath = 'E:\'

<----------Form Command to Create Nano Server-----------------------

$MyNanoServer = 'New-NanoServerImage -MediaPath ' + $MediaPath + ' -DeploymentType ' + $Type + ' -Edition ' + $Edition + ' -BasePath ' + $BasePath + ' -TargetPath ' + $TargetPath + ' -MaxSize ' + $MaxSize + ' -ComputerName ' + $Computername + ' ' + $SelectedPackage + ' -AdministratorPassword (ConvertTo-SecureString ' + $MyPassword + ' -AsPlainText -Force)'

Invoke-Expression $MyNanoServer
}

<------ Define All GUI Objects-------

# Define Label - This label will be used to prompt the administrator to populate the form
$Label1 = New-Object System.Windows.Forms.label
$Label1.Location = new-object System.Drawing.Size(30,20)
$Label1.Font = New-Object System.Drawing.Font("Times New Roman",18,[System.Drawing.FontStyle]::Bold)
$Label1.AutoSize = $True
$Label1.ForeColor = "DarkBlue"
$Label1.Text = "Please enter the parameters to be used by your new Nano Server."

 

<--------Prompt for Installation Package--------------

# Define Label2 - This label will be used to prompt the admin to select the package that they want to install
$Label2 = New-Object System.Windows.Forms.Label
$Label2.AutoSize = $True
$Label2.Location = new-object System.Drawing.Size(20,50)
$Label2.Font = New-Object System.Drawing.Font("Times New Roman",18,[System.Drawing.FontStyle]::Bold)
$Label2.ForeColor = "DarkBlue"
$Label2.Text = "Please select the package that you wish to install."

 

<----------------Host or Guest Mode-----------------

# Define Label3 - Host or Guest
$Label3 = New-Object System.Windows.Forms.Label
$Label3.AutoSize = $True
$Label3.Location = new-object System.Drawing.Size(50,70)
$Label3.ForeColor = "DarkBlue"
$Label3.Text = "Will this Nano Server act as a host or a guest?"

 

$RadioButton1 = New-Object System.Windows.Forms.RadioButton
$RadioButton1.Location = '5,10'
$RadioButton1.AutoSize = $True
$RadioButton1.Checked = $false
$RadioButton1.Text = "Host"

$RadioButton2 = New-Object System.Windows.Forms.RadioButton
$RadioButton2.Location = '100,10'
$RadioButton2.AutoSize=$True
$RadioButton2.Checked = $True
$RadioButton2.Text = "Guest"

$GroupBox1 = New-Object System.Windows.Forms.GroupBox
$GroupBox1.Location = '300,60'
$GroupBox1.Size = '200,30'

 

<----------------Standard or Datacenter Edition-----------

# Define Label4 - Standard or Datacenter Edition
$Label4 = New-Object System.Windows.Forms.Label
$Label4.AutoSize = $True
$Label4.Location = new-object System.Drawing.Size(50,110)
$Label4.ForeColor = "DarkBlue"
$Label4.Text = "Will the Nano Server use Standard or Datacenter Edition?"

$RadioButton3 = New-Object System.Windows.Forms.RadioButton
$RadioButton3.Location = '5,10'
$RadioButton3.AutoSize = $True
$RadioButton3.Checked = $false
$RadioButton3.Text = "Standard"

$RadioButton4 = New-Object System.Windows.Forms.RadioButton
$RadioButton4.Location = '100,10'
$RadioButton4.AutoSize=$True
$RadioButton4.Checked = $True
$RadioButton4.Text = "Datacenter"

$GroupBox2 = New-Object System.Windows.Forms.GroupBox
$GroupBox2.Location = '350,100'
$GroupBox2.Size = '200,30'

<---------------Computer Name----------------

# Define Label5 - Computer Name
$Label5 = New-Object System.Windows.Forms.Label
$Label5.AutoSize = $True
$Label5.Location = new-object System.Drawing.Size(50,160)
$Label5.ForeColor = "DarkBlue"
$Label5.Text = "What computer name should the Nano Server use?"

$TextBox1 = New-Object System.Windows.Forms.TextBox
$TextBox1.AutoSize = $True
$TextBox1.Location = New-Object System.Drawing.Size(310,155)
$TextBox1.Text="MyMinWinPC"

<---------------Media Type----------------

# Define Label6 - Media Type
$Label6 = New-Object System.Windows.Forms.Label
$Label6.AutoSize = $True
$Label6.Location = new-object System.Drawing.Size(50,200)
$Label6.ForeColor = "DarkBlue"
$Label6.Text = "What type of media do you want to create?"

$RadioButton5 = New-Object System.Windows.Forms.RadioButton
$RadioButton5.Location = '5,10'
$RadioButton5.AutoSize = $True
$RadioButton5.Checked = $false
$RadioButton5.Text = "WIM"

$RadioButton6 = New-Object System.Windows.Forms.RadioButton
$RadioButton6.Location = '100,10'
$RadioButton6.AutoSize=$True
$RadioButton6.Checked = $True
$RadioButton6.Text = "VHD"

$GroupBox3 = New-Object System.Windows.Forms.GroupBox
$GroupBox3.Location = '275,190'
$GroupBox3.Size = '200,30'

 

<--------------Password----------------------

# Define Label7 - Administrative Password
$Label7 = New-Object System.Windows.Forms.Label
$Label7.AutoSize = $True
$Label7.Location = new-object System.Drawing.Size(50,240)
$Label7.ForeColor = "DarkBlue"
$Label7.Text = "Enter the administrative password for this server:"

 

$TextBox2 = New-Object System.Windows.Forms.MaskedTextBox
$TextBox2.PasswordChar='*'
$TextBox2.AutoSize = $True
$TextBox2.Location = New-Object System.Drawing.Size(305,235)

 

<----------Packages-------------------------

# Define List Box - This will display the choices of packages that can be installed into the Nano Server

$ListBox1 = New-Object System.Windows.Forms.ListBox
$ListBox1.Location = New-Object System.Drawing.Size(20,80)
$ListBox1.Size = New-Object System.Drawing.Size(280,20)
$ListBox1.Height = 130

[void] $ListBox1.Items.Add('DNS Server')
[void] $ListBox1.Items.Add('Desired State Configuration (DSC)')
[void] $ListBox1.Items.Add('Internet Information Server (IIS)')
[void] $ListBox1.Items.Add('Network Performance Diagnostics Service (NPDS)')
[Void] $ListBox1.Items.Add('Datacenter Bridging')
[void] $ListBox1.Items.Add('Secure Startup')
[void] $ListBox1.Items.Add('Shielded VM')
[void] $ListBox1.Items.Add('None')

 

<-----------Exit Text-------------------

# Define Label8 - Media Type
$Label8 = New-Object System.Windows.Forms.Label
$Label8.AutoSize = $True
$Label8.Location = new-object System.Drawing.Size(50,200)
$Label8.ForeColor = "DarkBlue"
$Label8.Text = "Your Nano Server is Being Created."

 

<------------VHD Size------------------

# Define Label9 - Media Type
$Label9 = New-Object System.Windows.Forms.Label
$Label9.AutoSize = $True
$Label9.Location = new-object System.Drawing.Size(50,280)
$Label9.ForeColor = "DarkBlue"
$Label9.Text = "Enter the Maximum Size (in GB)."

$TextBox3 = New-Object System.Windows.Forms.TextBox
$TextBox3.Size = New-Object Drawing.Size (35,20)
$TextBox3.Location = New-Object System.Drawing.Size(220,275)
$TextBox3.Text="20"

<--------------Define Buttons-------------
# Define Button 1  - This is the selection screen's OK button
$Button1 = new-object System.Windows.Forms.Button
$Button1.Location = new-object System.Drawing.Size(20,320)
$Button1.Size = new-object System.Drawing.Size(70,30)
$Button1.BackColor ="LightGray"
$Button1.Text = "OK"
$Button1.Add_Click({Acquire-ServerPackage})

 

# Define Button 2 - This is the selection screen's Cancel button
$Button2 = New-Object System.Windows.Forms.Button
$Button2.Location = New-Object System.Drawing.Size(120,320)
$Button2.Size = New-Object System.Drawing.Size(70,30)
$Button2.BackColor ="LightGray"
$Button2.Text = "Cancel"
$Button2.Add_Click({$Form.Close()})

 

# Define Button 3 - This is the Back button
$Button3 = New-Object System.Windows.Forms.Button
$Button3.Location = New-Object System.Drawing.Size(50,220)
$Button3.Size = New-Object System.Drawing.Size(70,30)
$Button3.BackColor ="LightGray"
$Button3.Text = "Return"
$Button3.Add_Click({Return-MainScreen})

 

# Define Button 4 - This is the Create button
$Button4 = New-Object System.Windows.Forms.Button
$Button4.Location = New-Object System.Drawing.Size(140,220)
$Button4.Size = New-Object System.Drawing.Size(150,30)
$Button4.BackColor ="LightGray"
$Button4.Text = "Create Nano Server"
$Button4.Add_Click({$SelectedPackage=$ListBox1.SelectedItem;Create-NanoServer $SelectedPackage})

 

# Define Button 5 - This is button exits the wizard
$Button5 = New-Object System.Windows.Forms.Button
$Button5.Location = New-Object System.Drawing.Size(120,300)
$Button5.Size = New-Object System.Drawing.Size(70,30)
$Button5.BackColor ="LightGray"
$Button5.Text = "Exit"
$Button5.Add_Click({$Form.Close()})

# -------- This is the end of the object definition section ------

 

# -----Draw the empty form----
$Form = New-Object System.Windows.Forms.Form
$Form.width = 750
$Form.height = 550
$Form.BackColor = "lightblue"
$Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D
$Form.Text = "Brien Poseys Nano Server Installation Tool"
$Form.maximumsize = New-Object System.Drawing.Size(800,600)
$Form.startposition = "centerscreen"
$Form.KeyPreview = $True
$Form.Add_KeyDown({if ($_.KeyCode -eq "Enter") {}})
$Form.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$Form.Close()}})

<----Populate the form----
Acquire-NanoInfo
$Form.Add_Shown({$Form.Activate()})
$Form.ShowDialog()

 

About the Author

Brien Posey is a 22-time Microsoft MVP with decades of IT experience. As a freelance writer, Posey has written thousands of articles and contributed to several dozen books on a wide variety of IT topics. Prior to going freelance, Posey was a CIO for a national chain of hospitals and health care facilities. He has also served as a network administrator for some of the country's largest insurance companies and for the Department of Defense at Fort Knox. In addition to his continued work in IT, Posey has spent the last several years actively training as a commercial scientist-astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space. You can follow his spaceflight training on his Web site.

Featured

comments powered by Disqus

Subscribe on YouTube

Upcoming Training Events

0 AM
TechMentor @ Microsoft HQ
August 11-15, 2025