winReferenceFactory.psm1

<#
.Synopsis
   Powershell Module for build Windows reference images on Hyper-V host
.DESCRIPTION
   Functions in this module:
.EXAMPLE
   New-RefImage REFW10X64-001
.EXAMPLE
   Remove-RefImage REFW10X64-001
#>


function Get-FactoryConfig
{
    # Read Settings from XML
    [xml]$Global:Settings = Get-Content "$($PSScriptRoot)\winReferenceFactory.xml"

    $Global:SWitchName = $Global:Settings.Settings.HyperVHostNetwork
    $Global:VLANID = $Global:Settings.Settings.VLANID
    $Global:StartUpRAM = 1024*1024*1024*$Global:Settings.Settings.StartUpRAM
    $Global:VMLocation = $Global:Settings.Settings.HyperVStorage
    $Global:VHDSize = 1024*1024*1024*$Global:Settings.Settings.VHDSize
    $Global:HyperVISOFolder = $Global:Settings.Settings.HyperVISOFolder
    $Global:DeploymentShare = $Global:Settings.Settings.DeploymentShare
    $Global:TaskSequenceFolder = $Global:Settings.Settings.TaskSequenceFolder
    $Global:ReportFrom = $Global:Settings.Settings.ReportFrom
    $Global:ReportTo = $Global:Settings.Settings.ReportTo
    $Global:ReportSmtp = $Global:Settings.Settings.ReportSmtp
}

function New-AutoGenRefImages
{
    Get-FactoryConfig

    #Connect to MDT:
    Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
    Remove-PSDrive MDT -ErrorAction SilentlyContinue
    $Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
    $MDTSettings = Get-ItemProperty MDT:
    $ISO = $MDTSettings.'Boot.x86.LiteTouchISOName'

    #Check if ISO exists
    $ISOFileExist = Test-Path "$($Global:DeploymentShare)\Boot\$($ISO)" -ErrorAction SilentlyContinue
    If (!$ISOFileExist) {
        Write-Output "Unable to find ISO, exit"
        exit
    }

    #Create Folders
    $Null = New-Item -Path $HyperVISOFolder -ItemType Directory -Force -ErrorAction SilentlyContinue

    #Copy the BootImage from MDTServer to Hyper-VHost
    Copy-Item "$($Global:DeploymentShare)\Boot\$($ISO)" $Global:HyperVISOFolder\ -Container -Force -ErrorAction Stop

    #Check if ISO exists
    $ISOFileExist = Test-Path ($Global:HyperVISOFolder + "\" + $ISO) -ErrorAction Stop
    If (!$ISOFileExist) {
        Write-Output "Unable to find ISO, exit"
        exit
    }

    #Check if VMSwitch on host exists
    $VMSwitchExist = Get-VMSwitch -Name $Global:SWitchName -ErrorAction SilentlyContinue
    If ($VMSwitchExist.Name -ne $Global:SWitchName) {
        Write-Output "Unable to find VMSwitch, exit"
        exit
    }

    #Create the VMs
    $RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
    Foreach ($TS in $RefTS) {
        #Set VMName to ID
        $VMName = $TS.ID

        #Check if VM exists
        $VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
        If ($VMexist.Name -eq $VMName) {
            Write-Output "VM already exist, exit"
            exit
        }

        $VM = New-VM �Name $VMname -Path $Global:VMLocation �MemoryStartupBytes $Global:StartUpRAM `
            -SwitchName $Global:SWitchName -NewVHDPath "$Global:VMLocation\$VMName\Virtual Hard Disks\$VMName.vhdx" `
            -NewVHDSizeBytes $Global:VHDSize `

        Add-VMDvdDrive -VM $VM -Path ($Global:HyperVISOFolder + "\" + $ISO)

        #Set
        Get-VM -Name $VMName | Set-VMProcessor -CompatibilityForMigrationEnabled $True
        Get-VM -Name $VMName | Set-VMProcessor -Count 2
        If ($Global:VLANID -and $Global:VLANID -ne "0") {
            Get-VM -Name $VMName | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $VLANID
        }
    }

    if ($RefTS.Count -eq 1) {
        #Start one VM
        $VMName = $RefTS.ID
        Start-VM -Name $VMName
        Start-Sleep 60
        $VM = Get-VM -Name $VMName
        $StartTime = Get-Date
        while ($VM.State -eq "Running") {
            Start-Sleep "120"
            $VM = Get-VM -Name $VMName
        }
        $EndTime = Get-Date
        $ElapsedTime = $EndTime - $StartTime
        If ($Global:ReportFrom -and $Global:ReportTo -and $Global:ReportSmtp) {
                Send-AutoGenReport $RefTS.Name $ElapsedTime $Global:ReportFrom $Global:ReportTo $Global:ReportSmtp
        }

        # Remove reference VM
        Remove-RefImage $VMName
    }
    else {
        #Start multiple VMs
        workflow Start-VMs {
            param(
                [System.Object[]]$RefTS,
                [string]$ReportFrom,
                [string]$ReportTo,
                [string]$ReportSmtp
            )

            Foreach -parallel ($TS in $RefTS) {
                $VMName = $TS.ID
                Start-VM -Name $VMName
                Start-Sleep 60
                $VM = Get-VM -Name $VMName
                $StartTime = Get-Date
                while ($VM.State -eq "Running") {
                    Start-Sleep "120"
                    $VM = Get-VM -Name $VMName
                }
                $EndTime = Get-Date
                $ElapsedTime = $EndTime - $StartTime
                If ($ReportFrom -and $ReportTo -and $ReportSmtp) {
                    Send-AutoGenReport $TS.Name $ElapsedTime $ReportFrom $ReportTo $ReportSmtp
                }

                # Remove reference VM
                Remove-RefImage $VMName
            }
        }

        Start-VMs $RefTS $Global:ReportFrom $Global:ReportTo $Global:ReportSmtp
    }
}

function Remove-AutoGenRefImages
{
    Get-FactoryConfig

    #Connect to MDT:
    $Null = Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue
    Remove-PSDrive MDT -ErrorAction SilentlyContinue
    $Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
    $MDTSettings = Get-ItemProperty MDT:
    $ISO = $MDTSettings.'Boot.x86.LiteTouchISOName'

    #Remove the VMs
    $RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
    Foreach ($TS in $RefTS) {
        #Set VMName to ID
        $VMName = $TS.ID

        #Check if VM exists
        $VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
        If ($VMexist.Name -eq $VMName) {
            Write-Output "Removing $VMName"
            $VMToRemove = Get-VM -Name $VMName
            $FolderPath = $VMToRemove.path
            if ($VMToRemove.state -eq "Running") {Stop-VM $VMToRemove -Force}
            $VMToRemove | Remove-VM -Force
            $FolderPath | Remove-Item -Force -Recurse
        }
    }
}

function New-RefImage
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        [Parameter(Mandatory=$false,
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true,
        ValueFromRemainingArguments=$false,
        Position=0)]
        [String]$TaskSequenceID
    )

    Get-FactoryConfig

    #Connect to MDT:
    Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
    Remove-PSDrive MDT -ErrorAction SilentlyContinue
    $Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
    $MDTSettings = Get-ItemProperty MDT:
    $ISO = $MDTSettings.'Boot.x86.LiteTouchISOName'

    #Check if ISO exists
    $ISOFileExist = Test-Path "$($Global:DeploymentShare)\Boot\$($ISO)" -ErrorAction SilentlyContinue
    If (!$ISOFileExist) {
        Write-Output "Unable to find ISO, exit"
        exit
    }

    #Create Folders
    $null = New-Item -Path $HyperVISOFolder -ItemType Directory -Force -ErrorAction SilentlyContinue

    #Copy the BootImage from MDTServer to Hyper-VHost
    Copy-Item "$($Global:DeploymentShare)\Boot\$($ISO)" $Global:HyperVISOFolder\ -Container -Force -ErrorAction Stop

    #Check if ISO exists
    $ISOFileExist = Test-Path ($Global:HyperVISOFolder + "\" + $ISO) -ErrorAction Stop
    If (!$ISOFileExist) {
        Write-Output "Unable to find ISO, exit"
        exit
    }

    #Check if VMSwitch on host exists
    $VMSwitchExist = Get-VMSwitch -Name $Global:SWitchName -ErrorAction SilentlyContinue
    If ($VMSwitchExist.Name -ne $Global:SWitchName) {
        Write-Output "Unable to find VMSwitch, exit"
        exit
    }

    #Check if VM exists
    $VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
    If ($VMexist.Name -eq $VMName) {
        Write-Output "VM already exist, exit"
        exit
    }

    $VM = New-VM �Name $TaskSequenceID -Path $Global:VMLocation �MemoryStartupBytes $Global:StartUpRAM `
        -SwitchName $Global:SWitchName `
        -NewVHDPath "$Global:VMLocation\$TaskSequenceID\Virtual Hard Disks\$TaskSequenceID.vhdx" `
        -NewVHDSizeBytes $Global:VHDSize 
    Add-VMDvdDrive -VM $VM -Path ($Global:HyperVISOFolder + "\" + $ISO)

    #Set
    Get-VM -Name $TaskSequenceID | Set-VMProcessor -CompatibilityForMigrationEnabled $True -VM $VM
    Get-VM -Name $TaskSequenceID | Set-VMProcessor -Count 2
    If ($Global:VLANID -ne "0") {
        Get-VM -Name $TaskSequenceID | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $VLANID
    }
}

function Remove-RefImage
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        [Parameter(Mandatory=$false,
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true,
        ValueFromRemainingArguments=$false,
        Position=0)]
        [String]$VMName
    )

    #Check if VM exists
    $VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
    If ($VMexist.Name -eq $VMName) {
        Write-Output "Removing $VMName"
        $VMToRemove = Get-VM -Name $VMName
        $FolderPath = $VMToRemove.path
        if ($VMToRemove.state -eq "Running") {Stop-VM $VMToRemove -Force}
        $VMToRemove | Remove-VM -Force
        $FolderPath | Remove-Item -Force -Recurse
    }
}

function Get-RefTaskSequence
{
    Get-FactoryConfig

    #Connect to MDT:
    Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
    Remove-PSDrive MDT -ErrorAction SilentlyContinue
    $Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force

    #Get TS
    $RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
    Foreach($TS in $RefTS) {
        New-Object PSObject -Property @{ 
            TaskSequenceID = $TS.ID
            Name = $TS.Name
            Comments = $TS.Comments
            Version = $TS.Version
            Enabled = $TS.enable
            LastModified = $TS.LastModifiedTime
        }
    }
}

function Send-AutoGenReport($ImageName, $ElapsedTime, $ReportFrom, $ReportTo, $ReportSmtp)
{
    $subject = "Image $ImageName"
    $encoding = [System.Text.Encoding]::UTF8

    $hours = [math]::floor($ElapsedTime.TotalHours)
    $mins = [int]$ElapsedTime.TotalMinutes - $hours*60
    $body = "Image [$ImageName] was builded at $hours h. $mins min."
    Send-MailMessage -From $ReportFrom -To $ReportTo -Subject $subject -SmtpServer $ReportSmtp -Encoding $encoding -BodyAsHtml $body
} 

Export-ModuleMember -function *