PowerShell: Image Factory for Microsoft Deployment Toolkit and Hyper-V (Update 2.7)

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 Microsoft TechNet Gallery and the PowerShell Gallery.

Features and Requirements

  • The script is designed to run on a device with MDT installed.
  • The device must also have Hyper-V management tools installed.
  • The MDT shares can be local or on a remote device.
  • The Hyper-V host can be local or on a remote device.

The script has been tested on Hyper-V installations on Windows 10, Windows Server 2016 (Datacenter and Core installations) and Windows Server 2012 R2 (Datacenter and Core Installations) and MDT installations on Windows 10 and Windows Server 2016 (GUI installs only).

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.

The script should be run with the -remote switch when the Hyper-V host is a remote device.

The script should be run with the -compat switch when the Hyper-V host a remote server running Windows Server 2012 R2.

Generating an encrypted password file

If you’ve used a previous version I’ve changed how the script handles configuring a password for the log notification e-mail. Specifically the password must now be in an encrypted text file. The advantage of this is that the password will no longer be in plain text, which is a security risk. The downside is that you will now need to generate a password file. The command to do this is pretty simple, but it must be generated on the computer the script will be running on, and as the user used to run the script.

To generate the password file, run the following command in PowerShell. When running the command you will be prompted for a username and password. The username doesn’t matter and can be anything, but the password must be the password you want to use to authenticate to your SMTP server.

$creds = Get-Credential
$creds.Password | ConvertFrom-SecureString | Set-Content c:\scripts\ps-script-pwd.txt

After running the commands, you should have a text file contained the encrypted password. Enter the path and filename for the -pwd switch to configure authenticated e-mail notification.

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. If the name of the switch contains space, it should be surrounded by “double quotes”. 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. me@contoso.com
-from No* The email address that the log file should be sent from.

*This switch isn’t mandatory but is required if you wish to email the log file.

ImageFactory@contoso.com
-smtp No* SMTP server address to use for the email functionality.

*This switch isn’t mandatory but is required if you wish to email the log file.

mail01.contoso.com

OR

smtp.live.com

OR

smtp.office365.com

-user No* The username of the account to use for SMTP authentication.

*This switch isn’t mandatory but may be required depending on the configuration of the SMTP server.

example@contoso.com
-pwd No* The location of the file containing the encrypted password of the account to use for SMTP authentication.

*This switch isn’t mandatory but may be required depending on your SMTP server.

 

c:\scripts\ps-script-pwd.txt
-usessl No* Add this option if you wish to use SSL with the configured SMTP server.

Tip: If you wish to send email to outlook.com or office365.com you will need this.

*This switch isn’t mandatory but may be required depending on the configuration of the SMTP server.

N/A
-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

 

As mentioned above, this script can be run in a variety of configurations. You could run it on a Windows 10 device with MDT and Hyper-V Management tools installed or a single MDT deployment share on a file server and a remote Hyper-V host running Windows 10, Windows Server 2016 or Windows Server 2012 R2.

The script makes changes (shown below) to your MDT customsettings.ini file – after making a backup, of course! These changes are necessary so that the process runs completely automated. Depending on your environment, you may need to make additional changes.

Personally 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 has the bare minimum configuration 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

16/10/2017 2.7

  • Changed SMTP authentication to require an encrypted password file.
  • Added instructions on how to generate an encrypted password file.

09/10/2017 2.6

  • Added necessary information to add the script to the PowerShell Gallery.

18/09/2017 2.5

  • Added a sanity check of the MDT deployment share. The script now checks for an existing CustomSettings-backup.ini file. If it exists, it reports that the deployment share is not clean.
  • Added extra line breaks when editing the CustomSettings.ini as previously it was adding the required configuration on the last line of the ini file and causing the deployment to fail. Many thanks to Twitter user @thestardawg for reporting this bug.

26/08/2017 2.4

  • Improved logging so that the log file and console output is now more readable.

22/07/2017 2.3

  • Improved commenting on the code for documentation purposes.
  • Added authentication and SSL options for e-mail notification.

11/05/2017 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 2.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


<#PSScriptInfo .VERSION 2.7 .GUID 251ae35c-cc4e-417c-970c-848b221477fa .AUTHOR Mike Galvin twitter.com/digressive .COMPANYNAME .COPYRIGHT (C) Mike Galvin. All rights reserved. .TAGS Microsoft Deployment Toolkit MDT Hyper-V Windows OSD .LICENSEURI .PROJECTURI https://gal.vin/2017/08/26/image-factory .ICONURI .EXTERNALMODULEDEPENDENCIES Microsoft Deployment Toolkit PowerShell Modules, Hyper-v Management PowerShell Modules .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #>

<# .SYNOPSIS Automates the creation of WIM files for Windows deployment. .DESCRIPTION Automates the creation of WIM files for Windows deployment. This script will: Create disposable Hyper-V virtual machines to generate WIM files from Microsoft Deployment Toolkit task sequences. The process is as follows: Create a Hyper-V Virtual Machine. Boot it from the MDT LiteTouch boot media. Run the specified Task Sequence. Capture the .wim file to MDT. Destroy the Virtual Machine and VHD used. Move on to the next specified task sequence. Do the previous steps for all configured task sequences. Import the .wim files into the deployment share of MDT. Remove the captured .wim files from the capture folder. Optionally create a log file and email it to an address of your choice. Please note: to send a log file using ssl and an SMTP password you must generate an encrypted password file. The password file is unique to both the user and machine. The command is as follows: $creds = Get-Credential $creds.Password | ConvertFrom-SecureString | Set-Content c:\foo\ps-script-pwd.txt .PARAMETER Build The local or UNC path to the build share of MDT. This and the deploy switch can point to the same location. .PARAMETER Deploy The local or UNC path to the deploy share of MDT. This and the build switch can point to the same location. .PARAMETER Ts The comma-separated list of task sequence ID's to build. .PARAMETER Vh The name of the computer running Hyper-V. Can be local or remote. .PARAMETER Vhd The path relative to the Hyper-V server of where to store the VHD file for the VM(s). .PARAMETER Boot The path relative to the Hyper-V server of where the ISO file to boot from is stored. .PARAMETER VNic The name of the virtual switch that the VM should use to communicate with the network. .PARAMETER Compat 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. .PARAMETER Remote 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. .PARAMETER L The path to output the log file to. The file name will be Image-Factory-YYYY-MM-dd-HH-mm-ss.log .PARAMETER SendTo The e-mail address the log should be sent to. .PARAMETER From The from address the log should be sent from. .PARAMETER Smtp The DNS name or IP address of the SMTP server. .PARAMETER User The user account to connect to the SMTP server. .PARAMETER Pwd The password for the user account. .PARAMETER UseSsl Connect to the SMTP server using SSL. .EXAMPLE Image-Factory.ps1 -Build \\mdt01\BuildShare$ -Deploy \\mdt01\DeploymentShare$ -Vh hyperv01 -Vhd D:\Hyper-V\VHD -Boot F:\iso\LiteTouchPE_x64.iso -VNic vSwitch-Ext -Remote -L E:\logs -SendTo me@contoso.com -From Image-Factory@contoso.com -Smtp exch01.contoso.com -User me@contoso.com -Pwd P@ssw0rd -UseSsl -Ts W10-1703,WS16-S This string will build two WIM from the two task sequences: W10-1703 & WS16-S. They will be imported to the deployment share on MDT01. The Hyper-V server used will be hyperv01, the VHD for the VMs generated will be stored in D:\Hyper-V\VHD on the server hyperv01. The boot iso file will be F:\iso\LiteTouchPE_x64.iso located on the Hyper-V server. The Virtual Switch used by the VM will be called vSwitch-Ext. The log file will be output to E:\logs and it will be emailed using an SSL conection. #>

[CmdletBinding()]
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")]
    $MailTo,
    [alias("From")]
    $MailFrom,
    [alias("Smtp")]
    $SmtpServer,
    [alias("User")]
    $SmtpUser,
    [alias("Pwd")]
    $SmtpPwd,
    [switch]$UseSsl,
    [switch]$Compat,
    [switch]$Remote)

## If logging is configured, start log
If ($LogPath)
{
    $LogFile = ("Image-Factory-{0:yyyy-MM-dd-HH-mm-ss}.log" -f (Get-Date))
    $Log = "$LogPath\$LogFile"

    ## If the log file already exists, clear it
    $LogT = Test-Path -Path $Log

    If ($LogT)
    {
        Clear-Content -Path $Log
    }

    Add-Content -Path $Log -Value "****************************************"
    Add-Content -Path $Log -Value "$(Get-Date -Format G) Log started"
    Add-Content -Path $Log -Value ""
}

## If compat is configured, load the older Hyper-V PS module
If ($Compat) 
{
    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Importing Hyper-V 1.1 PowerShell Module"
    }
    
    Write-Host "$(Get-Date -Format G) Importing Hyper-V 1.1 PowerShell Module"
    Import-Module $env:windir\System32\WindowsPowerShell\v1.0\Modules\Hyper-V\1.1\Hyper-V.psd1
}

## Import MDT PS module
If ($LogPath)
{
    Add-Content -Path $Log -Value "$(Get-Date -Format G) Importing MDT PowerShell Module"
}

Write-Host "$(Get-Date -Format G) Importing MDT PowerShell Module"
Import-Module "$env:programfiles\Microsoft Deployment Toolkit\bin\MicrosoftDeploymentToolkit.psd1"

ForEach ($Id in $TsId)
{
    ## Test to see if the build environment is dirty.
    $EnvDirtyTest = Test-Path -Path $MdtBuildPath\Control\CustomSettings-backup.ini
    If ($EnvDirtyTest)
    {
        Write-Host "$(Get-Date -Format G) CustomSettings-backup.ini already exists."
        Write-Host "$(Get-Date -Format G) The build environment is dirty."
        Write-Host "$(Get-Date -Format G) Did the script finish successfully last time it was run?"

        If ($LogPath)
        {
            Add-Content -Path $Log -Value "$(Get-Date -Format G) CustomSettings-backup.ini already exists."
            Add-Content -Path $Log -Value "The build environment is dirty."
            Add-Content -Path $Log -Value "Did the script finish successfully last time it was run?"
        }

        Exit
    }
    
    ## Setup MDT custom settings for VM auto deploy
    If ($LogPath)
    {
        Add-Content -Path $Log -Value ""
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Starting process for $Id"
        Add-Content -Path $Log -Value ""
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Backing up current MDT CustomSettings.ini"
    }
    
    Write-Host ""
    Write-Host "$(Get-Date -Format G) Starting process for $Id"
    Write-Host ""
    Write-Host "$(Get-Date -Format G) Backing up current MDT CustomSettings.ini"

    Copy-Item $MdtBuildPath\Control\CustomSettings.ini $MdtBuildPath\Control\CustomSettings-backup.ini
    Start-Sleep -s 5

    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Setting up MDT CustomSettings.ini for Task Sequence ID: $Id"
    }

    Write-Host "$(Get-Date -Format G) Setting MDT CustomSettings.ini for Task Sequence ID: $Id"

    Add-Content $MdtBuildPath\Control\CustomSettings.ini ""
    Add-Content $MdtBuildPath\Control\CustomSettings.ini ""
    Add-Content $MdtBuildPath\Control\CustomSettings.ini "TaskSequenceID=$Id"
    Add-Content $MdtBuildPath\Control\CustomSettings.ini "SkipTaskSequence=YES"
    Add-Content $MdtBuildPath\Control\CustomSettings.ini "SkipComputerName=YES"

    ## Create VM
    $VmName = ("build-{0:yyyy-MM-dd-HH-mm-ss}" -f (Get-Date))

    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Creating VM: $VmName on $VmHost"
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Adding VHD: $VhdPath\$VmName.vhdx"
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Adding Virtual NIC: $VmNic"
    }

    Write-Host "$(Get-Date -Format G) Creating VM: $VmName on $VmHost"
    Write-Host "$(Get-Date -Format G) Adding VHD: $VhdPath\$VmName.vhdx"
    Write-Host "$(Get-Date -Format G) Adding Virtual NIC: $VmNic"

    New-VM -name $VmName -MemoryStartupBytes 4096MB -BootDevice CD -Generation 1 -NewVHDPath $VhdPath\$VmName.vhdx -NewVHDSizeBytes 130048MB -SwitchName $VmNic -ComputerName $VmHost

    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Configuring VM Processor Count"
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Configuring VM Static Memory"
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Configuring VM to boot from $BootMedia"
    }

    Write-Host "$(Get-Date -Format G) Configuring VM Processor Count"
    Write-Host "$(Get-Date -Format G) Configuring VM Static Memory"
    Write-Host "$(Get-Date -Format G) Configuring VM to boot from $BootMedia"

    Set-VM $VmName -ProcessorCount 2 -StaticMemory -ComputerName $VmHost
    Set-VMDvdDrive -VMName $VmName -ControllerNumber 1 -ControllerLocation 0 -Path $BootMedia -ComputerName $VmHost

    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Starting $VmName on $VmHost with $Id"
    }

    Write-Host "$(Get-Date -Format G) Starting $VmName on $VmHost with $Id"

    Start-VM $VmName -ComputerName $VmHost

    ## Wait for VM to stop
    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Waiting for $VmName to build $Id"
    }

    Write-Host "$(Get-Date -Format G) Waiting for $VmName to build $Id"

    While ((Get-VM -Name $VmName -ComputerName $VmHost).state -ne 'Off') {Start-Sleep -s 10}

    ## Remove VM and VHD
    If ($Remote)
    {
        $VmBye = Get-VM -Name $VmName -ComputerName $VmHost
        $Disks = Get-VHD -VMId $VmBye.Id -ComputerName $VmHost

        If ($LogPath)
        {
            Add-Content -Path $Log -Value "$(Get-Date -Format G) Deleting $VmName on $VmHost"
        }

        Write-Host "$(Get-Date -Format G) Deleting $VmName on $VmHost"

        Invoke-Command {Remove-Item $using:disks.path -Force} -ComputerName $VmBye.ComputerName
        Start-Sleep -s 5
    }

    Else
    {
        $VmLocal = Get-VM -Name $VmName -ComputerName $VmHost

        If ($LogPath)
        {
            Add-Content -Path $Log -Value "$(Get-Date -Format G) Deleting $VmName on $VmHost"
        }

        Write-Host "$(Get-Date -Format G) Deleting $VmName on $VmHost"

        Remove-Item $VmLocal.HardDrives.Path -Force
        Start-Sleep -s 5
    }

    Remove-VM $VmName -ComputerName $VmHost -Force

    ## Restore MDT custom settings
    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Restoring MDT CustomSettings.ini from backup"
    }

    Write-Host "$(Get-Date -Format G) Restoring MDT CustomSettings.ini from backup"

    Remove-Item $MdtBuildPath\Control\CustomSettings.ini
    Move-Item $MdtBuildPath\Control\CustomSettings-backup.ini $MdtBuildPath\Control\CustomSettings.ini
    Start-Sleep -s 5

    If ($LogPath)
    {
        Add-Content -Path $Log -Value ""
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Finished process for $Id"
        Add-Content -Path $Log -Value ""
    }

    Write-Host "$(Get-Date -Format G) Finished process for $Id"
}

## Connect to MDT
If ($LogPath)
{
    Add-Content -Path $Log -Value "$(Get-Date -Format G) Creating PSDrive to $MdtDeployPath"
}

Write-Host "$(Get-Date -Format G) Creating PSDrive to $MdtDeployPath"

New-PSDrive -Name "DS002" -PSProvider MDTProvider -Root $MdtDeployPath

## Get the WIM files and store them in a variable
$Wims = Get-ChildItem $MdtBuildPath\Captures\*.wim

## Import the WIMs from the variable above into MDT
ForEach ($file in $Wims)
{
    If ($LogPath)
    {
        Add-Content -Path $Log -Value "$(Get-Date -Format G) Importing WIM File: $file"
    }

    Write-Host "$(Get-Date -Format G) Importing WIM File: $file"

    Import-MDTOperatingSystem -path "DS002:\Operating Systems" -SourceFile $file -DestinationFolder $file.Name
}

## Remove captured WIMs
If ($LogPath)
{
    Add-Content -Path $Log -Value "$(Get-Date -Format G) Removing captured WIM files"
}

Write-Host "$(Get-Date -Format G) Removing captured WIM files"

Remove-Item $MdtBuildPath\Captures\*.wim

## If log was configured stop the log
If ($LogPath)
{
    Add-Content -Path $Log -Value ""
    Add-Content -Path $Log -Value "$(Get-Date -Format G) Log finished"
    Add-Content -Path $Log -Value "****************************************"

    ## If email was configured, set the variables for the email subject and body
    If ($SmtpServer)
    {
        $MailSubject = "Image Factory Log"
        $MailBody = Get-Content -Path $Log | Out-String

        ## If an email password was configured, create a variable with the username and password
        If ($SmtpPwd)
        {
            $SmtpPwdEncrypt = Get-Content $SmtpPwd | ConvertTo-SecureString
            $SmtpCreds = New-Object System.Management.Automation.PSCredential -ArgumentList ($SmtpUser, $SmtpPwdEncrypt)

            ## If ssl was configured, send the email with ssl
            If ($UseSsl)
            {
                Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -SmtpServer $SmtpServer -UseSsl -Credential $SmtpCreds
            }

            ## If ssl wasn't configured, send the email without ssl
            Else
            {
                Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -SmtpServer $SmtpServer -Credential $SmtpCreds
            }
        }

        ## If an email username and password were not configured, send the email without authentication
        Else
        {
            Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -SmtpServer $SmtpServer
        }
    }
}

## 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 “PowerShell: Image Factory for Microsoft Deployment Toolkit and Hyper-V (Update 2.7)

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