TL;DR – Here is a script to get past the Disk0 to Disk2 mapping issue with the new Surface Pro with a 1TB drive.
Surface Hardware
OK, first a bit of history, I used to work for the Surface Imaging team back in 2015 to 2016. Overall a cool job, I learned a lot, and got to sharpen my PowerShell coding skills.
During that time I got to see my first Surface Studio device, even before it was released. Once of the unique features of the device was it’s unique disk architecture, it contains TWO disk drives, one a SSD in a M.2 format, and a Spinning Hard disk in a 2.5″ format. The OS contains a driver that uses the SSD as a cache. The idea is that you get the size of the 2TB hard disk, with (generally) the speed of the SSD.
Of course this creates a problem for OS deployment because we need to load the Special Caching driver into WinPE before deployment, so both drives are properly identified.
The Surface Pro with the 1TB drive is also unique in this manner, on the inside it isn’t a single 1TB drive, instead it’s two 512GB drives running in a Raid 0 configuration.
So you’re probably wondering how this works within WinPE on MDT, well the good news is that the built in 1709 drivers can correctly identify the two SSD disk as a single 1TB drive…
… The only problem is that it’s identified as Disk(2), and that breaks stuff.
ZTIDiskPart
Yes, yes, I know… mea culpa…
MDT (and SCCM/OSD) make an assumption on the “Format and Partition Disk” step: The target disk number is fixed for each Task Sequence. Now, we can change the target disk dynamically within the Task Sequence by chaning the OSDDiskIndex variable. But it will require some coding.
Fix 1
One fix, if you are OK with some WMI queries, is to test for a “Surface Pro” model and a 1TB disk at index 2. I would prefer to test for the ABSENCE of a disk at index 0, but not sure how to do that.
Fix 2
The following is a modification of my ZTISelectBootDisk.wsf script. Designed specifically for this configuration. Just drop it into the scripts folder and add a step in the Task Sequence before the “Format and Partition disk step.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<job id="ZTISurface1TBBootDisk"> | |
<script language="VBScript" src="ZTIUtility.vbs"/> | |
<script language="VBScript" src="ZTIDiskUtility.vbs"/> | |
<script language="VBScript"> | |
' // *************************************************************************** | |
' // | |
' // Copyright (c) Microsoft Corporation. All rights reserved. | |
' // | |
' // Microsoft Deployment Toolkit Solution Accelerator | |
' // | |
' // File: ZTISurface1TBBootDisk.wsf | |
' // | |
' // Version: <VERSION> | |
' // | |
' // Purpose: Given a collection of Storage Devices on a machine, | |
' // this program will assist in finding the correct | |
' // device to be processed by "ZTISurface1TBBootDisk.wsf" | |
' // | |
' // Currently hard coded to select the *FIRST* disk. | |
' // | |
' // REQUIRES that you install the correct WinPE Storage Components! | |
' // | |
' // | |
' // WARNING: If there are any *other* disks that need to be Cleaned | |
' // and formatted, they should be processed first. | |
' // And this the global Variable OSDDiskIndex should be | |
' // set to <blank> when done being processed by ZTIDiskPart.wsf. | |
' // | |
' // Variables: | |
' // OSDDiskIndex [ Output ] – Disk Index | |
' // | |
' // Usage: | |
' // cscript.exe [//nologo] ZTISelectBootDisk.wsf [/debug:true] | |
' // cscript.exe [//nologo] ZTIDiskPart.wsf [/debug:true] | |
' // cscript.exe [//nologo] ZTISetVariable.wsf [/debug:true] /OSDDiskIndex:"" | |
' // | |
' // *************************************************************************** | |
Option Explicit | |
RunNewInstance | |
'//—————————————————————————- | |
'// Main Class | |
'//—————————————————————————- | |
Class ZTISurface1TBBootDisk | |
'//—————————————————————————- | |
'// Main routine | |
'//—————————————————————————- | |
Function Main | |
Dim oWMIDisk | |
Dim bFound | |
Dim oDiskPartBoot | |
Dim oContext, oLocator, objQuery, objStorageWMI, objStorage | |
oLogging.CreateEntry "—————- Initialization —————-", LogTypeInfo | |
IF oEnvironment.Item("DEPLOYMENTTYPE") <> "NEWCOMPUTER" Then | |
oLogging.ReportFailure "Not a new computer scenario, exiting Select Boot Disk.", 7700 | |
End If | |
IF oEnvironment.Item("Model") <> "Surface Pro" Then | |
oLogging.CreateEntry "Not a surface machine OK!",LogTypeInfo | |
exit function | |
End If | |
bFound = FAILURE | |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
' | |
' 1st Pass – Find any disk that matches the Query | |
' | |
Set oContext = CreateObject("WbemScripting.SWbemNamedValueSet") | |
oContext.Add "__ProviderArchitecture", 64 | |
Set oLocator = CreateObject("Wbemscripting.SWbemLocator") | |
set objStorageWMI = oLocator.ConnectServer("","root\Microsoft\Windows\Storage","","",,,,oContext) | |
set objQuery = objStorageWMI.ExecQuery("select number,size,bustype,model from msft_disk where BusType <> 7 and BusType <> 12 and Size > 900000000000") | |
If objQuery.Count = 0 then | |
oLogging.CreateEntry "No Disk Drives Found!?!?! Dude, did you install the right storage drivers into WinPE 0x7b.",LogTypeError | |
exit function | |
elseif objQuery.Count > 1 then | |
oLogging.CreateEntry "more than one disk found",LogTypeError | |
exit function | |
End if | |
For each objStorage in objQuery | |
oLogging.CreateEntry "Found Device: N:" & ObjStorage.Number & " S:" & ObjStorage.Size & " M:" & ObjStorage.Model & " T:" & ObjStorage.BusType & " " , LogTypeInfo | |
oEnvironment.Item("OSDDiskIndex") = ObjStorage.Number | |
bFound = SUCCESS | |
exit for | |
Next | |
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | |
' | |
' 2nd pass – Use the 1st Partition larger than 15GB on the first disk with a bootable partition. | |
' | |
If bFound = FAILURE then | |
oLogging.CreateEntry "No drive was found using search parameters, Use the 1st \Windows Partition found.", LogTypeInfo | |
set oDiskPartBoot = GetBootDriveEx( false, oEnvironment.Item("ImageBuild"), false ) | |
If not oDiskPartBoot is nothing then | |
oEnvironment.Item("OSDDiskIndex") = oDiskPartBoot.Disk | |
bFound = SUCCESS | |
End if | |
End if | |
TestAndLog bFound = SUCCESS, "Verify OSDDiskIndex was found and set: " & oEnvironment.Item("OSDDiskIndex") | |
Main = bFound | |
End Function | |
End class | |
</script> | |
</job> |
Testing
Now this script has NOT been tested on a 1TB Surface device. However I *AM* available for testing the 1TB surface device. I can forward my home mailing address, if you want to send me one :^).
Thanks for the help Keith. Just a heads up that the code preview on this page differs from the raw code, it’s missing bits of syntax throughout
I don’t see any problems with the code on the page.