Src/LabVMDiskFile.ps1

function SetLabVMDiskDscResource {
<#
    .SYNOPSIS
        Copies the local DSC resources to a VHDX file.
#>

    [CmdletBinding()]
    param (
        ## The target VHDX modules path
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.String] $DestinationPath
    )
    process {
        $dscResourceModules = GetDscResourceModule -Path "$env:ProgramFiles\WindowsPowershell\Modules";
        foreach ($dscResourceModule in $dscResourceModules) {
            $targetModulePath = '{0}\{1}' -f $Destinationpath, $dscResourceModule.ModuleName;
            ## Check if path already exists and remove if necessary as it may be the wrong DSC resource version
            if (Test-Path -Path $targetModulePath -PathType Container) {
                WriteWarning -Message ($localized.RemovingDSCResourceModule -f $targetModulePath);
                Remove-Item -Path $targetModulePath -Recurse -Force -Confirm:$false;
            }
            WriteVerbose ($localized.AddingDSCResource -f $dscResourceModule.ModuleName, $dscResourceModule.ModuleVersion);
            Copy-Item -Path $dscResourceModule.Path -Destination $targetModulePath -Recurse -Force;
        }
    } #end process
} #end function SetLabVMDiskDscResource

function SetLabVMDiskResource {
<#
    .SYNOPSIS
        Copies lab resources to a VHDX file.
#>

    [CmdletBinding()]
    param (
        ## Lab DSC configuration data
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Collections.Hashtable]
        [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformationAttribute()]
        $ConfigurationData,

        ## Lab VM/Node name
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.String] $NodeName,

        ## Prefixed/suffixed lab VM/Node name
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.String] $DisplayName
    )
    begin {
        $hostDefaults = GetConfigurationData -Configuration Host;
    }
    process {
        ## Temporarily disable Windows Explorer popup disk initialization and format notifications
        ## http://blogs.technet.com/b/heyscriptingguy/archive/2013/05/29/use-powershell-to-initialize-raw-disks-and-partition-and-format-volumes.aspx
        Stop-Service -Name 'ShellHWDetection' -Force -ErrorAction Ignore;

        $vhdPath = ResolveLabVMDiskPath -Name $DisplayName;
        WriteVerbose ($localized.MountingDiskImage -f $VhdPath);
        $vhd = Mount-Vhd -Path $vhdPath -Passthru;
        [ref] $null = Get-PSDrive;
        $vhdDriveLetter = Get-Partition -DiskNumber $vhd.DiskNumber | Where-Object DriveLetter | Select-Object -Last 1 -ExpandProperty DriveLetter;
        Start-Service -Name 'ShellHWDetection';

        $destinationPath = '{0}:\{1}' -f $vhdDriveLetter, $hostDefaults.ResourceShareName;
        ExpandLabResource -ConfigurationData $ConfigurationData -Name $NodeName -DestinationPath $destinationPath;

        WriteVerbose ($localized.DismountingDiskImage -f $VhdPath);
        Dismount-Vhd -Path $VhdPath;
    } #end process
} #end function SetLabVMDiskResource

function SetLabVMDiskFile {
<#
    .SYNOPSIS
        Copies one or more files to a VHDX file.
#>

    [CmdletBinding()]
    param (
        ## Lab VM/Node name
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.String] $Name,

        ## Lab VM/Node configuration data
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.Collections.Hashtable] $NodeData,

        ## Local administrator password of the VM
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.CredentialAttribute()]
        $Credential,

        ## Lab VM/Node DSC .mof and .meta.mof configuration files
        [Parameter(ValueFromPipelineByPropertyName)]
        [System.String] $Path,

        ## Custom bootstrap script
        [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()]
        [System.String] $CustomBootstrap,

        ## CoreCLR
        [Parameter(ValueFromPipelineByPropertyName)]
        [System.Management.Automation.SwitchParameter] $CoreCLR
    )
    process {
        ## Temporarily disable Windows Explorer popup disk initialization and format notifications
        ## http://blogs.technet.com/b/heyscriptingguy/archive/2013/05/29/use-powershell-to-initialize-raw-disks-and-partition-and-format-volumes.aspx
        Stop-Service -Name 'ShellHWDetection' -Force -ErrorAction Ignore;

        $vhdPath = ResolveLabVMDiskPath -Name $NodeData.NodeDisplayName;
        WriteVerbose ($localized.MountingDiskImage -f $VhdPath);
        $vhd = Mount-Vhd -Path $vhdPath -Passthru;
        [ref] $null = Get-PSDrive;
        $vhdDriveLetter = Get-Partition -DiskNumber $vhd.DiskNumber |
                            Where-Object DriveLetter |
                                Select-Object -Last 1 -ExpandProperty DriveLetter;
        Start-Service -Name 'ShellHWDetection';

        ## Create Unattend.xml
        $newUnattendXmlParams = @{
            ComputerName = $NodeData.NodeName;
            Credential = $Credential;
            InputLocale = $NodeData.InputLocale;
            SystemLocale = $NodeData.SystemLocale;
            UserLocale = $NodeData.UserLocale;
            UILanguage = 'en-US';
            Timezone = $NodeData.Timezone;
            RegisteredOwner = $NodeData.RegisteredOwner;
            RegisteredOrganization = $NodeData.RegisteredOrganization;
        }
        WriteVerbose ($localized.SettingAdministratorPassword -f $Credential.GetNetworkCredential().Password);
        if ($NodeData.CustomData.ProductKey) {
            $newUnattendXmlParams['ProductKey'] = $NodeData.CustomData.ProductKey;
        }
        ## TODO: We probably need to be localise the \Windows\ and \Program Files\ directories?
        $unattendXmlPath = '{0}:\Windows\System32\Sysprep\Unattend.xml' -f $vhdDriveLetter;
        WriteVerbose ($localized.AddingUnattendXmlFile -f $unattendXmlPath);
        [ref] $null = SetUnattendXml @newUnattendXmlParams -Path $unattendXmlPath;

        $destinationPath = '{0}:\Program Files\WindowsPowershell\Modules' -f $vhdDriveLetter;
        WriteVerbose ($localized.AddingDSCResourceModules -f $destinationPath);
        SetLabVMDiskDscResource -DestinationPath $destinationPath;

        $bootStrapPath = '{0}:\BootStrap' -f $vhdDriveLetter;
        WriteVerbose ($localized.AddingBootStrapFile -f $bootStrapPath);
        if ($CustomBootStrap) {
            SetBootStrap -Path $bootStrapPath -CustomBootStrap $CustomBootStrap -CoreCLR:$CoreCLR;
        }
        else {
            SetBootStrap -Path $bootStrapPath -CoreCLR:$CoreCLR;
        }

        $setupCompleteCmdPath = '{0}:\Windows\Setup\Scripts' -f $vhdDriveLetter;
        WriteVerbose ($localized.AddingSetupCompleteCmdFile -f $setupCompleteCmdPath);
        SetSetupCompleteCmd -Path $setupCompleteCmdPath -CoreCLR:$CoreCLR;

        ## Copy MOF files to \BootStrap\localhost.mof and \BootStrap\localhost.meta.mof
        if ($Path) {
            $mofPath = Join-Path -Path $Path -ChildPath ('{0}.mof' -f $NodeData.NodeName);
            $destinationMofPath = Join-Path -Path $bootStrapPath -ChildPath 'localhost.mof';
            WriteVerbose ($localized.AddingDscConfiguration -f $destinationMofPath);
            if (-not (Test-Path -Path $mofPath)) { WriteWarning ($localized.CannotLocateMofFileError -f $mofPath); }
            else { Copy-Item -Path $mofPath -Destination $destinationMofPath -Force -ErrorAction Stop; }

            $metaMofPath = Join-Path -Path $Path -ChildPath ('{0}.meta.mof' -f $NodeData.NodeName);
            if (Test-Path -Path $metaMofPath -PathType Leaf) {
                $destinationMetaMofPath = Join-Path -Path $bootStrapPath -ChildPath 'localhost.meta.mof';
                WriteVerbose ($localized.AddingDscConfiguration -f $destinationMetaMofPath);
                Copy-Item -Path $metaMofPath -Destination $destinationMetaMofPath -Force;
            }
        }

        ## Copy certificates
        if (-not [System.String]::IsNullOrWhitespace($NodeData.ClientCertificatePath)) {
            $destinationCertificatePath = Join-Path -Path $bootStrapPath -ChildPath 'LabClient.pfx';
            $expandedClientCertificatePath = [System.Environment]::ExpandEnvironmentVariables($NodeData.ClientCertificatePath);
            WriteVerbose ($localized.AddingCertificate -f 'Client', $destinationCertificatePath);
            Copy-Item -Path $expandedClientCertificatePath -Destination $destinationCertificatePath -Force;
        }
        if (-not [System.String]::IsNullOrWhitespace($NodeData.RootCertificatePath)) {
            $destinationCertificatePath = Join-Path -Path $bootStrapPath -ChildPath 'LabRoot.cer';
            $expandedRootCertificatePath = [System.Environment]::ExpandEnvironmentVariables($NodeData.RootCertificatePath);
            WriteVerbose ($localized.AddingCertificate -f 'Root', $destinationCertificatePath);
            Copy-Item -Path $expandedRootCertificatePath -Destination $destinationCertificatePath -Force;
        }

        WriteVerbose ($localized.DismountingDiskImage -f $VhdPath);
        Dismount-Vhd -Path $VhdPath;
    } #end process
} #end function SetLabVMDiskFile