Microsoft Emergency Repair Disk, PGP, and Windows System Recovery

Microsoft Campus Agreement includes access to the Microsoft "Diagnostics and Recovery Toolkit" (DaRT), the chief component of which is the Emergency Repair Disk (ERD).  ERD boot images can be found in the Microsoft Campus Agreement share:
\files.uvm.edumcaWindowsERD

DaRT is part of the larger Microsoft Desktop Optimization Pack (MDOP).  You can locate the DaRT installer and repair disk generation utility in the MDOP distribution utility:
\files.uvm.edumcaWindowsMDOP_2010DaRT

The DaRT recovery disk contains many immensely useful utilities, including:

  • Offline Registry Editor
  • NTFS File Restore (undelete utiltiy)
  • Disk Commander (disk repair)
  • Secure Wipe (securely erases a drive)
  • Offline Hotfix Uninstaller
  • System File Consistency (SFC) scanner
  • Offline "Standalone System Sweeper" (malware removal tool)

Those of you who have been using PGP Whole Disk Encryption might be wondering if any of these utilities may be wondering if these sorts of utilities will be at all useful on systems that have been encrypted.  The answer is yes, as long as the boot media has had PGP command line utilities added to it.  We have generated an ERD image with PGP drivers already pre-injected:
ERD65-Win7(32bit)-withPGP.iso

You also can transfer the ERD image to a bootable USB drive by following the directions in the README file here:

Unfortunately, PGP has not (yet) provided command line utilities for 64-bit WinPE environments.  But fortunately, you can use 32-bit WinPE to access 64-bit versions of Windows.  In this case, you will only be able to run a small subset of the ERD utilities against the offline OS.  However, you can decrypt your 64-bit OS using the 32-bit ERD, and then run the 64-bit ERD against the decrypted drive (clearly, this will take a large time commitment).

To access an encrypted disk for use with the DaRT ERD, you may need to "fake out" the ERD boot menu. 

  1. When the system restore process starts, the tool will not be able to detect an Operating System.  Select the "Restore your computer using a system image…" option, as shown below:
    clip_image001 
  2. When the tool fails to detect a restoration image, click "Cancel":
    clip_image002 
  3. Then click "cancel" again.  From the System Recovery Options dialog, select "Command Prompt":
    clip_image003
  4. Once inside the command prompt you can use the "PGPWDE" utility to access your drive. 

Here are some sample PGPWDE commands:

  • "pgpwde.exe –enum" – Take note of the disk numbers of any encrypted drives that you wish to unlock (typically "0" for the first disk on the system).
  • "pgpwde.exe –auth –disk 0 –interactive" – To unlock the disk for direct access by utilities on the DaRT ERD.
  • "pgpwde.exe –decrypt –disk 0 –interactive" – To fully decrypt the disk (note that this can take a long time, and there is no progress indicator).
  • "pgpwde.exe –status –disk 0" – To view the status of a disk encryption or decryption process on a specified drive.

Note that after you have run the "pgpwde.exe –auth" command, you can then re-launch the System Recovery conosle by running the command:

  • winpeshl.exe

You now should be able to launch the Microsoft Diagnostics and Recovery Toolset or use the "System Restore" option in the System Recovery Options dialog, and have full access to the Operating System on the encrypted disk.

Share and enjoy.

Advertisements

WSUS – Missing Servers

All of the Server 2003 virtual machines are missing from the WSUS inventory. Poor servers… they are missing the party.

Well not really, they are still getting updates, according to the logs. However, they are not reporting in. They are party lurkers.

This is an old problem, and only took a little digging. All of our 2003 VMs came from a common VMware template. Since the template once connected to our WSUS server, it already had a unique SusID in the registry, so all the clones have the same ID.

To fix, I used the cmd script here:
http://msmvps.com/blogs/athif/archive/2005/09/04/65174.aspx

I had to remove the “pause” commands, then I used “dsquery” to find all of of the relevant servers in our infrastructure:

dsquery * ou=Servers,ou=ets,ou=resources,dc=campus,dc=ad,dc=uvm,dc=edu -attr cn operatingSystem -limit 2000 > servers.txt

I isolated the Server 2003 systems from this list:

find "2003" servers.txt > 2003servers.txt

I then did some quick text processing to remove everything but the host names from the output file.  The final step, we use psexec.exe from SysInternals to run the SusID reset script:

psexec.exe @2003servers.txt -s -c AU_Clean_SID.cmd

I ended up running “psexec.exe” a second time to force the “wuauclt.exe /resetauthorization /detectnow” bit a second time.  Psexec.exe requires the “-d” switch when running this command remotely.  I think the WUAU service needed time to get fully operational before running the authorization token reset.  Perhaps a pause command would be of assistance in cmd script linked above?  Anyway, all of the Server 2003 hosts have come back to the party and are socializing nicely.

For my next trick, I am going to try to match up the WUAU XP client list with our AD XP client list to see if we have a lot of silent XP systems.  If we rely on standard tools, we could use a query similar to the following to extract XP computer objects with their last logon time:

dsquery * domainRoot -Filter "(&(objectclass=computer)(operatingSystem=Windows XP Professional))" -attr Name LastLogonTimeStamp -limit 20000 > xp.txt

There is an excellent cmd script here that will convert the “lastLogonTimestamp” into human-readable format.

However, it probably would be easier to use “dsquery computer domainRoot -inactive 4”, since processing of “lastLogonTimestamp” against current local time can be challenging in CMD (easier with PowerShell).

WSUS – Programatic Access

Windows Server Update Service – great service, poor interface. Ever try to manage computers in bulk with the WSUS GUI? You can’t… there are limited filtering and search options, and the GUI hangs a lot when performing group operations. Surely there is a better way…

Maybe, at least if you are a programmer. If not, then there at least is another way, if not better.

.NET to the rescue…

Use the “Microsoft.UpdateServices.Administration” Reflection Assembly to expose WSUS .NET objects to PowerShell, and you are limited only by your PS-foo.

My task last night was to add a list of computer objects (obtained using “dsquery” to a named group in WSUS.  Because I wanted to save time, I used Google to get some base code to work with. The code below is derived largely from the good work found here:
https://windowspowered.wordpress.com/2008/10/31/wsus-script-to-add-list-of-computers-to-a-group-in-wsus/

Ultimately, I am not sure if this saved time, because troubleshooting other people’s code generally takes about twice as long a fixing your own.

Anyway, the following script will get the job done. It requires an input file (srvlist.txt) with one computer name per line. You will need to add your WSUS server, port number, SSL boolean value, and WSUS target group to make the script run.

#Script to add machines to a WSUS group automatically:
#The script needs Admin credentials and the WSUS Administration Console installed on the machine where it runs
 
#Initialize Variables
	$wsusGroup = [string] "ServerGroupC"
	$wsusParentGroup = [string] "All Computers"
	$date = get-date
	$date = [string] $date.day + $date.month + $date.year + $date.hour + $date.minute
	$succeslog = [string] ".logs" + $date + "_success.log"
	$errorlog = [string] ".logs" + $date + "_errors.log"
	$WindowsUpdateServer= [string] "winupdate.uvm.edu"
	$useSecureConnection = [bool] $true
	$portNumber = [int] "443"

#Instantiate Objects:
	#Required WSUS Assembly – auto installed with WSUS Administration Tools
	[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
	if (!$wsus) {
		$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WindowsUpdateServer,$useSecureConnection,$portNumber)
	}
	$serverList = Get-Content ".srvlist.txt"
	$updateGroups = $Wsus.GetComputerTargetGroups()
	$updateGroup = $UpdateGroups | Where-Object{$_.Name -eq $wsusgroup} | Where-Object{$_.getparenttargetgroup().name -eq $wsusparentgroup}
	$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope
	$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::All
	$computers = $wsus.GetComputerTargets($computerScope)
	$wsusServers = @()
	$WsusServersShortNames = @()

#Create arrays:
# $wsusServer = Array of WSUS Computer objects
# $wsusServerShortName = Array strings, with one server RDN per line
Write-Host "Collecting Server List from WSUS…"
$computers | foreach-object {
	$wsusServer = $_.FullDomainName
	#cut off DNS suffix and store shortname
	$wsusServerShortName = $WsusServer.split(‘.’)[0]
	$wsusServers += $WsusServer
	$wsusServersShortNames += $wsusServerShortName
} #End ForEach $computers

#loop to add servers to group
ForEach ($server in $serverList)  {
		#Check if server Netbios name is present in WSUS, if present move to group – if not log an error
		$wsusComputer = $wsusServersShortNames | Where-Object {$_ -eq $server.Trim()} #Checks for a match in WSUS for the current server in the import list.
		If ($wsusComputer) {
			$searchStr = [string] $server.Trim() + "." #String representing a RegEx match for the relative part of the server FQDN
			$wsusComputer1 = $wsusServers | where-object {$_ -match $searchStr } #Get a WSUS computer object representing the current server in the import list.
			If ($wsusComputer1.getType().Name -match "string") { #Current $wsusComptuer1 must be a [string] object, or next step will fail.
				Write-Host "$wsusComputer1 will be added to $($updateGroup.name) group"
				$computer = $wsus.GetComputerTargetByName($wsusComputer1)
				$updateGroup.AddComputerTarget($computer)
				out-file -append -inputobject "$Server added to $($updategroup.name) group" -filepath $succeslog
			}
			Else {
				#More than one server was matched in WSUS – this will happen if your regEx is not properly formed.
				write-host "count $($wsusComputer1.count)"
				Out-File -append -inputobject "$werver has ambiguous name – check server in WSUS and add to group manually" -filepath $errorlog
			} 
		} #End If $wsusComputer
	Else {
		Write-Host "$Server not found in WSUS"
		out-file -append -inputobject "$Server not found in WSUS" -filepath $errorlog
	} 
} #End ForEach $server