Creating a small footprint, base image Part 3 | SysPrep and Compacting Images

New-WindowsImage -size small | Test-Lab

One of the time consuming steps to deploying new VMs is the time spend managing Images and and applying patches. I’m not big on Golden images. I tend to use a fully patched VHDX or VMDK  and let DSC handle the configuration and software. This is not the fastest, and at scale you need to create more then one image based on what saves the most time.  (IIS, SQL, Exchange, etc…). In this series, I’m going to go over how I create a a baseline image of 2012r2 with PowerShell. Also because Install-WindowsFeature has issues when the target VM has been patched, we are also going to create a fully patched WIM to use as -source.

Blogs in this Series

SysPrep and Compacting Images

Sysprep the Core Image

Now I need to sysprep the core image before it’s usable. but I don’t want to repeat this whole process from scratch next month. So I’m going to copy the VHDX and create a new VM that I will sysprep.  So back to the host

copy .\CorePatched.vhdx CoreSysprep.vhdx
new-vm -Name CoreSysprep -MemoryStartupBytes 512MB -BootDevice VHD -VHDPath G:\temp\CoreSysprep.vhdx -Generation 2 -SwitchName TestLab
Name        State CPUUsage(%) MemoryAssigned(M) Uptime   Status
 ----        ----- ----------- ----------------- ------   ------
 CoreSysprep Off   0           0                 00:00:00 Operating normally
start-vm coreSysprep
vmconnect localhost coresysprep

Now on the new VM run

c:\windows\System32\Sysprep\sysprep.exe /quiet /oobe /generalize /shutdown

Once the VM is shutdown it’s time to look at our progress on the host.

Compacting the Images

dir core*
    Directory: G:\temp
Mode                LastWriteTime         Length Name
 ----                -------------         ------ ----
 -a----        5/14/2015   9:20 PM     5641338880 CoreFromIso.vhdx
 -a----        5/15/2015   4:10 PM     9265217536 CorePatched.vhdx
 -a----        5/15/2015   4:27 PM     9265217536 CoreSysprep.vhdx

Wow, almost 10 gigs. not exactly small. Well we are not done. We need to convert both our images to WIM and the core one back to VHDX. The transfer from VHDX to WMI and back to VHDX does a better job then using a utility to write all 0’s to the disk and then compact it. This is partly due to the swap file. Back on the host we need to create a folder to mount the VHDX into and then create the WIM.

mkdir g:\mount
    Directory: G:\
Mode                LastWriteTime         Length Name
 ----                -------------         ------ ----
 d-----        5/15/2015   8:54 PM                mount
Mount-WindowsImage -ImagePath G:\temp\CoreSysprep.vhdx -Path G:\Mount -Index 1
Path           : G:\Mount
 Online         : False
 Restart Needed : False
New-WindowsImage -CapturePath G:\Mount -Name 2012r2_Core -ImagePath G:\Temp\2012r2Core.wim -Description "2012r2 Core Patched May 2015" -Verify
LogPath : C:\Windows\Logs\DISM\dism.log
Dismount-WindowsImage -Path G:\mount -Discard
LogPath : C:\Windows\Logs\DISM\dism.log
Mount-WindowsImage -ImagePath G:\temp\GUIPatched.vhdx -Path G:\Mount -Index 1
Path           : G:\Mount
 Online         : False
 Restart Needed : False
New-WindowsImage -CapturePath G:\Mount -Name 2012r2_Source -ImagePath G:\Temp\2012r2Source.wim -Description "2012r2 Source Patched May 2015" -Verify
LogPath : C:\Windows\Logs\DISM\dism.log
Dismount-WindowsImage -Path G:\mount -Discard
LogPath : C:\Windows\Logs\DISM\dism.log

Converting the Core WIM back to VHDX is going to require that we make a change to Convert-WindowsImage.ps1. The logic of the script looks at the WIM and if there is only one image it uses that one. But it does so using metadata that does not exist when a WIM is created using New-WindowsImage. So down on line 4020 we nee to comment out a few lines

        # If there's only one image in the WIM, just selected that.
        #if ($openWim.Images.Count -eq 1) { 
        #    $Edition   = $openWim.Images[0].ImageFlags
        #    $openImage = $openWim[$Edition]
        #} else {

            if ([String]::IsNullOrEmpty($Edition)) {
                Write-W2VError "You must specify an Edition or SKU index, since the WIM has more than one image."
                Write-W2VError "Valid edition names are:"
                $openWim.Images | %{ Write-W2VError "  $($_.ImageFlags)" }
                throw
            } 

            if ([Int32]::TryParse($Edition, [ref]$null)) {
                $openImage = $openWim[[Int32]$Edition]    
            } else {
                $openImage = $openWim[$Edition]
            }        
        #}

Now it will work using -edition 1 (There is only one OS inside the WIM)

G:\temp\Convert-WindowsImage.ps1 -SourcePath G:\temp\2012r2Core.wim -VHDPath G:\temp\2012R2Core.vhdx -SizeBytes 40gb -VHDType Dynamic -VHDFormat VHDX -VHDPartitionStyle GPT -Edition 1 -Verbose
Windows(R) Image to Virtual Hard Disk Converter for Windows(R) 8
 Copyright (C) Microsoft Corporation.  All rights reserved.
 Version 6.3.9600.7.amd64fre.fbl_core1_hyp_dev(mikekol).140217-3000 Release to Web
 VERBOSE: isUserAdmin? True
 VERBOSE: isWindows8? True
 VERBOSE: Temporary VHDX path is : G:\temp\faf6d4fa-fb64-41d7-95f3-5a1ab3825940.vhdx
 INFO   : Image 1 selected ()...
 INFO   : Creating sparse disk...
 INFO   : Attaching VHDX...
 INFO   : Disk initialized with GPT...
 INFO   : Disk partitioned with two Volumes...
 INFO   : System Volume formatted (with DiskPart)...
 INFO   : Boot Volume formatted (with Format-Volume)...
 INFO   : Access path (L:\) has been assigned to the System Volume...
 INFO   : Access path (M:\) has been assigned to the Boot Volume...
 INFO   : Applying image to VHDX. This could take a while...
 INFO   : Signing disk...
 INFO   : Image applied. Making image bootable...
 VERBOSE: Running bcdboot.exe M:\Windows /s L:\ /v /f UEFI
 VERBOSE: Return code was 0.
 INFO   : Drive is bootable. Cleaning up...
 INFO   : Closing VHDX...
 INFO   : Closing Windows image...
 INFO   : Done.
dir *core* | sort -Property LastWriteTime
    Directory: G:\temp
 Mode                LastWriteTime         Length Name
 ----                -------------         ------ ----
 -a----        5/14/2015   9:20 PM     5641338880 CoreFromIso.vhdx
 -a----        5/15/2015   4:10 PM     9265217536 CorePatched.vhdx
 -a----        5/15/2015   8:00 PM     9265217536 CoreSysprep.vhdx
 -a----        5/15/2015   9:39 PM     2376356767 2012r2Core.wim
 -a----        5/15/2015  10:15 PM     4936695808 2012R2Core.vhdx
dir *gui*, *source* | sort -Property LastWriteTime
    Directory: G:\temp
 Mode                LastWriteTime         Length Name
 ----                -------------         ------ ----
 -a----        5/14/2015   9:29 PM     9130999808 GUIFromIso.vhdx
 -a----        5/15/2015   3:56 PM    16143876096 GuiPatched.vhdx
 -a----        5/15/2015  10:03 PM     6153716725 2012r2Source.wim

As you can see our Source.WIM is 6.1Gig and our Core VHDX is only 4.9gig. fully patched it’s smaller then the baseline Core image. We can place the WIM on a share that is accessible to new VM’s and they can use that for adding features. In another blog I will go over how to update the WIM file automatically each month.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s