Public/New-OSDDisk.ps1

<#
.SYNOPSIS
Creates System | OS | Recovery Partitions for MBR or UEFI Drives in WinPE
 
.DESCRIPTION
Creates System | OS | Recovery Partitions for MBR or UEFI Drives in WinPE
 
.LINK
https://osd.osdeploy.com/module/functions/new-osddisk
 
.NOTES
19.10.10 Created by David Segura @SeguraOSD
#>

function New-OSDDisk {
    [CmdletBinding()]
    param (
        #Title displayed during script execution
        #Default = New-OSDDisk
        #Alias = T
        [Alias('T')]
        [string]$Title = 'New-OSDDisk',

        #Fixed Disk Number
        #For multiple Fixed Disks, use the SelectDisk parameter
        #Default = 0
        #Alias = Disk, Number
        [Alias('Disk','Number')]
        [int]$DiskNumber,

        #Clear-Disk Scope
        #All will Clear all non-RAW Fixed Disks
        #OSDDisk will Clear only the DiskNumber or SelectDisk
        #Default = All
        #Alias = Clear
        #[Alias('Clear')]
        #[ValidateSet('All','OSDDisk')]
        #[string]$ClearDisk = 'All',

        #Drive Label of the System Partition
        #Default = System
        #Alias = LS, LabelS
        [Alias('LS','LabelS')]
        [string]$LabelSystem = 'System',
        
        #Drive Label of the Windows Partition
        #Default = OS
        #Alias = LW, LabelW
        [Alias('LW','LabelW')]
        [string]$LabelWindows = 'OS',
        
        #Drive Label of the Recovery Partition
        #Default = Recovery
        #Alias = LR, LabelR
        [Alias('LR','LabelR')]
        [string]$LabelRecovery = 'Recovery',

        #System Partition size for BIOS MBR based Computers
        #Default = 260MB
        #Range = 100MB - 3000MB (3GB)
        #Alias = SSM, Mbr, SystemM
        [Alias('SSM','Mbr','SystemM')]
        [ValidateRange(100MB,3000MB)]
        [uint64]$SizeSystemMbr = 260MB,

        #System Partition size for UEFI GPT based Computers
        #Default = 260MB
        #Range = 100MB - 3000MB (3GB)
        #Alias = SSG, Efi, SystemG
        [Alias('SSG','Efi','SystemG')]
        [ValidateRange(100MB,3000MB)]
        [uint64]$SizeSystemGpt = 260MB,

        #MSR Partition size
        #Default = 16MB
        #Range = 16MB - 128MB
        #Alias = MSR
        [Alias('MSR')]
        [ValidateRange(16MB,128MB)]
        [uint64]$SizeMSR = 16MB,

        #Size of the Recovery Partition
        #Default = 990MB
        #Range = 350MB - 80000MB (80GB)
        #Alias = SR, Recovery
        [Alias('SR','Recovery')]
        [ValidateRange(350MB,80000MB)]
        [uint64]$SizeRecovery = 990MB,

        #Select OSDDisk if multiple Fixed Disks are present
        #Supersedes the DiskNumber parameter
        #Ignored if only one Fixed Disk is present
        #[switch]$SelectDisk,

        #Skips the creation of the Recovery Partition
        [Alias('SkipRecovery')]
        [switch]$SkipRecoveryPartition,

        #Required for execution as a safety precaution
        [switch]$Force
    )
    
    #======================================================================================================
    # Set Defaults
    #======================================================================================================
    $global:OSDDisk = $null
    $global:OSDFixedDisks = $null
    $global:OSDDirtyDisks = $null
    $global:OSDDiskSandbox = $false
    $global:OSDDiskSelect = $false
    $OSDDiskSkipDisplay = $false
    #======================================================================================================
    # OSD Module Information
    #======================================================================================================
    $OSDVersion = $($MyInvocation.MyCommand.Module.Version)
    Write-Host "OSD $OSDVersion $Title" -ForegroundColor Cyan
    #======================================================================================================
    # Get all Fixed Disks
    #======================================================================================================
    $global:OSDFixedDisks = Get-Disk | Where-Object {($_.BusType -ne 'USB') -and ($_.BusType -notmatch 'Virtual') -and ($_.Size -gt 15GB)} | Sort-Object Number
    #======================================================================================================
    # Get all Fixed Disks that are Dirty
    #======================================================================================================
    $global:OSDDirtyDisks = $global:OSDFixedDisks | Where-Object {$_.PartitionStyle -ne 'RAW'}
    #======================================================================================================
    # Failure: No Fixed Disks are present
    #======================================================================================================
    if ($null -eq $global:OSDFixedDisks) {Write-Warning "$Title could not find any Fixed Disks"; Break}
    #======================================================================================================
    # If there is only one Fixed Disk, then it is the OSDDisk
    #======================================================================================================
    if (($global:OSDFixedDisks | Measure-Object).Count -eq 1) {
        $OSDDisk = $global:OSDFixedDisks
        if ($OSDDisk.PartitionStyle -ne 'RAW') {
            if (! $Force.IsPresent) {
                $global:OSDDiskSandbox = $true
                Write-Warning "$Title is running in Sandbox Mode due to existing Partitions or Data"
                Write-Warning "Use the -Force parameter to bypass Sandbox Mode"
            }
        }
        if ($OSDDisk.PartitionStyle -eq 'RAW') {$OSDDiskSkipDisplay = $true}
    } else {
        if (! $Force.IsPresent) {
            $global:OSDDiskSandbox = $true
            Write-Warning "$Title is running in Sandbox Mode due to multiple Fixed Disks"
            Write-Warning "Use the -Force parameter to bypass Sandbox Mode"
        }
        if ($DiskNumber) {
            #OSDDisk was specified
            $OSDDisk = $global:OSDFixedDisks | Where-Object {$_.DiskNumber -eq $DiskNumber}
        } else {
            #More than one Fixed Disk
            $global:OSDDiskSelect = $true
        }
    }
    #======================================================================================================
    # Force Validation
    #======================================================================================================
    if ($Force.IsPresent) {$global:OSDDiskSandbox = $false}
    #======================================================================================================
    # Enable Sandbox
    #======================================================================================================
    #if ($global:OSDDiskSandbox -eq $true) {Write-Verbose "$Title is running in Sandbox. Use the Force parameter for execution" -Verbose}
    #======================================================================================================
    # IsWinPE
    #======================================================================================================
    if (Get-OSDGather -Property IsWinPE) {Write-Host "$Title is running in WinPE" -ForegroundColor DarkGray}
    else {
        Write-Warning "$Title requires WinPE"
        if ($global:OSDDiskSandbox -eq $false) {Break}
    }
    #======================================================================================================
    # IsAdmin
    #======================================================================================================
    if (Get-OSDGather -Property IsAdmin) {Write-Host "$Title is running with Administrative Rights" -ForegroundColor DarkGray}
    else {
        Write-Warning "$Title requires Administrative Rights"
        if ($global:OSDDiskSandbox -eq $false) {Break}
    }
    #======================================================================================================
    # DisplayOSDFixedDisks
    #======================================================================================================
    if ($OSDDiskSkipDisplay -eq $false) {
        Write-Host "=================================================================================================" -ForegroundColor Cyan
        foreach ($item in $global:OSDFixedDisks) {Write-Host "Disk $($item.Number) - $($item.FriendlyName) ($([math]::Round($item.Size / 1000000000))GB $($item.PartitionStyle)) BusType=$($item.BusType) Partitions=$($item.NumberOfPartitions) IsBoot=$($item.BootFromDisk)" -ForegroundColor Cyan}
        Write-Host "=================================================================================================" -ForegroundColor Cyan
    }
    #======================================================================================================
    # OSDDiskSelect
    #======================================================================================================
    if ($global:OSDDiskSelect -eq $true) {
        do {$ConfirmOSDDisk = Read-Host "Multiple Disks: Type the DiskNumber to use as the OSDDisk, or press X to EXIT (and press Enter)"}
        until (($global:OSDFixedDisks.Number -Contains $ConfirmOSDDisk) -or $ConfirmOSDDisk -eq 'X')
        if ($Selected -eq 'X') {Break}
        $OSDDisk = $global:OSDFixedDisks | Where-Object {$_.Number -eq $ConfirmOSDDisk}
    }
    #======================================================================================================
    # No GetOSDDisk
    #======================================================================================================
    if ($null -eq $OSDDisk) {Write-Warning "$Title is unable to find a suitable Disk"; Break}
    #======================================================================================================
    # Clear GetOSDDisk
    #======================================================================================================
    if ($OSDDisk.PartitionStyle -ne 'RAW') {
        #Write-Host "Clear Disk $($OSDDisk.Number) $($OSDDisk.FriendlyName) ($([math]::Round($OSDDisk.Size / 1000000000))GB $($OSDDisk.PartitionStyle)) BusType=$($OSDDisk.BusType) Partitions=$($OSDDisk.NumberOfPartitions)" -ForegroundColor Yellow
        
        if ($global:OSDDiskSandbox -eq $true) {
            Write-Host "SANDBOX: DISKPART select disk $($OSDDisk.Number)" -ForegroundColor DarkGray
            Write-Host "SANDBOX: DISKPART clean" -ForegroundColor DarkGray
        }

        if ($global:OSDDiskSandbox -eq $false) {
            do {$ConfirmInit = Read-Host "Press C to CLEAR this Disk, or X to EXIT (and press Enter)"}
            until ($ConfirmInit -eq 'C' -or $ConfirmInit -eq 'X')
            if ($ConfirmInit -eq 'X') {Break}
            #Virtual Machines have issues using PowerShell for Clear-Disk
            #$OSDDisk | Clear-Disk -RemoveOEM -RemoveData -Confirm:$true -PassThru -ErrorAction SilentlyContinue | Out-Null
            Write-Warning "DISKPART select disk $($OSDDisk.Number)"
            Write-Warning "DISKPART clean"
            
$null = @"
select disk $($OSDDisk.Number)
clean
exit
"@
 | diskpart.exe
        }
    }

    #======================================================================================================
    # Clear additional Dirty Disks
    #======================================================================================================
    $global:OSDDirtyDisks = $global:OSDDirtyDisks | Where-Object {$_.Number -ne $OSDDisk.Number}

    foreach ($item in $global:OSDDirtyDisks) {
        Write-Host "Secondary Disk: Clear Disk $($item.Number) $($item.FriendlyName) ($([math]::Round($item.Size / 1000000000))GB $($item.PartitionStyle)) BusType=$($item.BusType) Partitions=$($item.NumberOfPartitions)" -ForegroundColor Yellow

        if ($global:OSDDiskSandbox -eq $false) {
            $null = $ConfirmClearDisk
            do {$ConfirmClearDisk = Read-Host "Press C to CLEAR this disk, or S to SKIP (and press Enter)"}
            until ($ConfirmClearDisk -eq 'C' -or $ConfirmClearDisk -eq 'S')

            #$DirtyFixedDisk | Clear-Disk -RemoveOEM -RemoveData -Confirm:$false -PassThru -ErrorAction SilentlyContinue | Out-Null

$null = @"
select disk $($item.Number)
clean
exit
"@
 | diskpart.exe
        }
    }




<# #======================================================================================================
    # Simulation
    #======================================================================================================
    if (Get-OSDGather -Property IsUEFI) {
        Write-Verbose "Disk $($OSDDisk.Number) will be Initialized as GPT (UEFI)" -Verbose
        $PartitionStyle = 'GPT'
        Write-Verbose "Initialize Disk $($OSDDisk.Number) $($OSDDisk.FriendlyName) ($([math]::Round($OSDDisk.Size / 1000000000))GB) $PartitionStyle" -Verbose
        Write-Verbose "Disk $($OSDDisk.Number) System Partition $($SizeSystemGpt / 1MB)MB FAT32 $LabelSystem" -Verbose
        Write-Verbose "Disk $($OSDDisk.Number) MSR Partition $($SizeMSR / 1MB)MB" -Verbose
        if ($SkipRecoveryPartition.IsPresent) {
            $SizeWindows = $($OSDDisk.Size) - $SizeSystemGpt - $SizeMSR
            $SizeWindowsGB = [math]::Round($SizeWindows / 1GB,1)
            Write-Verbose "Disk $($OSDDisk.Number) Windows Partition $($SizeWindowsGB)GB NTFS $LabelWindows" -Verbose
        } else {
            $SizeWindows = $($OSDDisk.Size) - $SizeSystemGpt - $SizeMSR - $SizeRecovery
            $SizeWindowsGB = [math]::Round($SizeWindows / 1GB,1)
            Write-Verbose "Disk $($OSDDisk.Number) Windows Partition $($SizeWindowsGB)GB NTFS $LabelWindows" -Verbose
            Write-Verbose "Disk $($OSDDisk.Number) Recovery Partition $($SizeRecovery / 1MB)MB NTFS $LabelRecovery" -Verbose
        }
    } else {
        Write-Verbose "Disk will be Initialized as MBR (BIOS)" -Verbose
        $PartitionStyle = 'MBR'
        Write-Verbose "Initialize Disk $($OSDDisk.Number) $($OSDDisk.FriendlyName) ($([math]::Round($OSDDisk.Size / 1000000000))GB) $PartitionStyle" -Verbose
        Write-Verbose "Disk $($OSDDisk.Number) System Partition $($SizeSystemMbr / 1MB)MB FAT32 $LabelSystem" -Verbose
        if ($SkipRecoveryPartition.IsPresent) {
            $SizeWindows = $($OSDDisk.Size) - $SizeSystemMbr - $SizeMSR
            $SizeWindowsGB = [math]::Round($SizeWindows / 1GB,1)
            Write-Verbose "Disk $($OSDDisk.Number) Windows Partition $($SizeWindowsGB)GB NTFS $LabelWindows" -Verbose
        } else {
            $SizeWindows = $($OSDDisk.Size) - $SizeSystemMbr - $SizeRecovery
            $SizeWindowsGB = [math]::Round($SizeWindows / 1GB,1)
            Write-Verbose "Disk $($OSDDisk.Number) Windows Partition $($SizeWindowsGB)GB NTFS $LabelWindows" -Verbose
            Write-Verbose "Disk $($OSDDisk.Number) Recovery Partition $($SizeRecovery / 1MB)MB NTFS $LabelRecovery" -Verbose
        }
    } #>

    #======================================================================================================
    # Get OSDDisks
    # Update the OSDDisk information
    #======================================================================================================
    $OSDDisk = Get-Disk -Number $OSDDisk.Number
    #======================================================================================================
    # RAW
    # Force: Make sure that the OSDDisk is RAW, if not we need to exit
    # Simulation: No need to evaluate
    #======================================================================================================
    if (($global:OSDDiskSandbox -eq $false) -and ($OSDDisk.PartitionStyle -ne 'RAW')) {Write-Warning "OSDDisk does not have RAW PartitionStyle. $Title cannot create additional Partitions. Exiting"; Break}
    #======================================================================================================
    # Display OSDDisk
    # Show the current information about this Disk. At this point, it should be RAW
    #======================================================================================================
    Write-Host "=================================================================================================" -ForegroundColor Cyan
    Write-Host "Disk $($OSDDisk.Number) - $($OSDDisk.FriendlyName) ($([math]::Round($OSDDisk.Size / 1000000000))GB $($OSDDisk.PartitionStyle)) BusType=$($OSDDisk.BusType)" -ForegroundColor Cyan
    Write-Host "=================================================================================================" -ForegroundColor Cyan
    #======================================================================================================
    # AskPartition
    # Ask if it is ok to Partition the Drive
    # Simulation: No need to evaluate
    # P to Partition
    # X to exit
    #======================================================================================================
    if ($global:OSDDiskSandbox -eq $false) {
        do {$AskPartition = Read-Host "Press P to Partition this Disk, or X to quit (and press Enter)"}
        until ($AskPartition -eq 'P' -or $AskPartition -eq 'X')
        if ($AskPartition -eq 'X') {Break}
    }
    #======================================================================================================
    # Initialize-OSDDisk
    # OSDDisk is RAW so it needs to be Initialized
    #======================================================================================================
    Initialize-OSDDisk -DiskNumber $($OSDDisk.Number)
    #======================================================================================================
    # New-OSDPartitionSystem
    #======================================================================================================
    New-OSDPartitionSystem -DiskNumber $($OSDDisk.Number) -SizeSystemMbr $SizeSystemMbr -SizeSystemGpt $SizeSystemGpt -LabelSystem $LabelSystem -SizeMSR $SizeMSR

    if ($SkipRecoveryPartition.IsPresent) {
        New-OSDPartitionWindows -DiskNumber $($OSDDisk.Number) -LabelWindows $LabelWindows -SkipRecoveryPartition
    } else {
        New-OSDPartitionWindows -DiskNumber $($OSDDisk.Number) -LabelWindows $LabelWindows -LabelRecovery $LabelRecovery -SizeRecovery $SizeRecovery
    }
    #======================================================================================================
    # Parameters
    #======================================================================================================
    if (-not ($Force.IsPresent)) {
        Write-Host "=================================================================================================" -ForegroundColor Cyan
        Write-Host "Parameters" -ForegroundColor Cyan
        Write-Host "=================================================================================================" -ForegroundColor Cyan
        Write-Host "-Title: $Title" -ForegroundColor Cyan
        Write-Host "-DiskNumber: $DiskNumber" -ForegroundColor Cyan
        Write-Host "-LabelSystem: $LabelSystem" -ForegroundColor Cyan
        Write-Host "-LabelWindows: $LabelWindows" -ForegroundColor Cyan
        if (Get-OSDGather -Property IsUEFI) {
            Write-Host "-LabelRecovery (GPT): $LabelRecovery" -ForegroundColor Cyan
            Write-Host "-SizeSystemGpt (GPT): $($SizeSystemGpt/ 1MB)MB" -ForegroundColor Cyan
            Write-Host "-SizeMSR (GPT): $($SizeMSR / 1MB)MB" -ForegroundColor Cyan
            Write-Host "-SizeRecovery (GPT): $($SizeRecovery/ 1MB)MB" -ForegroundColor Cyan
            Write-Host "-SkipRecoveryPartition (GPT): $SkipRecoveryPartition" -ForegroundColor Cyan
        } else {
            Write-Host "-SizeSystemMbr (MBR): $($SizeSystemMbr/ 1MB)MB" -ForegroundColor Cyan
        }
        Write-Host "-Force: $Force" -ForegroundColor Cyan
    }
}