none
ReadFile using winapi with pinvoke (image a physical disk) RRS feed

  • Question

  • I'm trying to read files with powershell by using the winapi (CreateFile, ReadFile, CloseHandle). Of course there exist easier ways to read files, but ultimetaly I want to read from physical disk, that's why. I am familiar with the api's and have done this many times in other script language. But now I'm learning powershell.. Anyways, I believe the problem is in the creation of the structure where ReadFile will put its content. I've put GetLastError in there which return code 5 (access denied). The other api's seem to work fine. Any help is much appreciated. The code;

    $pinvoke = add-type -name pinvoke21 -passThru -memberDefinition @'
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes
            );
            
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
         
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern uint GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);
    
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern uint GetLastError();
    
    '@
    
    $lpFileName = "c:\tmp\dummytest.txt"
    $dwDesiredAccess = 0x2
    $dwShareMode = 0x6
    $lpSecurityAttributes = 0
    $dwCreationDisposition = 0x4
    $dwFlagsAndAttributes = 0x0 
    $hFile = $pinvoke::CreateFile($lpFileName, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes)
    $hFile
    $FileSize = $pinvoke::GetFileSize($hFile,0)
    $FileSize
    add-type @"
    public struct teststruct {
    public byte FileBuff;
    }
    "@
    $FileBuffer1 = new-object teststruct
    $FileBuffer = new-object $FileBuffer1.FileBuff
    $rFile = $pinvoke::ReadFile($hFile, $FileBuffer, $FileSize, [ref]$nBytes, 0)
    $pinvoke::GetLastError()
    $rFile
    $FileBuffer
    $pinvoke::CloseHandle($hFile)
    
    

     

    Joakim



    • Edited by Joakim Schicht Monday, November 7, 2011 9:03 AM modified title
    Thursday, November 3, 2011 1:20 PM

Answers

  • $pinvoke = add-type -name pinvoke -passThru -memberDefinition @'
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes
            );
            
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern uint GetLastError();
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern uint GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
    '@
    
    $lpFileName = "F:\test.txt"
    $dwDesiredAccess = 2147483648
    $dwShareMode = 0x1
    $lpSecurityAttributes = 0
    $dwCreationDisposition = 3
    $dwFlagsAndAttributes = 0x0 
    $hFile = $pinvoke::CreateFile($lpFileName, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes)
    $FileSize = $pinvoke::GetFileSize($hFile,0)
    
    $buffer = New-Object byte[] $FileSize
    $read = [uint32]::MinValue
    $pinvoke::ReadFile($hFile,$buffer,$FileSize,[ref]$read,0)
    [Text.Encoding]::ASCII.GetString($buffer)
    
    test.txt contains
    PS >  gc F:\test.txt
    Hello! How are you?
    
    Output:
    PS >  $buffer = New-Object byte[] $FileSize
    PS >  $read = [uint32]::MinValue
    PS >  $pinvoke::ReadFile($hFile,$buffer,$FileSize,[ref]$read,0)
    True
    PS >  [Text.Encoding]::ASCII.GetString($buffer)
    Hello! How are you?
    



    • Edited by Kazun Friday, November 4, 2011 11:10 AM
    • Marked as answer by Joakim Schicht Friday, November 4, 2011 12:13 PM
    Friday, November 4, 2011 11:02 AM

All replies

  • if you've done this before, do you have a straight C# example?
     
    also, it looks like you have an empty buffer?
     
    public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint
    nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
    ..
    add-type @"
    public struct teststruct {
    public byte FileBuff;
    }
    "@
    $FileBuffer1 = new-object teststruct
    $FileBuffer = new-object $FileBuffer1.FileBuff
    $rFile = $pinvoke::ReadFile($hFile, $FileBuffer, $FileSize, [ref]$nBytes, 0)
     
    so you create a struct that is pretty basic, all it contains is a a byte
    object (not even an array of bytes) which means you only would get one byte
    at a time?
     
    my C++ is almost non existent, and my my C# is only ok, but my powershell is
    pretty good, and this isnt a powershell problem :)
     
    I've managed to write a couple of pinvoke things in powershell, so I'll
    screw around with it and see what I can do.
     
     

    Justin Rich
    http://jrich523.wordpress.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Thursday, November 3, 2011 1:48 PM
  • Unfortunately I don't have any C# code at all, as I've previously done this in AutoIt with its DLLCalling. And it's just so different! I don't quite understand where & how to specify the size of the buffer. Does the creation of FileBuff look sane at all?
    Thursday, November 3, 2011 2:16 PM
  • thanks Kazun, let me see what I can do with making that PowerShell friendly.
     

    Justin Rich
    http://jrich523.wordpress.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Thursday, November 3, 2011 4:03 PM
  • Sounds good Justin. I will try myself too.
    Thursday, November 3, 2011 5:21 PM
  • I did $fileBuffer = new-object byte [] $filesize
     
    which seems sort of ok, I get an error 203 back, which, after tracking it
    down, makes no sense because it refers to an env var?
     
     

    Justin Rich
    http://jrich523.wordpress.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Thursday, November 3, 2011 5:32 PM
  • I can successfully do the opposite and write to a file with WriteFile(). I just don't understand how to create and use the buffer correctly with ReadFile(). This is rather frustrating. Please help. Here's my code with WriteFile() that works by creating and writing binary data to a file with winapi only:

    $pinvoke = add-type -name pinvoke -passThru -memberDefinition @'
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes
            );
            
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern uint GetLastError();
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
    
    '@
    
    $lpFileName = "c:\tmp\binary.bin"
    $dwDesiredAccess = 0x6
    $dwShareMode = 0x6
    $lpSecurityAttributes = 0
    $dwCreationDisposition = 0x2 
    $dwFlagsAndAttributes = 0x0 
    $hFile = $pinvoke::CreateFile($lpFileName, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes)
    [byte[]]$FileBuffer = (0x48,0x65,0x6c,0x6c,0x6f,0x21,0x20,0x48,0x6f,0x77,0x20,0x61,0x72,0x65,0x20,0x79,0x6f,0x75,0x3f) # Hello! How are you?
    $FileSize = $FileBuffer.length
    $nBytes = 0
    $rFile = $pinvoke::WriteFile($hFile, $FileBuffer, $FileSize, [ref]$nBytes, 0)
    $pinvoke::CloseHandle($hFile)
    
    

     

    Friday, November 4, 2011 9:54 AM
  • $pinvoke = add-type -name pinvoke -passThru -memberDefinition @'
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes
            );
            
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern uint GetLastError();
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern uint GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
    '@
    
    $lpFileName = "F:\test.txt"
    $dwDesiredAccess = 2147483648
    $dwShareMode = 0x1
    $lpSecurityAttributes = 0
    $dwCreationDisposition = 3
    $dwFlagsAndAttributes = 0x0 
    $hFile = $pinvoke::CreateFile($lpFileName, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes)
    $FileSize = $pinvoke::GetFileSize($hFile,0)
    
    $buffer = New-Object byte[] $FileSize
    $read = [uint32]::MinValue
    $pinvoke::ReadFile($hFile,$buffer,$FileSize,[ref]$read,0)
    [Text.Encoding]::ASCII.GetString($buffer)
    
    test.txt contains
    PS >  gc F:\test.txt
    Hello! How are you?
    
    Output:
    PS >  $buffer = New-Object byte[] $FileSize
    PS >  $read = [uint32]::MinValue
    PS >  $pinvoke::ReadFile($hFile,$buffer,$FileSize,[ref]$read,0)
    True
    PS >  [Text.Encoding]::ASCII.GetString($buffer)
    Hello! How are you?
    



    • Edited by Kazun Friday, November 4, 2011 11:10 AM
    • Marked as answer by Joakim Schicht Friday, November 4, 2011 12:13 PM
    Friday, November 4, 2011 11:02 AM
  • OK so it turned out that the dwDesiredAccess parameter was incorrectly set. Thanks.
    Friday, November 4, 2011 12:12 PM
  • Anybody knows why dwDesiredAccess with 0x80000000 will fail, whereas 0x7fffffff+1 will succeed?
    Friday, November 4, 2011 12:19 PM
  • Anybody knows why dwDesiredAccess with 0x80000000 will fail, whereas 0x7fffffff+1 will succeed?

    0x80000000 - powershell convert to int32 (maxvalue =2147483647),0x7fffffff+1 - powershell conver to double(maxvalue = 1.79769313486232E+308)

    or use uint32(maxvalue = 4294967295).

    PS  >  [convert]::ToUInt32("0x80000000",16)
    2147483648


     


    • Edited by Kazun Friday, November 4, 2011 12:49 PM
    Friday, November 4, 2011 12:40 PM
  • Here is some sample powershell code to read and backup data from a given sector on your \\.\PhysicalDriveN. Takes 3 parameters; disk number, backup filename and sector number. Sample usage for backing up MBR; "BackupSector "\\.\PhysicalDrive0" "C:\tmp\mbr_backup.bin" 0". And the code;

    $pinvoke = add-type -name pinvoke -passThru -memberDefinition @'
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes
            );
            
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
         
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern uint GetFileSizeEx(IntPtr hFile, ref long lpFileSize);
    
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern uint GetLastError();
    
    [DllImport("kernel32.dll")]
    public static extern bool SetFilePointerEx(IntPtr hFile, long liDistanceToMove, IntPtr lpNewFilePointer, uint dwMoveMethod);
    
    [DllImport("kernel32.dll", SetLastError=true)]
    public static extern bool SetEndOfFile(IntPtr hFile);
    
    [DllImport("Crypt32.dll", SetLastError = true)]
    public static extern bool CryptBinaryToString(byte[] pbBinary, uint cbBinary, uint dwFlags, [Out] byte[] pszString, uint pcchString);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool FlushFileBuffers(IntPtr hFile);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
    
    
    '@
    function BackupSector{
    Param(
    [Parameter(
    Mandatory = $True,
    Position = 0)]
    [string]$Drive,
    [Parameter(
    Mandatory = $True,
    Position = 1)]
    [string]$BackupName,
    [Parameter(
    Mandatory = $True,
    Position = 2)]
    [int]$Sector
    )
    $WMIDrive = get-wmiobject win32_diskdrive | where {$_.DeviceID -eq $Drive}
    $WMIDriveSize = $WMIDrive.size
    $TotalSectors = ($WMIDriveSize/512)
    If ($Sector -ge $TotalSectors) {return ("Error - Chosen sector exceeds total number of sectors.")}
    $lpFileName = $Drive
    $dwDesiredAccess = 0x7fffffff+1
    $dwShareMode = 0x1
    $lpSecurityAttributes = 0
    $dwCreationDisposition = 0x3
    $dwFlagsAndAttributes = 0x0 
    $hFile = $pinvoke::CreateFile($Drive, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CreateFile on physical disk returned error code: $lasterror")}
    $CurrentFilePosition = [uint32]::MinValue
    $MoveBytes = ($sector * 512)
    $FilePosition = $pinvoke::SetFilePointerEx($hFile, $MoveBytes, $CurrentFilePosition, 0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - SetFilePointerEx setting new position on disk returned error code: $lasterror")}
    $backupFile = $pinvoke::CreateFile($BackupName, 0x6, 0x6, $lpSecurityAttributes, 0x3, $dwFlagsAndAttributes)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CreateFile on backup file returned error code: $lasterror")}
    $ByteToRead = 512
    [byte[]]$FileBuffer = new-object byte[] $ByteToRead
    $nBytes = [uint32]::MinValue 
    $rFile = $pinvoke::ReadFile($hFile, $FileBuffer, $ByteToRead, [ref]$nBytes, 0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - ReadFile on physical disk returned error code: $lasterror")}
    $FileSize = $ByteToRead
    $WriteBackup = $pinvoke::WriteFile($backupFile, $FileBuffer, $FileSize, [ref]$nBytes, 0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - WriteFile on backup file returned error code: $lasterror")}
    $pinvoke::CloseHandle($hFile)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CloseHandle on physical disk returned error code: $lasterror")}
    $pinvoke::CloseHandle($backupFile)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CloseHandle on backup file returned error code: $lasterror")}
    }
    
    BackupSector "\\.\PhysicalDrive0" "C:\tmp\mbr_backup.bin" 0
    

    I know it does not look very elegant. I just got into the powershell world..


    Sunday, November 6, 2011 12:03 AM
  • So I finished my script that will make a sector for sector copy (image) of a physical disk. I ran into some issues with getting the total size (allocated + unallocated space) of a disk. I started out with "get-wmiobject win32_diskdrive", but the size property reported there only considers allocated space, and produced incorretly sized images. Therefore I needed to use IOCTL_DISK_GET_LENGTH_INFO with the DeviceIoControl function. I verified that the script produces correct disk images by comparing the MD5 against output of commercial utilities.

    The api's used are;

    CreateFile
    ReadFile
    WriteFile
    CloseHandle
    GetLastError
    SetFilePointerEx
    SetEndOfFile
    FlushFileBuffers
    GetDiskFreeSpaceEx
    DeviceIoControl

    The complete script:

    $pinvoke = add-type -name pinvoke -passThru -memberDefinition @'
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes
            );
            
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr lpOverlapped);
         
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
    public static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern uint GetLastError();
    
    [DllImport("kernel32.dll")]
    public static extern bool SetFilePointerEx(IntPtr hFile, ulong liDistanceToMove, IntPtr lpNewFilePointer, uint dwMoveMethod);
    
    [DllImport("kernel32.dll", SetLastError=true)]
    public static extern bool SetEndOfFile(IntPtr hFile);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool FlushFileBuffers(IntPtr hFile);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, out ulong lpFreeBytesAvailable, out ulong lpTotalNumberOfBytes, out ulong lpTotalNumberOfFreeBytes);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, ref long InBuffer, int nInBufferSize, ref long OutBuffer, int nOutBufferSize, ref int pBytesReturned, IntPtr lpOverlapped);
    
    '@
    
    function BackupDisk{
    Param(
    [Parameter(
    Mandatory = $True,
    Position = 0)]
    [string]$Drive,
    [Parameter(
    Mandatory = $True,
    Position = 1)]
    [string]$BackupName
    )
    $dwDesiredAccess = 0x7fffffff+1
    $dwShareMode = 0x1
    $lpSecurityAttributes = 0
    $dwCreationDisposition = 0x3
    $dwFlagsAndAttributes = 0x0 
    $hFile = $pinvoke::CreateFile($Drive, $dwDesiredAccess, $dwShareMode, $lpSecurityAttributes, $dwCreationDisposition, $dwFlagsAndAttributes)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CreateFile on physical disk returned error code: $lasterror")}
    $InBuffer1 = [uint64]::MinValue
    [int64]$OutBuffer = 0
    $nOutBufferSize = 0xffff
    $pBytesReturned = [uint64]::MinValue
    $IOCTL_DISK_GET_LENGTH_INFO = 0x0007405c
    $DISK_LENGTH = $pinvoke::DeviceIoControl($hFile,$IOCTL_DISK_GET_LENGTH_INFO,[ref] $InBuffer1, 0,[ref] $OutBuffer,$nOutBufferSize,[ref] $pBytesReturned,0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - IOCTL_DISK_GET_LENGTH_INFO returned error code: $lasterror")}
    $TotalPhysicalSize = $OutBuffer
    $TotalSectors = ($TotalPhysicalSize/512)
    $block = 8388608
    $remainder = 0
    $sizediff = $TotalPhysicalSize/$block
    $maxblocks = [system.math]::ceiling($sizediff)
    $maxblocks_low = [system.math]::floor($sizediff)
    $sizediff2 = $sizediff-$maxblocks_low
    $remainder = $sizediff2 * $block
    If ($Sector -ge $TotalSectors) {return ("Error - Chosen sector exceeds total number of sectors.")}
    $lpDirectoryName = $BackupName.substring(0,3)
    $lpFreeBytesAvailable = [uint64]::MinValue
    $lpTotalNumberOfBytes = [uint64]::MinValue
    $lpTotalNumberOfFreeBytes = [uint64]::MinValue
    $GetDiskFreeSpaceEx = $pinvoke::GetDiskFreeSpaceEx($lpDirectoryName,[ref]$lpFreeBytesAvailable,[ref]$lpTotalNumberOfBytes,[ref]$lpTotalNumberOfFreeBytes)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - GetDiskFreeSpaceEx returned error code: $lasterror")}
    If ($TotalPhysicalSize -ge $lpFreeBytesAvailable) {return ("Error - Not enough free space to save image on $lpDirectoryName")}
    $SectorSize = 512
    $lpFileName = $Drive
    $CurrentFilePosition = [uint32]::MinValue
    $backupFile = $pinvoke::CreateFile($BackupName, 0x6, 0x6, $lpSecurityAttributes, 0x4, $dwFlagsAndAttributes)
    $lasterror = $pinvoke::GetLastError()
    If (($lasterror -ne 0) -AND ($lasterror -ne  183))  {return ("Error - CreateFile on backup file returned error code: $lasterror")}
    $pinvoke::SetFilePointerEx($backupFile,$TotalPhysicalSize,0,0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - SetFilePointerEx before main loop returned error code: $lasterror")}
    $pinvoke::SetEndOfFile($backupFile)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - SetEndOfFile before main loop returned error code: $lasterror")}
    $pinvoke::FlushFileBuffers($backupFile)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - FlushFileBuffers before main loop returned error code: $lasterror")}
    $pinvoke::SetFilePointerEx($backupFile,0,0,0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - SetFilePointerEx before main loop returned error code: $lasterror")}
    $nBytes = [uint32]::MinValue 
    For ($i = 0; $i -lt $maxblocks+1; $i++)
    {
    "Now working on chunk number: $i of $maxblocks"
    $a = $i
    If ($a -eq $maxblocks) {$block = $remainder}
    [byte[]]$FileBuffer = new-object byte[] $block
    $rFile = $pinvoke::ReadFile($hFile, $FileBuffer, $block, [ref]$nBytes, 0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - ReadFile on physical disk returned error code: $lasterror")}
    $FileSize = $block
    $WriteBackup = $pinvoke::WriteFile($backupFile, $FileBuffer, $FileSize, [ref]$nBytes, 0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - WriteFile on backup file returned error code: $lasterror")}
    If ($a -eq $maxblocks) 
    {
    $pinvoke::FlushFileBuffers($backupFile)
    return
    }
    $NewPointer = $pinvoke::SetFilePointerEx($hFile,$i*$block,0,0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - SetFilePointerEx disk inside main loop returned error code: $lasterror")}
    $NewPointer = $pinvoke::SetFilePointerEx($backupFile,$i*$block,0,0)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - SetFilePointerEx backup inside main loop returned error code: $lasterror")}
    }
    $pinvoke::CloseHandle($hFile)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CloseHandle on physical disk returned error code: $lasterror")}
    $pinvoke::CloseHandle($backupFile)
    $lasterror = $pinvoke::GetLastError()
    If ($lasterror -ne 0)  {return ("Error - CloseHandle on backup file returned error code: $lasterror")}
    }
    
    BackupDisk "\\.\PhysicalDrive2" "E:\tmp\disk2_powershell.img"
    

    I am sure there exist much faster solutions for the task. This is just a powershell sample to show roughly what it takes for such a task.

    Monday, November 7, 2011 8:59 AM
  • Joakin,

    I need to talk to badliy about some mft code that the StCroixSkipper wrote.

    Renee rmctwo at gmail dot com


    "MODERN PROGRAMMING is deficient in elementary ways BECAUSE of problems INTRODUCED by MODERN PROGRAMMING." Me

    Wednesday, March 28, 2012 2:06 AM