Ever had multiple disks hardware builds and the Operating System is not getting installed on the expected hard drive…..well here are steps to overcome that.
The script will identify the total number of Physical Disks by ‘BusType’ technology and ‘Size’.
The default configuration sets the ‘latest’ BusType technology and ‘smallest’ sized hard drive as the Primary Disk. (This can be reconfigured in the script)
The Configuration Manager variable ‘OSDDiskIndex’ will be assigned the disk number of the ‘Primary Disk’ and used in the deployment step ‘Partition Disk 0 – BIOS’ or ‘Partition Disk 0 – UEFI’, ‘Pre-provsion BitLocker’ and Apply Operating System.
Remaining, detected hard drives will be formatted as a simple volume
More information on the Configuration Manager variable OSDDiskIndex:
https://docs.microsoft.com/en-us/mem/configmgr/osd/understand/task-sequence-variables#OSDDiskIndex
- Set Disk and Format – PowerShell Script

Add a ‘Run Powershell Script’ to the task sequence before the step ‘Partition Disk’.
Type: Run PowerShell Script
Edit Script: Copy and Paste PowerShell script
PowerShell Execution Policy: Bypass
<# .WARNING This script is destructive as it contains Clear-Disk .SYNOPSIS Warning Destructive - Created to run in WinPE OSD to Clear-Disk and assign OSDDiskIndex to task sequence Disk Advanced Option Partition Variable .DESCRIPTION Runs in WinPE OSD to find, sort and format disk drive(s) and assign fastest and smallest disk as OSDDiskIndex variable to be used in the task sequence .NOTES File Name : osddiskcleanadvanced.ps1 Author : S.P.Drake .COMPONENT (WinPE-EnhancedStorage),Windows PowerShell (WinPE-StorageWMI),Microsoft .NET (WinPE-NetFx),Windows PowerShell (WinPE-PowerShell). Need to added to the WinPE Boot Image to enable the script to run The COMObject Microsoft.SMS.TSEnvironment is only available in MDT\SCCM WinPE #> # Log file function, just change destaination path if required Function Write-Log { [CmdletBinding()] Param( [Parameter(Mandatory=$False)] [ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")] [String] $Level, [Parameter(Mandatory=$False)] [string] $Message, [Parameter(Mandatory=$False)] [string] $logfile = "$($TSEnv.value('_SMSTSLogPath'))\OSD_DiskSearchandClean.log" ) $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") $Line = "$Stamp $Level $Message" If($logfile) { Add-Content $logfile -Value $Line } Else { Write-Output $Line } } # Outer Try Catch try{ # Import Microsoft.SMS.TSEnvironment $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment # Read Task Sequnce Variable _SMSTSBootUEFI and set Partition Style if ($TSEnv.Value('_SMSTSBootUEFI') -eq $True){$Style = 'GPT'} else {$Style = 'MBR'} # Build array of BusTypes to search for and in order of priority - (Highest to Lowest) : https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-disk $diskorder = @('NVMe','SD','SATA','SAS','RAID','ATA','ATAPI','SCSI') Write-Log -Message "Only the following BusTypes are searched : $diskorder" Write-Log # Get only physical disks that are specified in $diskorder array and sort in the same order, followed by Size {min-max} (Smallest Disk Capacity to Largest Disk Capacity) $physicalDisks = Get-PhysicalDisk | where-object{$diskorder -match $_.BusType} | Sort-Object {$diskorder.IndexOf($_.BusType)} , @{Expression = "Size"; Descending = $False} # Did we find any matching physical disks ? if ($null-eq $physicalDisks) { Write-Log -Message "No physical disks have been detected" Write-Log } else { Write-Log -Message "The following physical disks have been detected: -" Write-Log # Display all physical disks that have been found foreach ($disk in $physicalDisks) { Write-Log -Message "FriendlyName: $($disk.FriendlyName)" Write-Log -Message "MediaType: $($disk.MediaType)" Write-Log -Message "BusType: $($disk.BusType)" Write-Log -Message "Size: $($disk.Size /1GB)" Write-Log -Message "DeviceID: $($disk.DeviceID)" Write-Log } } # Display action to be performed $firstItem = 0 foreach ($disk in $physicalDisks) { # Is it the first item in the list ? if ($firstItem -eq 0){ # Get first physical disk in our list - Ordered by BusType and Size Write-Log -Message "The physical drive $($disk.FriendlyName) of Bustype $($disk.BusType) and Media Type $($disk.MediaType) on Device ID : $($disk.DeviceId) will be assigned to OSDDiskIndex" # Assign task sequence variable OSDDiskIndex $TSEnv.Value('OSDDiskIndex') = $disk.DeviceId } else { Write-Log -Message "The physical drive $($disk.FriendlyName) of Bustype $($disk.BusType) and Media Type $($disk.MediaType) on Device ID : $($disk.DeviceId) will be cleaned and used as a Data Disk" # If disk is new and Partition Style 'RAW' then Initialize Disk if (get-disk -Number $disk.DeviceId | Where-Object {$_.PartitionStyle -eq 'RAW'}){Initialize-Disk -Number $disk.DeviceId -PartitionStyle $style} # Clear disk partition and data Clear-Disk -Number $disk.DeviceId -RemoveOEM -RemoveData -Confirm:$false Write-Log -Message "Command: Clear-Disk -Number $($disk.DeviceId) -RemoveOEM -RemoveData -Confirm:$false" # Initialize-Disk Initialize-Disk -Number $disk.DeviceId -PartitionStyle $style Write-Log -Message "Command: Initialize-Disk -Number $($disk.DeviceId) -PartitionStyle $($style)" # Create and format data disk New-Partition -DiskNumber $disk.DeviceId -UseMaximumSize -AssignDriveLetter | Format-Volume -FileSystem NTFS -NewFileSystemLabel Data -Confirm:$False Write-Log -Message "Command: New-Partition -DiskNumber $disk.DeviceId -UseMaximumSize -AssignDriveLetter | Format-Volume -FileSystem NTFS -NewFileSystemLabel Data -Confirm:$False" Write-Log } $firstItem = $firstItem +1 } }catcH{ Write-Log Write-Log -Level ERROR -Message $_.Exception.Message Write-Log Exit 1 }
NOTE : To change the searchable disk BusTypes amend line 62
$diskorder = @(‘NVMe’,’SD’,’SATA’,’SAS’,’RAID’,’ATA’,’ATAPI’,’SCSI’)
Add\remove the BusType you wish to search, with the highest priority first
For more information on BusType read https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-physicaldisk
To change the disk drive selection from largest to smallest amend line 68
@{Expression = “Size”; Descending = $True}
- Configure Partition Disk 0 – BIOS

Partition Disk 0 – BIOS : Select the ‘Windows (Primary)’ volume and Set the ‘Advance options Variable’ to ‘OSDisk’.
The variable ‘OSDisk’ will be used in the ‘Apply Operating System’ to ensure the operating system gets applied to the correct hard drive.
NOTE: There is no need to change the ‘Disk number’, as this was dynamically assigned in the PowerShell script ‘OSDDiskIndex’
- Configure Partition Disk 0 – UEFI

Partition Disk 0 – UEFI : Select the ‘Windows (Primary)’ volume and Set the ‘Advance options Variable’ to ‘OSDisk’.
The variable ‘OSDisk’ will be used in the ‘Apply Operating System’ to ensure the operating system gets applied to the correct hard drive.
NOTE: There is no need to change the ‘Disk number’, as this was dynamically assigned in the PowerShell script ‘OSDDiskIndex’
- Pre-provision BitLocker

Pre-Provision Bitlocker : Under ‘Apply BitLocker to the specified drive’, select the ‘Properties’ tab and change the ‘Destination’ to Logical driver letter stored and ‘Variable name’ to OSDisk
NOTE: The Pre-Provision is applied to the Operating System as the ‘OSDisk’ variable was assigned in the PowerShell script
- Apply Operating System

Apply Operating System : Select the ‘Properties’ tab and change the ‘Destination’ to ‘Logical driver letter stored in a variable‘ and ‘Variable name’ to ‘OSDisk‘
NOTE: The Operating System is applied to the correct Drive as the ‘OSDisk’ variable was assigned in the PowerShell script
Log log file of the actions performed can be found at C:\Windows\CCM\Logs\OSD_DiskSearchandClean.log
Downloadable source files can be found at https://github.com/Drakey2000/CommunityHelper/tree/master/OSDDiskFormat
Update : Since writing, Microsoft has enhanced the Task Sequence Step Properties for ‘Format and Partition Disk‘. So check in out
This enables you to use scripts to assign variables to all disks, not just ‘OSDDiskIndex‘ and use the ‘Format and Partition Disk‘ in the Task Sequence to dynamically perform actions.