Integrating Windows Server 2016 Core under KVM/QEMU

Integrating Windows Server 2016 Core under KVM/QEMU
Jérémie Kassianoff
October 17, 2017
12 min read

Discover integrating Windows Server 2016 Core under KVM/QEMU. Installing and configuring Active Directory in PowerShell.

Certified inVeeam Certified Engineer (VMCE)

Real-world use case

You want a lightweight, secure Windows server on an open-source hypervisor: here's how to integrate Windows Server 2016 Core under KVM/QEMU.

Windows Server 2016 Core

The core version of Windows Server is overall lighter and more resource-efficient. It doesn't contain the built-in software of the User Experience version, which helps reduce Microsoft's system's attack surface.

Integrating Windows Server 2016 Core under KVM/QEMU into my infrastructure lets me centralize my identification and authentication, but also orchestrate my backups with Veeam Backup & Replication 9.5.

Table of contents:

  1. Integrating Windows Server into KVM/QEMU
  2. Basic configuration of Windows Server 2016 Core
  3. Quick installation and configuration of Active Directory
  4. Conclusion on Windows Server 2016 Core

Integrating Windows Server into KVM/QEMU

To start, we'll create an XML file compatible with our hypervisor:

bash
<domain type='kvm' id='10'>
  <name>Windows2016core</name>
  <uuid>154d0X-va57-5fc4-f51c-c5d4fgg4rv</uuid>
  <description>None</description>
  <memory unit='KiB'>2000000</memory>
  <currentMemory unit='KiB'>0000000</currentMemory>
  <vcpu placement='static'>2</vcpu>
  <os>
    <type arch='x86_64' machine='pc-1.1'>hvm</type>
    <boot dev='hd'/>
    <boot dev='cdrom'/>
    <bootmenu enable='yes'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <cpu mode='host-model'>
    <model fallback='allow'/>
  </cpu>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/bin/kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/windows2016core'/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/windows2016core-vtl'/>
      <target dev='vdb' bus='virtio'/>
      <alias name='virtio-disk1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </disk>
        <disk type='file' device='cdrom'>
      <source file='/var/lib/libvirt/iso/Microsoft/fr_windows_server_2016_standard_and_datacenter_x64.iso'/>
      <target dev='hdc' bus='sata'/>
      <readonly/>
    </disk>
    <disk type='file' device='cdrom'>
      <source file='/var/lib/libvirt/iso/Drivers/virtio-windows.iso'/>
      <target dev='hdb' bus='sata'/>
      <readonly/>
    </disk>
    <controller type='usb' index='0'>
      <alias name='usb0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='ide' index='0'>
      <alias name='ide0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:5f:5v:5v:5v'/>
      <source network='lbr300'/>
      <target dev='vnet13'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/0'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/0'>
      <source path='/dev/pts/0'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='5900' autoport='no' listen='127.0.0.1' keymap='fr'>
      <listen type='address' address='127.0.0.1'/>
    </graphics>
    <video>
      <model type='vga' vram='9216' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </memballoon>
  </devices>
  <seclabel type='none'/>
</domain>

For information: you'll need to adapt certain tags to your configuration: paths to image files, the Windows Server ISO, and the VirtIO driver location, as well as the network and graphics tags.

Creating a disk image

We start by generating an image file for the C: volume (minimum 32GB). In my case, I created two images: one of 50GB (System) and one of 100GB (Backups) with dynamic provisioning:

bash
qemu-img create -f qcow2 windows2016core 50G
qemu-img create -f qcow2 windows2016core-vtl 100G

We add our XML configuration file: windows2016core.xml into KVM/QEMU with virsh:

bash
virsh define windows2016core.xml
virsh start windows2016core

It's now possible via VNC or spice (depending on your choice), following your management solution, to carry out the installation.
During the installation process: nothing special, leave the default choice: without user experience.

RedHat's VirtIO drivers for Windows Server 2016

Integrating the VirtIO drivers contained in the ISO is very important: download link VirtIO. It lets you load the virtio bus driver during Windows installation for disk image recognition via viostor.
The NetKVM driver handles network card recognition, here's the ISO's contents:

  • netKVM/: Virtio Network driver
  • viostor/: Virtio Block driver
  • vioscsi/: Virtio SCSI driver
  • viorng/: Virtio RNG driver
  • vioser/: Virtio serial driver
  • Balloon/: Virtio Memory Balloon driver
  • qxl/: QXL graphics driver for Windows 7 and earlier. (build virtio-win-0.1.103-1 and later)
  • qxldod/: QXL graphics driver for Windows 8 and later. (build virtio-win-0.1.103-2 and later)
  • pvpanic/: QEMU pvpanic device driver (build virtio-win-0.1.103-2 and later)
  • guest-agent/: QEMU Guest Agent 32bit and 64bit MSI installers
  • qemupciserial/: QEMU PCI serial device driver
  • *.vfd: VFD floppy images for using during install of Windows XP

Basic configuration of Windows Server 2016 Core

Once your administrator password is configured, a cmd.exe interface appears. To take advantage of Windows 2016's features, you need to switch to PowerShell like this:

bash
start powershell

Every time you log in, you'd need to juggle between cmd.exe and powershell.exe. I invite you to change the value of a registry key so it starts with PowerShell by default:

powershell
Set-ItemProperty -Path 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon' -Name Shell -Value 'PowerShell.exe -NoExit'

Getting off to a good start also means running the server configuration command for core mode:

bash
sconfig

A menu appears with different choices numbered 1 to 15, here's the server currently:

bash
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

Inspecting system...

===============================================================================
                         Server Configuration
===============================================================================

1) Domain or workgroup:                          Domain:  kassianoff.local
2) Computer name:                                DC-W2K16
3) Add local administrator
4) Configure remote management                    disabled

5) Windows Update settings:                       Manual
6) Download and install updates
7) Remote desktop:                                Enabled (all clients)

8) Network settings
9) Date and time
10) Telemetry settings                          Security
11) Windows activation

12) Log off user
13) Restart server
14) Shut down server
15) Exit to command line

Enter a number to select an option:

To start, I recommend renaming the computer, changing the network settings, and checking the date and time.
For the rest, it's a matter of personal preference. Once done: a restart is needed.

Now let's initialize the second disk present on the server, which is 100GB:

powershell
Get-Disk |
Where partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle MBR -PassThru |
New-Partition -AssignDriveLetter -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel "disk2" -Confirm:$false

To list the volumes present on the server:

powershell
Get-PSDrive -PSProvider 'FileSystem'

Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
----           ---------     --------- --------      ----                                               ---------------
C                  15,60         33,91 FileSystem    C:                                               Windowssystem32
D                   0,29          0,00 FileSystem    D:
E                   5,36          0,00 FileSystem    E:
G                   0,11         99,89 FileSystem    G:

To assign a different letter to a volume: example changing letter G to V

powershell
Get-Partition -DriveLetter G | Set-Partition -NewDriveLetter V.

I won't be using Windows Defender's real-time protection, here's how to disable it:

powershell
Set-MpPreference -DisableRealtimeMonitoring $true

Installing and configuring Active Directory

Let's add the Active Directory Domain Services:

bash
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools

We finish by promoting the Server Core system to a domain controller:

bash
Install-ADDSforest -DomainName kassianoff.local

At the end of the installation process, we need to provide a password for Directory Services Restore Mode. Once done, let's restart the server to see the server's promotion.

Useful commands

Let's create our first user in PowerShell like this:

powershell
New-ADUser -Name "Jérémie KASSIANOFF" -GivenNaMe Jeremie -Surname KASSIANOFF -SamAccountName Jeremie -Ac
countPassword (Read-Host -AsSecureString "AccountPassword") -PassThru | Enable-ADAccount

We also have another option with dsadd:

yaml
dsadd user "cn=Jeremie, dc=kassianoff, dc=local" -fn Jeremie -ln KASSIANOFF -pwd (Read-Host -AsSecureString "pwd") -disabled no
pwd: ***********************
dsadd success:cn=Jeremie,dc=kassianoff,dc=local

Now let's display our user's primary group:

powershell
Get-ADPrincipalGroupMembership Jeremie | select name

name
-----
Domain Users

It's possible to add the user to another group, for example as Domain Admins

bash
Add-ADGroupMember "Domain Admins" Jeremie

If forgotten, we have the option to securely change a user's password in two steps:

powershell
$newpwd = Read-Host "Enter the new password" -AsSecureString
Enter the new password: ********

We finish with the command that includes the secure variable:

powershell
Set-ADAccountPassword Jeremie -NewPassword $newpwd –Reset

A more standard solution is also possible to continue configuring objects in Active Directory. Use a Windows client compatible with the AD DS – AD LDS and DNS administration tools. These simply let you open a remote MMC to manage the server like the standard user experience.

Backing up Windows system state

Backing up the systemstate lets you preserve the Active Directory configuration but also system files (Boot and WFP), Sysvol, the authority's certificates, the registry database, and the Component Service Class databases. To do this, you need to install the Windows Server Backup command-line tool:

bash
Install-WindowsFeature -Name Windows-Server-Backup

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
True    No             Success        {Windows Server Backup}

We'll use the wbadmin command, and now back up the Windows system state to the V: target:

bash
wbadmin.exe start systemstatebackup -backuptarget:v:

wbadmin 1.0 - Backup command-line tool
(C) Copyright 2013 Microsoft Corporation. All rights reserved.

Starting system state backup [10/17/2017 18:23]...
Retrieving volume information...
This operation will back up the system state of System Reserved (500.00 MB),(C:) to v:.
Do you want to start the backup operation?
[Y] Yes [N] No Y

Creating a snapshot of the volumes specified for backup...
Creating a snapshot of the volumes specified for backup...
Windows Server Backup is updating the existing backup to remove files
that have been deleted from the server since the last backup.
This operation might take a few minutes.
(128) files found.
(128) files found.
(5759) files found.
(16838) files found.
(25640) files found.
(27545) files found.
(32136) files found.
(38401) files found.
(40891) files found.
(46330) files found.
(51592) files found.
(57589) files found.
(62223) files found.
(65702) files found.
(67775) files found.
(74302) files found.
(80408) files found.
(86037) files found.
(91284) files found.
(93183) files found.
The search for files on the system state is complete.
Starting to back up files...
Backup of the files reported by "Task Scheduler Writer" is complete.
Backup of the files reported by "VSS Metadata Store Writer" is complete.
Backup of the files reported by "Performance Counters Writer" is complete.
Progress: 0%.
Backing up files reported by "System Writer"...
Progress: 100%.
Backing up files reported by "System Writer"...

Summary of the backup operation:
-------------------------

The backup operation was successful.
The system state backup was successful [10/16/2017 16:37].
Log of successfully backed-up files:
C:WindowsLogsWindowsServerBackupBackup-16-10-2017_16-23-37.log

Scheduling a task is recommended to back up the system state:

bash
wbadmin enable backup -addtarget:V: -schedule:00:00 -systemState -quiet

Conclusion on Windows Server 2016 Core

I'd say Windows Server 2016 Core won me over much more for its low resource consumption than for the ergonomics of using PowerShell. Fortunately, I was able to install my directory service and configure it with the help of Microsoft's TechNet site.

Today, I'm satisfied with the result, and I made sure to back it up right away.