How to Check if a Drive is a Removable Drive in Batch Script
When your script is about to format a drive, copy sensitive data, or run a cleanup routine, you need to ensure it targets the correct type of storage. Accidentally formatting a USB flash drive thinking it was a local partition, or vice versa, can be catastrophic. Windows classifies drives by their type: Fixed (internal hard drives), Removable (USB sticks, SD cards), CD-ROM, Network, and more. A Batch script can check this classification before performing any destructive action, providing a critical safety gate.
This guide will explain how to identify removable media programmatically.
Drive Type Classifications
| Type Code | Name | Description | Examples |
|---|---|---|---|
| 0 | Unknown | Drive type cannot be determined | Rare, damaged or unusual hardware |
| 1 | No Root Directory | Root path is invalid | Very rare |
| 2 | Removable | Removable media | USB flash drives, SD cards, floppy drives |
| 3 | Fixed | Non-removable local disk | Internal HDDs, SSDs, and most external USB hard drives |
| 4 | Network | Network-mapped drive | \\Server\Share mapped to a letter |
| 5 | CD-ROM | Optical disc drive | CD, DVD, Blu-ray |
| 6 | RAM Disk | RAM-based virtual disk | RAM drives |
External USB hard drives (both 2.5" and 3.5") are classified as DriveType 3 (Fixed), not 2 (Removable), even though they are physically removable. This is because the USB-SATA bridge controller reports them as fixed disks. Only USB flash drives and SD cards report as DriveType 2. To distinguish external HDDs from internal ones, check the bus type (USB vs. SATA/NVMe) using Method 3.
Method 1: Check a Specific Drive
This method queries the drive type of a specific drive and provides a clear classification with human-readable output.
@echo off
setlocal EnableDelayedExpansion
set "Drive=%~1"
if "%Drive%"=="" (
echo Usage: %~nx0 ^<drive_letter^>
echo.
echo Examples:
echo %~nx0 C
echo %~nx0 E:
echo.
echo Available drives:
wmic logicaldisk get deviceid,volumename,drivetype 2>nul
endlocal
exit /b 1
)
:: Normalize drive letter (handle both "C" and "C:")
set "DriveLetter=%Drive:~0,1%"
set "DriveColon=%DriveLetter%:"
if not exist %DriveColon%\ (
echo [ERROR] Drive %DriveColon% does not exist or is not accessible. >&2
endlocal
exit /b 1
)
echo ============================================================
echo Drive Information Query
echo ============================================================
echo.
echo Querying: %DriveColon%
echo.
:: Build PowerShell command with proper escaping
set "PSCmd=$vol = Get-CimInstance Win32_LogicalDisk -Filter \"DeviceID='%DriveColon%'\" -ErrorAction SilentlyContinue;"
set "PSCmd=!PSCmd! if (-not $vol) { Write-Output 'NOT_FOUND~~~'; exit 1 };"
set "PSCmd=!PSCmd! $typeName = switch ($vol.DriveType) {"
set "PSCmd=!PSCmd! 0 { 'Unknown' }"
set "PSCmd=!PSCmd! 1 { 'No Root Directory' }"
set "PSCmd=!PSCmd! 2 { 'Removable' }"
set "PSCmd=!PSCmd! 3 { 'Fixed' }"
set "PSCmd=!PSCmd! 4 { 'Network' }"
set "PSCmd=!PSCmd! 5 { 'CD-ROM' }"
set "PSCmd=!PSCmd! 6 { 'RAM Disk' }"
set "PSCmd=!PSCmd! default { 'Unknown' }"
set "PSCmd=!PSCmd! };"
set "PSCmd=!PSCmd! $label = if ($vol.VolumeName) { $vol.VolumeName } else { '(No Label)' };"
set "PSCmd=!PSCmd! $sizeGB = if ($vol.Size -gt 0) { [math]::Round($vol.Size / 1GB, 2) } else { 'N/A' };"
set "PSCmd=!PSCmd! $freeGB = if ($vol.FreeSpace -gt 0) { [math]::Round($vol.FreeSpace / 1GB, 2) } else { 'N/A' };"
set "PSCmd=!PSCmd! $fs = if ($vol.FileSystem) { $vol.FileSystem } else { 'N/A' };"
set "PSCmd=!PSCmd! Write-Output ('{0}~{1}~{2}~{3}~{4}~{5}' -f $vol.DriveType, $typeName, $label, $sizeGB, $freeGB, $fs)"
:: Execute PowerShell and parse output (using ~ as delimiter)
set "TypeCode="
set "TypeName="
set "Label="
set "SizeGB="
set "FreeGB="
set "FileSystem="
for /f "tokens=1-6 delims=~" %%a in (
'powershell -NoProfile -ExecutionPolicy Bypass -Command "!PSCmd!" 2^>nul'
) do (
set "TypeCode=%%a"
set "TypeName=%%b"
set "Label=%%c"
set "SizeGB=%%d"
set "FreeGB=%%e"
set "FileSystem=%%f"
)
:: Validate output
if "!TypeCode!"=="NOT_FOUND" (
echo [ERROR] Could not query drive %DriveColon%. >&2
endlocal
exit /b 1
)
if not defined TypeCode (
echo [ERROR] PowerShell query failed. >&2
endlocal
exit /b 1
)
:: Display results
echo ============================================================
echo Drive Details
echo ============================================================
echo.
echo Drive: %DriveColon%
echo Label: !Label!
echo Type: !TypeName! (Code: !TypeCode!)
echo File System: !FileSystem!
if "!SizeGB!" neq "N/A" (
echo Size: !SizeGB! GB
echo Free: !FreeGB! GB
:: Calculate used percentage
for /f %%p in ('powershell -NoProfile -Command "if (!SizeGB! -gt 0) { [math]::Round(((!SizeGB! - !FreeGB!) / !SizeGB!) * 100, 1) } else { 0 }"') do set "UsedPct=%%p"
echo Used: !UsedPct!%%
)
echo ============================================================
echo.
:: Interpret drive type
if "!TypeCode!"=="2" (
echo [REMOVABLE MEDIA]
echo.
echo Characteristics:
echo - USB flash drives, SD cards, external SSDs
echo - Can be safely ejected
echo - Hot-pluggable
echo.
echo Recommendations:
echo - Always use "Safely Remove Hardware"
echo - Verify backups before formatting
) else if "!TypeCode!"=="3" (
echo [FIXED DISK]
echo.
echo Characteristics:
echo - Internal hard drives, SSDs
echo - External USB hard drives also show as Fixed
echo - Permanent storage
echo.
:: Check if disk is getting full
if defined UsedPct (
for /f %%n in ("!UsedPct!") do set /a "UsedInt=%%n"
if !UsedInt! GEQ 90 (
echo [WARNING] Disk is !UsedPct!%% full - consider cleanup
) else if !UsedInt! GEQ 80 (
echo [INFO] Disk is !UsedPct!%% full - monitor space usage
)
)
) else if "!TypeCode!"=="4" (
echo [NETWORK DRIVE]
echo.
echo Characteristics:
echo - Mapped network share
echo - Requires network connectivity
echo - May have access restrictions
echo.
echo Note: Performance depends on network speed
) else if "!TypeCode!"=="5" (
echo [OPTICAL DRIVE]
echo.
echo Characteristics:
echo - CD-ROM, DVD, or Blu-ray drive
echo - Read-only or writable depending on media
echo - May be empty (no disc inserted^)
) else if "!TypeCode!"=="6" (
echo [RAM DISK]
echo.
echo Characteristics:
echo - Virtual drive in system memory
echo - Extremely fast access
echo - Data lost on shutdown/reboot
echo.
echo Warning: All data is volatile
) else (
echo [UNKNOWN TYPE]
echo.
echo Drive type code !TypeCode! is not recognized.
echo This may be a specialized or virtual drive.
)
echo ============================================================
echo.
endlocal
exit /b 0
Why Get-CimInstance instead of wmic:
wmicis deprecated since Windows 10 21H1 and produces\r-corrupted output. When parsingwmic logicaldisk get drivetype /value, the\rcharacter becomes part of the variable, causingif "%Type%"=="2"to fail because the variable actually contains2\r.Get-CimInstance Win32_LogicalDiskreturns the same data as clean typed values.
Method 2: Complete Drive Inventory by Type
Shows every connected drive organized by type, useful for understanding the full storage landscape before running any automated operation.
@echo off
setlocal
echo [INFO] Drive inventory by type:
echo --------------------------------------------------
powershell -NoProfile -Command ^
"$drives = Get-CimInstance Win32_LogicalDisk;" ^
"if (-not $drives) { Write-Host 'No drives found.'; exit 0 };" ^
"$drives | ForEach-Object {" ^
" $typeName = switch ($_.DriveType) {" ^
" 0 { 'Unknown' } 1 { 'No Root' } 2 { 'Removable' }" ^
" 3 { 'Fixed' } 4 { 'Network' } 5 { 'CD-ROM' } 6 { 'RAM Disk' }" ^
" default { 'Unknown' }" ^
" };" ^
" $sizeGB = if ($_.Size) { [math]::Round($_.Size / 1GB, 1) } else { 'N/A' };" ^
" $freeGB = if ($_.FreeSpace) { [math]::Round($_.FreeSpace / 1GB, 1) } else { 'N/A' };" ^
" [PSCustomObject]@{" ^
" Drive = $_.DeviceID;" ^
" Type = $typeName;" ^
" Label = if ($_.VolumeName) { $_.VolumeName } else { '(none)' };" ^
" FileSystem = if ($_.FileSystem) { $_.FileSystem } else { 'N/A' };" ^
" 'Size GB' = $sizeGB;" ^
" 'Free GB' = $freeGB" ^
" }" ^
"} | Sort-Object Type, Drive | Format-Table -AutoSize"
echo --------------------------------------------------
endlocal
exit /b 0
Sample output:
Drive Type Label FileSystem Size GB Free GB
----- ---- ----- ---------- ------- -------
C: Fixed Windows NTFS 476.9 234.1
D: Fixed Data NTFS 931.5 612.3
E: Network SharedDocs NTFS N/A N/A
F: Removable KINGSTON FAT32 28.9 15.2
G: CD-ROM (none) N/A N/A N/A
Method 3: Deep Drive Classification (Bus Type + Media Type)
For the most accurate classification, distinguishing internal drives from external USB hard drives, NVMe from SATA, and SSDs from HDDs, query the physical disk properties.
@echo off
setlocal
echo [INFO] Detailed drive classification:
echo --------------------------------------------------
powershell -NoProfile -Command ^
"Get-CimInstance Win32_LogicalDisk | Where-Object { $_.DriveType -in 2,3 } | ForEach-Object {" ^
" $logicalDisk = $_;" ^
" $partition = Get-CimAssociatedInstance $logicalDisk -ResultClassName Win32_DiskPartition -ErrorAction SilentlyContinue;" ^
" $physDisk = if ($partition) {" ^
" Get-CimAssociatedInstance $partition -ResultClassName Win32_DiskDrive -ErrorAction SilentlyContinue" ^
" };" ^
" $psDisk = if ($physDisk) {" ^
" Get-PhysicalDisk | Where-Object { $_.DeviceId -eq $physDisk.Index } | Select-Object -First 1" ^
" };" ^
" $busType = if ($psDisk) { [string]$psDisk.BusType } elseif ($physDisk) { $physDisk.InterfaceType } else { 'Unknown' };" ^
" $mediaType = if ($psDisk.MediaType) { [string]$psDisk.MediaType } else { 'Unknown' };" ^
" $classification = switch ($true) {" ^
" ($logicalDisk.DriveType -eq 2) { 'Removable Media' }" ^
" ($busType -eq 'USB') { 'External (USB)' }" ^
" ($busType -eq 'NVMe') { 'Internal (NVMe)' }" ^
" ($busType -match 'SATA|ATA') { 'Internal (SATA)' }" ^
" ($busType -eq 'SAS') { 'Internal (SAS)' }" ^
" default { 'Local' }" ^
" };" ^
" [PSCustomObject]@{" ^
" Drive = $logicalDisk.DeviceID;" ^
" Classification = $classification;" ^
" Bus = $busType;" ^
" Media = $mediaType;" ^
" Label = if ($logicalDisk.VolumeName) { $logicalDisk.VolumeName } else { '-' };" ^
" 'Size GB' = [math]::Round($logicalDisk.Size / 1GB, 1)" ^
" }" ^
"} | Format-Table -AutoSize"
echo --------------------------------------------------
echo.
echo Key: Removable Media = USB flash/SD card
echo External (USB) = USB hard drive (reports as Fixed/type 3)
echo Internal (NVMe) = NVMe SSD
echo Internal (SATA) = SATA HDD or SSD
endlocal
exit /b 0
Sample output:
Drive Classification Bus Media Label Size GB
----- -------------- --- ----- ----- -------
C: Internal (NVMe) NVMe SSD Windows 476.9
D: Internal (SATA) SATA HDD Data 931.5
E: External (USB) USB Unspecified Backup 465.8
F: Removable Media USB Unspecified KINGSTON 28.9
Why bus type matters more than drive type code:
DriveType 3 (Fixed) includes both internal SATA/NVMe drives AND external USB hard drives. If your safety gate blocks only DriveType 2 (Removable), an external USB HDD would pass the check and could be accidentally formatted. Method 3's classification distinguishes Internal (SATA) from External (USB) by checking the bus type, providing a more accurate safety check.
Method 4: Safety Gate for Destructive Operations
Use this before any format, wipe, or destructive operation to prevent accidentally targeting removable or external media.
@echo off
setlocal EnableDelayedExpansion
set "TargetDrive=%~1"
if "%TargetDrive%"=="" (
echo ============================================================
echo Drive Safety Gate - Usage
echo ============================================================
echo.
echo Usage: %~nx0 ^<drive_letter^>
echo.
echo Purpose:
echo Verifies a drive is a fixed internal drive before allowing
echo destructive operations (format, wipe, partition, cleanup^)
echo.
echo Examples:
echo %~nx0 D
echo %~nx0 E:
echo.
endlocal
exit /b 1
)
:: Normalize drive letter
set "DriveLetter=%TargetDrive:~0,1%"
set "DriveColon=%DriveLetter%:"
if not exist %DriveColon%\ (
echo [ERROR] Drive %DriveColon% not found or not accessible. >&2
endlocal
exit /b 1
)
echo ============================================================
echo Safety Gate: Destructive Operation Check
echo ============================================================
echo.
echo Target Drive: %DriveColon%
echo.
echo [SAFETY] Verifying drive type...
echo.
:: Build PowerShell command with proper escaping
set "PSCmd=$ErrorActionPreference = 'Stop';"
set "PSCmd=!PSCmd! try {"
set "PSCmd=!PSCmd! $ld = Get-CimInstance Win32_LogicalDisk -Filter \"DeviceID='%DriveColon%'\";"
set "PSCmd=!PSCmd! if (-not $ld) { Write-Output 'ERROR~Drive not found'; exit 2 };"
set "PSCmd=!PSCmd! "
set "PSCmd=!PSCmd! # Check basic drive type"
set "PSCmd=!PSCmd! if ($ld.DriveType -eq 2) { Write-Output 'REMOVABLE~USB flash or SD card'; exit 1 };"
set "PSCmd=!PSCmd! if ($ld.DriveType -eq 4) { Write-Output 'NETWORK~Network mapped drive'; exit 1 };"
set "PSCmd=!PSCmd! if ($ld.DriveType -eq 5) { Write-Output 'OPTICAL~CD/DVD drive'; exit 1 };"
set "PSCmd=!PSCmd! if ($ld.DriveType -eq 6) { Write-Output 'RAMDISK~RAM Disk'; exit 1 };"
set "PSCmd=!PSCmd! if ($ld.DriveType -ne 3) { Write-Output \"OTHER~Unknown type ($($ld.DriveType))\"; exit 1 };"
set "PSCmd=!PSCmd! "
set "PSCmd=!PSCmd! # DriveType is 3 (Fixed), but need to check if it's external USB"
set "PSCmd=!PSCmd! $part = Get-CimAssociatedInstance $ld -ResultClassName Win32_DiskPartition -ErrorAction SilentlyContinue;"
set "PSCmd=!PSCmd! $disk = if ($part) { Get-CimAssociatedInstance $part -ResultClassName Win32_DiskDrive -ErrorAction SilentlyContinue };"
set "PSCmd=!PSCmd! "
set "PSCmd=!PSCmd! if ($disk) {"
set "PSCmd=!PSCmd! $interface = $disk.InterfaceType;"
set "PSCmd=!PSCmd! $model = $disk.Model;"
set "PSCmd=!PSCmd! $size = [math]::Round($disk.Size / 1GB, 1);"
set "PSCmd=!PSCmd! "
set "PSCmd=!PSCmd! # Check for USB interface"
set "PSCmd=!PSCmd! if ($interface -eq 'USB') {"
set "PSCmd=!PSCmd! Write-Output \"EXTERNAL_USB~External USB HDD ($model, ${size}GB)\"; exit 1;"
set "PSCmd=!PSCmd! }"
set "PSCmd=!PSCmd! "
set "PSCmd=!PSCmd! # Additional check: MediaType for removable"
set "PSCmd=!PSCmd! if ($disk.MediaType -match 'Removable') {"
set "PSCmd=!PSCmd! Write-Output \"REMOVABLE_DISK~Removable disk ($model)\"; exit 1;"
set "PSCmd=!PSCmd! }"
set "PSCmd=!PSCmd! "
set "PSCmd=!PSCmd! Write-Output \"INTERNAL~Internal fixed drive ($interface, $model, ${size}GB)\"; exit 0;"
set "PSCmd=!PSCmd! } else {"
set "PSCmd=!PSCmd! # Could not get physical disk info, assume internal but warn"
set "PSCmd=!PSCmd! Write-Output 'INTERNAL_UNKNOWN~Fixed drive (physical disk info unavailable)'; exit 0;"
set "PSCmd=!PSCmd! }"
set "PSCmd=!PSCmd! } catch {"
set "PSCmd=!PSCmd! Write-Output \"ERROR~$($_.Exception.Message)\"; exit 2;"
set "PSCmd=!PSCmd! }"
:: Execute PowerShell command
set "DriveClass="
set "DriveDesc="
for /f "tokens=1,2 delims=~" %%a in (
'powershell -NoProfile -ExecutionPolicy Bypass -Command "!PSCmd!" 2^>nul'
) do (
set "DriveClass=%%a"
set "DriveDesc=%%b"
)
set "GateResult=!errorlevel!"
echo ============================================================
echo Analysis Results
echo ============================================================
echo.
:: Evaluate result
if !GateResult! equ 0 (
echo Classification: !DriveClass!
echo Details: !DriveDesc!
echo.
echo ============================================================
echo SAFETY CHECK PASSED
echo ============================================================
echo.
echo [CLEAR] Drive %DriveColon% is verified as an internal drive.
echo [CLEAR] Destructive operations are PERMITTED.
echo.
echo WARNING: Ensure you have backups before proceeding!
echo.
endlocal
exit /b 0
)
if !GateResult! equ 2 (
echo [ERROR] Could not determine drive type for %DriveColon%. >&2
echo [ERROR] Reason: !DriveDesc! >&2
echo.
echo ============================================================
echo OPERATION BLOCKED (Error)
echo ============================================================
echo.
echo Destructive operation blocked for safety.
echo.
endlocal
exit /b 1
)
:: Drive is not internal - BLOCK
echo Classification: !DriveClass!
echo Details: !DriveDesc!
echo.
echo ============================================================
echo OPERATION BLOCKED (Safety Gate)
echo ============================================================
echo.
echo [BLOCKED] Drive %DriveColon% is NOT an internal fixed drive.
echo [BLOCKED] Destructive operations are PROHIBITED.
echo.
:: Provide specific guidance based on drive type
if "!DriveClass!"=="REMOVABLE" (
echo Drive Type: Removable media
echo.
echo This includes USB flash drives, SD cards, and similar devices.
echo These should never be formatted without explicit user confirmation.
) else if "!DriveClass!"=="EXTERNAL_USB" (
echo Drive Type: External USB hard drive
echo.
echo External USB drives are blocked by default because they:
echo - Are physically removable
echo - May contain user backup data
echo - Can be easily disconnected during operations
echo.
echo If you INTENTIONALLY want to format this drive:
echo 1. Verify this is the correct drive
echo 2. Ensure you have backups of any important data
echo 3. Modify the safety gate script to allow USB drives
echo (search for "EXTERNAL_USB" in the script^)
) else if "!DriveClass!"=="NETWORK" (
echo Drive Type: Network drive
echo.
echo Network drives cannot be formatted locally.
echo Manage storage on the network share server.
) else if "!DriveClass!"=="OPTICAL" (
echo Drive Type: Optical drive (CD/DVD^)
echo.
echo Optical drives cannot be formatted like hard drives.
echo Use disc burning software instead.
) else (
echo Drive Type: !DriveClass!
echo.
echo This drive type is not permitted for automated destructive operations.
)
echo.
echo ============================================================
echo.
endlocal
exit /b 1
Integration into destructive scripts:
:: Before any format, wipe, or cleanup
call check_drive_type.bat D
if errorlevel 1 (
echo [ABORT] Target drive is not a fixed internal drive.
exit /b 1
)
:: Only reaches here if the drive is internal and fixed
echo [PROCEED] Formatting D: ...
format D: /fs:ntfs /q /v:DataDrive
The default gate blocks ALL non-internal drives. You can customize it for your environment:
- Allow external USB HDDs (for backup drives): Remove the USB bus type check.
- Block specific drive letters: Add letter-based exclusions (e.g., never allow C:).
- Require a minimum size: Prevent operating on drives smaller than a threshold (catches USB flash drives that report as Fixed on some enclosures).
Method 5: Fleet-Wide Removable Drive Audit
For security monitoring, track which machines have removable drives attached. This is useful for data loss prevention (DLP) policies.
@echo off
setlocal
set "CSVFile=\\Server\Audit\removable_drives.csv"
if not exist "%CSVFile%" (
echo "Timestamp","Computer","Drive","Type","Label","FileSystem","SizeGB","BusType" > "%CSVFile%" 2>nul
)
powershell -NoProfile -Command ^
"$ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss';" ^
"$removable = Get-CimInstance Win32_LogicalDisk | Where-Object { $_.DriveType -eq 2 };" ^
"foreach ($r in $removable) {" ^
" $label = if ($r.VolumeName) { $r.VolumeName } else { 'none' };" ^
" $fs = if ($r.FileSystem) { $r.FileSystem } else { 'N/A' };" ^
" $sizeGB = if ($r.Size) { [math]::Round($r.Size / 1GB, 1) } else { 0 };" ^
" Write-Output ('\"' + $ts + '\",\"' + $env:COMPUTERNAME + '\",\"' + $r.DeviceID + '\",\"Removable\",\"' + $label + '\",\"' + $fs + '\",\"' + $sizeGB + '\",\"USB\"')" ^
"}" >> "%CSVFile%" 2>nul
echo [OK] Removable drive data exported for %COMPUTERNAME%.
endlocal
exit /b 0
What to look for:
- Removable drives on servers: Servers typically should not have USB flash drives attached. This may indicate unauthorized data transfer.
- Large removable drives: A 256 GB USB drive can hold significant amounts of data. DLP policies may restrict removable media above certain sizes.
- Unrecognized labels: A drive labeled "BACKUP" on a workstation that doesn't have an approved backup policy may be an unauthorized personal device.
How to Avoid Common Errors
Wrong Way: Guessing Drive Type by Letter
:: WRONG - drive letters are assigned dynamically
if "%TargetDrive%"=="C:" echo Fixed
if "%TargetDrive%"=="E:" echo Removable
Drive letters change based on plug order, existing mappings, and user configuration. C: is almost always the OS drive, but D:, E:, F: can be anything.
Correct Way: Always query the DriveType property (Methods 1–4). Hardware classification comes from the operating system, not the letter.
Problem: External USB HDD Reports as Fixed (Type 3)
External USB hard drives report DriveType 3 (Fixed) because the USB-SATA bridge controller presents them to Windows as fixed disks. A safety check that only blocks DriveType 2 will allow formatting an external backup drive.
Solution: Method 3 checks the physical bus type (USB, SATA, NVMe) in addition to the logical drive type. Method 4's safety gate blocks both DriveType 2 (removable) and USB bus type (external HDD).
Problem: wmic Drive Type Parsing Fails
:: BROKEN: \r character from wmic corrupts the variable
for /f "tokens=2 delims==" %%t in ('wmic logicaldisk where "DeviceID='E:'" get drivetype /value') do set "Type=%%t"
if "%Type%"=="2" echo Removable
:: This comparison fails because Type actually contains "2\r"
Correct Way: Use Get-CimInstance in PowerShell, which returns clean typed values.
Best Practices and Rules
1. Check Drive Type Before ANY Destructive Operation
Format, wipe, delete-all, and partition operations should always include a drive type check as a pre-condition. This is the simplest protection against accidentally destroying data on the wrong drive.
2. Check Bus Type, Not Just Drive Type
DriveType alone misclassifies external USB hard drives as "Fixed." For accurate protection, check the bus type (USB, SATA, NVMe) using Method 3 or 4.
3. Use as a Pre-Condition, Not a Suggestion
The safety gate (Method 4) should return a non-zero exit code that the calling script checks. If the gate fails, the destructive operation must not proceed, not just display a warning.
4. Log Removable Drive Activity for Security
For data loss prevention, track when removable drives appear on workstations and servers. Method 5 provides this as a fleet-wide CSV audit.
5. Never Assume by Drive Letter
Drive letters are dynamic. A script that assumes "E: is always the USB drive" will eventually format the wrong drive when the letter assignment changes.
Conclusions
Checking whether a drive is removable is a critical safety measure for any automated storage operation.
By combining logical drive type classification with physical bus type detection, you accurately distinguish internal fixed drives from USB flash drives AND external USB hard drives, preventing accidental data loss on the wrong type of media.
Integrating this check as a mandatory pre-condition in destructive scripts ensures that human error in drive identification never results in catastrophic data loss.