VNC, ConfigMgr and WINPE

Customer asked me to hobble together a solution, that would allow them to VNC into a WINPE session as soon as WINPE has finished starting up, and before the ConfigMgr pre-execution hook kicked in. Someone still needs to boot WINPE and look for the IP, but once the IP lease is issued, it’ll be reused by the VM if WINPE is rebooted, making a reconnection reasonably reliable.

If you try this approach using ConfigMgr’s pre-execution hook, it won’t kick in until someone interacts with the ConfigMgr Task Sequence wizards welcome screen, and click’s Next, at which point the script is launched.

What I carved out was made so, using WINPE from ADK 10.1.16299.15, on ConfigMgr Current Branch (1805 TP)

I tried to leverage startnet.cmd right off the bat, pouring in my additions, and during my final tests looking like this:

wpeinit.exe
%WINDIR%\System32\wpeutil.exe DisableFirewall
%WINDIR%\regedit.exe -s “%SYSTEMDRIVE%\Program Files\TightVNC\TightVNCServerSettings.reg”
“%SYSTEMDRIVE%\Program Files\TightVNC\tvnserver.exe” -install -silent
“%SYSTEMDRIVE%\Program Files\TightVNC\tvnserver.exe” -start -silent

Didn’t work.

But I read from several sources, including Microsoft, that you just need to add your commands to startnet.cmd, and they will be executed before WINPE is finished starting up.

Wpeinit.exe would not launch my fun stuff, the log in windows\system32 showed that it had started up, but none of my fancy stuff happened.

I tried variations:

%WINDIR%\System32\wpeutil.exe InitializeNetwork
%WINDIR%\System32\wpeutil.exe DisableFirewall
%WINDIR%\regedit.exe -s “%SYSTEMDRIVE%\Program Files\TightVNC\TightVNCServerSettings.reg”
“%SYSTEMDRIVE%\Program Files\TightVNC\tvnserver.exe” -install -silent
“%SYSTEMDRIVE%\Program Files\TightVNC\tvnserver.exe” -start -silent

I even tried to nest the cmd scripts, so startnet.cmd called wpeinit.exe, and then invoked startnet2.cmd, which contained the calls to configure for and launch VNC.

No luck.

If I look back, no doubt I’ll figure out why, or maybe you can explain if you’ve come across this, I put it down to ConfigMgr being involved, and the boot process for WINPE modified.

Instead, I turned to unattend.xml, and instructing wpeinit.exe to read it from the root of the wim, so as to process a RunSynchronous command, which worked like a champ.

Since it was a variant on what I was seeing, in how to achieve the end goal of launching VNC from WINPE early on, I thought I’d blog a guide on how to get it setup and working.

First the high-level steps

  • Download TightVNC and prepare the files
  • Insert TightVNC files into your sites boot wim
  • Create unattend.xml for WINPE, and insert into the wim
  • Modify startnet.cmd and insert Startnet2.cmd file into the wim
  • Update your sites boot image on the DP
  • Create new boot media (if not exclusively relying on PXE) using the modified boot image

A VNC alternative can be used, but most likely will require tweaks to how it is configured, and which files to bring across to the boot wim.

Download TightVNC and prepare the files

You can fetch TightVNC from here.

TightVNC Home

  • Create a temporary folder called TightVNC, we’re going to use this folder as the repository destined for the WINPE boot image
  • Install the TightVNC product on any device, it doesn’t have to reside on the Site server, we just want the files and the registry once the VNC service is configured
  • Once TightVNC is installed, launch and configure the TightVNC server, most importantly setting the admin\viewer passwords
  • Once configured, head to REGEDIT, and export the HKEY_LOCAL_MACHINE\SOFTWARE\TightVNC\Server registry key to your temporary TightVNC folder, and call it TightVNCServerSettings.reg
  • Now navigate to the TightVNC installation folder
  • Copy LICENSE.txt, the two screenhook DLL’s, the tnvserver.exe and hookldr.exe files, into the temporary TightVNC folder

Insert TightVNC files into boot wim

We now need to mount your site servers boot wim, we’ll focus on the x64 architecture boot image, you can easily switch to the x86 if that is required.

  • On the Site server, open up an elevated CMD prompt as administrator
  • Create a new folder to act as your mount folder for this WIM, C:\MOUNTWIM for example
  • From the CMD prompt, navigate to the site servers installation folder, then into OSD and then boot, you’ll see the i386 (x86) and x64 folders, both of which contain the latest boot.wim, and the site’s version of that boot.wim which, if it has been distributed, is out on the distribution points
  • Type the following DISM command into your elevated CMD prompt

DISM /Mount-WIM /WimFile:boot.wim /index:1 /MountDir:c\MOUNTWIM

You should get an operated completed successfully message like this:

Deployment Image Servicing and Management tool
Version: 10.0.14393.0

Mounting image
[==========================100.0%==========================]
The operation completed successfully.

  • Now open File Explorer, navigate to your C:\MOUNTWIM folder
  • At this point, if the folder is empty, something went wrong with the mount, review and come back
  • Navigate into Program Files
  • Copy the custom TightVNC folder you made containing the selection of TightVNC files, into Program Files

image

Create unattend.xml for WINPE

This step requires some fiddling around to get done. You are going to need to generate an unattend XML that WINPE can use, or scrape what I show down below.

You can do this using Windows System Image Manager, loading in the install.wim from a Win10 ISO, and then adding the amd64_Microsoft-Windows-Setup section to the WindowsPE pass, add a new RunSynchronousCommand like this:

image

Order: 1

Path: %WINDIR%\System32\Startnet2.cmd

  • Click on the amd64_Microsoft-Windows-Setup step and change EnableFirewall to false
  • Save the answer file to C:\MOUNTWIM as unattend.xml
  • Open unattend.xml in notepad now that it has been saved, and clip out the path to the ISO and save the file back, so that it looks like this:

cpi:offlineImage cpi:source=””

Go have a look at the XML, it should look very similar to this:

<?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” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
             <RunSynchronous>
                 <RunSynchronousCommand wcm:action=”add”>
                     <Order>1</Order>
                     <Path>%WINDIR%\System32\startnet2.cmd</Path>
                     <Description>Run custom script</Description>
                 </RunSynchronousCommand>
             </RunSynchronous>
             <EnableFirewall>false</EnableFirewall>
             <EnableNetwork>true</EnableNetwork>
         </component>
     </settings>
     <cpi:offlineImage cpi:source=”” xmlns:cpi=”urn:schemas-microsoft-com:cpi” />
</unattend>

Modify startnet.cmd and insert Startnet2.cmd file

We now need to tweak startnet.cmd, so that it processes the unattend xml file during its startup cycle, which then launches our soon to be made startnet2.cmd file which then invokes TightVNC.

  • From your elevated CMD prompt, navigate to C:\MOUNTWIM\Windows\System32
  • Type Notepad startnet.cmd
  • Modify startnet.cmd so that it looks like this:

Wpeinit.exe -unattend:%SYSTEMDRIVE%\unattend.xml

  • Save the file, make sure the edit takes, no permissions issues

Create a new file called Startnet2.cmd in the same location as Startnet.cmd, pour in the following:

%WINDIR%\System32\wpeutil.exe InitializeNetwork
%WINDIR%\System32\wpeutil.exe DisableFirewall
%WINDIR%\regedit.exe -s “%SYSTEMDRIVE%\Program Files\TightVNC\TightVNCServerSettings.reg”
“%SYSTEMDRIVE%\Program Files\TightVNC\tvnserver.exe” -install -silent
“%SYSTEMDRIVE%\Program Files\TightVNC\tvnserver.exe” -start -silent

The wpeutil lines can probably be pulled, wpeinit should be initialising the network, and the unattend should be disabling the firewall.

We now need to commit the changes made to the WIM.

  • Make sure all windows and files that reference C:\MOUNTWIM are closed
  • From the elevated CMD prompt, type the following:

DISM /Unmount-WIM /MountDir:c:\DISMMOUNT /Commit

  • It should save and dismount the WIM like this:

Deployment Image Servicing and Management tool
Version: 10.0.14393.0

Image File : c:\Program Files\Microsoft Configuration Manager\OSD\boot\x64\boot.wim
Image Index : 1
Saving image
[==========================100.0%==========================]
Unmounting image
[==========================100.0%==========================]
The operation completed successfully.

If the save fails (with error 0xc1420117) it is most likely due to something having a lock in the C:\MOUNTWIM folder, swap /Commit to /Discard to dismount properly.

Update your sites boot image on the DP

  • From the ConfigMgr Console, update the boot image, making sure it is deployed to a distribution point, do not rebuild the WIM from the ADK (new option in latest CB builds)
  • Make sure the Distribution Manager component has processed the update, you can do that via the log, or in-console by looking at the last targeted time for the boot image

Create new boot media

  • Simply generate yourself new boot media, and use the newly modified boot image

Boot up a Virtual Machine or whatever, and see if TightVNC spins up when using the modified boot image. You can check to whether the VNC is service running, to do this from WINPE type NET START, and review the listed services.

Someone will need to provide the IP address of the WINPE session to the remote viewer, or the remote viewer has to have access to DHCP to see what leases have been issued, and try to triangulate that way, or alternative modify the scripts so that they write some metadata to a share somewhere, the file could be their hostname and inside is their IP address, but in a large organisation, that kind of process would fall apart.

Good luck!