Image Factory for Microsoft Deployment Toolkit and Hyper-V

In a previous post I wrote about my Image Factory for MDT, powered by Hyper-V and PowerShell. This post will serve as a change log and documentation page, as my previous post was more about how the script is written as a reference.

 

My Image Factory script is also available to download from the TechNet Gallery.

When run, the script will:

  1. Create a Hyper-V Virtual Machine
  2. Boot it from the MDT LiteTouch boot media
  3. Run the specified Task Sequence
  4. Capture the .wim file to MDT
  5. Destroy the Virtual Machine and VHD used
  6. Move on to the next specified task sequence
  7. Do steps 1-6 for all specified TS
  8. Import the .wim files into the deployment share of MDT
  9. Remove the captured .wim files
  10. Optionally create a log file and email it to an address of your choice.

Requirements/Features

  • The script must be run on a device with MDT installed.
  • The device must also have Hyper-V management tools installed
  • MDT shares can be local or on a remote device
  • Hyper-V can be local or on a remote device
  • Paths for VM configuration such as boot media, vhd location etc. must be local to the Hyper-V server
  • Hyper-V virtual switch name must have no spaces

Configuration

I’ve changed the configuration to be done via command line switches, instead of having to edit the script itself. Here’s a list of all the switches and example configurations

Command Line Switch Mandatory Description Example
-build Yes Location of the MDT build share. Can be the same share as the deployment share. Can be a local path or UNC. \\mdt01\buildshare$ OR E:\BuildShare
-deploy Yes Location of the MDT deployment share. Can be the same share as the deployment share. Can be a local path or UNC. \\mdt01\deploymentshare$ OR E:\DeploymentShare
-vh Yes Name of the Hyper-V server. Can be remote or local. VS01
-vhd Yes Path relative to the Hyper-V server of where to put the VHD file for the VM(s) that will be generated D:\Hyper-V\VHD
-boot Yes Path relative to the Hyper-V server of where the ISO file is to use to boot from. F:\iso\LiteTouchPE_x64.iso
-vnic Yes Name of the virtual switch that the Virtual Machine should use to communicate with the network. No spaces are accepted, nope not even with “” at this time. vSwitch-Ext
-ts Yes The Task Sequence IDs from MDT that should be ran. Separate more than one with a comma , and no spaces. REF-W10-1703,REF-W10-1607,REF-WS2016
-l No Location to store the optional log file. The name of the log file is automatically generated. C:\Users\sysadmin\Desktop
-sendto No* The email address to send the log file to. *Log file switch must be set, as well as other mail config options. me@contoso.com
-from No* The email address that the log file should be sent from. *Log file switch must be set, as well as other mail config options. image-factory@contoso.com
-mail No* Mail server to use to send the log file. *Log file switch must be set, as well as other mail config options. mail01.contoso.com
-compat No Set if the Hyper-V server is WS2012 R2 and the script is running on Windows 10 or Windows Server 2016.

This loads the older version of the Hyper-V module so it is able to manage WS2012 R2 Hyper-V VMs.

N/A
-remote No Set if the Hyper-V server is a remote device.

Do not include this switch if the script is running on the same device as Hyper-V

N/A

 

Expectations

I created this script originally for myself so I’m assuming that you already have MDT installed and use it to create and capture images.

As mentioned above, this script can be run in a variety of configurations. You could run it on a Windows 10 PC, with MDT and Hyper-V Management tools installed, a single MDT deployment share on a file server (although depending on your MDT customsettings.ini configuration you may need to make some changes) and a remote Windows 10/Windows Server 2016 or Windows Server 2012 R2 Hyper-V.

The script makes the changes below to your MDT customsettings.ini file, after making a backup of course! These changes are necessary so that the entire process runs completely automated. Depending on your environment, you may need to make additional changes. This is one reason why I recommend running a separate “Build Share” so that:

  1. You don’t tie up the main Deployment Share whilst running the factory.
  2. You can have an environment which is set up to only run the bare minimum to build images on a Hyper-V VM.
  3. You can set the boot media to auto logon into the deployment environment without compromising your main deployment share.

Here are the settings you’ll need to add to your Bootstrap.ini to auto login to your Build Share. Don’t forget to update your build share in MDT and regenerate your boot images!

[Settings]
Priority=Default

[Default]
DeployRoot=\\mdt01\e$\BuildShare
UserDomain=corp.contoso.com
UserID=mdt_admin
UserPassword=P@ssw0rd
SkipBDDWelcome=YES

I’ve listed my bare minimum customsettings.ini that I use for my own image building below.

The script makes these changes to your customsettings.ini. It sets the current task sequence to run, tells the WinPE deployment environment to skip asking for a Task Sequence and skip asking for a computer name.

TaskSequenceID=$id
SkipTaskSequence=YES
SkipComputerName=YES

My bare minimum customsettings.ini for my Build Share

[Settings]
Priority=Default
Properties=MyCustomProperty

[Default]
OSInstall=Y
SkipCapture=YES
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=YES
SkipBitLocker=YES
SkipLocaleSelection=YES
SkipTimeZone=YES
SkipDomainMembership=YES
SkipSummary=YES
SkipFinalSummary=YES
SkipComputerName=YES
SkipUserData=YES

_SMSTSORGNAME=gal.vin | Build Share
_SMSTSPackageName=%TaskSequenceName%
DoCapture=YES
ComputerBackupLocation=\\mdt01\buildshare$\Captures
BackupFile=%TaskSequenceID%_#year(date) & "-" & month(date) & "-" & day(date) & "-" & hour(time) & "-" & minute(time)#.wim
WSUSServer=http://wsus01:8530
FinishAction=SHUTDOWN
SLShare=\\mdt01\buildshare$\Logs
EventService=http://admin01:9800

 

Change Log

11/05/2017 Updated to 2.2

  • Added command line configuration options so the script itself does not need to be edited.
  • Added code to manage the Virtual Machines without the need for extra configuration options.
  • Removed some unnecessary extra configuration options and variables.

25/04/2017 Updated to v2.1

I’ve added logging to the script and the ability to email the log on completion. I’ve also added a variable to configure the Virtual Switch that the VM’s Network Adaptor should use. This was an oversight on the previous version.

17/04/2017 Minor update

I’ve added hour and minutes to the WIM file creation name as I have been running multiple images of the same Task Sequence within a day and needed some extra data to prevent the image from over writing the previous one. I’ve also made another script, using this one as a base so I can generate VMs to test the deployment of the captured images after I’ve manually renamed them in MDT and added to the task sequences. The VMs are named after the Task Sequence ID and do not delete after the Task Sequence completes.

 

PowerShell Code

# -------------------------------------------
# Script: image-factory_v2-2.ps1
# Version: 2.2
# Author: Mike Galvin twitter.com/digressive
# Date: 11/05/2017
# -------------------------------------------

Param(
    [parameter(Mandatory=$true)]
    [alias("build")]
    $mdtbuildpath,
    [parameter(Mandatory=$true)]
    [alias("deploy")]
    $mdtdeploypath,
    [parameter(Mandatory=$true)]
    [alias("ts")]
    $tsid,
    [parameter(Mandatory=$true)]
    [alias("vh")]
    $vmhost,
    [parameter(Mandatory=$true)]
    [alias("vhd")]
    $vhdpath,
    [parameter(Mandatory=$true)]
    [alias("boot")]
    $bootmedia,
    [parameter(Mandatory=$true)]
    [alias("vnic")]
    $vmnic,
    [alias("l")]
    $logpath,
    [alias("sendto")]
    $toaddress,
    [alias("from")]
    $fromaddress,
    [alias("mail")]
    $mailserver,
    [switch]$compat,
    [switch]$remote)

##Log file location
$logfile = ("imagefactory-{0:yyyy-MM-dd-HH-mm-ss}.log" -f (Get-Date))
$log = "$logpath\$logfile"

##Configure MDT Paths
$mdt = "$env:programfiles\Microsoft Deployment Toolkit\bin\MicrosoftDeploymentToolkit.psd1"

##Configure Mail For Log
$subject = "Image Factory Log"

If ($compat) {
    Import-Module $env:windir\System32\WindowsPowerShell\v1.0\Modules\Hyper-V\1.1\Hyper-V.psd1 -Verbose
}

##Start Log
If ($logpath) {
    Start-Transcript $log
}

##Import MDT Module
Import-Module $mdt -Verbose

ForEach ($id in $tsid) {

    ##Setup MDT Custom Settings for VM
    Copy-Item $mdtbuildpath\Control\CustomSettings.ini $mdtbuildpath\Control\CustomSettings-backup.ini -Verbose
    Start-Sleep -s 5
    Add-Content $mdtbuildpath\Control\CustomSettings.ini "TaskSequenceID=$id" -Verbose
    Add-Content $mdtbuildpath\Control\CustomSettings.ini "SkipTaskSequence=YES" -Verbose
    Add-Content $mdtbuildpath\Control\CustomSettings.ini "SkipComputerName=YES" -Verbose

    ##Create VM
    $vmname = ("build-{0:yyyy-MM-dd-HH-mm-ss}" -f (Get-Date))
    New-VM -name $vmname -MemoryStartupBytes 4096MB -BootDevice CD -Generation 1 -NewVHDPath $vhdpath\$vmname.vhdx -NewVHDSizeBytes 130048MB -SwitchName $vmnic -ComputerName $vmhost -Verbose
    Set-VM $vmname -ProcessorCount 2 -StaticMemory -ComputerName $vmhost -Verbose
    Set-VMDvdDrive -VMName $vmname -ControllerNumber 1 -ControllerLocation 0 -Path $bootmedia -ComputerName $vmhost -Verbose
    Start-VM $vmname -ComputerName $vmhost -Verbose

    ##Wait for VM to stop
    While ((Get-VM -Name $vmname -ComputerName $vmhost).state -ne 'Off') { Start-Sleep -s 5 }

    ##Remove VM and VHD
    If ($remote) {
        $vmbye = Get-VM -Name $vmname -ComputerName $vmhost
        $disks = Get-VHD -VMId $vmbye.Id -ComputerName $vmhost
        Invoke-Command {Remove-Item $using:disks.path -Force -Verbose} -ComputerName $vmbye.ComputerName
        Start-Sleep -s 5
    }

    Else {
        $vmlocal = Get-VM -Name $vmname -ComputerName $vmhost
        Remove-Item $vmlocal.HardDrives.Path -Force -Verbose
        Start-Sleep -s 5
    }

    Remove-VM $vmname -ComputerName $vmhost -Force -Verbose

    ##Reset MDT Custom Settings
    Remove-Item $mdtbuildpath\Control\CustomSettings.ini -Verbose
    Move-Item $mdtbuildpath\Control\CustomSettings-backup.ini $mdtbuildpath\Control\CustomSettings.ini -Verbose
    Start-Sleep -s 5
}

##Connect to MDT Production
New-PSDrive -Name "DS002" -PSProvider MDTProvider -Root $mdtdeploypath -Verbose

##Get files
$wims = Get-ChildItem $mdtbuildpath\Captures\*.wim

##Import the Captured REF Image into MDT Production
ForEach ($file in $wims) {
    Import-MDTOperatingSystem -path "DS002:\Operating Systems" -SourceFile $file -DestinationFolder $file.Name -Verbose
}

##Remove Captured WIMs
Remove-Item $mdtbuildpath\Captures\*.wim -Verbose

##Stop Log
If ($logpath) {
    Stop-Transcript
}

##Send Mail
If ($mailserver) {
    $body = Get-Content -Path $log | Out-String
    Send-MailMessage -To $toaddress -From $fromaddress -Subject $subject -Body $body -SmtpServer $mailserver
}

##END

If you’d like to get in touch with me please leave a comment or tweet me.

-Mike

Follow Mike on Twitter: @Digressive

One thought on “Image Factory for Microsoft Deployment Toolkit and Hyper-V

  1. Pingback: PowerShell: Fully Automated Image Factory for Microsoft Deployment Toolkit | Stick To The Script!

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