Skip to main content

How to Clean (Wipe) a Disk with DiskPart in Batch Script

When you decommission a hard drive, recycle a laptop, or repurpose a server disk, you need to ensure that all data is completely erased, not just deleted. A simple "Delete Partition" only removes the index; the actual data remains on the disk and can be recovered with forensic tools. DiskPart's clean command removes the partition table instantly (data remains recoverable), while clean all performs a sector-by-sector overwrite with zeros, making data recovery virtually impossible with standard tools.

This guide will explain how to wipe disks safely and securely using DiskPart from a Batch script.

Critical Safety Warning

DiskPart's clean and clean all commands permanently destroy data. There is no confirmation prompt, no undo, and no recycle bin.

Before running any wipe script:

  1. Run list disk and identify the target disk by its size, not by a remembered number.
  2. Disconnect USB drives and external storage you don't intend to wipe, to reduce the risk of targeting the wrong device.
  3. NEVER target Disk 0 unless you explicitly intend to destroy your Windows installation.
  4. Back up anything you need from the target disk, wiping is irreversible.
  5. Verify the disk number IMMEDIATELY before wiping, disk numbers can change between reboots when drives are added or removed.

Understanding Clean vs. Clean All

CommandWhat It DoesTimeData Recoverable?Use Case
cleanRemoves partition table and volume structuresSecondsYes, with forensic toolsRepurposing a disk for new use
clean allWrites zeros to every sector on the diskHours (depends on disk size)No, with standard tools*Decommissioning, recycling, compliance

*Note: clean all performs a single-pass zero write. For compliance with strict standards (NIST SP 800-88, DoD 5220.22-M), verify that a single-pass zero fill meets your organization's requirements. For modern SSDs and hard drives, NIST SP 800-88 considers a single overwrite pass sufficient for "Clear" level sanitization.

Method 1: Interactive Wipe with Full Safety Checks

This method lists all disks, requires the user to identify the target by number, shows the disk details for verification, and requires typing a confirmation word before proceeding.

Implementation

@echo off
setlocal EnableDelayedExpansion

:: Verify admin privileges
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] DiskPart requires administrator privileges. >&2
echo Right-click and select "Run as administrator." >&2
endlocal
exit /b 1
)

echo ============================================================
echo DISK WIPE TOOL
echo ============================================================
echo.
echo [WARNING] This tool permanently destroys data on a disk.
echo [WARNING] Ensure you have backed up any needed data.
echo.

:: =============================================
:: Step 1: List all disks
:: =============================================
echo [INFO] Connected disks:
echo.

set "DPList=%TEMP%\dp_list_%RANDOM%.txt"
(echo list disk) > "%DPList%"
diskpart /s "%DPList%" 2>nul
del "%DPList%" 2>nul

echo.
echo [IMPORTANT] Identify the target disk by its SIZE.
echo [IMPORTANT] Disk 0 is almost always the OS drive, do NOT wipe it.
echo.

:: =============================================
:: Step 2: Get user input
:: =============================================
set /p "DiskNum=Enter disk number to wipe (or Q to quit): "

if /i "%DiskNum%"=="Q" (
echo [INFO] Operation cancelled.
endlocal
exit /b 0
)

if "%DiskNum%"=="" (
echo [ERROR] No disk number entered. >&2
endlocal
exit /b 1
)

:: Safety: refuse disk 0
if "%DiskNum%"=="0" (
echo [ERROR] Refusing to wipe Disk 0 (OS drive protection^). >&2
echo If you truly need to wipe Disk 0, edit the script to remove this check. >&2
endlocal
exit /b 1
)

:: =============================================
:: Step 3: Verify the disk exists and show details
:: =============================================
for /f "tokens=1-3 delims=|" %%a in (
'powershell -NoProfile -Command ^
"$disk = Get-Disk -Number %DiskNum% -ErrorAction SilentlyContinue;" ^
"if (-not $disk) { Write-Output ''NOT_FOUND||''; exit 1 };" ^
"$sizeGB = [math]::Round($disk.Size / 1GB, 1);" ^
"Write-Output \"$($disk.FriendlyName)|$sizeGB|$($disk.BusType)\""'
) do (
set "DiskName=%%a"
set "DiskSize=%%b"
set "DiskBus=%%c"
)

if "%DiskName%"=="NOT_FOUND" (
echo [ERROR] Disk %DiskNum% does not exist. >&2
endlocal
exit /b 1
)

echo.
echo Disk Number: %DiskNum%
echo Name: !DiskName!
echo Size: !DiskSize! GB
echo Bus Type: !DiskBus!
echo.

:: =============================================
:: Step 4: Choose wipe method
:: =============================================
echo Wipe options:
echo 1. Quick clean (removes partitions, data may be recoverable^)
echo 2. Secure wipe (writes zeros to entire disk, takes hours^)
echo.

set /p "WipeMethod=Select option (1 or 2): "

if "%WipeMethod%"=="1" (
set "CleanCmd=clean"
set "WipeType=Quick clean"
) else if "%WipeMethod%"=="2" (
set "CleanCmd=clean all"
set "WipeType=Secure zero-fill wipe"
) else (
echo [ERROR] Invalid option. >&2
endlocal
exit /b 1
)

:: =============================================
:: Step 5: Final confirmation
:: =============================================
echo.
echo ============================================================
echo FINAL CONFIRMATION
echo ============================================================
echo.
echo Target: Disk %DiskNum% - !DiskName! (!DiskSize! GB^)
echo Method: !WipeType!
echo.
echo *** ALL DATA ON THIS DISK WILL BE PERMANENTLY DESTROYED ***
echo.
echo ============================================================

set /p "Confirm=Type WIPE to proceed (anything else cancels): "
if /i not "%Confirm%"=="WIPE" (
echo [INFO] Operation cancelled. No changes were made.
endlocal
exit /b 0
)

:: =============================================
:: Step 6: Execute the wipe
:: =============================================
echo.

if "%WipeMethod%"=="2" (
echo [ACTION] Starting secure zero-fill wipe on Disk %DiskNum%...
echo [INFO] This may take several hours for large drives. Do not interrupt.
) else (
echo [ACTION] Wiping partition table on Disk %DiskNum%...
)

set "DPScript=%TEMP%\dp_wipe_%RANDOM%.txt"
(
echo select disk %DiskNum%
echo !CleanCmd!
) > "%DPScript%"

diskpart /s "%DPScript%" >nul 2>&1
set "DPResult=%errorlevel%"

del "%DPScript%" 2>nul

if %DPResult% neq 0 (
echo [ERROR] Wipe failed. The disk may be in use or write-protected. >&2
endlocal
exit /b 1
)

echo [OK] Disk %DiskNum% has been wiped (!WipeType!^).
echo [INFO] The disk is now unallocated and ready for reuse.

:: =============================================
:: Step 7: Log the operation
:: =============================================
set "LogFile=%~dp0disk_wipe_log.txt"

for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do set "Timestamp=%%t"

echo [%Timestamp%] WIPED Disk %DiskNum% (!DiskName!, !DiskSize! GB^) Method: !WipeType! By: %USERNAME% on %COMPUTERNAME% >> "%LogFile%"

echo [INFO] Operation logged to: %LogFile%

endlocal
exit /b 0

Why the confirmation word is "WIPE":

Requiring the user to type "WIPE" (rather than "Y" or "YES") ensures they consciously acknowledge the destructive nature of the operation. It is harder to type "WIPE" reflexively than to press "Y" in response to a prompt.

Method 2: Scripted Quick Clean (for Automation)

For automated workflows where the disk number is known and confirmed (e.g., a deployment pipeline that wipes a specific disk slot), this method provides a non-interactive wipe with safety checks but no interactive prompts.

@echo off
setlocal

set "DiskNum=%~1"
set "LogFile=%~dp0disk_wipe_log.txt"

if "%DiskNum%"=="" (
echo Usage: %~nx0 ^<disk_number^> [--secure]
echo.
echo --secure Performs zero-fill wipe (takes hours^)
echo (default^) Quick clean (removes partitions only^)
echo.
echo Example:
echo %~nx0 2 Quick clean Disk 2
echo %~nx0 3 --secure Secure wipe Disk 3
endlocal
exit /b 1
)

:: Check for --secure flag
set "CleanCmd=clean"
set "WipeType=Quick clean"
for %%a in (%*) do (
if /i "%%~a"=="--secure" (
set "CleanCmd=clean all"
set "WipeType=Secure zero-fill"
)
)

net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)

:: Safety: refuse disk 0
if "%DiskNum%"=="0" (
echo [ERROR] Refusing to wipe Disk 0 (OS drive^). >&2
endlocal
exit /b 1
)

:: Verify the disk exists
for /f "tokens=1-2 delims=|" %%a in (
'powershell -NoProfile -Command ^
"$d = Get-Disk -Number %DiskNum% -ErrorAction SilentlyContinue;" ^
"if (-not $d) { Write-Output ''NOT_FOUND|0''; exit 1 };" ^
"Write-Output \"$($d.FriendlyName)|$([math]::Round($d.Size/1GB,1))\""'
) do (
set "DiskName=%%a"
set "DiskSize=%%b"
)

if "%DiskName%"=="NOT_FOUND" (
echo [ERROR] Disk %DiskNum% not found. >&2
endlocal
exit /b 1
)

echo [ACTION] %WipeType% on Disk %DiskNum% (%DiskName%, %DiskSize% GB^)...

set "DPScript=%TEMP%\dp_clean_%RANDOM%.txt"
(
echo select disk %DiskNum%
echo %CleanCmd%
) > "%DPScript%"

diskpart /s "%DPScript%" >nul 2>&1
set "DPResult=%errorlevel%"

del "%DPScript%" 2>nul

if %DPResult% neq 0 (
echo [ERROR] Wipe failed. >&2
endlocal
exit /b 1
)

:: Log the operation
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do set "Timestamp=%%t"

echo [%Timestamp%] %WipeType%: Disk %DiskNum% (%DiskName%, %DiskSize% GB^) by %USERNAME% on %COMPUTERNAME% >> "%LogFile%"

echo [OK] Disk %DiskNum% wiped successfully (%WipeType%^).

endlocal
exit /b 0

When to use Method 1 vs. Method 2:

ScenarioMethod
Administrator wiping a specific disk manuallyMethod 1 (interactive with all safety prompts)
Deployment script that repurposes disks in a known slotMethod 2 (scripted, no interactive prompts)
Compliance-driven secure destructionMethod 1 or 2 with --secure flag

Method 3: Secure Wipe with Progress Estimation

clean all provides no progress indicator, it appears to hang for hours while silently writing zeros. This method estimates the completion time based on disk size and type.

@echo off
setlocal

set "DiskNum=%~1"

if "%DiskNum%"=="" (
echo Usage: %~nx0 ^<disk_number^>
echo.
echo Performs a secure zero-fill wipe with time estimation.
endlocal
exit /b 1
)

net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)

if "%DiskNum%"=="0" (
echo [ERROR] Refusing to wipe Disk 0. >&2
endlocal
exit /b 1
)

:: Get disk details for time estimation
for /f "tokens=1-3 delims=|" %%a in (
'powershell -NoProfile -Command ^
"$d = Get-Disk -Number %DiskNum% -ErrorAction SilentlyContinue;" ^
"if (-not $d) { Write-Output ''NOT_FOUND|0|Unknown''; exit 1 };" ^
"$sizeGB = [math]::Round($d.Size / 1GB, 1);" ^
"Write-Output \"$($d.FriendlyName)|$sizeGB|$($d.BusType)\""'
) do (
set "DiskName=%%a"
set "DiskSizeGB=%%b"
set "BusType=%%c"
)

if "%DiskName%"=="NOT_FOUND" (
echo [ERROR] Disk %DiskNum% not found. >&2
endlocal
exit /b 1
)

:: Estimate time based on bus type and size
:: Approximate write speeds: HDD ~100 MB/s, USB3 ~50 MB/s, USB2 ~20 MB/s, SSD ~500 MB/s
powershell -NoProfile -Command ^
"$sizeGB = %DiskSizeGB%;" ^
"$bus = '%BusType%';" ^
"$speedMBs = switch -Regex ($bus) {" ^
" 'USB' { 40 }" ^
" 'NVMe' { 500 }" ^
" 'SAS|SATA' { 120 }" ^
" default { 100 }" ^
"};" ^
"$seconds = ($sizeGB * 1024) / $speedMBs;" ^
"$hours = [math]::Floor($seconds / 3600);" ^
"$minutes = [math]::Floor(($seconds %% 3600) / 60);" ^
"Write-Host \" Estimated time: ${hours}h ${minutes}m (approximate)\""

echo.
echo Disk: %DiskNum% (%DiskName%)
echo Size: %DiskSizeGB% GB
echo Bus: %BusType%
echo.
echo Method: Secure zero-fill (clean all)
echo.
echo *** ALL DATA WILL BE PERMANENTLY DESTROYED ***
echo.

set /p "Confirm=Type WIPE to proceed: "
if /i not "%Confirm%"=="WIPE" (
echo [INFO] Cancelled.
endlocal
exit /b 0
)

echo.
echo [ACTION] Secure wipe started at %time%. Do NOT interrupt or shut down.
echo [INFO] The disk will appear unresponsive during this process.
echo [INFO] Check Task Manager, DiskPart will show disk activity.

set "DPScript=%TEMP%\dp_secwipe_%RANDOM%.txt"
(
echo select disk %DiskNum%
echo clean all
) > "%DPScript%"

diskpart /s "%DPScript%" >nul 2>&1
set "DPResult=%errorlevel%"

del "%DPScript%" 2>nul

if %DPResult% neq 0 (
echo [ERROR] Secure wipe failed. >&2
endlocal
exit /b 1
)

echo [OK] Secure wipe completed at %time%.

:: Log with timestamp
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] SECURE WIPE: Disk %DiskNum% (%DiskName%, %DiskSizeGB% GB) by %USERNAME% >> "%~dp0disk_wipe_log.txt"

endlocal
exit /b 0

Approximate clean all duration:

Disk SizeHDD (~100 MB/s)USB 3.0 (~40 MB/s)SSD (~500 MB/s)
256 GB~45 min~1.8 hr~9 min
500 GB~1.5 hr~3.5 hr~17 min
1 TB~3 hr~7 hr~35 min
4 TB~11 hr~28 hr~2.3 hr

These are rough estimates. Actual times depend on disk health, controller speed, and system load.

A note about SSDs and clean all:

On SSDs, clean all writes zeros to every sector, which is effective but may reduce the drive's lifespan (SSDs have limited write cycles). For SSD secure erasure, the preferred method is the manufacturer's Secure Erase command (accessed via manufacturer tools like Samsung Magician, Intel SSD Toolbox, or the generic hdparm on Linux). DiskPart's clean all is a reliable fallback when manufacturer tools are not available.

How to Avoid Common Errors

Wrong Way: Hardcoding Disk 0

:: CATASTROPHIC: destroys Windows and all data
select disk 0
clean

Disk 0 is almost always the operating system drive. Wiping it destroys Windows, all applications, and all user data instantly.

Correct Way: All methods in this guide refuse to target Disk 0 with a clear error message. If you genuinely need to wipe Disk 0, you must edit the script to remove the safety check, this deliberate action ensures accidental wipes don't happen.

Wrong Way: No Verification Before Wiping

A script that wipes a disk based on a variable or parameter without showing the user which disk is targeted and confirming their intent is dangerous, a typo in the disk number destroys the wrong drive.

Correct Way: Method 1 shows the disk name, size, and bus type before asking for confirmation. Method 2 (for automation) still performs disk existence verification.

Problem: clean all Appears to Hang

clean all provides no progress output. On a 4 TB HDD, the command runs for 10+ hours with no feedback, the script appears frozen.

Solution: Method 3 provides a time estimate before starting. During the wipe, verify the process is active by checking disk activity in Task Manager (the target disk should show continuous write activity) or Resource Monitor.

Problem: Disk Numbers Change Between Reboots

Adding or removing USB drives can shift disk numbers. The disk you identified as Disk 2 yesterday might be Disk 3 today.

Solution: Always run list disk and identify the target by its SIZE immediately before wiping. Method 1 includes this step.

Problem: Write-Protected Disks

Some disks have hardware or firmware write protection that prevents clean from executing.

Solution: Check for write protection:

:: Check and clear software write-protection
set "DPScript=%TEMP%\dp_wpcheck_%RANDOM%.txt"
(
echo select disk %DiskNum%
echo attributes disk clear readonly
) > "%DPScript%"
diskpart /s "%DPScript%" >nul 2>&1
del "%DPScript%" 2>nul

If the disk has a physical write-protect switch (common on SD cards and some USB drives), toggle it off.

Best Practices and Rules

1. Always Identify by Size, Not Number

Disk numbers are dynamic and change when drives are added or removed. The size column in list disk is the only reliable way to identify a specific physical disk.

2. Disconnect Unrelated Storage

Before wiping, disconnect USB drives, external enclosures, and card readers that you don't intend to touch. Fewer connected disks means less chance of targeting the wrong one.

3. Log Every Wipe Operation

For corporate compliance and auditing, record every wipe with the disk serial number, method used, and operator:

:: Get disk serial number for the log
powershell -NoProfile -Command ^
"$sn = (Get-Disk -Number %DiskNum%).SerialNumber;" ^
"Write-Host \"Serial: $sn\""

Many compliance frameworks (NIST, ISO 27001, PCI-DSS) require documented proof of data destruction.

4. Choose the Right Wipe Level

  • Repurposing within your organization: clean (quick) is sufficient. The disk stays within your control.
  • Returning a leased device or recycling: clean all (secure zero-fill) is recommended. Third parties should not be able to recover your data.
  • Classified or regulated data: Check your compliance framework. Some require multiple overwrite passes (use specialized tools) or physical destruction.

5. Consider SSD Secure Erase for SSDs

clean all on an SSD writes zeros to every sector, which works but is not the most efficient method. SSD manufacturers provide Secure Erase commands that reset the drive's internal encryption key (for self-encrypting drives) or instruct the controller to erase all flash cells, including over-provisioned areas that clean all cannot reach.

6. Verify the Wipe Completed

After wiping, verify the disk shows as unallocated:

powershell -NoProfile -Command ^
"$d = Get-Disk -Number %DiskNum%;" ^
"Write-Host \"Style: $($d.PartitionStyle) Size: $([math]::Round($d.Size/1GB,1)) GB\""

A successfully wiped disk should show PartitionStyle: RAW.

Conclusions

Wiping a disk with DiskPart is a critical task for data security and hardware lifecycle management. By implementing rigorous safety checks, disk identification by size, Disk 0 protection, explicit confirmation prompts, and mandatory logging, you protect against the catastrophic risk of wiping the wrong drive. Whether using quick clean for repurposing or secure zero-fill for decommissioning, automated wipe scripts ensure that sensitive data never leaves your control and that every destruction event is documented for compliance.