private/disk/disk-osdcloud-v2.ps1

function New-OSDCloudPartitionSystem {
    <#
    .SYNOPSIS
    Creates the system partition layout for GPT or MBR disks.
 
    .DESCRIPTION
    Creates the system partition layout for GPT or MBR disks, formats the partition,
    applies the expected partition attributes, and assigns drive letter S for OSDCloud workflows.
 
    .PARAMETER DiskNumber
    Target disk number to partition.
 
    .PARAMETER LabelSystem
    Volume label to apply to the system partition.
 
    .PARAMETER PartitionStyle
    Partition style to use, GPT or MBR. If omitted, the style is inferred from the current boot mode.
 
    .PARAMETER SizeSystemMbr
    System partition size for MBR layouts.
 
    .PARAMETER SizeSystemGpt
    System partition size for GPT layouts.
 
    .PARAMETER SizeMSR
    MSR partition size for GPT layouts.
 
    .EXAMPLE
    New-OSDCloudPartitionSystem -DiskNumber 0 -PartitionStyle GPT
    Creates and formats GPT system and MSR partitions on disk 0.
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-21 - Refreshed help, parameter comments, and verbose tracing
    #>

    [CmdletBinding()]
    param (
        #Target disk number to partition
        #Aliases: Disk, Number
        [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
        [Alias('Disk','Number')]
        [uint32]$DiskNumber,

        #Volume label for the system partition
        #Default = System
        [string]$LabelSystem = 'System',

        [Alias('PS')]
        [ValidateSet('GPT','MBR')]
        [string]$PartitionStyle,

        #System partition size for BIOS or legacy MBR layouts
        #Default = 499MB
        #Range = 100MB - 3000MB (3GB)
        [ValidateRange(100MB,3000MB)]
        [uint64]$SizeSystemMbr = 499MB,

        #System partition size for UEFI GPT layouts
        #Default = 499MB
        #Range = 100MB - 3000MB (3GB)
        [ValidateRange(100MB,3000MB)]
        [uint64]$SizeSystemGpt = 499MB,

        #MSR partition size for GPT layouts
        #Default = 16MB
        #Range = 16MB - 128MB
        [ValidateRange(16MB,128MB)]
        [uint64]$SizeMSR = 16MB
    )
    #=================================================
    # PartitionStyle
    #=================================================
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Starting system partition workflow for disk $DiskNumber"
    if (-NOT ($PartitionStyle)) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PartitionStyle was not supplied; inferring from current boot mode"
        if ($global:OSDCloudDevice.IsUEFI -eq $true) {
            $PartitionStyle = 'GPT'
        } else {
            $PartitionStyle = 'MBR'
        }
    }
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PartitionStyle is set to $PartitionStyle"
    #=================================================
    # GPT
    #=================================================
    if ($PartitionStyle -eq 'GPT') {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT system partition on disk $DiskNumber"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT System Partition"
        $PartitionSystem = New-Partition -GptType '{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}' -DiskNumber $DiskNumber -Size $SizeSystemGpt

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting GPT system partition as FAT32 with label $LabelSystem"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting GPT System Partition FAT32 with Label $LabelSystem"
        Invoke-DiskpartFormatSystemPartition -DiskNumber $DiskNumber -PartitionNumber $PartitionSystem.PartitionNumber -FileSystem 'fat32' -LabelSystem $LabelSystem

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Applying the EFI system partition GPT type"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Setting GPT System Partition GptType {c12a7328-f81f-11d2-ba4b-00a0c93ec93b}"
        $PartitionSystem | Set-Partition -GptType '{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}'

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Assigning drive letter S to the GPT system partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Setting GPT System Partition NewDriveLetter S"
        $PartitionSystem | Set-Partition -NewDriveLetter S

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT MSR partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MSR Partition GptType {e3c9e316-0b5c-4db8-817d-f92df00215ae}"
        $null = New-Partition -DiskNumber $DiskNumber -Size $SizeMSR -GptType '{e3c9e316-0b5c-4db8-817d-f92df00215ae}'
    }
    #=================================================
    # MBR
    #=================================================
    if ($PartitionStyle -eq 'MBR') {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating active MBR system partition on disk $DiskNumber"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MBR System Partition as Active"
        $PartitionSystem = New-Partition -DiskNumber $DiskNumber -Size $SizeSystemMbr -IsActive

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting MBR system partition as NTFS with label $LabelSystem"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting MBR System Partition NTFS with Label $LabelSystem"
        Invoke-DiskpartFormatSystemPartition -DiskNumber $DiskNumber -PartitionNumber $PartitionSystem.PartitionNumber -FileSystem 'ntfs' -LabelSystem $LabelSystem

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Assigning drive letter S to the MBR system partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Setting MBR System Partition NewDriveLetter S"
        $PartitionSystem | Set-Partition -NewDriveLetter S
    }
}
function New-OSDCloudPartitionWindows {
    <#
    .SYNOPSIS
    Creates the Windows and optional recovery partitions.
 
    .DESCRIPTION
    Builds GPT or MBR Windows layouts, formats the Windows partition, optionally creates the recovery partition,
    and assigns the drive letters and recovery attributes expected by Windows deployment workflows.
 
    .PARAMETER DiskNumber
    Target disk number to partition.
 
    .PARAMETER LabelRecovery
    Volume label to apply to the recovery partition.
 
    .PARAMETER LabelWindows
    Volume label to apply to the Windows partition.
 
    .PARAMETER PartitionStyle
    Partition style to use, GPT or MBR. If omitted, the style is inferred from the current boot mode.
 
    .PARAMETER SizeRecovery
    Recovery partition size when the recovery partition is created.
 
    .PARAMETER NoRecoveryPartition
    Skips creation of the recovery partition.
 
    .EXAMPLE
    New-OSDPartitionWindows -DiskNumber 0 -PartitionStyle GPT
    Creates Windows and recovery partitions on disk 0.
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-21 - Refreshed help, parameter comments, and verbose tracing
    #>

    [CmdletBinding()]
    param (
        #Target disk number to partition
        #Default = 0
        #Aliases: Disk, Number
        [Alias('Disk','Number')]
        [int]$DiskNumber = 0,

        #Volume label for the recovery partition
        #Default = Recovery
        #Aliases: LR, LabelR
        [Alias('LR','LabelR')]
        [string]$LabelRecovery = 'Recovery',

        #Volume label for the Windows partition
        #Default = Windows
        #Aliases: LW, LabelW
        [Alias('LW','LabelW')]
        [string]$LabelWindows = 'Windows',

        [Alias('PS')]
        [ValidateSet('GPT','MBR')]
        [string]$PartitionStyle,

        #Recovery partition size when recovery is created
        #Default = 2000MB
        #Range = 350MB - 80000MB (80GB)
        #Aliases: SR, Recovery
        [Alias('SR','Recovery')]
        [ValidateRange(350MB,80000MB)]
        [uint64]$SizeRecovery = 2000MB,

        #Skips creation of the recovery partition
        [Alias('SkipRecovery','SkipRecoveryPartition')]
        [System.Management.Automation.SwitchParameter]$NoRecoveryPartition
    )
    #=================================================
    # Get-OSDCloudDisk
    #=================================================
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Starting Windows partition workflow for disk $DiskNumber"
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Looking up disk metadata for disk $DiskNumber"
    $GetOSDDisk = Get-OSDCloudDisk -Number $DiskNumber
    #=================================================
    # Failure: No Fixed Disks are present
    #=================================================
    if ($null -eq $GetOSDDisk) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Disk lookup failed for disk $DiskNumber"
        Write-Warning "No Fixed Disks were found"
        Break
    }
    #=================================================
    # PartitionStyle
    #=================================================
    if (-NOT ($PartitionStyle)) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PartitionStyle was not supplied; inferring from current boot mode"
        if ($global:OSDCloudDevice.IsUEFI -eq $true) {
            $PartitionStyle = 'GPT'
        } else {
            $PartitionStyle = 'MBR'
        }
    }
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PartitionStyle is set to $PartitionStyle"
    #=================================================
    # GPT WINDOWS
    #=================================================
    if ($PartitionStyle -eq 'GPT' -and $NoRecoveryPartition -eq $true) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT Windows partition without a recovery partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT Windows Partition"
        $PartitionWindows = New-Partition -DiskNumber $DiskNumber -UseMaximumSize -GptType '{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}' -DriveLetter C

        #$null = Format-Volume -Partition $PartitionWindows -NewFileSystemLabel "$LabelWindows" -FileSystem NTFS -Force -Confirm:$false
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting the GPT Windows partition as NTFS with label $LabelWindows"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] DISKPART> select disk $DiskNumber"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] DISKPART> select partition $($PartitionWindows.PartitionNumber)"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] DISKPART> format fs=$FileSystem quick label='$LabelWindows'"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] DISKPART> assign letter C"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] DISKPART> exit"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting GPT Windows Partition NTFS with Label $LabelWindows on Drive Letter C"

$null = @"
select disk $DiskNumber
select partition $($PartitionWindows.PartitionNumber)
format fs=ntfs quick label="$LabelWindows"
assign letter C
exit
"@
 | diskpart.exe
    }
    #=================================================
    # GPT WINDOWS + RECOVERY
    #=================================================
    if ($PartitionStyle -eq 'GPT' -and $NoRecoveryPartition -eq $false) {

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Calculating Windows partition size from the remaining free space"
        $SizeWindows = $($GetOSDDisk.LargestFreeExtent) - $SizeRecovery
        $SizeWindowsGB = [math]::Round($SizeWindows / 1GB,1)

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT Windows partition with a recovery partition reserved"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT Windows Partition"
        $PartitionWindows = New-Partition -DiskNumber $DiskNumber -Size $SizeWindows -GptType '{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}' -DriveLetter C

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting the GPT Windows partition as NTFS with label $LabelWindows"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting GPT Windows Partition NTFS with Label $LabelWindows on Drive Letter C"
        #$null = Format-Volume -Partition $PartitionWindows -NewFileSystemLabel "$LabelWindows" -FileSystem NTFS -Force -Confirm:$false

$null = @"
select disk $DiskNumber
select partition $($PartitionWindows.PartitionNumber)
format fs=ntfs quick label="$LabelWindows"
assign letter C
exit
"@
 | diskpart.exe

    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT recovery partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating GPT Recovery Partition"
        $PartitionRecovery = New-Partition -DiskNumber $DiskNumber -GptType '{de94bba4-06d1-4d40-a16a-bfd50179d6ac}' -UseMaximumSize

    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting the GPT recovery partition as NTFS with label $LabelRecovery"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Format-Volume FileSystem NTFS NewFileSystemLabel $LabelRecovery"
        #$null = Format-Volume -Partition $PartitionRecovery -NewFileSystemLabel "$LabelRecovery" -FileSystem NTFS -Confirm:$false
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting GPT Recovery Partition NTFS with Label $LabelRecovery on Drive Letter R"

$null = @"
select disk $DiskNumber
select partition $($PartitionRecovery.PartitionNumber)
format fs=ntfs quick label="$LabelRecovery"
assign letter R
exit
"@
 | diskpart.exe

            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Applying the recovery partition GPT attributes"
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Set-Partition Attributes 0x8000000000000001"
$null = @"
select disk $DiskNumber
select partition $($PartitionRecovery.PartitionNumber)
gpt attributes=0x8000000000000001
exit
"@
 | diskpart.exe
    }
    #=================================================
    # MBR WINDOWS
    #=================================================
    if ($PartitionStyle -eq 'MBR' -and $NoRecoveryPartition -eq $true) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MBR Windows partition without a recovery partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MBR Windows Partition"
        $PartitionWindows = New-Partition -DiskNumber $DiskNumber -UseMaximumSize -MbrType IFS -DriveLetter C

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting the MBR Windows partition as NTFS with label $LabelWindows"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Format-Volume -DriveLetter C -FileSystem NTFS -NewFileSystemLabel $LabelWindows"
        #$null = Format-Volume -Partition $PartitionWindows -NewFileSystemLabel "$LabelWindows" -FileSystem NTFS -Force -Confirm:$false
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting MBR Recovery Partition NTFS with Label $LabelRecovery on Drive Letter R"
$null = @"
select disk $DiskNumber
select partition $($PartitionWindows.PartitionNumber)
format fs=ntfs quick label="$LabelWindows"
assign letter C
exit
"@
 | diskpart.exe
    }
    #=================================================
    # MBR WINDOWS + RECOVERY
    #=================================================
    if ($PartitionStyle -eq 'MBR' -and $NoRecoveryPartition -eq $false) {

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Reading disk geometry before creating the MBR Windows partition"
        $OSDDisk = Get-Disk -Number $DiskNumber
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Calculating Windows partition size from the remaining free space"
        $SizeWindows = $($OSDDisk.LargestFreeExtent) - $SizeRecovery
        $SizeWindowsGB = [math]::Round($SizeWindows / 1GB,1)

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MBR Windows partition with a recovery partition reserved"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MBR Windows Partition"
        $PartitionWindows = New-Partition -DiskNumber $DiskNumber -Size $SizeWindows -MbrType IFS -DriveLetter c

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting the MBR Windows partition as NTFS with label $LabelWindows"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Format-Volume FileSystem NTFS NewFileSystemLabel $LabelWindows"
        #$null = Format-Volume -Partition $PartitionWindows -NewFileSystemLabel "$LabelWindows" -FileSystem NTFS -Force -Confirm:$false
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting MBR Recovery Partition NTFS with Label $LabelRecovery on Drive Letter R"

$null = @"
select disk $DiskNumber
select partition $($PartitionWindows.PartitionNumber)
format fs=ntfs quick label="$LabelWindows"
assign letter C
exit
"@
 | diskpart.exe

    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating MBR recovery partition"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] New-Partition -DiskNumber $DiskNumber -UseMaximumSize"
        $PartitionRecovery = New-Partition -DiskNumber $DiskNumber -UseMaximumSize

    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Formatting the MBR recovery partition as NTFS with label $LabelRecovery"
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Format-Volume -FileSystem NTFS -NewFileSystemLabel $LabelRecovery"
        #$null = Format-Volume -Partition $PartitionRecovery -NewFileSystemLabel "$LabelRecovery" -FileSystem NTFS -Confirm:$false

$null = @"
select disk $DiskNumber
select partition $($PartitionRecovery.PartitionNumber)
format fs=ntfs quick label="$LabelRecovery"
assign letter R
exit
"@
 | diskpart.exe

            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Applying the recovery partition ID 27"
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Set-Partition id 27"
$null = @"
select disk $DiskNumber
select partition $($PartitionRecovery.PartitionNumber)
set id=27
exit
"@
 | diskpart.exe
    }
}
function Clear-DeviceLocalDisk {
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,

        [Alias('Disk','Number')]
        [uint32]$DiskNumber,

        [Alias('I')]
        [System.Management.Automation.SwitchParameter]$Initialize,

        [Alias('PS')]
        [ValidateSet('GPT','MBR')]
        [string]$PartitionStyle,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [Alias('F')]
        [System.Management.Automation.SwitchParameter]$Force,

        [System.Management.Automation.SwitchParameter]$NoResults,

        [Alias('W','Warn','Warning')]
        [System.Management.Automation.SwitchParameter]$ShowWarning
    )
    #=================================================
    # PSBoundParameters
    #=================================================
    $IsConfirmPresent   = $PSBoundParameters.ContainsKey('Confirm')
    $IsForcePresent     = $PSBoundParameters.ContainsKey('Force')
    $IsVerbosePresent   = $PSBoundParameters.ContainsKey('Verbose')
    #=================================================
    # Enable Verbose if Force parameter is not $true
    #=================================================
    if ($IsForcePresent -eq $false) {
        $VerbosePreference = 'Continue'
    }
    #=================================================
    # Get-Disk
    #=================================================
    if ($Input) {
        $GetDisk = $Input
    } else {
        $GetDisk = Get-DeviceLocalDisk | Where-Object {$_.IsBoot -eq $false} | Sort-Object Number
    }
    #=================================================
    # Get DiskNumber
    #=================================================
    if ($PSBoundParameters.ContainsKey('DiskNumber')) {
        $GetDisk = $GetDisk | Where-Object {$_.DiskNumber -eq $DiskNumber}
    }
    #=================================================
    # -PartitionStyle
    #=================================================
    if (-NOT ($PSBoundParameters.ContainsKey('PartitionStyle'))) {
        if ($global:OSDCloudDevice.IsUEFI -eq $true) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] IsUEFI = $true"
            $PartitionStyle = 'GPT'
        } else {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] IsUEFI = $false"
            $PartitionStyle = 'MBR'
        }
    }
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PartitionStyle = $PartitionStyle"
    #=================================================
    # Get-Help
    #=================================================
    if ($IsForcePresent -eq $false) {
        Get-Help $($MyInvocation.MyCommand.Name)
    }
    #=================================================
    # Display Disk Information
    #=================================================
    $GetDisk | Select-Object -Property DiskNumber, BusType,`
    @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
    FriendlyName,Model, PartitionStyle,`
    @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
    Format-Table | Out-Host

    if ($IsForcePresent -eq $false) {
        Break
    }
    #=================================================
    # Display Warning
    #=================================================
    if ($PSBoundParameters.ContainsKey('ShowWarning')) {
        Write-Warning "All data on the cleared Disk will be cleared and all data will be lost"
        pause
    }
    #=================================================
    # Clear-Disk
    #=================================================
    $ClearDisk = @()
    foreach ($Item in $GetDisk) {
        if ($PSCmdlet.ShouldProcess(
            "Disk $($Item.Number) $($Item.BusType) $([int]($Item.Size / 1000000000))GB $($Item.FriendlyName) [$($Item.PartitionStyle) $($Item.NumberOfPartitions) Partitions]",
            "Clear-Disk"
        ))
        {
            Write-Warning "Cleaning Disk $($Item.Number) $($Item.BusType) $([int]($Item.Size / 1000000000))GB $($Item.FriendlyName) [$($Item.PartitionStyle) $($Item.NumberOfPartitions) Partitions]"
            Invoke-DiskpartClean -DiskNumber $Item.Number

            if ($Initialize -eq $true) {
                Write-Warning "Initializing $PartitionStyle Disk $($Item.Number) $($Item.BusType) $([int]($Item.Size / 1000000000))GB $($Item.FriendlyName)"
                $Item | Initialize-Disk -PartitionStyle $PartitionStyle
            }

            $ClearDisk += Get-OSDCloudDisk -Number $Item.Number
        }
    }
    #=================================================
    # Return
    #=================================================
    if ($PSBoundParameters.ContainsKey('NoResults')) {
        #Don't return results
    }
    else {
        $ClearDisk | Select-Object -Property DiskNumber, BusType,`
        @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
        FriendlyName, Model, PartitionStyle,`
        @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
        Format-Table | Out-Host
    }
    #=================================================
}
function Get-DeviceDataDisk {
    [CmdletBinding()]
    param ()
    #=================================================
    # Get-Partition Information
    #=================================================
    $GetPartition = Get-Partition | `
    Where-Object {$_.DriveLetter -gt 0} | `
    Where-Object {$_.IsOffline -eq $false} | `
    Where-Object {$_.IsReadOnly -ne $true} | `
    Where-Object {$_.Size -gt 10000000000} | `
    Sort-Object -Property DriveLetter | `
    Select-Object -Property DriveLetter, DiskNumber
    #=================================================
    # Get-Volume Information
    #=================================================
    $GetVolume = $(Get-Volume | `
    Sort-Object -Property DriveLetter | `
    Select-Object -Property DriveLetter,FileSystem,OperationalStatus,DriveType,FileSystemLabel,Size,SizeRemaining)
    #=================================================
    # Create Object
    #=================================================
    $LocalResults = foreach ($Item in $GetPartition) {
        $GetVolumeProperties = $GetVolume | Where-Object {$_.DriveLetter -eq $Item.DriveLetter}
        $ObjectProperties = @{

            DiskNumber          = $Item.DiskNumber
            DriveLetter         = $GetVolumeProperties.DriveLetter
            FileSystem          = $GetVolumeProperties.FileSystem
            OperationalStatus   = $GetVolumeProperties.OperationalStatus
            DriveType           = $GetVolumeProperties.DriveType
            FileSystemLabel     = $GetVolumeProperties.FileSystemLabel
            Size                = $GetVolumeProperties.Size
            SizeRemaining       = $GetVolumeProperties.SizeRemaining

        }
        New-Object -TypeName PSObject -Property $ObjectProperties
    }
    #=================================================
    # Get-DriveInfo
    #=================================================
    $GetNetworkDrives = [System.IO.DriveInfo]::getdrives() | Where-Object {$_.DriveType -eq 'Network'} | Where-Object {$_.DriveFormat -eq 'NTFS'}
    $NetworkResults = foreach ($Item in $GetNetworkDrives) {
        $ObjectProperties = @{
            DiskNumber          = 99
            DriveLetter         = ($Item.Name).substring(0,1)
            FileSystem          = 'NTFS'
            OperationalStatus   = $Item.IsReady
            DriveType           = 'Network'
            FileSystemLabel     = $Item.VolumeLabel
            Size                = $Item.TotalSize
            SizeRemaining       = $Item.TotalFreeSpace

        }
        New-Object -TypeName PSObject -Property $ObjectProperties
    }
    #=================================================
    # Return Results
    #=================================================
    $LocalResults = $LocalResults | Sort-Object -Property DriveLetter
    $LocalResults = $LocalResults | Where-Object {$_.FileSystem -eq 'NTFS'}
    [array]$Results = [array]$LocalResults + [array]$NetworkResults
    Return [array]$Results
}
function Get-DeviceLocalDisk {
    [CmdletBinding()]
    param ()
    #=================================================
    # Get-OSDCloudDisk
    #=================================================
    $GetDisk = Get-OSDCloudDisk -BusTypeNot 'File Backed Virtual',MAX,'Microsoft Reserved',USB,Virtual
    #=================================================
    # Return
    #=================================================
    Return $GetDisk
    #=================================================
}
function Get-DeviceLocalDiskPartition {
    [CmdletBinding()]
    param ()

    #=================================================
    # Return
    #=================================================
    Return (Get-OSDCloudPartition | Where-Object {$_.IsUSB -eq $false})
    #=================================================
}
function Get-DeviceLocalDiskVolume {
    [CmdletBinding()]
    param ()
    #=================================================
    # Return
    #=================================================
    Return (Get-OSDCloudVolume | Where-Object {$_.IsUSB -eq $false})
    #=================================================
}
function Get-OSDCloudDisk {
    [CmdletBinding()]
    param (
        [Alias('Disk','DiskNumber')]
        [uint32]$Number,

        [bool]$BootFromDisk,
        [bool]$IsBoot,
        [bool]$IsReadOnly,
        [bool]$IsSystem,

        [ValidateSet('1394','ATA','ATAPI','Fibre Channel','File Backed Virtual','iSCSI','MMC','MAX','Microsoft Reserved','NVMe','RAID','SAS','SATA','SCSI','SD','SSA','Storage Spaces','USB','Virtual')]
        [string[]]$BusType,
        [ValidateSet('1394','ATA','ATAPI','Fibre Channel','File Backed Virtual','iSCSI','MMC','MAX','Microsoft Reserved','NVMe','RAID','SAS','SATA','SCSI','SD','SSA','Storage Spaces','USB','Virtual')]
        [string[]]$BusTypeNot,

        [ValidateSet('SSD','HDD','SCM','Unspecified')]
        [string[]]$MediaType,
        [ValidateSet('SSD','HDD','SCM','Unspecified')]
        [string[]]$MediaTypeNot,

        [ValidateSet('GPT','MBR','RAW')]
        [string[]]$PartitionStyle,
        [ValidateSet('GPT','MBR','RAW')]
        [string[]]$PartitionStyleNot
    )
    #=================================================
    # PSBoundParameters
    #=================================================
    $IsConfirmPresent   = $PSBoundParameters.ContainsKey('Confirm')
    $IsForcePresent     = $PSBoundParameters.ContainsKey('Force')
    $IsVerbosePresent   = $PSBoundParameters.ContainsKey('Verbose')
    #=================================================
    # Get Variables
    #=================================================
    $GetDisk = Get-Disk | Sort-Object DiskNumber | Select-Object -Property *
    $GetPhysicalDisk = Get-PhysicalDisk | Sort-Object DeviceId
    #=================================================
    # Add Property MediaType
    #=================================================
    foreach ($Disk in $GetDisk) {
        foreach ($PhysicalDisk in $GetPhysicalDisk | Where-Object {$_.DeviceId -eq $Disk.Number}) {
            $Disk | Add-Member -NotePropertyName 'MediaType' -NotePropertyValue $PhysicalDisk.MediaType
        }
    }
    #=================================================
    # Exclude Empty Disks or Card Readers
    #=================================================
    $GetDisk = $GetDisk | Where-Object {$_.IsOffline -eq $false}
    $GetDisk = $GetDisk | Where-Object {$_.OperationalStatus -ne 'No Media'}
    #=================================================
    # -Number
    #=================================================
    if ($PSBoundParameters.ContainsKey('Number')) {
        $GetDisk = $GetDisk | Where-Object {$_.DiskNumber -eq $Number}
    }
    #=================================================
    # Filters
    #=================================================
    if ($PSBoundParameters.ContainsKey('BootFromDisk')) {$GetDisk = $GetDisk | Where-Object {$_.BootFromDisk -eq $BootFromDisk}}
    if ($PSBoundParameters.ContainsKey('IsBoot')) {$GetDisk = $GetDisk | Where-Object {$_.IsBoot -eq $IsBoot}}
    if ($PSBoundParameters.ContainsKey('IsReadOnly')) {$GetDisk = $GetDisk | Where-Object {$_.IsReadOnly -eq $IsReadOnly}}
    if ($PSBoundParameters.ContainsKey('IsSystem')) {$GetDisk = $GetDisk | Where-Object {$_.IsSystem -eq $IsSystem}}

    if ($BusType)               {$GetDisk = $GetDisk | Where-Object {$_.BusType -in $BusType}}
    if ($BusTypeNot)            {$GetDisk = $GetDisk | Where-Object {$_.BusType -notin $BusTypeNot}}
    if ($MediaType)             {$GetDisk = $GetDisk | Where-Object {$_.MediaType -in $MediaType}}
    if ($MediaTypeNot)          {$GetDisk = $GetDisk | Where-Object {$_.MediaType -notin $MediaTypeNot}}
    if ($PartitionStyle)        {$GetDisk = $GetDisk | Where-Object {$_.PartitionStyle -in $PartitionStyle}}
    if ($PartitionStyleNot)     {$GetDisk = $GetDisk | Where-Object {$_.PartitionStyle -notin $PartitionStyleNot}}
    #=================================================
    # Return
    #=================================================
    Return $GetDisk
    #=================================================
}
function Get-OSDCloudPartition {
    [CmdletBinding()]
    param ()
    #=================================================
    # PSBoundParameters
    #=================================================
    $IsConfirmPresent   = $PSBoundParameters.ContainsKey('Confirm')
    $IsForcePresent     = $PSBoundParameters.ContainsKey('Force')
    $IsVerbosePresent   = $PSBoundParameters.ContainsKey('Verbose')
    #=================================================
    # Get Variables
    #=================================================
    $GetDisk = Get-OSDCloudDisk -BusType USB
    $GetPartition = Get-Partition | Sort-Object DiskNumber, PartitionNumber
    #=================================================
    # Add Property IsUSB
    #=================================================
    foreach ($Partition in $GetPartition) {
        if ($Partition.DiskNumber -in $($GetDisk).DiskNumber) {
            $Partition | Add-Member -NotePropertyName 'IsUSB' -NotePropertyValue $true -Force
        } else {
            $Partition | Add-Member -NotePropertyName 'IsUSB' -NotePropertyValue $false -Force
        }
    }
    #=================================================
    # Return
    #=================================================
    Return $GetPartition
    #=================================================
}
function Get-OSDCloudVolume {
    [CmdletBinding()]
    param ()
    #=================================================
    # PSBoundParameters
    #=================================================
    $IsConfirmPresent   = $PSBoundParameters.ContainsKey('Confirm')
    $IsForcePresent     = $PSBoundParameters.ContainsKey('Force')
    $IsVerbosePresent   = $PSBoundParameters.ContainsKey('Verbose')
    #=================================================
    # Get Variables
    #=================================================
    $GetPartition = Get-DeviceUSBPartition
    $GetVolume = Get-Volume | Sort-Object DriveLetter
    #=================================================
    # Add Property IsUSB
    #=================================================
    foreach ($Volume in $GetVolume) {
        if ($Volume.Path -in $($GetPartition).AccessPaths) {
            $Volume | Add-Member -NotePropertyName 'IsUSB' -NotePropertyValue $true -Force
        } else {
            $Volume | Add-Member -NotePropertyName 'IsUSB' -NotePropertyValue $false -Force
        }
    }
    #=================================================
    # Return
    #=================================================
    Return $GetVolume | Sort-Object DriveLetter | Select-Object -Property DriveLetter, FileSystemLabel, FileSystem, `
                        @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}}, `
                        @{Name='SizeRemainingGB';Expression={[int]($_.SizeRemaining / 1000000000)}}, `
                        @{Name='SizeRemainingMB';Expression={[int]($_.SizeRemaining / 1000000)}}, `
                        IsUSB, DriveType, OperationalStatus, HealthStatus
    #=================================================
}
function Get-DeviceUSBDisk {
    [CmdletBinding()]
    param ()
    #=================================================
    # Get-OSDCloudDisk
    #=================================================
    $GetDisk = Get-OSDCloudDisk -BusType USB
    #=================================================
    # Return
    #=================================================
    Return $GetDisk
    #=================================================
}
function Get-DeviceUSBPartition {
    [CmdletBinding()]
    param ()

    #=================================================
    # Return
    #=================================================
    Return (Get-OSDCloudPartition | Where-Object {$_.IsUSB -eq $true})
    #=================================================
}
function Get-DeviceUSBVolume {
    [CmdletBinding()]
    param ()
    #=================================================
    # Return
    #=================================================
    Return (Get-OSDCloudVolume | Where-Object {$_.IsUSB -eq $true})
    #=================================================
}
function Invoke-SelectDeviceDataDisk {
    [CmdletBinding()]
    param (
        [int]$NotDiskNumber,
        [System.Management.Automation.SwitchParameter]$Skip,
        [System.Management.Automation.SwitchParameter]$SelectOne
    )
    #=================================================
    # Get USB Disk and add the MinimumSizeGB filter
    #=================================================
    $Results = Get-DeviceDataDisk | Sort-Object -Property DriveLetter
    #=================================================
    # Filter NotDiskNumber
    #=================================================
    if ($PSBoundParameters.ContainsKey('NotDiskNumber')) {
        $Results = $Results | Where-Object {$_.DiskNumber -ne $NotDiskNumber}
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($Results | Measure-Object).Count -eq 1) {
                $SelectedItem = $Results
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $Results | Select-Object -Property DriveLetter, FileSystemLabel,`
        @{Name='FreeGB';Expression={[int]($_.SizeRemaining / 1000000000)}},`
        @{Name='TotalGB';Expression={[int]($_.Size / 1000000000)}},`
        FileSystem, DriveType, DiskNumber | Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a Disk to save the FFU on by DriveLetter, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a Disk to save the FFU on by DriveLetter"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($Results | Where-Object {$_.DriveLetter -eq $Selection})
        #=================================================
    }
}
function Invoke-SelectDeviceLocalDisk {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,
        [System.Management.Automation.SwitchParameter]$Skip,
        [System.Management.Automation.SwitchParameter]$SelectOne
    )
    #=================================================
    # Get-Disk
    #=================================================
    if ($Input) {
        $Results = $Input
    } else {
        $Results = Get-DeviceLocalDisk
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($Results | Measure-Object).Count -eq 1) {
                $SelectedItem = $Results
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $Results | Select-Object -Property DiskNumber, BusType, MediaType,`
        @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
        FriendlyName,Model, PartitionStyle,`
        @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
        Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a Fixed Disk by DiskNumber, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DiskNumber) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a Fixed Disk by DiskNumber"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DiskNumber))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($Results | Where-Object {$_.DiskNumber -eq $Selection})
        #=================================================
    }
}
function Invoke-SelectDeviceLocalVolume {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,
        [int]$MinimumSizeGB = 1,

        [ValidateSet('FAT32','NTFS')]
        [string]$FileSystem,

        [System.Management.Automation.SwitchParameter]$Skip,
        [System.Management.Automation.SwitchParameter]$SelectOne
    )
    #=================================================
    # Get-Volume
    #=================================================
    if ($Input) {
        $Results = $Input
    } else {
        $Results = Get-DeviceLocalDiskVolume | Sort-Object -Property DriveLetter | `
        Where-Object {$_.SizeGB -gt $MinimumSizeGB}
    }
    #=================================================
    # Filter the File System
    #=================================================
    if ($PSBoundParameters.ContainsKey('FileSystem')) {
        $Results = $Results | Where-Object {$_.FileSystem -eq $FileSystem}
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($Results | Measure-Object).Count -eq 1) {
                $SelectedItem = $Results
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $Results | Select-Object -Property DriveLetter, FileSystemLabel,`
        SizeGB, SizeRemainingGB, SizeRemainingMB, DriveType | `
        Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a Fixed Volume by DriveLetter, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a Fixed Volume by DriveLetter"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($Results | Where-Object {$_.DriveLetter -eq $Selection})
        #=================================================
    }
}
function Invoke-SelectOSDCloudDisk {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,
        [System.Management.Automation.SwitchParameter]$Skip,
        [System.Management.Automation.SwitchParameter]$SelectOne
    )
    #=================================================
    # Get-Disk
    #=================================================
    if ($Input) {
        $Results = $Input
    } else {
        $Results = Get-DeviceLocalDisk
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($GetDisk | Measure-Object).Count -eq 1) {
                $SelectedItem = $GetDisk
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $GetDisk | Select-Object -Property DiskNumber, BusType, MediaType,`
        @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
        FriendlyName,Model, PartitionStyle,`
        @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
        Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a Disk by DiskNumber, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $GetDisk.DiskNumber) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a Disk by DiskNumber"}
            until (($Selection -ge 0) -and ($Selection -in $GetDisk.DiskNumber))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($GetDisk | Where-Object {$_.DiskNumber -eq $Selection})
        #=================================================
    }
}
function Invoke-SelectOSDCloudVolume {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,
        [int]$MinimumSizeGB = 1,

        [ValidateSet('FAT32','NTFS')]
        [string]$FileSystem,

        [System.Management.Automation.SwitchParameter]$Skip,
        [System.Management.Automation.SwitchParameter]$SelectOne
    )
    #=================================================
    # Get-Volume
    #=================================================
    if ($Input) {
        $Results = $Input
    } else {
        $Results = Get-OSDCloudVolume | Sort-Object -Property DriveLetter | `
        Where-Object {$_.SizeGB -gt $MinimumSizeGB}
    }
    #=================================================
    # Filter the File System
    #=================================================
    if ($PSBoundParameters.ContainsKey('FileSystem')) {
        $Results = $Results | Where-Object {$_.FileSystem -eq $FileSystem}
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($Results | Measure-Object).Count -eq 1) {
                $SelectedItem = $Results
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $Results | Select-Object -Property DriveLetter, FileSystemLabel,`
        SizeGB, SizeRemainingGB, SizeRemainingMB, `
        IsUSB, DriveType | `
        Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a Volume by DriveLetter, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a Volume by DriveLetter"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($Results | Where-Object {$_.DriveLetter -eq $Selection})
        #=================================================
    }
}
function Invoke-SelectDeviceUSBDisk {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,

        [Alias('Min','MinGB','MinSize')]
        [int]$MinimumSizeGB = 8,

        [Alias('Max','MaxGB','MaxSize')]
        [int]$MaximumSizeGB = 1800,

        [System.Management.Automation.SwitchParameter]$Skip,
        [System.Management.Automation.SwitchParameter]$SelectOne
    )
    #=================================================
    # Get-Disk
    #=================================================
    if ($Input) {
        $Results = $Input
    } else {
        $Results = Get-DeviceUSBDisk | Where-Object {($_.Size -gt ($MinimumSizeGB * 1GB)) -and ($_.Size -lt ($MaximumSizeGB * 1GB))}
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($Results | Measure-Object).Count -eq 1) {
                $SelectedItem = $Results
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $Results | Select-Object -Property DiskNumber, BusType, MediaType,`
        @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
        FriendlyName,Model, PartitionStyle,`
        @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
        Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a USB Disk by DiskNumber, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DiskNumber) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a USB Disk by DiskNumber"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DiskNumber))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($Results | Where-Object {$_.DiskNumber -eq $Selection})
        #=================================================
    }
}
function Invoke-SelectDeviceUSBVolume {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,
        [int]$MinimumSizeGB = 1,

        [ValidateSet('FAT32','NTFS')]
        [string]$FileSystem,

        [System.Management.Automation.SwitchParameter]
        $Skip,

        [System.Management.Automation.SwitchParameter]
        $SelectOne
    )
    #=================================================
    # Get-Volume
    #=================================================
    if ($Input) {
        $Results = $Input
    } else {
        $Results = Get-DeviceUSBVolume | Sort-Object -Property DriveLetter | `
        Where-Object {$_.SizeGB -gt $MinimumSizeGB}
    }
    #=================================================
    # Filter the File System
    #=================================================
    if ($PSBoundParameters.ContainsKey('FileSystem')) {
        $Results = $Results | Where-Object {$_.FileSystem -eq $FileSystem}
    }
    #=================================================
    # Process Results
    #=================================================
    if ($Results) {
        #=================================================
        # There was only 1 Item, then we will select it automatically
        #=================================================
        if ($PSBoundParameters.ContainsKey('SelectOne')) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Automatically select "
            if (($Results | Measure-Object).Count -eq 1) {
                $SelectedItem = $Results
                Return $SelectedItem
            }
        }
        #=================================================
        # Table of Items
        #=================================================
        $Results | Select-Object -Property DriveLetter, FileSystemLabel,`
        SizeGB, SizeRemainingGB, SizeRemainingMB, DriveType | `
        Format-Table | Out-Host
        #=================================================
        # Select an Item
        #=================================================
        if ($PSBoundParameters.ContainsKey('Skip')) {
            do {$Selection = Read-Host -Prompt "Select a USB Volume by DriveLetter, or press S to SKIP"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter) -or ($Selection -eq 'S'))

            if ($Selection -eq 'S') {Return $false}
        }
        else {
            do {$Selection = Read-Host -Prompt "Select a USB Volume by DriveLetter"}
            until (($Selection -ge 0) -and ($Selection -in $Results.DriveLetter))
        }
        #=================================================
        # Return Selection
        #=================================================
        Return ($Results | Where-Object {$_.DriveLetter -eq $Selection})
        #=================================================
    }
}
function New-OSDCloudDisk {
    <#
    .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
 
    .PARAMETER DiskNumber
    Specifies the disk number for which to get the associated Disk object
    Alias = Disk, Number
 
    .PARAMETER Force
    Required for execution
    Alias = F
 
    .PARAMETER LabelRecovery
    Drive Label of the Recovery Partition
    Default = Recovery
    Alias = LR, LabelR
 
    .PARAMETER LabelSystem
    Drive Label of the System Partition
    Default = System
    Alias = LS, LabelS
 
    .PARAMETER LabelWindows
    Drive Label of the Windows Partition
    Default = OS
    Alias = LW, LabelW
 
    .PARAMETER NoRecoveryPartition
    Alias = SkipRecovery, SkipRecoveryPartition
    Skips the creation of the Recovery Partition
 
    .PARAMETER PartitionStyle
    Override the automatic Partition Style of the Initialized Disk
    EFI Default = GPT
    BIOS Default = MBR
    Alias = PS
 
    .PARAMETER SizeMSR
    MSR Partition size
    Default = 16MB
    Range = 16MB - 128MB
    Alias = MSR
 
    .PARAMETER SizeRecovery
    Size of the Recovery Partition
    Default = 2000MB
    Range = 350MB - 80000MB (80GB)
    Alias = SR, Recovery
 
    .PARAMETER SizeSystemGpt
    System Partition size for UEFI GPT based Computers
    Default = 260MB
    Range = 100MB - 3000MB (3GB)
    Alias = SSG, Efi, SystemG
 
    .PARAMETER SizeSystemMbr
    System Partition size for BIOS MBR based Computers
    Default = 260MB
    Range = 100MB - 3000MB (3GB)
    Alias = SSM, Mbr, SystemM
 
    .EXAMPLE
    New-OSDCloudDisk
    Displays Get-Help New-OSDCloudDisk
 
    .EXAMPLE
    New-OSDCloudDisk -Force
    Interactive. Prompted to Confirm Clear-Disk for each Local Disk
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/Docs
 
    .NOTES
    19.10.10 Created by David Segura @SeguraOSD
    21.2.19 Complete redesign
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$Input,

        [Alias('Disk','Number')]
        [uint32]$DiskNumber,

        [Alias('PS')]
        [ValidateSet('GPT','MBR')]
        [string]$PartitionStyle,

        [Alias('LS','LabelS')]
        [string]$LabelSystem = 'System',

        [Alias('SSG','Efi','SystemG')]
        [ValidateRange(100MB,3000MB)]
        [uint64]$SizeSystemGpt = 500MB,

        [Alias('SSM','Mbr','SystemM')]
        [ValidateRange(100MB,3000MB)]
        [uint64]$SizeSystemMbr = 500MB,

        [Alias('MSR')]
        [ValidateRange(16MB,128MB)]
        [uint64]$SizeMSR = 16MB,

        [Alias('LW','LabelW')]
        [string]$LabelWindows = 'OS',

        [Alias('SkipRecovery','SkipRecoveryPartition')]
        [System.Management.Automation.SwitchParameter]$NoRecoveryPartition,

        [Alias('LR','LabelR')]
        [string]$LabelRecovery = 'Recovery',

        [Alias('SR','Recovery')]
        [ValidateRange(350MB,80000MB)]
        [uint64]$SizeRecovery = 2000MB,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [Alias('F')]
        [System.Management.Automation.SwitchParameter]$Force
    )
    #=================================================
    # PSBoundParameters
    #=================================================
    $IsConfirmPresent   = $PSBoundParameters.ContainsKey('Confirm')
    $IsForcePresent     = $PSBoundParameters.ContainsKey('Force')
    $IsVerbosePresent   = $PSBoundParameters.ContainsKey('Verbose')
    #=================================================
    # Enable Verbose if Force parameter is not $true
    #=================================================
    if ($IsForcePresent -eq $false) {
        $VerbosePreference = 'Continue'
    }
    #=================================================
    # Get-Disk
    #=================================================
    if ($Input) {
        $GetDisk = $Input
    } else {
        $GetDisk = Get-DeviceLocalDisk | Sort-Object Number
    }
    #=================================================
    # Get DiskNumber
    #=================================================
    if ($PSBoundParameters.ContainsKey('DiskNumber')) {
        $GetDisk = $GetDisk | Where-Object {$_.DiskNumber -eq $DiskNumber}
    }
    #=================================================
    # OSDisks must be large enough for a Windows installation
    #=================================================
    $GetDisk = $GetDisk | Where-Object {$_.Size -gt 15GB}
    #=================================================
    # -PartitionStyle
    #=================================================
    if (-NOT ($PSBoundParameters.ContainsKey('PartitionStyle'))) {
        if ($global:OSDCloudDevice.IsUEFI -eq $true) {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] IsUEFI = $true"
            $PartitionStyle = 'GPT'
        } else {
            Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] IsUEFI = $false"
            $PartitionStyle = 'MBR'
        }
    }
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PartitionStyle = $PartitionStyle"
    #=================================================
    # Get-Help
    #=================================================
    if ($IsForcePresent -eq $false) {
        Get-Help $($MyInvocation.MyCommand.Name)
    }
    #=================================================
    # Display Disk Information
    #=================================================
    if ($IsForcePresent -eq $false) {
        $GetDisk | Select-Object -Property DiskNumber, BusType,`
        @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
        FriendlyName, Model, PartitionStyle,`
        @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
        Format-Table | Out-Host

        Break
    }
    #=================================================
    # Failure: No Fixed Disks are present
    #=================================================
    if ($null -eq $GetDisk) {
        Write-Warning "No Fixed Disks were found"
        Break
    }
    #=================================================
    # Set Defaults
    #=================================================
    $OSDisk = $null
    $DataDisks = $null
    #=================================================
    # Identify OSDisk
    #=================================================
    if (($GetDisk | Measure-Object).Count -eq 1) {
        $OSDisk = $GetDisk
    } else {

        $OSDisk = Invoke-SelectDeviceLocalDisk -Input $GetDisk
        $DataDisks = $GetDisk | Where-Object {$_.Number -ne $OSDisk.Number}
    }
    Write-Host ""
    #=================================================
    # Make sure there is only one OSDisk
    #=================================================
    if (($OSDisk | Measure-Object).Count -gt 1) {
        Write-Warning "Something went wrong"
        Break
    }
    #=================================================
    # Create OSDisk
    #=================================================
    #Create from RAW Disk
    if (($OSDisk.NumberOfPartitions -eq 0) -and ($OSDisk.PartitionStyle -eq 'RAW')) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Initializing Disk $($OSDisk.Number) as $PartitionStyle"
        $OSDisk | Initialize-Disk -PartitionStyle $PartitionStyle

    }
    #Create from unpartitioned Disk
    elseif (($OSDisk.NumberOfPartitions -eq 0) -and ($OSDisk.PartitionStyle -ne $PartitionStyle)) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Cleaning Disk $($OSDisk.Number)"
        Invoke-DiskpartClean -DiskNumber $OSDisk.Number

        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Initializing Disk $($OSDisk.Number) as $PartitionStyle"
        $OSDisk | Initialize-Disk -PartitionStyle $PartitionStyle
    }
    #Prompt for confirmation to clear the existing disk
    else {
        if ($PSCmdlet.ShouldProcess(
            "Disk $($OSDisk.Number) $($OSDisk.BusType) $($OSDisk.SizeGB) $($OSDisk.FriendlyName) $($OSDisk.Model) [$($OSDisk.PartitionStyle) $($OSDisk.NumberOfPartitions) Partitions]",
            "Clear-Disk"
        ))
        {
            Write-Warning "Cleaning Disk $($OSDisk.Number) $($OSDisk.BusType) $($OSDisk.SizeGB) $($OSDisk.FriendlyName) $($OSDisk.Model) [$($OSDisk.PartitionStyle) $($OSDisk.NumberOfPartitions) Partitions]"
            Invoke-DiskpartClean -DiskNumber $OSDisk.Number

            Write-Warning "Initializing $PartitionStyle Disk $($OSDisk.Number) $($OSDisk.BusType) $($OSDisk.SizeGB) $($OSDisk.FriendlyName) $($OSDisk.Model)"
            $OSDisk | Initialize-Disk -PartitionStyle $PartitionStyle
        }
    }
    #=================================================
    # Reassign Volume S
    #=================================================
    $GetVolume = Get-Volume | Where-Object {$_.DriveLetter -eq 'S'}

    if ($GetVolume) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Reassigning Drive Letter S"
        #Get-Partition -DriveLetter 'S' | Set-Partition -NewDriveLetter (Get-LastAvailableDriveLetter)
        Get-Volume -DriveLetter S | Get-Partition | Remove-PartitionAccessPath -AccessPath 'S:\' -ErrorAction SilentlyContinue
    }
    #=================================================
    # System Partition
    #=================================================
    $SystemPartition = @{
        DiskNumber          = $OSDisk.Number
        LabelSystem         = $LabelSystem
        PartitionStyle      = $PartitionStyle
        SizeMSR             = $SizeMSR
        SizeSystemMbr       = $SizeSystemMbr
        SizeSystemGpt       = $SizeSystemGpt
    }
    New-OSDCloudPartitionSystem @SystemPartition
    #=================================================
    # Reassign Volume C
    #=================================================
    $GetVolume = Get-Volume | Where-Object {$_.DriveLetter -eq 'C'}

    if ($GetVolume) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Reassigning Drive Letter C"
        Get-Partition -DriveLetter 'C' | Set-Partition -NewDriveLetter (Get-LastAvailableDriveLetter)
    }
    #=================================================
    # Reassign Volume R
    #=================================================
    $GetVolume = Get-Volume | Where-Object {$_.DriveLetter -eq 'R'}

    if ($GetVolume) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Reassigning Drive Letter R"
        #Get-Partition -DriveLetter 'R' | Set-Partition -NewDriveLetter (Get-LastAvailableDriveLetter)
        Get-Volume -DriveLetter R | Get-Partition | Remove-PartitionAccessPath -AccessPath 'R:\' -ErrorAction SilentlyContinue
    }
    #=================================================
    # Windows Partition
    #=================================================
    $WindowsPartition = @{
        DiskNumber              = $OSDisk.Number
        LabelRecovery           = $LabelRecovery
        LabelWindows            = $LabelWindows
        PartitionStyle          = $PartitionStyle
        SizeRecovery            = $SizeRecovery
        NoRecoveryPartition     = $NoRecoveryPartition
    }
    New-OSDCloudPartitionWindows @WindowsPartition
    #=================================================
    # DataDisks
    #=================================================
    Get-OSDCloudDisk | Select-Object -Property DiskNumber, BusType,`
    @{Name='SizeGB';Expression={[int]($_.Size / 1000000000)}},`
    FriendlyName, Model, PartitionStyle,`
    @{Name='Partitions';Expression={$_.NumberOfPartitions}} | `
    Format-Table | Out-Host
}