MDT 2013 offers an astounding 37,403 lines of code for free.

By | October 28, 2013
Share

I took a couple of minutes out Today to pull the amount of code is offered for free by implementing MDT 2013 from Micosoft.  Here is the powershell I wrote up for querying up the number:

Get-ChildItem -Path C:\HydrationCM2012R2\DS\Scripts\ -Recurse | `
    Where-Object {$_.Extension -eq ".WSF" -or $_.Extension -eq ".VBS"} | `
    foreach{(Get-Content $_.FullName).Count} | Measure-Object -Sum

Results:

Count : 95
Average :
Sum : 37403
Maximum :
Minimum :
Property :

 

/Brian G

MDT 2013 has released!

By | October 21, 2013
Share

Download Link: http://www.microsoft.com/en-us/download/details.aspx?id=40796

What’s changed: http://download.microsoft.com/download/B/F/5/BF5DF779-ED74-4BEC-A07E-9EB25694C6BB/Whats%20New%20in%20MDT%202013%20Guide.docx

Major points:

1. No XP or Win Server 08 support.

2. Uses WinPE 5.0.

3. Deploys Win 8.1. http://www.microsoft.com/en-US/download/details.aspx?id=39982

 

Luckily, the MDT 2012 Update 1 link is still alive as well. http://www.microsoft.com/en-us/download/details.aspx?id=25175

 

/Brian G

MDT Wizard Screen to remind Deployment Technician to turn on the Wireless Switch.

By | October 11, 2013
Share

Our Toughbooks ship with the Wireless Switch in the OFF state.  So when you take the unit out the box and image the unit, it will not install the required WWAN, WLAN, Bluetooth drivers.  So to remind Deployment Technicians to Turn on the Wireless Switch, I built this Wizard screen using the OpenSource “MDT Wizard Studio”.

http://mdtwizardstudio.codeplex.com/

WirelessSwitchReminderWizardScreen

HTML used in Window:

<H1>Reminder: Make sure the wireless switch is set to "On".</H1>
<table>
<tr><td><H4>CF-19</H4></td></tr>
<tr><td><img src="19_left_open.png"></td></tr>
<tr><td><H4>CF-31</H4></td></tr>
<tr><td><img src="31_left_open.png"></td></tr>
</table>

Condition added to Pane: (Used to support skipping screen during Image capture)

UCase(Property("SkipWirelessSwitch"))<>"YES"

Images used in Wizard Screen: (Must be copied into \\DeployRoot\Scripts folder)

31_left_open

19_left_open

ZTIGather.XML Updates: (New SkipWizardSwitch Property needs to be added)

<!-- Wizard control variables (first value wins) -->

<property id="SkipWirelessSwitch" type="string" overwrite="false" description="Flag to skip the User Type page (if set to YES, default is blank)" />

Lastly, I update the CustomSettings.INI to not display the prompt during Image Capture:

[Settings]
Priority=OSVersion, Default
Properties=MyCustomProperty

[WinPE]
SkipCapture=YES
SkipWirelessSwitch=NO

[Default]
OSInstall=Y
SkipWirelessSwitch=YES
;.....

/Brian G

Need a Software Keyboard in WinPE, FreeVK to the rescue..

By | September 26, 2013
Share

I was prompting a tablet user for a password in WinPE prior to performing a recovery routine.  To get Windows OSK to appear was a lot more difficult that it should be.  In my search for a portable on-screen keyboard, I found FreeVK.  Its free and works in WinPE.  The only caviat is that it needs to be triggered from WinPEShl.ini and NOT from Startnet.cmd.

Link to FreeVK.exe: http://freevirtualkeyboard.com/

Here is my WinPeShl.ini:

[LaunchApps]
AppPath="wpeinit.exe"
AppPath="cmd.exe","/c powershell.exe -command Set-ExecutionPolicy Bypass"
AppPath="cmd.exe","/c start powershell.exe -file .\SearchAndApplyWRecovery.ps1"
AppPath="%SYSTEMROOT%\system32\tools\freevk\freevk.exe"

 

* Compliments to the guys @ http://www.911cd.net/forums/ !

/Brian G

My Search and Apply .WIM Image files script with recovery partition creation.

By | September 25, 2013
Share

Once powershell was supported in WinPE, I converted my .VBS search and apply script over.  I add this script into my startnet.cmd, so it is started after initializing WinPE.

Here are the steps of the script:

  1. Prompts the user asking them to verify that they want to run recovery.
  2. Prompts for recovery password if “$sRecoveryPassword” variable is set.
  3. Verifies that it sees a local disk (>100gb).
  4. Searches through each disk and pulls the latest .WIM file that is over 1gb.
  5. Creates a recovery partition and stages the .WIM along with WinPE in recovery partition.
  6. Applies .WIM file from Recovery Partition to System Drive.
    Preps the MBR and BCD file.
  7. Shuts down the system.

Script Source:

https://github.com/brianfgonzalez/Scripts/blob/master/SearchAndApplyWRecovery.ps1

$sRecoveryPassword = $null

Function fMain {
trap {"Error found: $_" | Out-File "x:\SearchAndApply.log"}

#Clear content in command window
Clear-Host

#Maximize Command Window
<# #Doesn't Work........... $sig = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32 $hwnd = @(Get-Process "*Windows Powershell*")[0].MainWindowHandle [Win32.NativeMethods]::ShowWindowAsync($hwnd, 3) #>

Write-Output "Beginning to search for .WIM file..."
#Finds the LATEST >1G .WIM File in the root of Logical Disks
$oWimFiles = Get-WmiObject -Query "SELECT * From Win32_LogicalDisk WHERE NOT DeviceID LIKE 'A' AND Size > 0 AND NOT DriveType LIKE '4'" | `
#Commented out on 9/6/2013 DriveType 5 is for CDr/DVDr Types.
#Where-Object { $_.DriveType -ne "5" } | `
foreach { Get-ChildItem -Force -Path @($_.DeviceID + "\") } | `
Where-Object { ($_.FullName -Like "*.wim") -and ($_.Length -ge 1000000000) } | `
Sort-Object -Descending CreationTime
If ($oWimFiles -eq $null) {Write-Output "No .WIM files found..."; Exit}

#Grab Drive Object of where .WIM was located.
$oWimDrive = Get-WmiObject -Query ("SELECT * From Win32_LogicalDisk WHERE DeviceID LIKE '%" + $oWimFiles[0].PSDrive + "%'")

#If .WIM is in RECOVERY partition, then only a format on the OSDISK partition is required.
If ($oWimDrive.VolumeName -eq "RECOVERY") {

$sRecDrive = $oWimDrive.DeviceID
Write-Output "Latest WIM was found IN Recovery Partition($sRecDrive)..."
Write-Output @("Found the following image: " + $oWimFiles[0].FullName)

$oDrives = Get-WmiObject -Query "SELECT * FROM Win32_LogicalDisk WHERE DriveType LIKE 3" | `
Sort-Object -Descending Size

fCreateAnswerFiles
If (!(Test-Path("$env:temp\configHD2.txt"))) {
Write-Output "Could not access Temp Drive..."; Exit}
Write-Output "Formating OSDIsk Partition..."
Start-Process "x:\windows\system32\cmd.exe" @('/C diskpart.exe /s configHD2.txt"') -Wait -WorkingDirectory $env:temp -WindowStyle Minimized | Out-Null

}else{

#.WIM was NOT located in RECOVERY, so re-building all partitions.
$sRecDrive = "R:"
Write-Output "Latest WIM was found OUT of Recovery Partion."
Write-Output @("Found the following image: " + $oWimFiles[0].FullName)

#Checks if "Local Disk" found is over 100GB.
$Disk = Get-Disk -Number 0 | Where-Object { $_.Size -gt 100000000000 }
If ($Disk -eq $null) {Write-Output "100GB Local Disk is not found, exiting script..."; Exit}

#Call Function to create Diskpart answer files.
fCreateAnswerFiles
If ((!(Test-Path("$env:temp\configHD.txt"))) -and (!(Test-Path("$env:temp\configHD2.txt")))) {
Write-Output "Could not access Temp Drive..."; Exit}
Write-Output "Re-Partitioning Disk..."

#Re-partition the disk
Start-Process "x:\windows\system32\cmd.exe" @('/C diskpart.exe /s configHD.txt"') -Wait -WorkingDirectory $env:temp -WindowStyle Minimized | Out-Null

Write-Output "Prep Recovery Partition before applying WIM to OSDISK..."
#Copy-Item -Path ($oWimFiles[0].DirectoryName + "*") -Destination $sRecDrive -Recurse -Confirm:$false -Force
Start-Process "x:\windows\system32\cmd.exe" @('/C robocopy.exe "' + $oWimFiles[0].DirectoryName.SubString(0,2) + `
'" "' + $sRecDrive + '" /MIR /NJS /NJH /NP') -Wait -NoNewWindow | Out-Null
}
#Provide Status on what .WIM file will be applied.
Write-Output @('Begin applying image to OS partition...')
Start-Process "x:\windows\system32\cmd.exe" @('/C "imagex /apply "' + `
$sRecDrive + '\' + $oWimFiles[0].Name + '" 1 C:"') -Wait -NoNewWindow | Out-Null
Write-Output "Completed with applying image."

#Delete old BCD file
attrib C:\Boot\BcD -H -S
Remove-Item C:\Boot\BcD -Force

#Build a new one using bcd boot
Start-Process "x:\windows\system32\cmd.exe" @('/C bcdboot c:\windows /s c:') -Wait -WindowStyle Minimized | Out-Null

#Add Recovery WinPE boot option to BCD using BCDEdit script
fCreateBuildBCDFile
If (!(Test-Path("$env:temp\configBCD.bat"))) {
Write-Output "Could not access Temp Drive..."; Exit}
Start-Process "x:\windows\system32\cmd.exe" @('/C call configBCD.bat ' + $sRecDrive) -Wait -WorkingDirectory $env:temp -WindowStyle Minimized | Out-Null

Write-Output @("Boot sector and BCD is prepped.")
Sleep -Seconds 5
If (Test-Path("C:\Windows")) {
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") | Out-Null
[Microsoft.VisualBasic.Interaction]::MsgBox("Image was recovered. Click OK to Shut Down the System.",'OKOnly,Information', "Process Complete") | Out-Null
Start-Process "x:\windows\system32\wpeutil.exe" @('"shutdown"')
} else {
Write-Output @("ImageX did not apply image successfully.... Shutting down in 5 seconds...")
"ImageX did not apply image successfully." | Out-File "x:\SearchAndApplyError.log"
Exit
}
}

Function fCreateAnswerFiles {
'select disk 0
clean
create partition primary size=25000
select partition 1
format fs=ntfs label="RECOVERY" quick
assign letter = R
create partition primary
select partition 2
format fs=ntfs label="OSDISK" quick
assign letter = C
active
exit' | Out-File "$env:temp\configHD.txt" -Encoding ascii

'select disk 0
select partition 2
format fs=ntfs label="OSDISK" quick
assign letter = C
exit' | Out-File "$env:temp\configHD2.txt" -Encoding ascii
}

Function fCreateBuildBCDFile {
'@echo off
setlocal

SET BCDEDIT=bcdedit.exe
SET BCDSTORE=C:\Boot\BCD
SET SDI_FILE=boot.sdi
SET WIM_File=boot.wim
SET RECDRV=%1

REM Replace 7 Bootmgr with 8 Bootmgr
attrib c:\bootmgr -H -S
del c:\bootmgr /F
copy %RECDRV%\bootmgr c:\bootmgr

REM Set Timeout value to 5
%BCDEDIT% /store %BCDSTORE% /timeout 5

echo.
echo Adding Ram Disk Options
echo ===========

for /f "Tokens=3" %%A in (''%BCDEDIT% /store %BCDSTORE% /create /device'') do set ramdisk=%%A

%BCDEDIT% /store %BCDSTORE% /set %ramdisk% ramdisksdidevice partition=%RECDRV%
%BCDEDIT% /store %BCDSTORE% /set %ramdisk% ramdisksdipath \boot\%SDI_FILE%
echo.

echo.
echo Adding Win PE
echo ===========
echo.

for /f "Tokens=3" %%A in (''%BCDEDIT% /store %BCDSTORE% /create /application osloader'') do set GUID=%%A

echo.
echo recovery guid=%GUID%
echo.

%BCDEDIT% /store %BCDSTORE% /set %GUID% systemroot \Windows
%BCDEDIT% /store %BCDSTORE% /set %GUID% detecthal Yes
%BCDEDIT% /store %BCDSTORE% /set %GUID% winpe Yes
%BCDEDIT% /store %BCDSTORE% /set %GUID% osdevice ramdisk=[%RECDRV%]\Sources\%WIM_File%,%ramdisk%
%BCDEDIT% /store %BCDSTORE% /set %GUID% device ramdisk=[%RECDRV%]\Sources\%WIM_File%,%ramdisk%
%BCDEDIT% /store %BCDSTORE% /set %GUID% description "Recovery"
%BCDEDIT% /store %BCDSTORE% /displayorder %guid% /addlast

echo.
echo.
endlocal' | Out-File "$env:temp\configBCD.bat" -Encoding ascii
}

#Prompt if they want to run Recovery
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") | Out-Null
$Answer = [Microsoft.VisualBasic.Interaction]::MsgBox("Would you like to run the recovery routine?",'YesNo,Question', "Execute Recovery")
If ($Answer -ne "Yes") {Exit}

#Prompt for Password
If ($sRecoveryPassword -ne $null) {
$PasswordMatch = $False
Do {
$password = Read-Host -Prompt "Please enter the Recovery password" -AsSecureString
$marshal = [System.Runtime.InteropServices.Marshal]
$ptr = $marshal::SecureStringToBSTR($password)
$password = $marshal::PtrToStringBSTR($ptr)
If ($password -eq $sRecoveryPassword) {$PasswordMatch = $true}
} While ($PasswordMatch -eq $false)
}

#Begin Recovery Routine
fMain

 

 
/Brian G