There are a few articles out there that detail DaRT Remote Viewer integration, I was unable to find one single article that covered MDOP 2013 R2 DaRT 8.1 integration with SCCM 2012 Task Sequences – specifically addressing the requirement for RemoteRecovery.exe to launch on WinPE load, not after clicking ‘Next’ on the initial start-up screen.
This article is focused on modification of existing Windows PE 4/5 images to facilitate RemoteRecovery.exe launch at boot. For a “true” DaRT image, refer to this article.
My requirements were ‘simple:’
- Launch DaRT RemoteRecovery on a static port during PXE-boot WinPE startup, allowing Operator selection of Task Sequence, including a WINRE/DaRT environment.
- Creation of shortcuts based upon Asset Tag if a Dell Platform, or IP address if not, on a remote File Share. Shortcuts should be created for both Dart 7 and DaRT 8.1 Remote Connections.
- I’m currently not using MDT-integration, so I also wanted to avoid using MDT components if possible – especiaslly for something as simple as this.
- The process should be automated for future/existing boot images – ideally using PowerShell.
Initially I reviewed using the Boot Image Prestart Files/Command however this meant that someone had to click ‘Next’ before RemoteRecovery was launched, unless the Task Sequence was mandatory.
Credits, the following sources were (bastardised!) used to compile the scripts/process outlined in this article:
- http://www.deploymentresearch.com/Research/tabid/62/EntryId/36/Software-Assurance-Pays-Off-Remote-Connection-to-WinPE-during-MDT-SCCM-deployments.aspx
- http://www.ideadata.co.uk/index.php/pxe-booting-dart-8-1-with-sccm-2012-including-remote-viewer/
- http://blog.coretech.dk/mip/adding-files-to-the-boot-image-in-cm2012/
- http://www.verboon.info/2013/04/integrating-dart-8-0-sp1-remote-connection-into-the-sccm-2012-osd-process/
Pre-requisite actions:
Check out my later post on creating the DaRT WinRE image itself, using Powershell. This will provide the required DartConfig.dat, PEremote.vbs and Unattend.xml files.
- Export files listed below, contained in DaRT Tools32.cab and Tools64.cab and DartConfig.dat*, to a remote file share or local folder. Ensure the files are extracted to folder structure as follows:
- amd64WindowsSystem32
- x86WindowsSystem32
- Create Unattend.xml and PEremote.vbs (code below). Place in folder structure as follows:
- Unattend.xml – root folder for each architecture created in #1.
- PEremote.vbs – WindowsSystem32 folder for each architecture created in #1.
- Download your vanilla winpe.wim files to a machine that has DISM cmdlets installed.
- Create a File Share, Username and Password for creation of DaRT Shortcuts
- Create and execute the DaRT-Enable.ps1 script (code below).
Example File/Folder Structure
Files/folders in amd64 folder:
Files in amd64WindowsSystem32 folder:
*Note you will need to extract the DartConfig.dat file form your existing DaRT image, or run through the wizard as outlined here: http://www.ideadata.co.uk/index.php/pxe-booting-dart-8-1-with-sccm-2012-including-remote-viewer/
Unattend.xml for amd64 platform (for x86 simply replace the “amd64” reference to “x86”):
<?xml version="1.0" encoding="utf-8"?> <unattend xmlns="urn:schemas-microsoft-com:unattend"> <settings pass="windowsPE"> <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> <Display> <ColorDepth>16</ColorDepth> <HorizontalResolution>1024</HorizontalResolution> <RefreshRate>60</RefreshRate> <VerticalResolution>768</VerticalResolution> </Display> <RunSynchronous> <RunSynchronousCommand wcm:action="add"> <Description>Start Remote Connection</Description> <Order>1</Order> <Path>CSCRIPT X:WindowsSystem32PEremote.vbs /ShortCutShare:\<Server FQDN>mapping$ /UserID:USER /UserDomain:DOM /UserPassword:PASSWORD</Path> </RunSynchronousCommand> </RunSynchronous> </component> </settings> </unattend>
PEremote.vbs code – note this is platform agnostic, use the same script for both x86 and amd64:
' Launch Remote Connect during WinPE Start-up - not using ZTIUtility Dim oEnv, oFSO, sShotcutName, strComputer Set oShell = CreateObject("WScript.Shell") Set oEnv = oShell.Environment("PROCESS") Set oFSO = CreateObject("Scripting.FileSystemObject") Set xmlDoc = CreateObject("Microsoft.XMLDOM") Set colNamedArguments = WScript.Arguments.Named Set dicIPList = CreateObject("Scripting.Dictionary") Set dicPortList = CreateObject("Scripting.Dictionary") strComputer = "." Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\" & strComputer & "rootcimv2") ' Validate all arguments are supplied. If colNamedArguments.Exists("ShortCutShare") AND colNamedArguments.Exists("UserID") _ AND colNamedArguments.Exists("UserDomain") AND colNamedArguments.Exists("UserPassword") Then strShortCutShare = colNamedArguments.Item("ShortCutShare") strUserID = colNamedArguments.Item("UserID") strUserDomain = colNamedArguments.Item("UserDomain") strUserPassword = colNamedArguments.Item("UserPassword") Else WScript.Echo "Example use: PEremote.vbs /ShortCutShare:\<server FQDN>mapping$ /UserID:USER /UserDomain:DOM /UserPassword:PASSWORD" WScript.Quit(1) End If 'Connect to target network share On Error Resume Next Set NetworkObject = CreateObject("WScript.Network") NetworkObject.MapNetworkDrive "", strShortCutShare, False, strUserDomain & "" & strUserID, strUserPassword If Err.Number <>0 Then WScript.Quit() End If On Error GoTo 0 'Check OS Environment is mapped to X: - if not script will fail If oEnv("SystemDrive") <> "X:" then Wscript.Quit(1) End if 'Check remote recovery executable is available If not oFSO.FileExists(oEnv("SystemRoot") & "System32RemoteRecovery.exe") then Wscript.Quit(1) End if ' Start RemoteRecovery.exe minimized sCmd = "remoterecovery.exe -nomessage" iRetVal = oSHell.Run(sCmd, 6, false) ' Sleep until we see the inv32.xml file; contains ticketID, port ID and IP addresses tries = 0 Do WScript.Sleep 1000 tries = tries + 1 Loop While not oFSO.FileExists("inv32.xml") and tries < 10 If not oFSO.FileExists("inv32.xml") then Wscript.Quit(1) End if 'Set oInv = oUtility.CreateXMLDOMObjectEx("inv32.xml") If xmlDoc.load("inv32.xml") = False Then ' Do nothing, required XML file missing Else Set oTicketNode = xmlDoc.SelectSingleNode("//A") strDartTicket = oTicketNode.Attributes.getNamedItem("ID").value ' First get the IPv4 entries (skipping locally-administered ones) i = 0 For each oIPNode in xmlDoc.SelectNodes("//L") If Instr(oIPNode.Attributes.getNamedItem("N").value, ":") = 0 and Left(oIPNode.Attributes.getNamedItem("N").value, 4) <> "169." then dicIPList.Add i, oIPNode.Attributes.getNamedItem("N").value dicPortList.Add i, oIPNode.Attributes.getNamedItem("P").value i=i+1 End if Next On Error Resume Next ' Then add the IPv6 entries i = 0 For each oIPNode in xmlDoc.SelectNodes("//L") If Instr(oIPNode.Attributes.getNamedItem("N").value, ":") > 0 then dicIPList.Add i, oIPNode.Attributes.getNamedItem("N").value dicPortList.Add i, oIPNode.Attributes.getNamedItem("P").value i=i+1 End if Next On Error GoTo 0 'For Dell Platforms we'll use the Asset Tag, otherwise the WinPE IPv4 address is used for Shortcut Name sShortcutName = assetTag 'Use subst to point to X: for long file names If not oFSO.DriveExists("C:") Then iRetVal = oShell.Run("cmd /c subst C: %SystemDrive%", 0, true) bSub = True End If Set oLink = oShell.CreateShortcut(strShortCutShare & "DaRTDaRT81_" & sShortcutName & ".lnk") oLink.TargetPath = """C:Program FilesMicrosoft DaRTv8.1DartRemoteViewer.exe""" oLink.Arguments = "-ticket=" & strDartTicket & " -ipaddress=" & dicIPList(0) & " -port=" & dicPortList(0) oLink.Save Set oLink = oShell.CreateShortcut(strShortCutShare & "DaRTDaRT7_" & sShortcutName & ".lnk") oLink.TargetPath = """C:Program FilesMicrosoft DaRT 7v7DartRemoteViewer.exe""" oLink.Arguments = "-ticket=" & strDartTicket & " -ipaddress=" & dicIPList(0) & " -port=" & dicPortList(0) oLink.Save End If Function assetTag 'Reads asset tag via WMI to generate machine name Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem") For Each objItem in colItems If inStr(objItem.Manufacturer, "Dell") > 0 Then Set colSMBIOS = objWMIService.ExecQuery("Select * from Win32_SystemEnclosure") For Each objSMBIOS in colSMBIOS assetTag = objSMBIOS.SerialNumber Next Else assetTag = dicIPList(0) End If Next End Function
When you have completed the above, open a Windows Powershell as Administrator and execute the DaRT-Enable.ps1 script.
DaRT-Enable.ps1 Code
Import-Module "Dism" $ErrorActionPreference = "Stop"; <# Ensure you have copied the following files into a local folder/remote file share: \(root) Unattend.xml - SUPPLIED in blog post. \Windows\System32: DartConfig.dat - created during DaRT image build, copy form Windows\System32 folder of image. FirewallExceptionChange.dll - ToolsXX.cab DaRT specific, obtain from MDOP 2013 R2 LockingHooks.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 mfc100u.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 MSDartCmn.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 msvcp100.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 msvcr100.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 PEremote.vbs - SUPPLIED in blog post. RdpCore.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 rdpencom.dll - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 RemoteRecovery.exe - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 WaitForConnection.exe - ToolsXX.cabDaRT specific, obtain from MDOP 2013 R2 #> # Function to confirm target computer is ping-able. Function Ping([string]$computerName) { if (Test-Connection -ComputerName $computerName -Quiet -Count 1) { return $true } else { write-host "Error, remote file server specified, $computerName, is inaccessible." -ForegroundColor Red -BackgroundColor Black exit 1 } } # Obtain source WIM file location. $imgPath = Read-Host "Enter path & file-name for WinPE4/5 image" $FileExists = Test-Path $imgPath While ($FileExists -ne $True) { $imgPath = Read-Host "Enter path & file-name for WinPE4/5 image" $FileExists = Test-Path $imgPath } # Get boot-image specific architecture While ($imgArch -ne "x86" -and $imgArch -ne "amd64") { $imgArch = Read-Host "Enter source WinPE4/5 image architecture(x86/amd64)" } #Find host name/local path of DaRT Files Share, if a UNC Path test server 'pings'. $dartFiles = Read-Host "Enter DaRT source UNC/local path (assumes x86 & amd64 sub-folders)" $arrDartFiles = $dartFiles.split("\") If ($arrDartFiles[0] -eq "") { #Null first item means UNC path due to "\\" $dartHost = $arrDartFiles[2] Ping($dartHost) } Else { $FileExists = Test-Path $dartFiles If ($FileExists -ne $True) { Write-Host "Supplied local DaRT files path invalid, please review." -ForegroundColor Red -BackgroundColor Black exit 1 } } #Build DaRT-enabled image $TempMountPath = "$([System.IO.Path]::GetTempPath())BootImage_$(Get-Random)"; New-Item -Path $TempMountPath -Type Directory -Force | Out-Null Write-Host "Mounting Windows Image $imgPath, in folder $TempMountPath. Index 1" Mount-WindowsImage -ImagePath $imgPath -Path $TempMountPath -Index 1 Write-host "Copying Unattend.xml file." copy-item "$dartFiles\$imgArch\Unattend.xml" $TempMountPath $peremoteSource = "$dartFiles\$imgArch\Windows\System32" Write-host "Copying DaRT RemoteRecovery files." #DaRT ToolsXX.cab files copy-item "$peRemoteSource\DartConfig.dat" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\FirewallExceptionChange.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\LockingHooks.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\mfc100u.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\MSDartCmn.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\msvcp100.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\msvcr100.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\RdpCore.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\rdpencom.dll" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\RemoteRecovery.exe" "$TempMountPath\Windows\System32" copy-item "$peRemoteSource\WaitForConnection.exe" "$TempMountPath\Windows\System32" Write-host "Copying Launcher Script." #Custom all-in-one launcher script copy-item "$peRemoteSource\PEremote.vbs" "$TempMountPath\Windows\System32" Write-host "Un-Mounting Windows Image." Dismount-WindowsImage -Path $TempMountPath -Save Remove-Item $tempMountPath -Force Write-host "Image preparation complete, now overwrite existing boot image file (make a backup!) and update distribution points."
Summary
The net result is realisation of all requirements:
- Launch DaRT RemoteRecovery on a static port during PXE-boot WinPE startup – check, achieved using Unattend.xml.
- Creation of shortcuts based upon Asset Tag if a Dell Platform, or IP address if not, on a remote File Share – check, shortcuts are created for both Dart 7 and DaRT 8.1 Remote Connections.
- I’m currently not using MDT-integration, so I also wanted to avoid using MDT components if possible – check, no MDT. A single launcher script has been created.
- The process should be automated for future/existing boot images – ideally using PowerShell – DaRT-Enable.ps1 script automates this task.