AftabHussain

ImageFactoryForHyper-VwithServer2008R2Support

Jun 23rd, 2015
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ### Original http://blogs.msdn.com/b/virtual_pc_guy/archive/2015/06/16/script-image-factory-for-hyper-v.aspx
  2. ### Modified to be able to build 2008 R2 images
  3. ### Changes required in the XML to remove HideLocalAccountScreen node
  4. ### PowerShell 2.0 doesn't have the unblock-file cmdlet, so added a check and a script to install PS 4.0:
  5. ### * Requires .NET 4.5.2 http://www.microsoft.com/en-gb/download/details.aspx?id=42642
  6. ### * Requires WMF 4.0 http://www.microsoft.com/en-gb/download/details.aspx?id=40855
  7. ### Aftab Hussain
  8. ### 23/06/2015
  9.  
  10. $workingDir = "C:\ImageFactory"
  11. $logFile = "$($workingDir)\Share\Details.csv"
  12. $factoryVMName = "Factory VM"
  13. $virtualSwitchName = "Virtual Switch"
  14. $ResourceDirectory = "$($workingDir)\Resources\Bits"
  15. $Organization = "The Power Elite"
  16. $Owner = "Ben Armstrong"
  17. $Timezone = "Pacific Standard Time"
  18. $adminPassword = "P@ssw0rd"
  19. $userPassword = "P@ssw0rd"
  20.  
  21. # Keys
  22. $Windows81Key = "..."
  23. $Windows2012R2Key = "..."
  24. $Windows8Key = "..."
  25. $Windows2012Key = "..."
  26. #$Windows2008R2Key = "YC6KT-GKW9T-YTKYR-T4X34-R7VHC"   ### Standard KMS Key
  27. $Windows2008R2Key = "74YFP-3QFB3-KQT8W-PMXWJ-7M648"   ### Datacenter KMS Key
  28.  
  29. # ISOs /  WIMs
  30. $2012Image = "$($workingDir)\ISOs\en_windows_server_2012_x64_dvd_915478.wim"
  31. $2012R2Image = "$($workingDir)\ISOs\en_windows_server_2012_r2_x64_dvd_2707946.wim"
  32. $2008R2Image = "$($workingDir)\ISOs\2008 R2.iso"
  33. $8x86Image = "$($workingDir)\ISOs\en_windows_8_x86_dvd_915417.wim"
  34. $8x64Image = "$($workingDir)\ISOs\en_windows_8_x64_dvd_915440.wim"
  35. $81x86Image = "$($workingDir)\ISOs\en_windows_8_1_x86_dvd_2707392.wim"
  36. $81x64Image = "$($workingDir)\ISOs\en_windows_8_1_x64_dvd_2707217.wim"
  37.  
  38. $startTime = get-date
  39.  
  40. ### Load Convert-WindowsImage
  41. . "$($workingDir)\Convert-WindowsImage.ps1"
  42.  
  43. ### Sysprep unattend XML
  44. $unattendSource = [xml]@"
  45. <?xml version="1.0" encoding="utf-8"?>
  46. <unattend xmlns="urn:schemas-microsoft-com:unattend">
  47.    <servicing></servicing>
  48.    <settings pass="specialize">
  49.        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  50.            <ComputerName>*</ComputerName>
  51.            <ProductKey>Key</ProductKey>
  52.            <RegisteredOrganization>Organization</RegisteredOrganization>
  53.            <RegisteredOwner>Owner</RegisteredOwner>
  54.            <TimeZone>TZ</TimeZone>
  55.        </component>
  56.        <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  57.             <fDenyTSConnections>false</fDenyTSConnections>
  58.         </component>
  59.         <component name="Microsoft-Windows-TerminalServices-RDP-WinStationExtensions" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  60.             <UserAuthentication>0</UserAuthentication>
  61.         </component>
  62.         <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  63.             <FirewallGroups>
  64.                 <FirewallGroup wcm:action="add" wcm:keyValue="RemoteDesktop">
  65.                     <Active>true</Active>
  66.                     <Profile>all</Profile>
  67.                     <Group>@FirewallAPI.dll,-28752</Group>
  68.                 </FirewallGroup>
  69.             </FirewallGroups>
  70.         </component>
  71.    </settings>
  72.    <settings pass="oobeSystem">
  73.        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  74.            <OOBE>
  75.                <HideEULAPage>true</HideEULAPage>
  76.                <HideLocalAccountScreen>true</HideLocalAccountScreen>
  77.                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
  78.                <NetworkLocation>Work</NetworkLocation>
  79.                <ProtectYourPC>1</ProtectYourPC>
  80.            </OOBE>
  81.            <UserAccounts>
  82.                <AdministratorPassword>
  83.                    <Value>password</Value>
  84.                    <PlainText>True</PlainText>
  85.                </AdministratorPassword>
  86.                <LocalAccounts>
  87.                   <LocalAccount wcm:action="add">
  88.                       <Password>
  89.                           <Value>password</Value>
  90.                           <PlainText>True</PlainText>
  91.                       </Password>
  92.                       <DisplayName>Demo</DisplayName>
  93.                       <Group>Administrators</Group>
  94.                       <Name>demo</Name>
  95.                   </LocalAccount>
  96.               </LocalAccounts>
  97.            </UserAccounts>
  98.            <AutoLogon>
  99.               <Password>
  100.                  <Value>password</Value>
  101.               </Password>
  102.               <Enabled>true</Enabled>
  103.               <LogonCount>1000</LogonCount>
  104.               <Username>Administrator</Username>
  105.            </AutoLogon>
  106.             <LogonCommands>
  107.                 <AsynchronousCommand wcm:action="add">
  108.                     <CommandLine>%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell -NoLogo -NonInteractive -ExecutionPolicy Unrestricted -File %SystemDrive%\Bits\Logon.ps1</CommandLine>
  109.                     <Order>1</Order>
  110.                 </AsynchronousCommand>
  111.             </LogonCommands>
  112.        </component>
  113.        <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  114.            <InputLocale>en-us</InputLocale>
  115.            <SystemLocale>en-us</SystemLocale>
  116.            <UILanguage>en-us</UILanguage>
  117.            <UILanguageFallback>en-us</UILanguageFallback>
  118.            <UserLocale>en-us</UserLocale>
  119.        </component>
  120.    </settings>
  121. </unattend>
  122. "@
  123.  
  124. function CSVLogger ([string]$vhd, [switch]$sysprepped) {
  125.  
  126.    $createLogFile = $false
  127.    $entryExists = $false
  128.    $logCsv = @()
  129.    $newEntry = $null
  130.  
  131.    # Check if the log file exists
  132.    if (!(test-path $logFile))
  133.       {$createLogFile = $true}
  134.    else
  135.       {$logCsv = import-csv $logFile
  136.        if (($logCsv.Image -eq $null) -or `
  137.            ($logCsv.Created -eq $null) -or `
  138.            ($logCsv.Sysprepped -eq $null) -or `
  139.            ($logCsv.Checked -eq $null))
  140.            {# Something is wrong with the log file
  141.             cleanupFile $logFile
  142.             $createLogFile = $true}
  143.             }
  144.  
  145.    if ($createLogFile) {$logCsv = @()} else {$logCsv = import-csv $logFile}
  146.  
  147.    # If we find an entry for the VHD, update it
  148.    foreach ($entry in $logCsv)
  149.       { if ($entry.Image -eq $vhd)
  150.         {$entryExists = $true
  151.          $entry.Checked = ((get-Date).ToShortDateString() + "::" + (Get-Date).ToShortTimeString())
  152.          if ($sysprepped) {$entry.Sysprepped = ((get-Date).ToShortDateString() + "::" + (Get-Date).ToShortTimeString())}
  153.         }
  154.       }
  155.  
  156.    # if no entry is found, create a new one
  157.    If (!$entryExists)
  158.       {$newEntry = New-Object PSObject -Property @{Image=$vhd; `
  159.                                                    Created=((get-Date).ToShortDateString() + "::" + (Get-Date).ToShortTimeString()); `
  160.                                                    Sysprepped=((get-Date).ToShortDateString() + "::" + (Get-Date).ToShortTimeString()); `
  161.                                                    Checked=((get-Date).ToShortDateString() + "::" + (Get-Date).ToShortTimeString())}}
  162.  
  163.    # Write out the CSV file
  164.    $logCsv | Export-CSV $logFile -notype
  165.    if (!($newEntry -eq $null)) {$newEntry | Export-CSV $logFile -notype -Append}
  166.    
  167. }
  168.  
  169. function Logger ([string]$systemName, [string]$message)
  170.     {# Function for displaying formatted log messages.  Also displays time in minutes since the script was started
  171.      write-host (Get-Date).ToShortTimeString() -ForegroundColor Cyan -NoNewline
  172.      write-host " - [" -ForegroundColor White -NoNewline
  173.      write-host $systemName -ForegroundColor Yellow -NoNewline
  174.      write-Host "]::$($message)" -ForegroundColor White}
  175.  
  176. # Helper function for no error file cleanup
  177. Function cleanupFile ([string]$file) {if (test-path $file) {Remove-Item $file}}
  178.  
  179. function GetUnattendChunk ([string]$pass, [string]$component, [xml]$unattend)
  180.     {# Helper function that returns one component chunk from the Unattend XML data structure
  181.      return $Unattend.unattend.settings | ? pass -eq $pass `
  182.                                         | select -ExpandProperty component `
  183.                                         | ? name -eq $component}
  184.  
  185. function makeUnattendFile ([string]$key, [string]$logonCount, [string]$filePath, [bool]$desktop = $false, [bool]$is32bit = $false, [bool]$is2008r2 = $false)
  186.     {# Composes unattend file and writes it to the specified filepath
  187.      
  188.      # Reload template - clone is necessary as PowerShell thinks this is a "complex" object
  189.      $unattend = $unattendSource.Clone()
  190.      
  191.      # Customize unattend XML
  192.      GetUnattendChunk "specialize" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.ProductKey = $key}
  193.      GetUnattendChunk "specialize" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.RegisteredOrganization = $Organization}
  194.      GetUnattendChunk "specialize" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.RegisteredOwner = $Owner}
  195.      GetUnattendChunk "specialize" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.TimeZone = $Timezone}
  196.      GetUnattendChunk "oobeSystem" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.UserAccounts.AdministratorPassword.Value = $adminPassword}
  197.      GetUnattendChunk "oobeSystem" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.AutoLogon.Password.Value = $adminPassword}
  198.      GetUnattendChunk "oobeSystem" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.AutoLogon.LogonCount = $logonCount}
  199.      if ($desktop)
  200.          {
  201.          GetUnattendChunk "oobeSystem" "Microsoft-Windows-Shell-Setup" $unattend | %{$_.UserAccounts.LocalAccounts.LocalAccount.Password.Value = $userPassword}
  202.          }
  203.      else
  204.          {# Desktop needs a user other than "Administrator" to be present
  205.           # This will remove the creation of the other user for server images
  206.           $ns = New-Object System.Xml.XmlNamespaceManager($unattend.NameTable)
  207.           $ns.AddNamespace("ns", $unattend.DocumentElement.NamespaceURI)
  208.           $node = $unattend.SelectSingleNode("//ns:LocalAccounts", $ns)
  209.           $node.ParentNode.RemoveChild($node) | Out-Null}
  210.  
  211.      if ($is2008r2)
  212.     {
  213.       # Removes the HideLocalAccountScreen Node, as this isn't available in 2008 R2
  214.       $ns = New-Object System.Xml.XmlNamespaceManager($unattend.NameTable)
  215.           $ns.AddNamespace("ns", $unattend.DocumentElement.NamespaceURI)
  216.           $node = $unattend.SelectSingleNode("//ns:HideLocalAccountScreen", $ns)
  217.           $node.ParentNode.RemoveChild($node) | Out-Null
  218.     }
  219.      
  220.      if ($is32bit) {$unattend.InnerXml = $unattend.InnerXml.Replace('processorArchitecture="amd64"', 'processorArchitecture="x86"')}
  221.  
  222.      # Write it out to disk
  223.      cleanupFile $filePath; $Unattend.Save($filePath)}
  224.  
  225. Function createRunAndWaitVM ([string]$vhd, [string]$gen) {
  226.       # Function for whenever I have a VHD that is ready to run
  227.       new-vm $factoryVMName -MemoryStartupBytes 2048mb -VHDPath $vhd -Generation $Gen `
  228.                             -SwitchName $virtualSwitchName | Out-Null
  229.       set-vm -Name $factoryVMName -ProcessorCount 2
  230.       Start-VM $factoryVMName
  231.  
  232.       # Give the VM a moment to start before we start checking for it to stop
  233.       Sleep -Seconds 10
  234.  
  235.       # Wait for the VM to be stopped for a good solid 5 seconds
  236.       do {$state1 = (Get-VM | ? name -eq $factoryVMName).State; sleep -Seconds 5
  237.           $state2 = (Get-VM | ? name -eq $factoryVMName).State; sleep -Seconds 5}
  238.           until (($state1 -eq "Off") -and ($state2 -eq "Off"))
  239.  
  240.       # Clean up the VM
  241.       Remove-VM $factoryVMName -Force}
  242.  
  243. Function MountVHDandRunBlock ([string]$vhd, [scriptblock]$block) {
  244.       # This function mounts a VHD, runs a script block and unmounts the VHD.
  245.       # Drive letter of the mounted VHD is stored in $driveLetter - can be used by script blocks
  246.       $driveLetter = (Mount-VHD $vhd –passthru | Get-Disk | Get-Partition | Get-Volume).DriveLetter
  247.       &$block
  248.       dismount-vhd $vhd
  249.  
  250.       # Wait 2 seconds for activity to clean up
  251.       Start-Sleep -Seconds 2
  252.       }
  253.  
  254. ### Update script block
  255. $updateCheckScriptBlock = {
  256.      # Clean up unattend file if it is there
  257.      if (test-path "$ENV:SystemDrive\Unattend.xml") {Remove-Item -Force "$ENV:SystemDrive\Unattend.xml"}
  258.  
  259.      # Install PowerShell 4.0 if version is less than 4.0
  260.      if ($PSVersionTable.PSVersion -lt '4.0')
  261.      {cmd.exe /c "$ENV:SystemDrive\Bits\NDP452-KB2901907-x86-x64-AllOS-ENU.exe /passive /norestart"
  262.       cmd.exe /c "$ENV:SystemDrive\Bits\Windows6.1-KB2819745-x64-MultiPkg.msu /quiet"
  263.      shutdown -r -t 0}
  264.      
  265.      # Check to see if files need to be unblocked - if they do, do it and reboot
  266.      if ((Get-ChildItem $env:SystemDrive\Bits\PSWindowsUpdate | `
  267.           get-item -Stream "Zone.Identifier" -ErrorAction SilentlyContinue).Count -gt 0)
  268.         {Get-ChildItem $env:SystemDrive\Bits\PSWindowsUpdate  | Unblock-File
  269.          invoke-expression 'shutdown -r -t 0'}
  270.  
  271.      # To get here - the files are unblocked
  272.      import-module $env:SystemDrive\Bits\PSWindowsUpdate\PSWindowsUpdate
  273.  
  274.      # Check if any updates are needed - leave a marker if there are
  275.      if ((Get-WUList).Count -gt 0)
  276.           {if (!(test-path $env:SystemDrive\Bits\changesMade.txt))
  277.           {New-Item $env:SystemDrive\Bits\changesMade.txt -type file}}
  278.  
  279.      # Apply all the updates
  280.      Get-WUInstall -AcceptAll -IgnoreReboot -IgnoreUserInput -NotCategory "Language packs"
  281.  
  282.      # Reboot if needed - otherwise shutdown because we are done
  283.      if (Get-WURebootStatus -Silent) {invoke-expression 'shutdown -r -t 0'}
  284.      else {invoke-expression 'shutdown -s -t 0'}}
  285.  
  286. ### Sysprep script block
  287. $sysprepScriptBlock = {
  288.      # Windows 10 issue - if the tiledatamodelsvc is running, it must be stopped first
  289.      get-service | ? name -eq tiledatamodelsvc | stop-service    
  290.          
  291.      $unattendedXmlPath = "$ENV:SystemDrive\Bits\Unattend.xml"
  292.      & "$ENV:SystemRoot\System32\Sysprep\Sysprep.exe" `/generalize `/oobe `/shutdown `/unattend:"$unattendedXmlPath"}
  293.  
  294. ### Post Sysprep script block
  295. $postSysprepScriptBlock = {
  296.      Remove-Item -Force "$ENV:SystemDrive\Unattend.xml"
  297.      # Put any code you want to run Post sysprep here
  298.      }
  299.  
  300. # This is the main function of this script
  301. Function RunTheFactory([string]$FriendlyName, `
  302.                        [string]$ISOFile, `
  303.                        [string]$ProductKey, `
  304.                        [string]$SKUEdition, `
  305.                        [bool]$desktop = $false, `
  306.                        [bool]$is32bit = $false, `
  307.                        [bool]$is2008r2 = $false, `
  308.                        [switch]$Generation2) {
  309.  
  310.    logger $FriendlyName "Starting a new cycle!"
  311.  
  312.    # Setup a bunch of variables
  313.    $sysprepNeeded = $true
  314.    $baseVHD = "$($workingDir)\bases\$($FriendlyName)-base.vhdx"
  315.    $updateVHD = "$($workingDir)\$($FriendlyName)-update.vhdx"
  316.    $sysprepVHD = "$($workingDir)\$($FriendlyName)-sysprep.vhdx"
  317.    $finalVHD = "$($workingDir)\share\$($FriendlyName).vhdx"
  318.    if ($Generation2) {$VHDPartitionStyle = "GPT"; $Gen = 2} else {$VHDPartitionStyle = "MBR"; $Gen = 1}
  319.  
  320.    logger $FriendlyName "Checking for existing Factory VM"
  321.  
  322.    # Check if there is already a factory VM - and kill it if there is
  323.    If ((Get-VM | ? name -eq $factoryVMName).Count -gt 0)
  324.       {stop-vm $factoryVMName -TurnOff -Confirm:$false -Passthru | Remove-VM -Force}
  325.  
  326.    # Check for a base VHD
  327.    if (!(test-path $baseVHD)) {
  328.       # No base VHD - we need to create one
  329.       logger $FriendlyName "No base VHD!"
  330.  
  331.       # Make unattend file
  332.       logger $FriendlyName "Creating unattend file for base VHD"
  333.       # Logon count is just "large number"
  334.       makeUnattendFile -key $ProductKey -logonCount "1000" -filePath "$($workingDir)\unattend.xml" -desktop $desktop -is32bit $is32bit -is2008r2 $is2008r2
  335.      
  336.       # Time to create the base VHD
  337.       logger $FriendlyName "Create base VHD using Convert-WindowsImage.ps1"
  338.       $ConvertCommand = "Convert-WindowsImage"
  339.       $ConvertCommand = $ConvertCommand + " -SourcePath `"$ISOFile`" -VHDPath `"$baseVHD`""
  340.       $ConvertCommand = $ConvertCommand + " -SizeBytes 80GB -VHDFormat VHDX -UnattendPath `"$($workingDir)\unattend.xml`""
  341.       $ConvertCommand = $ConvertCommand + " -Edition $SKUEdition -VHDPartitionStyle $VHDPartitionStyle"
  342.  
  343.       Invoke-Expression "& $ConvertCommand"
  344.  
  345.       # Clean up unattend file - we don't need it any more
  346.       logger $FriendlyName "Remove unattend file now that that is done"
  347.       cleanupFile "$($workingDir)\unattend.xml"
  348.  
  349.       logger $FriendlyName "Mount VHD and copy bits in, also set startup file"
  350.       MountVHDandRunBlock $baseVHD {
  351.                           # Copy ResourceDirectory in
  352.                           copy-item ($ResourceDirectory) -Destination ($driveLetter + ":\") -Recurse
  353.                           # Create first logon script
  354.                           $updateCheckScriptBlock | Out-String | Out-File -FilePath "$($driveLetter):\Bits\Logon.ps1" -Width 4096}
  355.  
  356.       logger $FriendlyName "Create virtual machine, start it and wait for it to stop..."
  357.       createRunAndWaitVM $baseVHD $Gen
  358.  
  359.       # Remove Page file
  360.       logger $FriendlyName "Removing the page file"
  361.       MountVHDandRunBlock $baseVHD {attrib -s -h "$($driveLetter):\pagefile.sys"
  362.                                     cleanupFile "$($driveLetter):\pagefile.sys"}
  363.  
  364.       # Compact the base file
  365.       logger $FriendlyName "Compacting the base file"
  366.       optimize-vhd -Path $baseVHD -Mode Full}
  367.    else
  368.       {# The base VHD existed - time to check if it needs an update
  369.        logger $FriendlyName "Base VHD exists - need to check for updates"
  370.  
  371.        # create new diff to check for updates
  372.        logger $FriendlyName "Create new differencing disk to check for updates"
  373.        cleanupFile $updateVHD; new-vhd -Path $updateVHD -ParentPath $baseVHD | Out-Null
  374.  
  375.        logger $FriendlyName "Copy login file for update check, also make sure flag file is cleared"
  376.        MountVHDandRunBlock $updateVHD {
  377.                            # Make the UpdateCheck script the logon script, make sure update flag file is deleted before we start
  378.                            cleanupFile "$($driveLetter):\Bits\changesMade.txt"
  379.                            cleanupFile "$($driveLetter):\Bits\Logon.ps1"
  380.                            $updateCheckScriptBlock | Out-String | Out-File -FilePath "$($driveLetter):\Bits\Logon.ps1" -Width 4096}
  381.  
  382.        logger $FriendlyName "Create virtual machine, start it and wait for it to stop..."
  383.        createRunAndWaitVM $updateVHD $Gen
  384.  
  385.        # Mount the VHD
  386.        logger $FriendlyName "Mount the differencing disk"
  387.        $driveLetter = (Mount-VHD $updateVHD –passthru | Get-Disk | Get-Partition | Get-Volume).DriveLetter
  388.        
  389.        # Check to see if changes were made
  390.        logger $FriendlyName "Check to see if there were any updates"
  391.        if (test-path "$($driveLetter):\Bits\changesMade.txt") {cleanupFile "$($driveLetter):\Bits\changesMade.txt"; logger $FriendlyName "Updates were found"}
  392.        else {logger $FriendlyName "No updates were found"; $sysprepNeeded = $false}
  393.  
  394.        # Dismount
  395.        logger $FriendlyName "Dismount the differencing disk"
  396.        dismount-vhd $updateVHD
  397.  
  398.        # Wait 2 seconds for activity to clean up
  399.       Start-Sleep -Seconds 2
  400.  
  401.        # If changes were made - merge them in.  If not, throw it away
  402.        if ($sysprepNeeded) {logger $FriendlyName "Merge the differencing disk"; Merge-VHD -Path $updateVHD -DestinationPath $baseVHD}
  403.        else {logger $FriendlyName "Delete the differencing disk"; CSVLogger $finalVHD; cleanupFile $updateVHD}
  404.        }
  405.  
  406.    # Final Check - if the final VHD is missing - we need to sysprep and make it
  407.    if (!(test-path $finalVHD)) {$sysprepNeeded = $true}
  408.  
  409.    if ($sysprepNeeded)
  410.       {# create new diff to sysprep
  411.        logger $FriendlyName "Need to run Sysprep"
  412.        logger $FriendlyName "Creating differencing disk"
  413.        cleanupFile $sysprepVHD; new-vhd -Path $sysprepVHD -ParentPath $baseVHD | Out-Null
  414.  
  415.        logger $FriendlyName "Mount the differencing disk and copy in files"
  416.        MountVHDandRunBlock $sysprepVHD {
  417.                            # Make unattend file
  418.                            makeUnattendFile -key $ProductKey -logonCount "1" -filePath "$($driveLetter):\Bits\unattend.xml" -desktop $desktop -is32bit $is32bit -is2008r2 $is2008r2
  419.                            # Make the logon script
  420.                            cleanupFile "$($driveLetter):\Bits\Logon.ps1"
  421.                            $sysprepScriptBlock | Out-String | Out-File -FilePath "$($driveLetter):\Bits\Logon.ps1" -Width 4096}
  422.  
  423.        logger $FriendlyName "Create virtual machine, start it and wait for it to stop..."
  424.        createRunAndWaitVM $sysprepVHD $Gen
  425.  
  426.        logger $FriendlyName "Mount the differencing disk and cleanup files"
  427.        MountVHDandRunBlock $sysprepVHD {
  428.                            cleanupFile "$($driveLetter):\Bits\unattend.xml"
  429.                            # Make the logon script
  430.                            cleanupFile "$($driveLetter):\Bits\Logon.ps1"
  431.                            $postSysprepScriptBlock | Out-String | Out-File -FilePath "$($driveLetter):\Bits\Logon.ps1" -Width 4096}
  432.  
  433.        # Remove Page file
  434.        logger $FriendlyName "Removing the page file"
  435.        MountVHDandRunBlock $sysprepVHD {attrib -s -h "$($driveLetter):\pagefile.sys"
  436.                                         cleanupFile "$($driveLetter):\pagefile.sys"}
  437.  
  438.        # Produce the final disk
  439.        cleanupFile $finalVHD
  440.        logger $FriendlyName "Convert differencing disk into pristine base image"
  441.        Convert-VHD -Path $sysprepVHD -DestinationPath $finalVHD -VHDType Dynamic
  442.        logger $FriendlyName "Delete differencing disk"
  443.        CSVLogger $finalVHD -sysprepped
  444.        cleanupFile $sysprepVHD
  445.       }
  446.    }
  447.  
  448. #RunTheFactory -FriendlyName "Windows Server 2012 R2 DataCenter with GUI" -ISOFile $2012R2Image -ProductKey $Windows2012R2Key -SKUEdition "ServerDataCenter"
  449. #RunTheFactory -FriendlyName "Windows Server 2012 R2 DataCenter Core" -ISOFile $2012R2Image -ProductKey $Windows2012R2Key -SKUEdition "ServerDataCenterCore"
  450. #RunTheFactory -FriendlyName "Windows Server 2012 R2 DataCenter with GUI - Gen 2" -ISOFile $2012R2Image -ProductKey $Windows2012R2Key -SKUEdition "ServerDataCenter" -Generation2
  451. #RunTheFactory -FriendlyName "Windows Server 2012 R2 DataCenter Core - Gen 2" -ISOFile $2012R2Image -ProductKey $Windows2012R2Key -SKUEdition "ServerDataCenterCore" -Generation2
  452. #RunTheFactory -FriendlyName "Windows Server 2012 DataCenter with GUI" -ISOFile $2012Image -ProductKey $Windows2012Key -SKUEdition "ServerDataCenter"
  453. #RunTheFactory -FriendlyName "Windows Server 2012 DataCenter Core" -ISOFile $2012Image -ProductKey $Windows2012Key -SKUEdition "ServerDataCenterCore"
  454. #RunTheFactory -FriendlyName "Windows Server 2012 DataCenter with GUI - Gen 2" -ISOFile $2012Image -ProductKey $Windows2012Key -SKUEdition "ServerDataCenter" -Generation2
  455. #RunTheFactory -FriendlyName "Windows Server 2012 DataCenter Core - Gen 2" -ISOFile $2012Image -ProductKey $Windows2012Key -SKUEdition "ServerDataCenterCore" -Generation2
  456. #RunTheFactory -FriendlyName "Windows 8.1 Professional" -ISOFile $81x64Image -ProductKey $Windows81Key -SKUEdition "Professional" -desktop $true
  457. #RunTheFactory -FriendlyName "Windows 8.1 Professional - Gen 2" -ISOFile $81x64Image -ProductKey $Windows81Key -SKUEdition "Professional" -Generation2  -desktop $true
  458. #RunTheFactory -FriendlyName "Windows 8.1 Professional - 32 bit" -ISOFile $81x86Image -ProductKey $Windows81Key -SKUEdition "Professional" -desktop $true -is32bit $true
  459. #RunTheFactory -FriendlyName "Windows 8 Professional" -ISOFile $8x64Image -ProductKey $Windows8Key -SKUEdition "Professional" -desktop $true
  460. #RunTheFactory -FriendlyName "Windows 8 Professional - Gen 2" -ISOFile $8x64Image -ProductKey $Windows8Key -SKUEdition "Professional" -Generation2 -desktop $true
  461. #RunTheFactory -FriendlyName "Windows 8 Professional - 32 bit" -ISOFile $8x86Image -ProductKey $Windows8Key -SKUEdition "Professional" -desktop $true -is32bit $true
  462. RunTheFactory -FriendlyName "Windows Server 2008 R2 DataCenter with GUI" -ISOFile $2008R2Image -ProductKey $Windows2008R2Key -SKUEdition "ServerDataCenter" -is2008r2 $true
Add Comment
Please, Sign In to add comment