søndag 18. august 2013

System Center: Deployment with PDT

If you want to deploy System Center you can use PowerShell Deployment Toolkit created by Rob Willis (MSFT). Grab your copy from the TechNet Gallery here. For documentation you can read the deployment track of the Building Clouds TechNet blog.

Updated 30. august 2013: In response to question from Rohit Kochher
Updated 7. november 2013: New version of PDT 2.5.2708
Updated 3. january 2014: New version of PDT 2.5.2509
Updated 8. april 2014: New version of PDT 2.64.2608

Step 1: Download PDT

To get started, extract (current version) on a workstation or Hyper-V host. You will get three PowerShell scripts and three XML files.

The scripts are not signed so to run them you probably need to change the execution policy to unrestricted (you can change it back to restricted later if needed). In PowerShell (Run as Administrator) type:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
cd C:\Users\Administrator\Downloads\PDT2.64.2608
Also, files downloaded from internet would have to be unblocked. You can see if this is the case by running:
dir * | Get-Item -Stream "Zone.Identifier" -ErrorAction SilentlyContinue | Select FileName,Stream
And to unblock the scripts, you can run:
dir *.ps1 | Unblock-File
To verify this run this and you should get no output if all files are unblocked:
dir *.ps1 | Get-Item -Stream "Zone.Identifier" -ErrorAction SilentlyContinue | Select FileName,Stream

Change C:\Users\Administrator\Downloads\PDT2.64.2608 to the folder where you extracted PDT.

Step 2: Install prerequisites

Before running Downloader.ps1, install 7-Zip or WinRar and WebPI on the workstation/server.

Before running VMCreator.ps1 or Installer.ps1, install Hyper-V and Hyper-V Module for Windows PowerShell:
On Windows Server 2012 / 2012 R2:
Install-WindowsFeature -Name Hyper-V -IncludeManagementTools
On Windows 8 / 8.1:
Get-WindowsOptionalFeature -Online -FeatureName *hyper-v*all | Enable-WindowsOptionalFeature –Online

Step 3: Prepare for custom deployment

Modify Variable.xml to create your own custom deployment. A few tips:
  1. Verify free space and correct path for the Download and SourcePath variables.
    PS! If using VMCreator.ps1, keep the SourcePath to the default value of "$SystemDrive\Temp". The VMCreator.ps1 script will mount the Domain Controllers OSDisk on the host and then copy the installation files to the Temp folder on this disk. After the Domain Controller has started it will automatically install Active Directory and then the System Center roles to the other servers. If you modify SourcePath, this will fail.
  2. I suggest to set the Download and TempPath variables to the same as SourcePath variable.
  3. Remove Components you don't want to install.
  4. Remove the Roles for each of the removed Components.
  5. Remove/edit the SQL > Instance sections so they match the Roles.
  6. Remove the VMs not used. Remember to adjust Count for each VM and the total Count.
  7. Specify default VM folders under VMs > Default > VMFolder and VHDFolder.
  8. Specify default VM host under VMs > Default > Host. This is required. The VMCreator.ps1 script use a logic to distribute VMs on more than one host. If you want this to happen the Hyper-V hosts must have a name that end with three numbers, e.g. Host001, and the Host variable must be either ~CLOdd or ~CLEven.
  9. Specify default TimeZone (default is Pacific Standard Time) under VMs > Default.
    Example: <TimeZone>W. Europe Standard Time</TimeZone>
  10. If you would like VMCreator.ps1 to create Generation 2 VMs add VMCeneration under VMs > Default.
    Example: <VMGeneration>2</VMGeneration>
  11. Verify Processor and Memory settings for each VM to avoid overcommit.
    1. Remember that VMM role requires a minimum of 2048 MB Memory.
  12. Specify path to default parent disk under VMs > DefaultOSDisk.
  13. Specify path to default pagefile disk under VMs > DefaultPagefileDisk. PS! Only do this if you have prepared a template VM with a PagefileDisk. By that I mean that you must create the parent OS disk by installing it to a VM, then create the pagefile disk on this VM, move the pagefile to this disk, and then use sysprep to prepare for deployment using the disks from this VM.
  14. Specify the virtual switch under VMs > Default > NetworkAdapter > VirtualSwitch.
  15. If you would like to use existing Active Directory, remove the <Domain></Domain> section after <VMs> in Variable.xml
  16. Unless you have prepared certificates in the VMs for the Service Manager Component, make sure you set the following variables to false:
    To create a parent disk (step 12 above) from the original windows media:
    • Download Convert-WindowsImage.ps1.
    • Locate the path to install.wim file from Windows Server 2012 R2 media.
    • Execute the convertion script to create a parent disk:
    .\Convert-WindowsImage.ps1 -SourcePath D:\Installer\WindowsServer2012R2\sources\install.wim -VHDPath D:\VHD\en-E-WS12R2D-G-P.vhdx -VHDFormat VHDX -Edition ServerDataCenterEval -VHDType Dynamic -SizeBytes 40GB

    If you want to create a Generation 2 VM execute this command instead (remember to add VMGeneration to Variable.xml):

    .\Convert-WindowsImage.ps1 -SourcePath D:\Installer\WindowsServer2012R2\sources\install.wim -VHDPath D:\VHD\en-E-WS12R2D-G-P.vhdx -VHDFormat VHDX -Edition ServerDataCenterEval -VHDType Dynamic -SizeBytes 40GB -VHDPartitionStyle GPT

    Replace ServerDataCenterEval with the correct edition for the image you will use.

    An alternative to using the original windows media directly and the Convert-WindowsImage.ps1 script, would be to install the operating system on a VM the traditional way.

    After creating this VM, you probably want to have it updated with patches and hotfixes and set various settings etc. To do this you create a VM and mount the vhdx file to this VM. This is how we could do it with PowerShell:
    $VMName = 'WS12R2DG2Template'
    $VMMemMaxBytes = 2048MB
    $VMMemStartup = 1024MB
    $VMMemMinBytes = 512MB
    $ScriptPath = 'C:\PDTLab\Scripts'
    $ISOPath = 'C:\PDTLab\ISOs\Microsoft\Eval\ws2012r2'
    $VMPath = 'C:\PDTLab\VMs'
    $VHDName = $VMTemplateName + '_disk1.vhdx'
    $VHDFolder = 'Virtual Hard Disks'
    $VMSwitchName = 'Internal'
    $VMSwitchIP = ''
    $VMSwitchDNSIP = ''
    $LABName = 'SCLAB'
    If ((Get-VMSwitch –Name $VMSwitchName -ErrorAction SilentlyContinue) -eq $null) {
      New-VMSwitch –Name $VMSwitchName -SwitchType Internal
      Set-NetIPInterface -InterfaceAlias "vEthernet ($VMSwitchName)" -AddressFamily IPv4 -DHCP Disabled
      Remove-NetIPAddress -InterfaceAlias "vEthernet ($VMSwitchName)" -AddressFamily IPv4 -Confirm:$false
      New-NetIPAddress -InterfaceAlias "vEthernet ($VMSwitchName)" -IPAddress $VMSwitchIP -PrefixLength 24 -Type Unicast
      Set-DnsClientServerAddress -InterfaceAlias "vEthernet ($VMSwitchName)" -ServerAddresses $VMSwitchDNSIP
    If (-Not (Test-Path "$VMPath\$VMTemplateName\$VHDFolder" -PathType Container)) {New-Item -Path "$VMPath\$VMTemplateName\$VHDFolder" -ItemType 'Directory'}
    # PS! If you get errors when setting sourcepath to ISO file, extract the ISO file and set SourcePath to install.wim instead
    $ScriptPath\Convert-WindowsImage.ps1 -SourcePath "$ISOPath\$ISONameOS" -VHDPath "$VMPath\$VMTemplateName\$VHDFolder\$VHDName" -SizeBytes 40GB -VHDFormat vhdx -VHDType Dynamic -VHDPartitionStyle GPT -Edition ServerStandardEval
    $VM = New-VM -Name $VMTemplateName -Path $VMpath -Generation 2 -SwitchName $VMSwitchName
    Set-VM -Name $VMTemplateName -DynamicMemory -MemoryStartupBytes $VMMemStartup -MemoryMinimumBytes $VMMemMinBytes -MemoryMaximumBytes $VMMemMaxBytes -AutomaticStartAction Nothing -AutomaticStopAction ShutDown
    Get-VM -Name $VMTemplateName | Get-VMIntegrationService -Name 'Guest Service Interface' | where Enabled -eq $false | Enable-VMIntegrationService -Passthru
    Add-VMHardDiskDrive -VMName $VMTemplateName -Path "$VMPath\$VMTemplateName\$VHDFolder\$VHDName"
    Add-VMDvdDrive -VMName $VMTemplateName
    $VMDisk = Get-VMHardDiskDrive -VMName $VMTemplateName
    Set-VMFirmware -VMName $VMTemplateName -FirstBootDevice $VMDisk
    Start-VM -Name $VMTemplateName
    # Now we want to update windows (remember to reboot and update again until no more updates are available)
    # Also install recommended hotfixes. A good source for Operations Manager is Kevin Holman's blog (recently updated):
    # PS! If Getting error 800F0922 during Windows Update with KB2920189, try to disable Secure Boot on VM Settings, remember to reenable it after the update
    # Example of settings to configure:
    # - Turn On Remote Desktop
    # - Set Windows Update to Never check for updates
    # - Turn off IE Enhanced Security Configuration
    # - Set the Time Zone
    # - Set other vairous settings in PowerShell:
    # fsutil.exe 8dot3name set C: 1
    # fsutil.exe 8dot3name set 1
    # powercfg.exe /SETACTIVE 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
    # powercfg.exe /HIBERNATE off
    # gwmi Win32_UserAccount -Filter "name = 'Administrator'" | swmi -Arguments @{PasswordExpires = 0}
    # gwmi Win32_OSRecoveryConfiguration -EnableAllPrivileges | swmi -Arguments @{DebugInfoType=1}
    # gwmi Win32_OSRecoveryConfiguration -EnableAllPrivileges | swmi -Arguments @{AutoReboot=$false}
    # Push-Location
    # Set-Location HKLM:\SOFTWARE\Microsoft\ServerManager
    # Set-ItemProperty . DoNotOpenServerManagerAtLogon 1
    # Set-ItemProperty .\Oobe DoNotOpenInitialConfigurationTasksAtLogon 1
    # Pop-Location
    # Shut Down the VM after this and create a CheckPoint, call it Patched-PreSysprep
    Checkpoint-VM -Name $VMTemplateName -SnapshotName 'Patched-PreSysprep'
    # Start the VM and sysprep: C:\Windows\System32\Sysprep\sysprep.exe /quiet /generalize /oobe /shutdown
    # Create another snapshot, export it and use it as parent disk for the lab:
    Checkpoint-VM -Name $VMTemplateName -SnapshotName 'Current'
    If (-Not (Test-Path "$VMPath\$LABName" -PathType Container)) {New-Item -Path "$VMPath\$LABName" -ItemType 'Directory'}
    Export-VMSnapshot -VMName $VMTemplateName -Name 'Current' -Path "$VMPath\$LABName"
    # Cleanup Snapshots to make ready for later updates:
    Remove-VMSnapshot -VMName $VMTemplateName -Name 'Current'
    Restore-VMSnapshot -VMName $VMTemplateName -Name 'Patched-PreSysprep' -Confirm:$false
    Remove-VMSnapshot -VMName $VMTemplateName -Name 'Patched-PreSysprep'
    move -Path "$VMPath\$LABName\$VMTemplateName\$VHDFolder\$VHDName" -Destination "$VMPath\$LABName\ParentDisk.vhdx"
    rm -Path "$VMPath\$LABName\$VMTemplateName" -Recurse -Force
    # PS! use the same process with snapshots etc to update the Template. The Lab would have to be recreated if you would like to use a new and updated parent disk because a parent disk cannot be changed after it has become a parent for other VMs differencing disks.

    PS! If you are installing the Service Manager Portal, you will also need to create a parent disk for this VM from the Windows Server 2008 R2 media (Windows Server 2012 is not supported).

    Using existing roles is easy - you just add Existing="True" to the role line in Variable.xml:
    <Role Name="System Center 2012 R2 Virtual Machine Manager Database Server" Server="" Instance="MSSQLSERVER" Existing="True">

    When done, save the Variable.xml in the same folder as the PDT scripts.

    When setting up a virtual switch (step 13 above) for my LAB VMs I usually choose Internal virtual switch (see the example above on how to create it with PowerShell). For external access I create a Generation 1 VM and use a Legacy Network Adapter for the Interfaces (delete the default interface if using GUI). Connect it to the External and Internal network, install IPFire (How to install) and configure IPFire with RED and GREEN interface. I advice to install the router before running VMCreator.ps1.

    As an alternative to this you could attach the VMs directly to your local network by creating an External switch instead, like this (be aware that you will loose connectivity for a short period of time):
    New-VMSwitch -Name External -NetAdapterName (Get-NetAdapter |?{$_.Status -eq "Up" -and $_.NdisPhysicalMedium -eq 14}).Name

    Step 4: Download Software

    You probably want to start with the Downloader.ps1 script to get all the required software. However, the script will not download all the required software.

    You will have to download the following manually:
    Windows Server 2012 R2
    Windows Server 2012
    System Center 2012 R2 App Controller
    System Center 2012 R2 Configuration Manager
    System Center 2012 R2 Data Protection Manager
    System Center 2012 R2 Operations Manager
    System Center 2012 R2 Orchestrator
    System Center 2012 R2 Service Manager
    System Center 2012 R2 Virtual Machine Manager

    After downloading those bits manually, copy the content of the installation media to the appropriate folders in your source location before running Downloader.ps1. For Example:


    For Windows Server, it is not necessary to copy the entire media – just setup.exe from the root folder, and the entire sources\sxs folder are required.

    Start the download
    When ready, start the downloader like this (PS! do not use ISE):
    cd C:\Users\Administrator\Downloads\PDT2.64.2608
    .\Downloader.ps1 -DeploymentOnly

    The Downloader .ps1 will start by verifying the content of Download path (specified in Variable.xml), if all the software exist in this path, nothing will be downloaded. Otherwise it will start to download software to a subfolder called Download. This can take some time. On my system it took about 50 minutes to download about 4 GB of software with a total of 54 files and extracting 6 of the downloads (like SQL server and ADK). Required space for a full download of the System Center 2012 R2 with requirements is about 18 GB. The content of the subfolder called Download in the Download path can be deleted after completion, this will save you about 2.6 GB diskspace.

    One thing that I find a bit confusing is the Download and SourcePath variables in Variables.xml. To clarify:
    • The Downloader.ps1 script only use the Download folder, it do not care about the SourcePath folder.
    • The Installer.ps1 script only use the SourcePath folder, it do not care about the Download folder.
    • The VMCreator.ps1 script use both paths and will copy content from the Download folder to the SourcePath folder.

    To make it easier you could specify the same path for the Download folder as for the SourcePath folder in the Variables.xml.

    What if you already have some of the software?
    If you want to use existing software, you have to place the content of your media in the location that you have specified as the SourcePath in Variable.xml.

    This is how the top level folders in SourcePath should look like after download completion (if you install all components):

    Step 5: Create VMs

    PS! Skip this step if you already have the VMs or physical machines prepared with OS and already joined to the domain.

    When using the current version of VMCreator.ps1 I was unable to get the System Center Components installed without modifying the script.

    After the Domain Controller has been created I logged in to the DC and I could see that the System Center software could not be found.

    So I looked at the source code of VMCreator.ps1 and I quickly found the relevant lines:
    $SystemDrive = "$Drive`:"
    Invoke-Expression("`$SourcePath = `"$SourcePath`"")
    Write-Host "      Copying source $Installable "
    Start-Process -FilePath "robocopy.exe" -ArgumentList "$Download\$DownloadFolder $SourcePath\$DownloadFolder /e" -Wait -WindowStyle Hidden

    I could see that the Download variable was not beeing set like the SourcePath was. So I added it and restarted the process, after deleting the VMs, and now it worked. This is how it lookes after adding:
    Invoke-Expression("`$Download = `"$Download`"")
    $SystemDrive = "$Drive`:"
    Invoke-Expression("`$SourcePath = `"$SourcePath`"")
    Write-Host "      Copying source $Installable "
    Start-Process -FilePath "robocopy.exe" -ArgumentList "$Download\$DownloadFolder $SourcePath\$DownloadFolder /e" -Wait -WindowStyle Hidden

    If you have configured your Variable.xml, all you have to do now is to run the script VMCreator.ps1 on a Windows Server 2012 (or Windows 8) with the Hyper-V role and Hyper-V PowerShell Module installed.

    Step 6: Set the installation in motion

    If the VMCreator.ps1 script also created the Domain Controller the installation will start automatically on that server and should not be disturbed. It will start to install all the roles to the other servers. You can connect to the Domain Controller VM console in Hyper-V Manager to see the progress.

    If you already have a Domain Controller, and all the machines you want to deploy to are ready and joined to the domain, just start the Installer.ps1 script from the Domain Controller or another computer that is member of the domain. The Variables.xml will tell the script where to deploy what. The VMs need to have PowerShell Remoting enabled and a few firewall rules enabled. Do this in PowerShell on each VM before you start the Installer.ps1 script:
    reg add HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell /v ExecutionPolicy /t REG_SZ /d "Unrestricted" /f
    Enable-PSRemoting -Force
    Get-NetFirewallRule -Group "@FirewallAPI.dll,-30267" | Set-NetFirewallRule -Profile Domain -Enabled True
    Get-NetFirewallRule -Group "@FirewallAPI.dll,-28502" | Set-NetFirewallRule -Profile Domain -Enabled True
    Get-NetFirewallRule -Group "@FirewallAPI.dll,-34251" | Set-NetFirewallRule -Profile Domain -Enabled True

    I would strongly suggest to only use English (United States) as your system locale in Regional Settings. System Center components tend to have issues when this is changed. Good thing is that you can set Input language to anything you like.

    For debugging with the Installer.ps1 script look at the logs in C:\Users\<username>\AppData\Local\Installer on the computer where the Installer.ps1 was started. You may also want to look at logs on the individual server. You can use CMTrace.exe (included with Configuration Manager) to view the log files. CMTrace is also included with the System Center 2012 Configuration Manager Service Pack 1 Component Add-ons and Extensions.

    I was able to install all the roles to a Hyper-V host with 32GB memory in about 95 minutes. Creating the VMs took about 15 minutes, and installing System Center components took about 80 minutes. The VM disks was using about 205 GB diskspace after installation.