Here is some useful code for raw disk writes using AutoIt. DISKWIPE.EXE
Note: An alternative AU3 app with source code from joakim can be found on reboot.pro.
It will cope with large hard disks (>137GB). The disk volume should be unlocked first or it will report a write error. This code does a disk wipe by filling all disk sectors with 0's.
After compiling to an EXE file, you must specify the Physical Disk number on the command line - e.g. WipeDisk.exe DRIVE=1
You can unlock the drive by running a DISKPART script with CLEAN, or by cleaning the disk using RMPartUSB (to clean a hard disk use ALLDRIVES on the command line).
To test this script, use RMPrepUSB to Clean a USB drive, then run DiskWipe DRIVE=n from the command line.
This application is useful to run from a WinPE environment after using DISKPART CLEAN to unlock the physical disk that you want to wipe.
Screenshot showing User confirmation window (right) and main application form (left).
The progress bar will start to fill during operation.
Disk Wipe in progress
;WIPEDISK
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_icon=hdd.ico
#AutoIt3Wrapper_outfile=DiskWipe32.exe
#AutoIt3Wrapper_Res_Fileversion=1.0.0.97
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
;RM.BMP logo is 71x24 x24bits resolution bitmap
;included files are in the default AutoIt3 folder when install AutiIt3 - or path them as .\Include\xxxxx.au3
#include <GUIConstantsEx.au3>
#include <ProgressConstants.au3>
#include <array.au3>
#include <Date.au3>
#include <Timers.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Opt('MustDeclareVars', 1)
Opt('GUIOnEventMode', 1) ;must define functions for all events
Global Const $tagDISKGEOMETRYEX = 'int64 Cylinders;dword MediaType;dword TracksPerCylinder;dword SectorsPerTrack;dword BytesPerSector;int64 DiskSize;dword Data'
Global Const $__WINAPCONSTANT_INVALID_SET_FILE_POINTER = -1
Global $progressbar1, $IDLabelp, $IDLabelDrv, $IDLabelProg, $IDCancel, $IDMe
Global $pc, $newpc, $Driveno, $IDLabelT
Global $Filename, $lTotalBlocks, $tDISKGEOMETRYEx, $lRemainingBlocks, $lPos, $Blocks, $result
Global $wbemServices, $wbemObjectSet, $GetDriveSize, $tBuffer, $lSuccess
Global $TDiff, $TRem, $lHandle
Global $bytArr[1] ;As Byte
Global $DN, $x, $Frame
$Frame = 7 ;$SS_BLACKFRAME - use to show position of labels for debug purposes
$Frame=0
$IDMe = GUICreate("Disk Wipe v1.0", 220, 240, 140, 100,$WS_CAPTION+ $WS_POPUP+ $WS_SYSMENU) ;width , height , left , top
$progressbar1 = GUICtrlCreateProgress (10, 10, 50,220, 4) ; left, top [, width [, height ,$PBS_SMOOTH $PBS_VERTICAL
GUICtrlSetColor(-1, 32250) ; not working with Windows XP Style - blue under WinPE
GUICtrlCreatePic ("RM.bmp", 70, 10, 47, 16) ; left, top , width , height
$IDLabelT = GUICtrlCreateLabel("Security Level 5 Erase",70, 30, 150, 20, $Frame)
$IDLabelDrv = GUICtrlCreateLabel("", 70, 60, 150, 20, $Frame)
$IDLabelp = GUICtrlCreateLabel("", 70, 120, 150, 20, $Frame)
$IDLabelProg = GUICtrlCreateLabel("", 70, 140, 150, 50, $Frame) ;Left,Top,Width,Height
$IDCancel=GUICtrlCreateButton("Cancel", 150, 210, 40, 20) ; left, top , width , height - Make sure label does not cover Cancel button or you cannot click it!
GUICtrlSetOnEvent($IDCancel, "Cancel")
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
GUISetState(@SW_SHOW)
If $CmdLine[0] > 0 Then ;check if $cmdLine[1] is valid
$DN = $CmdLine[1]
Else
$DN = ""
EndIf
$x = StringInStr($DN, "DRIVE=")
If $x > 0 Then
$Driveno = StringMid($DN, $x + 6)
if $Driveno = "" then Exit(3)
Else
$x = MsgBox(0, "Command Line Error", "Please use syntax DRIVE=n on command line")
Exit (3) ;1=OK
EndIf
$lTotalBlocks = 0
$Filename = "\\.\PhysicalDrive" & $Driveno
$tDISKGEOMETRYEx = _WinAPI_IOCtlDiskGetDriveGeometryEx($Driveno)
$lTotalBlocks = DllStructGetData($tDISKGEOMETRYEx, 'DiskSize') / 512 ;only one to return 0 if invalid disk! Also largest size returned
If $lTotalBlocks = 0 Then ;test this one as other sizes can return a false size!
MsgBox(0, "Disk Error", "Error - size of disk " & $Driveno & " cannot be determined!")
Exit (3)
EndIf
$x = ""
if Int($lTotalBlocks / (2)) < 1000 then $x = Int($lTotalBlocks / (2)) & "KB"
if $x = "" then
if Int($lTotalBlocks / (2000)) < 1000 then $x = Int($lTotalBlocks / (2000)) & "MB"
Endif
if $x = "" then
if Int($lTotalBlocks / (2000000)) < 1000 then $x = Int($lTotalBlocks / (2000000)) & "GB"
Endif
$x = "DISK " & $Driveno & " (" & $x & ")"
GUICtrlSetData($IDLabelDrv, $x) ;display drive size to user
$x = MsgBox(1+256, "WARNING: SECURITY DISK WIPE", "THIS WILL ERASE ALL DATA ON " & $x & @CR & @CR & "The entire disk will be filled with 00's." & @CR & "Windows, all user data, drivers and factory backup images will be wiped." & @CR & @CR & " OK to wipe Disk " & $Driveno & "?")
If $x <> 1 Then Exit (3)
Local $starttime = _Timer_Init()
DrawProgress(1) ;show we have started
;-- START DISK ACCESS --------------
;Get a handle to file
;hDrive = CreateFile($FileName, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, OPEN_EXISTING, 0&, 0&)
;_WinAPI_CreateFile($sFileName, $iCreation[, $iAccess = 4[, $iShare = 0[, $iAttributes = 0[, $pSecurity = 0]]]])
$lHandle = _WinAPI_CreateFile($Filename, 2, 6, 6) ;create new fail. write, write - t exist, 2=Read (4=Write), share rd+wr
If $lHandle = 0 Then
MsgBox(0, "Disk Access Error", "Cannot access disk " & $Filename)
Exit (2)
EndIf
$lRemainingBlocks = $lTotalBlocks
$lPos = 0
$pc = 0
$newpc = 0
While $lRemainingBlocks > 0
If $lRemainingBlocks < 65536 Then ;max 100000 = 48MB 131072=64MB 65536=32MB
$Blocks = $lRemainingBlocks
Else
$Blocks = 65536
EndIf
;ConsoleWrite(_now() & " ")
;ConsoleWrite("POS/BLOCKS/RemainingBlocks = " & $lPos & "/" & $Blocks & "/" & $lRemainingBlocks & @CRLF)
$result = WriteStringToDisk($Filename, $lPos, $Blocks)
;ConsoleWrite("File contents " & $result & @CRLF)
$lPos = $lPos + $Blocks
$lRemainingBlocks = $lRemainingBlocks - $Blocks
;calc percentage
$newpc = 100 - (($lRemainingBlocks / $lTotalBlocks) * 100)
$newpc = Int($newpc)
If $pc <> $newpc Then
DrawProgress($newpc) ;only draw if new
$TDiff = _Timer_Diff($starttime) / 1000 ;time so far in seconds
;we have done $lPos in $tdiff, so we have $lpos/$tdiff * $lremainingBlocks left
$TRem = $lRemainingBlocks * $TDiff / $lPos
$TRem = Int($TRem / 60) & " min " & Int($TRem - (Int($TRem / 60) * 60)) & " sec "
GUICtrlSetData($IDLabelProg, Int($lPos / (2048)) & "MB erased" & @CR & $TRem & " remaining")
$pc = $newpc
EndIf
WEnd
;ConsoleWrite("Total Blocks " & $lPos & @CRLF)
_WinAPI_CloseHandle($lHandle)
Exit(0) ;success
;---------------------------------
Func CLOSEClicked()
Exit(3)
EndFunc
;---------------------------------
Func Cancel()
If MsgBox(4, "RM Disk Security Wipe", "Cancel disk erase?", 0, $IDMe) = 6 Then Exit (1)
EndFunc ;==>Cancel
;---------------------------------
Func WriteStringToDisk($Pattern, $lPos, $lBlocks)
Local $lBytesWritten = 0
Local $lBytesToWrite = 0
$lBytesToWrite = $lBlocks ;get total number of bytes to read
;if $lBytesToWrite > 30000 then $lBytesToWrite = 30000 ;will fail if = 30000 blocks = 15360000 bytes
$lBytesToWrite = 512 * $lBytesToWrite ;131,000 OK 132,000 fail for string read
If $lHandle <> 0 Then ;$INVALID_HANDLE_VALUE Then
$tBuffer = DllStructCreate("char Text[" & $lBytesToWrite & "]")
$result = _WinAPI_SetFilePointerEx($lHandle, $lPos * 512)
If $result Then
$lSuccess = _WinAPI_WriteFile($lHandle, DllStructGetPtr($tBuffer), $lBytesToWrite, $lBytesWritten) ;write array
If $lSuccess Then
Else
$x = MsgBox(1, "ERROR", "Write FAIL at sector " & $lPos & @CRLF & "Click Cancel to abort disk erase.")
if $x <> 1 then Exit(2)
EndIf
Else
MsgBox(0, "Error", "Could not set disk FilePointer to " & $lPos * 512)
Exit (2)
EndIf
Else
MsgBox(0, "Error", "Could not access disk!")
Exit (2)
EndIf
EndFunc ;==>WriteStringToDisk
;---------------------------------
Func _WinAPI_SetFilePointerEx($hFile, $iPos, $iMethod = 0)
; Set filepointer for files > 4 GB
Local $aResult
$aResult = DllCall("kernel32.dll", "dword", "SetFilePointerEx", "hwnd", $hFile, "uint64", $iPos, "uint64*", 0, "dword", $iMethod)
If @error Then Return SetError(1, 0, -1)
If $aResult[0] = $__WINAPCONSTANT_INVALID_SET_FILE_POINTER Then Return SetError(2, 0, -1)
Return $aResult[0]
EndFunc ;==>_WinAPI_SetFilePointerEx
;---------------------------------
Func DrawProgress($Pos) ;$Pos is in Percent 0-100
Local $x, $Lastx
If $Pos > 100 Then $Pos = 100
If $Pos < 0 Then $Pos = 0
$x = $Pos
$x = Int($x)
If $x <> $Lastx Then
GUICtrlSetData($progressbar1, $x)
GUICtrlSetData($IDLabelp, "Percentage complete = " & $Pos & "%")
$Lastx = $x
EndIf
EndFunc ;==>DrawProgress
;---------------------------------
Func _WinAPI_IOCtlDiskGetDriveGeometryEx($iDrive)
Local $hFile = _WinAPI_CreateFile('\\.\PhysicalDrive' & $iDrive, 2, 2, 6, 128)
If $hFile = 0 Then
Return SetError(1, 0, 0)
EndIf
Local $tDISKGEOMETRYEx = DllStructCreate($tagDISKGEOMETRYEX)
Local $Ret = DllCall('kernel32.dll', 'int', 'DeviceIoControl', 'ptr', $hFile, 'dword', 0x000700A0, 'ptr', 0, 'dword', 0, 'ptr', DllStructGetPtr($tDISKGEOMETRYEx), 'dword', DllStructGetSize($tDISKGEOMETRYEx), 'dword*', 0, 'ptr', 0)
If (@error) Or ($Ret[0] = 0) Then
$Ret = 0
EndIf
_WinAPI_CloseHandle($hFile)
If Not IsArray($Ret) Then
Return SetError(2, 0, 0)
EndIf
Return SetError(0, 0, $tDISKGEOMETRYEx)
EndFunc ;==>_WinAPI_IOCtlDiskGetDriveGeometryEx
;---------------------------------
;keywords: raw write, sector write, physical disk, access, absolute writes, disk size, capacity, progress bar, timer