Jump to content

USB Burning tool for PE projects - (Progress Bar options, and disk list)


bobomb
 Share

Go to solution Solved by benners,

Recommended Posts

I am trying to use the stuff Ive learned so far to put a USB burning tool together for WinXPE and SE ISO's (Or any WinPE ISO that is boot.wim/winre based that contains CdUsb.Y empty marker file in root of ISO) , I usually cmd my way though things and I dont know all the alternatives in AutoIT yet, diskpart and xcopy are both pretty solid 😜 but I do love your language, and i am understanding it faster than I thought, but do still need some guidance..

My progress bar is riddled all throughout the script, I do not see a better way off the top of my head, anyone have any suggestions? Also is there an easy way to show progress % in titlebar? Everything works fine I just want to make it better.. Or if you see anything that looks dumb please point it out to me.

Is there a way to use stdout for xcopy other than using the process id? I am jumping around with it and reinstancing it.. Maybe use that entirely for my progress after format instead of what I'm doing now..

#NoTrayIcon
#RequireAdmin
#include <AutoItConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include <File.au3>
#include <Array.au3>
#include <String.au3>

Global $DiskList, $Selection, $Burn, $Refresh, $MountedDrive = ""
Global $IsoFile, $CachePath, $finalfiles, $finaldirs, $wimSize, $bootDrive, $dataDrive

GetCachePath()
ProperUse()
MountIso()
GetISODriveLetter()
CheckWIM()
Cleanup()

DirCreate($CachePath)
$listFile = FileOpen($CachePath & 'list.ini', 2)
FileWrite($listFile, 'lis dis')
FileClose($listFile)

Opt("GUIOnEventMode", 1)
MainMenu()

Cleanup()
Exit

Func MainMenu()
    GUICreate('USBTool (PE) v2.0', 300, 298)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents")
    GUISetIcon(@WorkingDir & '\USBTool.ico', 1)
    GUISetBkColor(0x797979)
    GUICtrlCreateLabel('1: Select a disk use...', 20, 10, 280)
    $DiskList = GUICtrlCreateList('', 20, 30, 260, 150)
    GUICtrlSetData(-1, DiskList())
    $Refresh = GUICtrlCreateButton('Refresh List', 110, 185, 80, 25)
    GUICtrlSetOnEvent(-1, "_RefreshPressed")
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlCreateLabel('________________________________________', 30, 210, 280, 30)
    $Burn = GUICtrlCreateButton('Burn', 90, 232, 120, 40)
    GUICtrlSetOnEvent(-1, "BurnPressed")
    GUICtrlCreateLabel('( * ) Disk is Currently GPT', 160, 278, 130, 30)
    GUISetState()
    ; Just idle around
    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>MainMenu

Func RefreshPressed()
    GUICtrlSetData($DiskList, "")
    GUICtrlSetData($DiskList, DiskList())
EndFunc   ;==>RefreshPressed

Func BurnPressed()
    Local $Disk = StringRegExpReplace(GUICtrlRead($DiskList), '(?i)^.*(Disk [\d]+).*$', '$1')
    Local $DiskN = StringSplit($Disk, "")
    Local $AreYouSure
    If $Disk = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "No disk has been selected")
    Else
        $AreYouSure = MsgBox(262452, 'This will FORMAT Disk ' & $DiskN[6], 'ALL DATA WILL BE ERASED FROM DISK ' & $DiskN[6] & @CRLF & 'Are you sure you want to proceed?')
        Select
            Case $AreYouSure = 6 ;Yes
                GUISetState(@SW_HIDE)
                ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
                PrepFormat($DiskN[6])
                ProgressSet(5 & "%", "Formatting Disk " & $DiskN[6])
                Format()
                ProgressSet(25 & "%", "Analyzing ISO Structure ")
                CleanDirList()
                CleanFileList()
                ProgressSet(26 & "%", "Copying Boot Partition ")
                CopyBootFiles()
                ;Progress in function; start at 55%
                CopyDataFilesF()
                ;Progress in function; start at 65%
                CopyDataFilesD()
                ProgressSet(100, "Finished", "ISO Applied!!")
                Sleep(2750)
                ProgressOff()
                Cleanup()
                UnmountIso()
                MsgBox($MB_ICONINFORMATION, "", " Enjoy! ")
                Exit
            Case $AreYouSure = 7 ;No
        EndSelect
    EndIf
EndFunc   ;==>BurnPressed

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Code below for actions on Close
            Cleanup()
            UnmountIso()
            Exit
        Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE
            ; Code below for actions on Minimize
        Case @GUI_CtrlId = $GUI_EVENT_RESTORE
            ; Code below for actions on Restore
    EndSelect
EndFunc   ;==>SpecialEvents

Func ProperUse()
    If Not ($CmdLine[0]) = 0 Then ;Something was dropped on the EXE file or CLI was used with a flag(s)
        $IsoFile = ($CmdLine[1]) ;Sets $IsoFile var to the full path of whatever was dropped onto the EXE file or the 1st CLI flag that was used
    Else
        MsgBox($MB_ICONERROR, "Notice: ", "This program cannot be run directly!" & @CRLF & "Please drag an ISO onto" & @CRLF & "the program to begin...")
        Exit
    EndIf
EndFunc   ;==>ProperUse

Func CheckWIM()
    Local $wimExists = FileExists($MountedDrive & ":\sources\boot.wim")
    If Not $wimExists Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    Else
        $wimSize = FileGetSize($MountedDrive & ":\sources\boot.wim")
        $wimSize = StringSplit(($wimSize + 200000000) / 1000000, ".") ; +200mb headroom on boot partition
        $wimSize = $wimSize[1] ;Get whole number after converting size from bytes to megabytes
    EndIf
EndFunc   ;==>CheckWIM

Func MountIso()
    RunWait('cmd /c powershell.exe ' & '"Mount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>MountIso

Func UnmountIso()
    RunWait('cmd /c powershell.exe ' & '"Dismount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>UnmountIso

Func Cleanup()
    If FileExists($CachePath) Then
        DirRemove($CachePath, $DIR_REMOVE)
    EndIf
EndFunc   ;==>Cleanup

Func GetISODriveLetter()
    Local $findiso = StringSplit("CDEFGHIJKLMNOPQRSTUVWXYZ", "", 1)
    For $i = 1 To $findiso[0] Step +1
        $isoExists = FileExists($findiso[$i] & ":\CdUsb.Y")
        If $isoExists Then
            If PathIsWritable($findiso[$i] & ":\") = False Then
                $MountedDrive = ($findiso[$i])
            EndIf
        EndIf
    Next
    If $MountedDrive = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "CdUsb.Y NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        Exit
    EndIf
EndFunc   ;==>GetISODriveLetter

Func PathIsWritable($sFile)
    Local $aRet = DllCall('kernel32.dll', 'handle', 'CreateFileW', _
            'wstr', $sFile, _
            'dword', 2, _
            'dword', 7, _
            'struct*', 0, _
            'dword', 3, _
            'dword', 0x02000000, _
            'handle', 0)
    If @error Or $aRet[0] = Ptr(-1) Or $aRet[0] = 0 Then Return False
    DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $aRet[0])
    Return True
EndFunc   ;==>PathIsWritable

Func DiskList()
    RunWait('cmd /c diskpart /s ' & '"' & $CachePath & 'list.ini' & '"' & '>' & '"' & $CachePath & 'dpoutput.txt' & '"', @WorkingDir, @SW_HIDE)
    Local $Filtered = '', $Array = _StringExplode(FileRead($CachePath & 'dpoutput.txt'), @LF)
    For $rawlist = 0 To UBound($Array) - 1
        If StringRegExp($Array[$rawlist], '(?i)Disk [\d]+') Then $Filtered &= $Array[$rawlist] & '|'
    Next
    $Filtered = StringRegExpReplace($Filtered, '[\s|]*$', '')
    Return $Filtered
EndFunc   ;==>DiskList

Func GetCachePath()
    $CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache')
    $CachePath = ($CachePath & '\')
EndFunc   ;==>GetCachePath

Func PrepFormat($Drive)
    GetDriveLetters()
    createDiskPartScriptFile($CachePath & 'clean.dat', 'Sel Dis ' & $Drive & @CRLF & 'clean' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'attrib.dat', 'Sel Dis ' & $Drive & @CRLF & 'attribute disk clear readonly' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'scrubber.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=NTFS label=scrubber' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'convert.dat', 'Sel Dis ' & $Drive & @CRLF & 'convert mbr' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'initdata.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'shrink minimum=' & $wimSize & @CRLF & 'format quick fs=ntfs label="WinPE Data"' & @CRLF & 'assign letter=' & $dataDrive & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'initboot.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=fat32 label="BOOTFILES"' & @CRLF & 'assign letter=' & $bootDrive & @CRLF & 'Active' & @CRLF & 'Exit')
EndFunc   ;==>PrepFormat

Func CopyBootFiles()
    Local $bmgrExists = FileExists($MountedDrive & ":\BOOTMGR.")
    Local $bmgrefiExists = FileExists($MountedDrive & ":\bootmgr.efi")
    Local $bmgrexeExists = FileExists($MountedDrive & ":\bootmgr.exe")
    Local $menulstExists = FileExists($MountedDrive & ":\menu.lst")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOT ' & $bootDrive & ':\BOOT /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(27 & "%", "Copying Boot Partition ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\EFI ' & $bootDrive & ':\EFI /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(40 & "%", "Copying Boot.wim, this may take a while... ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\sources ' & $bootDrive & ':\sources /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(50 & "%", "Copying Boot Files ")
    If $bmgrExists Then
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
    If $bmgrefiExists Then
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.efi ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
    If $bmgrexeExists Then
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.exe ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
    If $menulstExists Then ;Need to add grub support etc later if this gets expanded beyond PE SE or XPE ISO's
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\menu.lst ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
EndFunc   ;==>CopyBootFiles

Func CopyDataFilesF()
    Local $GoFiles = ($CachePath & $finalfiles), $StartProgAt
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 55
    For $i = 1 To UBound($aArray) - 1
        ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i] & " ")
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & ' /h /r /v /y', @WorkingDir, @SW_HIDE)
        $StartProgAt = ($StartProgAt + 1)
    Next
EndFunc   ;==>CopyDataFilesF

Func CopyDataFilesD()
    Local $GoFiles = ($CachePath & $finaldirs), $StartProgAt
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65
    For $i = 1 To UBound($aArray) - 1
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying Programs, this may take a while... ")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i] &" Folder ")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

Func createDiskPartScriptFile($fileName, $message)
    $CacheFile = ''
    $CacheFile = FileOpen($fileName, 2)
    FileWrite($CacheFile, $message)
    FileClose($CacheFile)
EndFunc   ;==>createDiskPartScriptFile

Func GetDriveLetters()
    Local $allDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ", $AvailDriveLetters
    Local $aArray = DriveGetDrive($DT_ALL)
    If @error Then
        ; An error occurred when retrieving the drives.
        MsgBox($MB_SYSTEMMODAL, "", "An Error Occurred! Unable to retrieve " & @CRLF & "available drive letters! Exiting Program...")
        Cleanup()
        UnmountIso()
        Exit
    Else
        For $i = 1 To $aArray[0]
            $driveLetter = StringLeft(StringUpper($aArray[$i]), 1)
            $allDriveLetters = StringReplace($allDriveLetters, $driveLetter, "")
        Next
    EndIf
    $AvailDriveLetters = StringSplit($allDriveLetters, "")
    $bootDrive = $AvailDriveLetters[1] ;Get first available letter
    $dataDrive = $AvailDriveLetters[2] ;Get second available letter
EndFunc   ;==>GetDriveLetters

Func CleanDirList()
    Local $rawlist = 'isod.dat'
    $finaldirs = 'isodirs.dat'
    RunWait('cmd /c DIR /B /A:D ' & $MountedDrive & ':\>' & '"' & $CachePath & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'efi' & '"' & ' /c:' & '"' & 'boot' & '"' & ' /c:' & '"' & 'sources' & '"' & ' "' & $CachePath & $rawlist & '"' & '>>' & '"' & $CachePath & $finaldirs & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanDirList

Func CleanFileList()
    Local $rawlist = 'isof.dat'
    $finalfiles = 'isofiles.dat'
    RunWait('cmd /c DIR /B /A-D ' & $MountedDrive & ':\>' & '"' & $CachePath & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'bootmgr' & '"' & ' /c:' & '"' & 'menu' & '"' & ' "' & $CachePath & $rawlist & '"' & '>>' & '"' & $CachePath & $finalfiles & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanFileList

Func Format()
    Local $aArray[7][3] = [ _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'clean.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'scrub.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'clean.dat' & '"'], _
            ["Resetting Disk Attributes", 'cmd /c diskpart /s ' & '"' & $CachePath & 'attrib.dat' & '"'], _
            ["Converting Layout to MBR", 'cmd /c diskpart /s ' & '"' & $CachePath & 'convert.dat' & '"'], _
            ["Creating Data Partition", 'cmd /c diskpart /s ' & '"' & $CachePath & 'initdata.dat' & '"'], _
            ["Creating Boot Partition", 'cmd /c diskpart /s ' & '"' & $CachePath & 'initboot.dat' & '"'] _
            ]

    For $i = 0 To UBound($aArray) - 1
        ProgressSet($i * 2 & "%", $aArray[$i][0])
        ;MsgBox($MB_ICONINFORMATION, "Troubleshooting.. ", $aArray[$i][1]) ;Troubleshoot Array Data
        RunWait($aArray[$i][1], @WorkingDir, @SW_HIDE)
        Sleep(750)
    Next

EndFunc   ;==>Format

 

Edited by bobomb
Link to comment
Share on other sites

You could call the functions in a loop and use the variable to calculate the percentage?

#NoTrayIcon
#RequireAdmin
#include <AutoItConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include <File.au3>
#include <Array.au3>
#include <String.au3>

Global $DiskList, $Selection, $Burn, $Refresh, $MountedDrive = ""
Global $IsoFile, $CachePath, $finalfiles, $finaldirs, $wimSize, $bootDrive, $dataDrive

GetCachePath()
ProperUse()
MountIso()
GetISODriveLetter()
CheckWIM()
Cleanup()

DirCreate($CachePath)
$listFile = FileOpen($CachePath & 'list.ini', 2)
FileWrite($listFile, 'lis dis')
FileClose($listFile)

Opt("GUIOnEventMode", 1)
MainMenu()

Cleanup()
Exit

Func MainMenu()
    GUICreate('USBTool (PE) v2.0', 300, 298)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents")
    GUISetIcon(@WorkingDir & '\USBTool.ico', 1)
    GUISetBkColor(0x797979)
    GUICtrlCreateLabel('1: Select a disk use...', 20, 10, 280)
    $DiskList = GUICtrlCreateList('', 20, 30, 260, 150)
    GUICtrlSetData(-1, DiskList())
    $Refresh = GUICtrlCreateButton('Refresh List', 110, 185, 80, 25)
    GUICtrlSetOnEvent(-1, "_RefreshPressed")
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlCreateLabel('________________________________________', 30, 210, 280, 30)
    $Burn = GUICtrlCreateButton('Burn', 90, 232, 120, 40)
    GUICtrlSetOnEvent(-1, "BurnPressed")
    GUICtrlCreateLabel('( * ) Disk is Currently GPT', 160, 278, 130, 30)
    GUISetState()
    ; Just idle around
    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>MainMenu

Func RefreshPressed()
    GUICtrlSetData($DiskList, "")
    GUICtrlSetData($DiskList, DiskList())
EndFunc   ;==>RefreshPressed

Func BurnPressed()
    Local $Disk = StringRegExpReplace(GUICtrlRead($DiskList), '(?i)^.*(Disk [\d]+).*$', '$1')
    Local $DiskN = StringSplit($Disk, "")
    Local $AreYouSure
    If $Disk = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "No disk has been selected")
    Else
        $AreYouSure = MsgBox(262452, 'This will FORMAT Disk ' & $DiskN[6], 'ALL DATA WILL BE ERASED FROM DISK ' & $DiskN[6] & @CRLF & 'Are you sure you want to proceed?')
        Select
            Case $AreYouSure = 6 ;Yes
                GUISetState(@SW_HIDE)
        ; $aFunctions - 0 = Function Name, 1 = Task Description, 2 = Param 1
                Local $aFunctions[7][3] = [ [ 'PrepFormat', 'Preparing Format..', $DiskN[6] ], _
                            [ 'Format', 'Formatting..', -1 ], _
                            [ 'CleanDirList', 'Cleaning Dir List..', -1 ], _
                            [ 'CleanFileList', ' Cleaning File List..', -1 ], _
                            [ 'CopyBootFiles', 'Copying Boot Files..', -1 ], _
                            [ 'CopyDataFilesF', 'Copying Boot Files F..', -1 ], _
                            [ 'CopyDataFilesD', 'Copying Boot Files D..', -1 ] ]
        ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
        For $i = 0 To (UBound($aFunctions) - 1) Step 1
            If $aFunctions[$i][2] <> -1 Then
                Call($aFunctions[$i][0], $aFunctions[$i][2])
            Else
                Call($aFunctions[$i][0])
            EndIf
            Local $iPercentage = Int(((100 / UBound($aFunctions)) * ($i + 1)))
            ProgressSet($iPercentage, $aFunctions[$i][1], $iPercentage & '%')
            Sleep(1000) ; You might want to remove this sleep - I added it for visibility
        Next
        ProgressOff()
                Cleanup()
                UnmountIso()
                MsgBox($MB_ICONINFORMATION, "", " Enjoy! ")
                Exit
            Case $AreYouSure = 7 ;No
        EndSelect
    EndIf
EndFunc   ;==>BurnPressed

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Code below for actions on Close
            Cleanup()
            UnmountIso()
            Exit
        Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE
            ; Code below for actions on Minimize
        Case @GUI_CtrlId = $GUI_EVENT_RESTORE
            ; Code below for actions on Restore
    EndSelect
EndFunc   ;==>SpecialEvents

Func ProperUse()
    If Not ($CmdLine[0]) = 0 Then ;Something was dropped on the EXE file or CLI was used with a flag(s)
        $IsoFile = ($CmdLine[1]) ;Sets $IsoFile var to the full path of whatever was dropped onto the EXE file or the 1st CLI flag that was used
    Else
        MsgBox($MB_ICONERROR, "Notice: ", "This program cannot be run directly!" & @CRLF & "Please drag an ISO onto" & @CRLF & "the program to begin...")
        Exit
    EndIf
EndFunc   ;==>ProperUse

Func CheckWIM()
    Local $wimExists = FileExists($MountedDrive & ":\sources\boot.wim")
    If Not $wimExists Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    Else
        $wimSize = FileGetSize($MountedDrive & ":\sources\boot.wim")
        $wimSize = StringSplit(($wimSize + 200000000) / 1000000, ".") ; +200mb headroom on boot partition
        $wimSize = $wimSize[1] ;Get whole number after converting size from bytes to megabytes
    EndIf
EndFunc   ;==>CheckWIM

Func MountIso()
    RunWait('cmd /c powershell.exe ' & '"Mount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>MountIso

Func UnmountIso()
    RunWait('cmd /c powershell.exe ' & '"Dismount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>UnmountIso

Func Cleanup()
    If FileExists($CachePath) Then
        DirRemove($CachePath, $DIR_REMOVE)
    EndIf
EndFunc   ;==>Cleanup

Func GetISODriveLetter()
    Local $findiso = StringSplit("CDEFGHIJKLMNOPQRSTUVWXYZ", "", 1)
    For $i = 1 To $findiso[0] Step +1
        $isoExists = FileExists($findiso[$i] & ":\CdUsb.Y")
        If $isoExists Then
            If PathIsWritable($findiso[$i] & ":\") = False Then
                $MountedDrive = ($findiso[$i])
            EndIf
        EndIf
    Next
    If $MountedDrive = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "CdUsb.Y NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        Exit
    EndIf
EndFunc   ;==>GetISODriveLetter

Func PathIsWritable($sFile)
    Local $aRet = DllCall('kernel32.dll', 'handle', 'CreateFileW', _
            'wstr', $sFile, _
            'dword', 2, _
            'dword', 7, _
            'struct*', 0, _
            'dword', 3, _
            'dword', 0x02000000, _
            'handle', 0)
    If @error Or $aRet[0] = Ptr(-1) Or $aRet[0] = 0 Then Return False
    DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $aRet[0])
    Return True
EndFunc   ;==>PathIsWritable

Func DiskList()
    RunWait('cmd /c diskpart /s ' & '"' & $CachePath & 'list.ini' & '"' & '>' & '"' & $CachePath & 'dpoutput.txt' & '"', @WorkingDir, @SW_HIDE)
    Local $Filtered = '', $Array = _StringExplode(FileRead($CachePath & 'dpoutput.txt'), @LF)
    For $rawlist = 0 To UBound($Array) - 1
        If StringRegExp($Array[$rawlist], '(?i)Disk [\d]+') Then $Filtered &= $Array[$rawlist] & '|'
    Next
    $Filtered = StringRegExpReplace($Filtered, '[\s|]*$', '')
    Return $Filtered
EndFunc   ;==>DiskList

Func GetCachePath()
    $CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache')
    $CachePath = ($CachePath & '\')
EndFunc   ;==>GetCachePath

Func PrepFormat($Drive)
    GetDriveLetters()
    createDiskPartScriptFile($CachePath & 'clean.dat', 'Sel Dis ' & $Drive & @CRLF & 'clean' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'attrib.dat', 'Sel Dis ' & $Drive & @CRLF & 'attribute disk clear readonly' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'scrubber.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=NTFS label=scrubber' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'convert.dat', 'Sel Dis ' & $Drive & @CRLF & 'convert mbr' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'initdata.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'shrink minimum=' & $wimSize & @CRLF & 'format quick fs=ntfs label="WinPE Data"' & @CRLF & 'assign letter=' & $dataDrive & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'initboot.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=fat32 label="BOOTFILES"' & @CRLF & 'assign letter=' & $bootDrive & @CRLF & 'Active' & @CRLF & 'Exit')
EndFunc   ;==>PrepFormat

Func CopyBootFiles()
    Local $bmgrExists = FileExists($MountedDrive & ":\BOOTMGR.")
    Local $bmgrefiExists = FileExists($MountedDrive & ":\bootmgr.efi")
    Local $bmgrexeExists = FileExists($MountedDrive & ":\bootmgr.exe")
    Local $menulstExists = FileExists($MountedDrive & ":\menu.lst")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOT ' & $bootDrive & ':\BOOT /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(27 & "%", "Copying Boot Partition ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\EFI ' & $bootDrive & ':\EFI /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(40 & "%", "Copying Boot.wim, this may take a while... ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\sources ' & $bootDrive & ':\sources /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(50 & "%", "Copying Boot Files ")
    If $bmgrExists Then
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
    If $bmgrefiExists Then
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.efi ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
    If $bmgrexeExists Then
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.exe ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
    If $menulstExists Then ;Need to add grub support etc later if this gets expanded beyond PE SE or XPE ISO's
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\menu.lst ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    EndIf
EndFunc   ;==>CopyBootFiles

Func CopyDataFilesF()
    Local $GoFiles = ($CachePath & $finalfiles), $StartProgAt
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 55
    For $i = 1 To UBound($aArray) - 1
        ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i] & " ")
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & ' /h /r /v /y', @WorkingDir, @SW_HIDE)
        $StartProgAt = ($StartProgAt + 1)
    Next
EndFunc   ;==>CopyDataFilesF

Func CopyDataFilesD()
    Local $GoFiles = ($CachePath & $finaldirs), $StartProgAt
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65
    For $i = 1 To UBound($aArray) - 1
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying Programs, this may take a while... ")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i] &" Folder ")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

Func createDiskPartScriptFile($fileName, $message)
    $CacheFile = ''
    $CacheFile = FileOpen($fileName, 2)
    FileWrite($CacheFile, $message)
    FileClose($CacheFile)
EndFunc   ;==>createDiskPartScriptFile

Func GetDriveLetters()
    Local $allDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ", $AvailDriveLetters
    Local $aArray = DriveGetDrive($DT_ALL)
    If @error Then
        ; An error occurred when retrieving the drives.
        MsgBox($MB_SYSTEMMODAL, "", "An Error Occurred! Unable to retrieve " & @CRLF & "available drive letters! Exiting Program...")
        Cleanup()
        UnmountIso()
        Exit
    Else
        For $i = 1 To $aArray[0]
            $driveLetter = StringLeft(StringUpper($aArray[$i]), 1)
            $allDriveLetters = StringReplace($allDriveLetters, $driveLetter, "")
        Next
    EndIf
    $AvailDriveLetters = StringSplit($allDriveLetters, "")
    $bootDrive = $AvailDriveLetters[1] ;Get first available letter
    $dataDrive = $AvailDriveLetters[2] ;Get second available letter
EndFunc   ;==>GetDriveLetters

Func CleanDirList()
    Local $rawlist = 'isod.dat'
    $finaldirs = 'isodirs.dat'
    RunWait('cmd /c DIR /B /A:D ' & $MountedDrive & ':\>' & '"' & $CachePath & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'efi' & '"' & ' /c:' & '"' & 'boot' & '"' & ' /c:' & '"' & 'sources' & '"' & ' "' & $CachePath & $rawlist & '"' & '>>' & '"' & $CachePath & $finaldirs & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanDirList

Func CleanFileList()
    Local $rawlist = 'isof.dat'
    $finalfiles = 'isofiles.dat'
    RunWait('cmd /c DIR /B /A-D ' & $MountedDrive & ':\>' & '"' & $CachePath & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'bootmgr' & '"' & ' /c:' & '"' & 'menu' & '"' & ' "' & $CachePath & $rawlist & '"' & '>>' & '"' & $CachePath & $finalfiles & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanFileList

Func Format()
    Local $aArray[7][3] = [ _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'clean.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'scrub.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'clean.dat' & '"'], _
            ["Resetting Disk Attributes", 'cmd /c diskpart /s ' & '"' & $CachePath & 'attrib.dat' & '"'], _
            ["Converting Layout to MBR", 'cmd /c diskpart /s ' & '"' & $CachePath & 'convert.dat' & '"'], _
            ["Creating Data Partition", 'cmd /c diskpart /s ' & '"' & $CachePath & 'initdata.dat' & '"'], _
            ["Creating Boot Partition", 'cmd /c diskpart /s ' & '"' & $CachePath & 'initboot.dat' & '"'] _
            ]

    For $i = 0 To UBound($aArray) - 1
        ProgressSet($i * 2 & "%", $aArray[$i][0])
        ;MsgBox($MB_ICONINFORMATION, "Troubleshooting.. ", $aArray[$i][1]) ;Troubleshoot Array Data
        RunWait($aArray[$i][1], @WorkingDir, @SW_HIDE)
        Sleep(750)
    Next

EndFunc   ;==>Format

 

Link to comment
Share on other sites

You could create your own progress gui and have a total progress for the whole process and a current progress for each function. You can then also design it to have labels that identify which part of the process is currently running.

A few suggestions after a quick glance :-

You could lose the $Burn and $Refresh globals as they are for buttons which have an onevent and are only used once in the posted code.

The $CachePath global can be dropped and the GetCachePath function altered to return the path. This can then be called directly.

Func GetCachePath()
    Return IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache') & '\'
EndFunc   ;==>GetCachePath

In the CopyBootFiles function, the four local variables can go and replaced with the Fileexists call, i.e.

If FileExists($MountedDrive & ":\BOOTMGR.") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)

In the CopyDataFiles functions, you could try FileReadToArray to create the array instead of creating one then redimming to fit the line count and looping to read the line.

 

Link to comment
Share on other sites

TL;DR Stuck on STDOUTRead, it appears there are issues with it working for xCopy with the /Y flag? The below bold highlighted functions contain loops with STDOUTRead commands I cannot display in the progress bar.. The copy process works.. I would like to use this for a more granular view of progress.. I added something I think should work but it's not...

@Luke94 thank you for your advice and time. I will attempt to incorporate that beautiful looking array when I get the STDOUT capture down for xcopy, so I can get all the sections to report progress back to it properly. It appears a /Y flag used to cause issues with AutoIT back in the day (circa 2005) but idk if thats still the case. Maybe I'm doing something wrong. I have in the CopyDataFilesF() and CopyDataFilesD() funtions added SDTOUTREAD commands, they will copy the files but I am trying to display the filenames/paths xcopy outputs into the progress bar label as the loop runs.. Any ideas?  The copy process completes fine I just can't get any output from the $line var in those functions for the progress bar.  Getting it to work in there will be nice but it will also open the door for me to pin down how stdout works and make use of it in other functions and probably be able to get rid of some of my dir cmds and txt files im creating and use more arrays instead to hold the vars within the program itself.  Seems like a very good path to take at this point.

@benners I used the direct if fileexists and it looks a lot cleaner idk why i over clutter like that sometimes.. For cachepath im worried about hitting the ini file that many times the var is used all over the script I might leave it in ram instead of on disk. but thank you very much. I will check FileReadToArray now. I post what I come up with here.

Over the weekend (maybe before) I think I will return the dir size of all names in the dir list and compare that against the iso size to break down the percentage of each section..

#NoTrayIcon
#RequireAdmin
#include <AutoItConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include <File.au3>
#include <Array.au3>
#include <String.au3>

Global $DiskList, $Selection, $IsoFile, $CachePath, $MountedDrive = ""
Global $finalfiles, $finaldirs, $wimSize, $bootDrive, $dataDrive

GetCachePath()
ProperUse()
MountIso()
GetISODriveLetter()
CheckWIM()
Cleanup()

DirCreate($CachePath)
$listFile = FileOpen($CachePath & 'list.ini', 2)
FileWrite($listFile, 'lis dis')
FileClose($listFile)

Opt("GUIOnEventMode", 1)
MainMenu()

Cleanup()
Exit

Func MainMenu()
    GUICreate('Burn Tool (XPE/SE) v2.0', 300, 298)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents")
    GUISetIcon(@WorkingDir & '\USBTool.ico', 1)
    GUISetBkColor(0x797979)
    GUICtrlCreateLabel('1: Select a disk use...', 20, 10, 280)
    $DiskList = GUICtrlCreateList('', 20, 30, 260, 150)
    GUICtrlSetData(-1, DiskList())
    $Refresh = GUICtrlCreateButton('Refresh List', 110, 185, 80, 25)
    GUICtrlSetOnEvent(-1, "RefreshPressed")
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlCreateLabel('________________________________________', 30, 210, 280, 30)
    $Burn = GUICtrlCreateButton('Burn', 90, 232, 120, 40)
    GUICtrlSetOnEvent(-1, "BurnPressed")
    GUICtrlCreateLabel('( * ) Disk is Currently GPT', 160, 278, 130, 30)
    GUISetState()
    ; Just idle around
    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>MainMenu

Func RefreshPressed()
    GUICtrlSetData($DiskList, "")
    GUICtrlSetData($DiskList, DiskList())
EndFunc   ;==>RefreshPressed

Func BurnPressed()
    Local $Disk = StringRegExpReplace(GUICtrlRead($DiskList), '(?i)^.*(Disk [\d]+).*$', '$1')
    Local $DiskN = StringSplit($Disk, "")
    Local $AreYouSure
    If $Disk = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "No disk has been selected")
    Else
        $AreYouSure = MsgBox(262452, 'This will FORMAT Disk ' & $DiskN[6], 'ALL DATA WILL BE ERASED FROM DISK ' & $DiskN[6] & @CRLF & 'Are you sure you want to proceed?')
        Select
            Case $AreYouSure = 6 ;Yes
                GUISetState(@SW_HIDE)
                ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
                PrepFormat($DiskN[6])
                ProgressSet(5 & "%", "Formatting Disk " & $DiskN[6])
                Format()
                ProgressSet(25 & "%", "Analyzing ISO Structure ")
                CleanDirList()
                CleanFileList()
                ProgressSet(26 & "%", "Copying Boot Partition ")
                CopyBootFiles()
                ;Progress in function; start at 55%
                CopyDataFilesF()
                ;Progress in function; start at 65%
                CopyDataFilesD()
                ProgressSet(100, "Finished", "ISO Applied!!")
                Sleep(2750)
                ProgressOff()
                Cleanup()
                UnmountIso()
                MsgBox($MB_ICONINFORMATION, "Bootable Media Ready", "     Enjoy!     ")
                Exit
            Case $AreYouSure = 7 ;No
        EndSelect
    EndIf
EndFunc   ;==>BurnPressed

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Code below for actions on Close
            Cleanup()
            UnmountIso()
            Exit
        Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE
            ; Code below for actions on Minimize
        Case @GUI_CtrlId = $GUI_EVENT_RESTORE
            ; Code below for actions on Restore
    EndSelect
EndFunc   ;==>SpecialEvents

Func ProperUse()
    If Not ($CmdLine[0]) = 0 Then ;Something was dropped on the EXE file or CLI was used with a flag(s)
        $IsoFile = ($CmdLine[1]) ;Sets $IsoFile var to the full path of whatever was dropped onto the EXE file or the 1st CLI flag that was used
    Else
        MsgBox($MB_ICONERROR, "Notice: ", "This program cannot be run directly!" & @CRLF & "Please drag an ISO onto" & @CRLF & "the program to begin...")
        Exit
    EndIf
EndFunc   ;==>ProperUse

Func CheckWIM()
    Local $wimExists = FileExists($MountedDrive & ":\sources\boot.wim")
    If Not $wimExists Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    Else
        $wimSize = FileGetSize($MountedDrive & ":\sources\boot.wim")
        $wimSize = StringSplit(($wimSize + 200000000) / 1000000, ".") ; +200mb headroom on boot partition
        $wimSize = $wimSize[1] ;Get whole number after converting size from bytes to megabytes
    EndIf
EndFunc   ;==>CheckWIM

Func MountIso()
    RunWait('cmd /c powershell.exe ' & '"Mount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>MountIso

Func UnmountIso()
    RunWait('cmd /c powershell.exe ' & '"Dismount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>UnmountIso

Func Cleanup()
    If FileExists($CachePath) Then
        DirRemove($CachePath, $DIR_REMOVE)
    EndIf
EndFunc   ;==>Cleanup

Func GetISODriveLetter()
    Local $findiso = StringSplit("CDEFGHIJKLMNOPQRSTUVWXYZ", "", 1)
    For $i = 1 To $findiso[0] Step +1
        $isoExists = FileExists($findiso[$i] & ":\CdUsb.Y")
        If $isoExists Then
            If PathIsWritable($findiso[$i] & ":\") = False Then
                $MountedDrive = ($findiso[$i])
            EndIf
        EndIf
    Next
    If $MountedDrive = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "CdUsb.Y NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        Exit
    EndIf
EndFunc   ;==>GetISODriveLetter

Func PathIsWritable($sFile)
    Local $aRet = DllCall('kernel32.dll', 'handle', 'CreateFileW', _
            'wstr', $sFile, _
            'dword', 2, _
            'dword', 7, _
            'struct*', 0, _
            'dword', 3, _
            'dword', 0x02000000, _
            'handle', 0)
    If @error Or $aRet[0] = Ptr(-1) Or $aRet[0] = 0 Then Return False
    DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $aRet[0])
    Return True
EndFunc   ;==>PathIsWritable

Func DiskList()
    RunWait('cmd /c diskpart /s ' & '"' & $CachePath & 'list.ini' & '"' & '>' & '"' & $CachePath & 'dpoutput.txt' & '"', @WorkingDir, @SW_HIDE)
    Local $Filtered = '', $Array = _StringExplode(FileRead($CachePath & 'dpoutput.txt'), @LF)
    For $rawlist = 0 To UBound($Array) - 1
        If StringRegExp($Array[$rawlist], '(?i)Disk [\d]+') Then $Filtered &= $Array[$rawlist] & '|'
    Next
    $Filtered = StringRegExpReplace($Filtered, '[\s|]*$', '')
    Return $Filtered
EndFunc   ;==>DiskList

Func GetCachePath()
    $CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache')
    $CachePath = ($CachePath & '\')
EndFunc   ;==>GetCachePath

Func PrepFormat($Drive)
    GetDriveLetters()
    createDiskPartScriptFile($CachePath & 'clean.dat', 'Sel Dis ' & $Drive & @CRLF & 'clean' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'attrib.dat', 'Sel Dis ' & $Drive & @CRLF & 'attribute disk clear readonly' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'scrubber.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=NTFS label=scrubber' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'convert.dat', 'Sel Dis ' & $Drive & @CRLF & 'convert mbr' & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'initdata.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'shrink minimum=' & $wimSize & @CRLF & 'format quick fs=ntfs label="WinPE Data"' & @CRLF & 'assign letter=' & $dataDrive & @CRLF & 'Exit')
    createDiskPartScriptFile($CachePath & 'initboot.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=fat32 label="BOOTFILES"' & @CRLF & 'assign letter=' & $bootDrive & @CRLF & 'Active' & @CRLF & 'Exit')
EndFunc   ;==>PrepFormat

Func CopyBootFiles()
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOT ' & $bootDrive & ':\BOOT /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(27 & "%", "Copying Boot Partition ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\EFI ' & $bootDrive & ':\EFI /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(40 & "%", "Copying Boot.wim, this may take a while... ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\sources ' & $bootDrive & ':\sources /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(50 & "%", "Copying Boot Files ")
    If FileExists($MountedDrive & ":\BOOTMGR.") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.efi") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.efi ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.exe") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.exe ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\menu.lst") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\menu.lst ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CopyBootFiles

Func CopyDataFilesF()
    Local $GoFiles = ($CachePath & $finalfiles), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 55
    For $i = 1 To UBound($aArray) - 1
        $line = StdoutRead($xcopycmd = RunWait('cmd /c echo | xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & ' /h /r /v /y', @WorkingDir, @SW_HIDE, 2))
        ProgressSet($StartProgAt & "%", "Copying " & $line)
        $StartProgAt = ($StartProgAt + 1)
    Next
EndFunc   ;==>CopyDataFilesF

Func CopyDataFilesD()
    Local $GoFiles = ($CachePath & $finaldirs), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65

    For $i = 1 To UBound($aArray) - 1
        $line = StdoutRead($xcopycmd = RunWait('cmd /c echo | xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2))
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying " & $line)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $line)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

Func createDiskPartScriptFile($fileName, $message)
    $CacheFile = ''
    $CacheFile = FileOpen($fileName, 2)
    FileWrite($CacheFile, $message)
    FileClose($CacheFile)
EndFunc   ;==>createDiskPartScriptFile

Func GetDriveLetters()
    Local $allDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ", $AvailDriveLetters
    Local $aArray = DriveGetDrive($DT_ALL)
    If @error Then
        ; An error occurred when retrieving the drives.
        MsgBox($MB_SYSTEMMODAL, "", "An Error Occurred! Unable to retrieve " & @CRLF & "available drive letters! Exiting Program...")
        Cleanup()
        UnmountIso()
        Exit
    Else
        For $i = 1 To $aArray[0]
            $driveLetter = StringLeft(StringUpper($aArray[$i]), 1)
            $allDriveLetters = StringReplace($allDriveLetters, $driveLetter, "")
        Next
    EndIf
    $AvailDriveLetters = StringSplit($allDriveLetters, "")
    $bootDrive = $AvailDriveLetters[1] ;Get first available letter
    $dataDrive = $AvailDriveLetters[2] ;Get second available letter
EndFunc   ;==>GetDriveLetters

Func CleanDirList()
    Local $rawlist = 'isod.dat'
    $finaldirs = 'isodirs.dat'
    RunWait('cmd /c DIR /B /A:D ' & $MountedDrive & ':\>' & '"' & $CachePath & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'efi' & '"' & ' /c:' & '"' & 'boot' & '"' & ' /c:' & '"' & 'sources' & '"' & ' "' & $CachePath & $rawlist & '"' & '>>' & '"' & $CachePath & $finaldirs & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanDirList

Func CleanFileList()
    Local $rawlist = 'isof.dat'
    $finalfiles = 'isofiles.dat'
    RunWait('cmd /c DIR /B /A-D ' & $MountedDrive & ':\>' & '"' & $CachePath & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'bootmgr' & '"' & ' /c:' & '"' & 'menu' & '"' & ' "' & $CachePath & $rawlist & '"' & '>>' & '"' & $CachePath & $finalfiles & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanFileList

Func Format()
    Local $aArray[7][3] = [ _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'clean.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'scrub.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & $CachePath & 'clean.dat' & '"'], _
            ["Resetting Disk Attributes", 'cmd /c diskpart /s ' & '"' & $CachePath & 'attrib.dat' & '"'], _
            ["Converting Layout to MBR", 'cmd /c diskpart /s ' & '"' & $CachePath & 'convert.dat' & '"'], _
            ["Creating Data Partition", 'cmd /c diskpart /s ' & '"' & $CachePath & 'initdata.dat' & '"'], _
            ["Creating Boot Partition", 'cmd /c diskpart /s ' & '"' & $CachePath & 'initboot.dat' & '"'] _
            ]

    For $i = 0 To UBound($aArray) - 1
        ProgressSet($i * 2 & "%", $aArray[$i][0])
        ;MsgBox($MB_ICONINFORMATION, "Troubleshooting.. ", $aArray[$i][1]) ;Troubleshoot Array Data
        RunWait($aArray[$i][1], @WorkingDir, @SW_HIDE)
        Sleep(750)
    Next

EndFunc   ;==>Format

 

Edited by bobomb
Link to comment
Share on other sites

Good point about the iniread. You could use a static local variable to hold the value. The ini will be read once when the variable is initialised, after that it is ignored and the value will just be returned. You can then remove the first call to the function in the script and start it from the DirCreate line.

Func GetCachePath()
    Local Static $s_CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache') & '\'
    Return $s_CachePath
EndFunc   ;==>GetCachePath

For me, using _FileReadToArray is easier. No need to ubound to get the total. An example below using the GetCachePath above

Func DiskList()
    RunWait('cmd /c diskpart /s ' & '"' & GetCachePath() & 'list.ini' & '"' & '>' & '"' & GetCachePath() & 'dpoutput.txt' & '"', @WorkingDir, @SW_HIDE)

    Local $as_diskpart = 0
    Local $s_Filtered = ''

    ; read the file to an array
    _FileReadToArray(GetCachePath() & 'dpoutput.txt', $as_diskpart)

    ; loop through the array
    For $i = 1 To $as_diskpart[0]
        If StringRegExp($as_diskpart[$i], '(?i)Disk [\d]+') Then $s_Filtered &= $as_diskpart[$i] & '|'
    Next

    ; return the filtered string
    Return StringRegExpReplace($s_Filtered, '[\s|]*$', '')
EndFunc   ;==>DiskList

You could also split the  CheckWIM function into two, one to test for the file and the other to get the size. Keeps the functions simple and have a single job. Also gets rid of another global ($wimSize)

; check for the boot wim file
Func BootWim_Check()
    If Not FileExists($MountedDrive & ':\sources\boot.wim') Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    EndIf
EndFunc

; get the boot wim size and add 200 megabytes for headroom on boot partition
Func BootWim_GetSize()
    Return Round((FileGetSize($MountedDrive & ':\sources\boot.wim') + 209715200) / 1048576)
EndFunc

In the burn pressed function, when you split the disk string to an array and use $DiskN[6], this will only work if the number of drives is less than 10. I know, who has that many. but for completeness you could try below. This should get disk numbers with double digits

Func BurnPressed()
    If GUICtrlRead($DiskList) = '' Then
        MsgBox( _
                $MB_ICONERROR, _
                "Notice: ", _
                "No disk has been selected")
    Else
        Local $s_DiskNumber = StringRegExp(GUICtrlRead($DiskList), '(?<=Disk\s)[0-9]+', $STR_REGEXPARRAYMATCH)[0]

        If @error Then
            MsgBox( _
                    $MB_ICONERROR, _
                    "Notice: ", _
                    "An error occured retrieving the disk number")
        Else
            If MsgBox( _
                    BitOR($MB_TOPMOST, $MB_ICONWARNING, $MB_YESNO, $MB_DEFBUTTON2), _
                    'This will FORMAT Disk ' & $s_DiskNumber, _
                    'ALL DATA WILL BE ERASED FROM DISK ' & $s_DiskNumber & @CRLF & 'Are you sure you want to proceed?') = $IDYES Then
            GUISetState(@SW_HIDE)
            ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
            PrepFormat($s_DiskNumber)
            ProgressSet(5 & "%", "Formatting Disk " & $s_DiskNumber)
            Format()
            ProgressSet(25 & "%", "Analyzing ISO Structure ")
            CleanDirList()
            CleanFileList()
            ProgressSet(26 & "%", "Copying Boot Partition ")
            CopyBootFiles()
            ;Progress in function; start at 55%
            CopyDataFilesF()
            ;Progress in function; start at 65%
            CopyDataFilesD()
            ProgressSet(100, "Finished", "ISO Applied!!")
            Sleep(2750)
            ProgressOff()
            Cleanup()
            UnmountIso()
            MsgBox($MB_ICONINFORMATION, "", " Enjoy! ")
            Exit
            EndIf
        EndIf
    EndIf
EndFunc   ;==>BurnPressed

For the files issue. You could use FileListToArray or FileListToArrayRec to list the files and use AutoIt to copy them. This would give you the names and path to display and save on txt file creation. Yashied has create a file copy udf here that works great.

On the subject of less file creation, if the contents of list.ini never change, you could create the file yourself and include it in the compiled exe. Use FIleInstall to copy it to the cache folder. You can then remove the code that creates it and lose another global variable.

Link to comment
Share on other sites

@bobomb, does this work?

Func CopyDataFilesD()
    Local $GoFiles = ($CachePath & $finaldirs), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65

    For $i = 1 To UBound($aArray) - 1
        $xcopycmd = Run('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
        ProcessWaitClose($xcopycmd)
        $line = StdoutRead($xcopycmd)
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying " & $line)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $line)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

You may want to write $line to the Console to see what's been returned by StdoutRead.

Link to comment
Share on other sites

@Luke94 that does work, is there any way to pipe the output of a copied dir in realtime?

This was originally a command script i put together a while back.  When The directories are copied as directories xcopy still displayed each file copied on the output running down the screen.  Im trying to get a similar effect if possible under the progress bar.

Edited by bobomb
Link to comment
Share on other sites

not working, nested in the loop or at the top of the function, i have this right now 

#NoTrayIcon
#RequireAdmin
#include <AutoItConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include <File.au3>
#include <Array.au3>
#include <String.au3>

Global $DiskList, $Selection, $IsoFile, $MountedDrive = ""
Global $finalfiles, $finaldirs, $wimSize, $bootDrive, $dataDrive

GetCachePath()
ProperUse()
MountIso()
GetISODriveLetter()
BootWim_Check()
Cleanup()

DirCreate(GetCachePath())
$listFile = FileOpen(GetCachePath() & 'list.ini', 2)
FileWrite($listFile, 'lis dis')
FileClose($listFile)

Opt("GUIOnEventMode", 1)
MainMenu()

Cleanup()
Exit

Func MainMenu()
    GUICreate('Burn Tool (XPE/SE) v2.0', 300, 298)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents")
    GUISetIcon(@WorkingDir & '\USBTool.ico', 1)
    GUISetBkColor(0x797979)
    GUICtrlCreateLabel('1: Select a disk use...', 20, 10, 280)
    $DiskList = GUICtrlCreateList('', 20, 30, 260, 150)
    GUICtrlSetData(-1, DiskList())
    $Refresh = GUICtrlCreateButton('Refresh List', 110, 185, 80, 25)
    GUICtrlSetOnEvent(-1, "RefreshPressed")
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlCreateLabel('________________________________________', 30, 210, 280, 30)
    $Burn = GUICtrlCreateButton('Burn', 90, 232, 120, 40)
    GUICtrlSetOnEvent(-1, "BurnPressed")
    GUICtrlCreateLabel('( * ) Disk is Currently GPT', 160, 278, 130, 30)
    GUISetState()
    ; Just idle around
    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>MainMenu

Func RefreshPressed()
    GUICtrlSetData($DiskList, "")
    GUICtrlSetData($DiskList, DiskList())
EndFunc   ;==>RefreshPressed

Func BurnPressed()
    If GUICtrlRead($DiskList) = '' Then
        MsgBox( _
                $MB_ICONERROR, _
                "Notice: ", _
                "No disk has been selected")
    Else
        Local $s_DiskNumber = StringRegExp(GUICtrlRead($DiskList), '(?<=Disk\s)[0-9]+', $STR_REGEXPARRAYMATCH)[0]

        If @error Then
            MsgBox( _
                    $MB_ICONERROR, _
                    "Notice: ", _
                    "An error occured retrieving the disk number")
        Else
            If MsgBox( _
                    BitOR($MB_TOPMOST, $MB_ICONWARNING, $MB_YESNO, $MB_DEFBUTTON2), _
                    'This will FORMAT Disk ' & $s_DiskNumber, _
                    'ALL DATA WILL BE ERASED FROM DISK ' & $s_DiskNumber & @CRLF & 'Are you sure you want to proceed?') = $IDYES Then
            GUISetState(@SW_HIDE)
            ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
            PrepFormat($s_DiskNumber)
            ProgressSet(5 & "%", "Formatting Disk " & $s_DiskNumber)
            Format()
            ProgressSet(25 & "%", "Analyzing ISO Structure ")
            CleanDirList()
            CleanFileList()
            ProgressSet(26 & "%", "Copying Boot Partition ")
            CopyBootFiles()
            ;Progress in function; start at 55%
            CopyDataFilesF()
            ;Progress in function; start at 65%
            CopyDataFilesD()
            ProgressSet(100, "Finished", "ISO Applied!!")
            Sleep(2750)
            ProgressOff()
            Cleanup()
            UnmountIso()
            MsgBox($MB_ICONINFORMATION, "", " Enjoy! ")
            Exit
            EndIf
        EndIf
    EndIf
EndFunc   ;==>BurnPressed

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Code below for actions on Close
            Cleanup()
            UnmountIso()
            Exit
        Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE
            ; Code below for actions on Minimize
        Case @GUI_CtrlId = $GUI_EVENT_RESTORE
            ; Code below for actions on Restore
    EndSelect
EndFunc   ;==>SpecialEvents

Func ProperUse()
    If Not ($CmdLine[0]) = 0 Then ;Something was dropped on the EXE file or CLI was used with a flag(s)
        $IsoFile = ($CmdLine[1]) ;Sets $IsoFile var to the full path of whatever was dropped onto the EXE file or the 1st CLI flag that was used
    Else
        MsgBox($MB_ICONERROR, "Notice: ", "This program cannot be run directly!" & @CRLF & "Please drag an ISO onto" & @CRLF & "the program to begin...")
        Exit
    EndIf
EndFunc   ;==>ProperUse


Func BootWim_Check() ; check for the boot wim file
    If Not FileExists($MountedDrive & ':\sources\boot.wim') Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    EndIf
EndFunc


Func BootWim_GetSize() ; get the boot wim size and add 200 megabytes for headroom on boot partition
    Return Round((FileGetSize($MountedDrive & ':\sources\boot.wim') + 209715200) / 1048576)
EndFunc

Func MountIso()
    RunWait('cmd /c powershell.exe ' & '"Mount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>MountIso

Func UnmountIso()
    RunWait('cmd /c powershell.exe ' & '"Dismount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>UnmountIso

Func Cleanup()
    If FileExists(GetCachePath()) Then
        DirRemove(GetCachePath(), $DIR_REMOVE)
    EndIf
EndFunc   ;==>Cleanup

Func GetISODriveLetter()
    Local $findiso = StringSplit("CDEFGHIJKLMNOPQRSTUVWXYZ", "", 1)
    For $i = 1 To $findiso[0] Step +1
        $isoExists = FileExists($findiso[$i] & ":\CdUsb.Y")
        If $isoExists Then
            If PathIsWritable($findiso[$i] & ":\") = False Then
                $MountedDrive = ($findiso[$i])
            EndIf
        EndIf
    Next
    If $MountedDrive = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "CdUsb.Y NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        Exit
    EndIf
EndFunc   ;==>GetISODriveLetter

Func PathIsWritable($sFile)
    Local $aRet = DllCall('kernel32.dll', 'handle', 'CreateFileW', _
            'wstr', $sFile, _
            'dword', 2, _
            'dword', 7, _
            'struct*', 0, _
            'dword', 3, _
            'dword', 0x02000000, _
            'handle', 0)
    If @error Or $aRet[0] = Ptr(-1) Or $aRet[0] = 0 Then Return False
    DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $aRet[0])
    Return True
EndFunc   ;==>PathIsWritable

Func DiskList()
    RunWait('cmd /c diskpart /s ' & '"' & GetCachePath() & 'list.ini' & '"' & '>' & '"' & GetCachePath() & 'dpoutput.txt' & '"', @WorkingDir, @SW_HIDE)

    Local $as_diskpart = 0
    Local $s_Filtered = ''

    ; read the file to an array
    _FileReadToArray(GetCachePath() & 'dpoutput.txt', $as_diskpart)

    ; loop through the array
    For $i = 1 To $as_diskpart[0]
        If StringRegExp($as_diskpart[$i], '(?i)Disk [\d]+') Then $s_Filtered &= $as_diskpart[$i] & '|'
    Next

    ; return the filtered string
    Return StringRegExpReplace($s_Filtered, '[\s|]*$', '')
EndFunc   ;==>DiskList

Func GetCachePath()
    Local Static $s_CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache') & '\'
    Return $s_CachePath
EndFunc   ;==>GetCachePath

Func PrepFormat($Drive)
    GetDriveLetters()
    createDiskPartScriptFile(GetCachePath() & 'clean.dat', 'Sel Dis ' & $Drive & @CRLF & 'clean' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'attrib.dat', 'Sel Dis ' & $Drive & @CRLF & 'attribute disk clear readonly' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'scrubber.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=NTFS label=scrubber' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'convert.dat', 'Sel Dis ' & $Drive & @CRLF & 'convert mbr' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'initdata.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'shrink minimum=' & BootWim_GetSize() & @CRLF & 'format quick fs=ntfs label="WinPE Data"' & @CRLF & 'assign letter=' & $dataDrive & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'initboot.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=fat32 label="BOOTFILES"' & @CRLF & 'assign letter=' & $bootDrive & @CRLF & 'Active' & @CRLF & 'Exit')
EndFunc   ;==>PrepFormat

Func CopyBootFiles()
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOT ' & $bootDrive & ':\BOOT /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(27 & "%", "Copying Boot Partition ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\EFI ' & $bootDrive & ':\EFI /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(40 & "%", "Copying Boot.wim, this may take a while... ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\sources ' & $bootDrive & ':\sources /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(50 & "%", "Copying Boot Files ")
    If FileExists($MountedDrive & ":\BOOTMGR.") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.efi") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.efi ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.exe") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.exe ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\menu.lst") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\menu.lst ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CopyBootFiles

Func CopyDataFilesF()
    Local $GoFiles = (GetCachePath() & $finalfiles), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 55
    For $i = 1 To UBound($aArray) - 1
        $xcopycmd = RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & ' /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
        ProcessWaitClose($xcopycmd)
        $line = StdoutRead($xcopycmd)
        $aLines = StringSplit($line, @CRLF)
        $sLastLine = $aLines[(UBound($aLines) - 1)]
        ProgressSet($StartProgAt & "%", "Copying " & $sLastLine)
        $StartProgAt = ($StartProgAt + 1)
    Next
EndFunc   ;==>CopyDataFilesF

Func CopyDataFilesD()
    Local $GoFiles = (GetCachePath() & $finaldirs), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65

    For $i = 1 To UBound($aArray) - 1
        $xcopycmd = Run('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
        ProcessWaitClose($xcopycmd)
        $line = StdoutRead($xcopycmd)
        $aLines = StringSplit($line, @CRLF)
        $sLastLine = $aLines[(UBound($aLines) - 1)]
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying " & $sLastLine)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $sLastLine)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

Func createDiskPartScriptFile($fileName, $message)
    $CacheFile = ''
    $CacheFile = FileOpen($fileName, 2)
    FileWrite($CacheFile, $message)
    FileClose($CacheFile)
EndFunc   ;==>createDiskPartScriptFile

Func GetDriveLetters()
    Local $allDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ", $AvailDriveLetters
    Local $aArray = DriveGetDrive($DT_ALL)
    If @error Then
        ; An error occurred when retrieving the drives.
        MsgBox($MB_SYSTEMMODAL, "", "An Error Occurred! Unable to retrieve " & @CRLF & "available drive letters! Exiting Program...")
        Cleanup()
        UnmountIso()
        Exit
    Else
        For $i = 1 To $aArray[0]
            $driveLetter = StringLeft(StringUpper($aArray[$i]), 1)
            $allDriveLetters = StringReplace($allDriveLetters, $driveLetter, "")
        Next
    EndIf
    $AvailDriveLetters = StringSplit($allDriveLetters, "")
    $bootDrive = $AvailDriveLetters[1] ;Get first available letter
    $dataDrive = $AvailDriveLetters[2] ;Get second available letter
EndFunc   ;==>GetDriveLetters

Func CleanDirList()
    Local $rawlist = 'isod.dat'
    $finaldirs = 'isodirs.dat'
    RunWait('cmd /c DIR /B /A:D ' & $MountedDrive & ':\>' & '"' & GetCachePath() & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'efi' & '"' & ' /c:' & '"' & 'boot' & '"' & ' /c:' & '"' & 'sources' & '"' & ' "' & GetCachePath() & $rawlist & '"' & '>>' & '"' & GetCachePath() & $finaldirs & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanDirList

Func CleanFileList()
    Local $rawlist = 'isof.dat'
    $finalfiles = 'isofiles.dat'
    RunWait('cmd /c DIR /B /A-D ' & $MountedDrive & ':\>' & '"' & GetCachePath() & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'bootmgr' & '"' & ' /c:' & '"' & 'menu' & '"' & ' "' & GetCachePath() & $rawlist & '"' & '>>' & '"' & GetCachePath() & $finalfiles & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanFileList

Func Format()
    Local $aArray[7][3] = [ _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'clean.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'scrub.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'clean.dat' & '"'], _
            ["Resetting Disk Attributes", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'attrib.dat' & '"'], _
            ["Converting Layout to MBR", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'convert.dat' & '"'], _
            ["Creating Data Partition", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'initdata.dat' & '"'], _
            ["Creating Boot Partition", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'initboot.dat' & '"'] _
            ]

    For $i = 0 To UBound($aArray) - 1
        ProgressSet($i * 2 & "%", $aArray[$i][0])
        ;MsgBox($MB_ICONINFORMATION, "Troubleshooting.. ", $aArray[$i][1]) ;Troubleshoot Array Data
        RunWait($aArray[$i][1], @WorkingDir, @SW_HIDE)
        Sleep(750)
    Next

EndFunc   ;==>Format

@benners has some awesome suggestions too all shown implemented and im looking into the UDF he suggested now 😜

EDITED**

Edited by bobomb
Link to comment
Share on other sites

I got rid of the STDout section i think I'm going to try @benners suggestion looking into AutoIT copy UDF etc... for now this is the updated code, the real goal is trying to get some way i can at least make an attempt to track an accurate progress bar.. if i cannot copy with xcopy and see lastline stdout then i probably cant get good progress tracking with xcopy ;( so hopefully autoit copy commands handle it

#NoTrayIcon
#RequireAdmin
#include <AutoItConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include <File.au3>
#include <Array.au3>
#include <String.au3>

Global $DiskList, $Selection, $IsoFile, $MountedDrive = ""
Global $finalfiles, $finaldirs, $wimSize, $bootDrive, $dataDrive

ProperUse()
MountIso()
GetISODriveLetter()
BootWim_Check()
Cleanup()

DirCreate(GetCachePath())
$listFile = FileOpen(GetCachePath() & 'list.ini', 2)
FileWrite($listFile, 'lis dis')
FileClose($listFile)

Opt("GUIOnEventMode", 1)
MainMenu()

Cleanup()
Exit

Func MainMenu()
    GUICreate('Burn Tool (XPE/SE) v2.0', 300, 298)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents")
    GUISetIcon(@WorkingDir & '\USBTool.ico', 1)
    GUISetBkColor(0x797979)
    GUICtrlCreateLabel('1: Select a disk use...', 20, 10, 280)
    $DiskList = GUICtrlCreateList('', 20, 30, 260, 150)
    GUICtrlSetData(-1, DiskList())
    $Refresh = GUICtrlCreateButton('Refresh List', 110, 185, 80, 25)
    GUICtrlSetOnEvent(-1, "RefreshPressed")
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlCreateLabel('________________________________________', 30, 210, 280, 30)
    $Burn = GUICtrlCreateButton('Burn', 90, 232, 120, 40)
    GUICtrlSetOnEvent(-1, "BurnPressed")
    GUICtrlCreateLabel('( * ) Disk is Currently GPT', 160, 278, 130, 30)
    GUISetState()
    ; Just idle around
    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>MainMenu

Func RefreshPressed()
    GUICtrlSetData($DiskList, "")
    GUICtrlSetData($DiskList, DiskList())
EndFunc   ;==>RefreshPressed

Func BurnPressed()
    If GUICtrlRead($DiskList) = '' Then
        MsgBox( _
                $MB_ICONERROR, _
                "Notice: ", _
                "No disk has been selected")
    Else
        Local $s_DiskNumber = StringRegExp(GUICtrlRead($DiskList), '(?<=Disk\s)[0-9]+', $STR_REGEXPARRAYMATCH)[0]

        If @error Then
            MsgBox( _
                    $MB_ICONERROR, _
                    "Notice: ", _
                    "An error occured retrieving the disk number")
        Else
            If MsgBox( _
                    BitOR($MB_TOPMOST, $MB_ICONWARNING, $MB_YESNO, $MB_DEFBUTTON2), _
                    'This will FORMAT Disk ' & $s_DiskNumber, _
                    'ALL DATA WILL BE ERASED FROM DISK ' & $s_DiskNumber & @CRLF & 'Are you sure you want to proceed?') = $IDYES Then
                GUISetState(@SW_HIDE)
                ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
                PrepFormat($s_DiskNumber)
                ProgressSet(5 & "%", "Formatting Disk " & $s_DiskNumber)
                Format()
                ProgressSet(25 & "%", "Analyzing ISO Structure ")
                CleanDirList()
                CleanFileList()
                ProgressSet(26 & "%", "Copying Boot Partition ")
                CopyBootFiles()
                ;Progress in function; start at 55%
                CopyDataFilesF()
                ;Progress in function; start at 65%
                CopyDataFilesD()
                ProgressSet(100, "Finished", "ISO Applied!!")
                Sleep(2750)
                ProgressOff()
                Cleanup()
                UnmountIso()
                MsgBox($MB_ICONINFORMATION, "", " Enjoy! ")
                Exit
            EndIf
        EndIf
    EndIf
EndFunc   ;==>BurnPressed

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Code below for actions on Close
            Cleanup()
            UnmountIso()
            Exit
        Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE
            ; Code below for actions on Minimize
        Case @GUI_CtrlId = $GUI_EVENT_RESTORE
            ; Code below for actions on Restore
    EndSelect
EndFunc   ;==>SpecialEvents

Func ProperUse()
    If Not ($CmdLine[0]) = 0 Then ;Something was dropped on the EXE file or CLI was used with a flag(s)
        $IsoFile = ($CmdLine[1]) ;Sets $IsoFile var to the full path of whatever was dropped onto the EXE file or the 1st CLI flag that was used
    Else
        MsgBox($MB_ICONERROR, "Notice: ", "This program cannot be run directly!" & @CRLF & "Please drag an ISO onto" & @CRLF & "the program to begin...")
        Exit
    EndIf
EndFunc   ;==>ProperUse


Func BootWim_Check() ; check for the boot wim file
    If Not FileExists($MountedDrive & ':\sources\boot.wim') Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    EndIf
EndFunc   ;==>BootWim_Check

Func BootWim_GetSize() ; get the boot wim size and add 200 megabytes for headroom on boot partition
    Return Round((FileGetSize($MountedDrive & ':\sources\boot.wim') + 209715200) / 1048576)
EndFunc   ;==>BootWim_GetSize

Func MountIso()
    RunWait('cmd /c powershell.exe ' & '"Mount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>MountIso

Func UnmountIso()
    RunWait('cmd /c powershell.exe ' & '"Dismount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>UnmountIso

Func Cleanup()
    If FileExists(GetCachePath()) Then
        DirRemove(GetCachePath(), $DIR_REMOVE)
    EndIf
EndFunc   ;==>Cleanup

Func GetISODriveLetter()
    Local $findiso = StringSplit("CDEFGHIJKLMNOPQRSTUVWXYZ", "", 1)
    For $i = 1 To $findiso[0] Step +1
        $isoExists = FileExists($findiso[$i] & ":\CdUsb.Y")
        If $isoExists Then
            If PathIsWritable($findiso[$i] & ":\") = False Then
                $MountedDrive = ($findiso[$i])
            EndIf
        EndIf
    Next
    If $MountedDrive = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "CdUsb.Y NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        Exit
    EndIf
EndFunc   ;==>GetISODriveLetter

Func PathIsWritable($sFile)
    Local $aRet = DllCall('kernel32.dll', 'handle', 'CreateFileW', _
            'wstr', $sFile, _
            'dword', 2, _
            'dword', 7, _
            'struct*', 0, _
            'dword', 3, _
            'dword', 0x02000000, _
            'handle', 0)
    If @error Or $aRet[0] = Ptr(-1) Or $aRet[0] = 0 Then Return False
    DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $aRet[0])
    Return True
EndFunc   ;==>PathIsWritable

Func DiskList()
    RunWait('cmd /c diskpart /s ' & '"' & GetCachePath() & 'list.ini' & '"' & '>' & '"' & GetCachePath() & 'dpoutput.txt' & '"', @WorkingDir, @SW_HIDE)

    Local $as_diskpart = 0
    Local $s_Filtered = ''

    ; read the file to an array
    _FileReadToArray(GetCachePath() & 'dpoutput.txt', $as_diskpart)

    ; loop through the array
    For $i = 1 To $as_diskpart[0]
        If StringRegExp($as_diskpart[$i], '(?i)Disk [\d]+') Then $s_Filtered &= $as_diskpart[$i] & '|'
    Next

    ; return the filtered string
    Return StringRegExpReplace($s_Filtered, '[\s|]*$', '')
EndFunc   ;==>DiskList

Func GetCachePath()
    Local Static $s_CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache') & '\'
    Return $s_CachePath
EndFunc   ;==>GetCachePath

Func PrepFormat($Drive)
    GetDriveLetters()
    createDiskPartScriptFile(GetCachePath() & 'clean.dat', 'Sel Dis ' & $Drive & @CRLF & 'clean' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'attrib.dat', 'Sel Dis ' & $Drive & @CRLF & 'attribute disk clear readonly' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'scrubber.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=NTFS label=scrubber' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'convert.dat', 'Sel Dis ' & $Drive & @CRLF & 'convert mbr' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'initdata.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'shrink minimum=' & BootWim_GetSize() & @CRLF & 'format quick fs=ntfs label="WinPE Data"' & @CRLF & 'assign letter=' & $dataDrive & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'initboot.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=fat32 label="BOOTFILES"' & @CRLF & 'assign letter=' & $bootDrive & @CRLF & 'Active' & @CRLF & 'Exit')
EndFunc   ;==>PrepFormat

Func CopyBootFiles()
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOT ' & $bootDrive & ':\BOOT /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(27 & "%", "Copying Boot Partition ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\EFI ' & $bootDrive & ':\EFI /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(40 & "%", "Copying Boot.wim, this may take a while... ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\sources ' & $bootDrive & ':\sources /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(50 & "%", "Copying Boot Files ")
    If FileExists($MountedDrive & ":\BOOTMGR.") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.efi") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.efi ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.exe") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.exe ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\menu.lst") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\menu.lst ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CopyBootFiles

Func CopyDataFilesF()
    Local $GoFiles = (GetCachePath() & $finalfiles), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 55
    For $i = 1 To UBound($aArray) - 1
        ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i])
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & ' /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
        $StartProgAt = ($StartProgAt + 1)
    Next
EndFunc   ;==>CopyDataFilesF

Func CopyDataFilesD()
    Local $GoFiles = (GetCachePath() & $finaldirs), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65

    For $i = 1 To UBound($aArray) - 1
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying Programs Folder, this may take a while...")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i] & " Folder")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

Func createDiskPartScriptFile($fileName, $message)
    $CacheFile = ''
    $CacheFile = FileOpen($fileName, 2)
    FileWrite($CacheFile, $message)
    FileClose($CacheFile)
EndFunc   ;==>createDiskPartScriptFile

Func GetDriveLetters()
    Local $allDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ", $AvailDriveLetters
    Local $aArray = DriveGetDrive($DT_ALL)
    If @error Then
        ; An error occurred when retrieving the drives.
        MsgBox($MB_SYSTEMMODAL, "", "An Error Occurred! Unable to retrieve " & @CRLF & "available drive letters! Exiting Program...")
        Cleanup()
        UnmountIso()
        Exit
    Else
        For $i = 1 To $aArray[0]
            $driveLetter = StringLeft(StringUpper($aArray[$i]), 1)
            $allDriveLetters = StringReplace($allDriveLetters, $driveLetter, "")
        Next
    EndIf
    $AvailDriveLetters = StringSplit($allDriveLetters, "")
    $bootDrive = $AvailDriveLetters[1] ;Get first available letter
    $dataDrive = $AvailDriveLetters[2] ;Get second available letter
EndFunc   ;==>GetDriveLetters

Func CleanDirList()
    Local $rawlist = 'isod.dat'
    $finaldirs = 'isodirs.dat'
    RunWait('cmd /c DIR /B /A:D ' & $MountedDrive & ':\>' & '"' & GetCachePath() & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'efi' & '"' & ' /c:' & '"' & 'boot' & '"' & ' /c:' & '"' & 'sources' & '"' & ' "' & GetCachePath() & $rawlist & '"' & '>>' & '"' & GetCachePath() & $finaldirs & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanDirList

Func CleanFileList()
    Local $rawlist = 'isof.dat'
    $finalfiles = 'isofiles.dat'
    RunWait('cmd /c DIR /B /A-D ' & $MountedDrive & ':\>' & '"' & GetCachePath() & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'bootmgr' & '"' & ' /c:' & '"' & 'menu' & '"' & ' "' & GetCachePath() & $rawlist & '"' & '>>' & '"' & GetCachePath() & $finalfiles & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanFileList

Func Format()
    Local $aArray[7][3] = [ _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'clean.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'scrub.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'clean.dat' & '"'], _
            ["Resetting Disk Attributes", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'attrib.dat' & '"'], _
            ["Converting Layout to MBR", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'convert.dat' & '"'], _
            ["Creating Data Partition", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'initdata.dat' & '"'], _
            ["Creating Boot Partition", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'initboot.dat' & '"'] _
            ]

    For $i = 0 To UBound($aArray) - 1
        ProgressSet($i * 2 & "%", $aArray[$i][0])
        ;MsgBox($MB_ICONINFORMATION, "Troubleshooting.. ", $aArray[$i][1]) ;Troubleshoot Array Data
        RunWait($aArray[$i][1], @WorkingDir, @SW_HIDE)
        Sleep(750)
    Next

EndFunc   ;==>Format

 

Edited by bobomb
Link to comment
Share on other sites

It would be better and easier to use AutoIt to copy the files. Benefits are as you know, no messing with STDOUT (some programs don't return the output until the end). Error checking with AutoIt functions. You can easily get the file names for progress or label updating.

From looking at the code, it seems the programs aim is to allow selection of a drive, format the drive and copy the contents of an iso image to it. Is this correct?

I have a couple of questions about it.

  1. In CleanFileList and CleanDirList, you get a ist of the files, then another list that excludes certain files. The excluded files are copied over anyway in CopyBootFiles. Is there a reason for this?
  2. There is a free program called Rufus that does this exact thing, albeit missing the check for the marker file, have you heard of this program or are you doing this project to learn AutoIt?

If you need help with the AutoIt commands, I don't mind helping.

Link to comment
Share on other sites

1.) Cleanfilelist and CleanDirlist remove all traces of boot files/folders from the data partition file list. The Boot files are always the same but the data files are an unknown factor depending on how you create your media. Originally this was a simple cmd script with text interface, I could hardcode the paths for the necessary bootfiles but not the other data...originally thats how I was doing it so I just have to break from that method is all... 

2.) This faster than rufus by a noticeable amount on USB 2.0 drives(when lots of small files are involved) but no real difference on faster 3.0 drives, maybe a few seconds. Its simpler, and it can be used on fixed HDD's... Rufus cannot... The original cmd script I made was before rufus allowed for UEFI + Legacy support option you used to have to choose one or the other with Rufus...I think sometime between 3.11 and 3.13. Cmd script works perfect still I just am doing this to replace the the below CMD script and retire it. ;) And ALSO MAINLY to learn....

Just as a reference the original CMD below (Dont want to post cmd scripts but we have been going over it so much I wanted to show u where this whole thing came from)

@ECHO OFF
CLS
SETLOCAL EnableExtensions EnableDelayedExpansion
TITLE Bob.Omb's USB Creation Tool
:PROPERUSE
IF [%1]==[] GOTO IMPROPERUSE
POWERSHELL.EXE "Mount-DiskImage ""%1""" >nul
for /f "tokens=3 delims=\:" %%d in ('reg query hklm\system\mounteddevices ^| findstr /c:"5C003F00" ^| findstr /v "{.*}"') do (  
IF EXIST %%d:\CdUsb.Y SET SOURCE=%%d
)
IF NOT EXIST %SOURCE%:\CdUsb.Y GOTO NOTCOMPAT2
SET SIZE=0
CALL :FILESIZE "%SOURCE%:\sources\boot.wim"
SET /A SIZE=(%size%+209715000)/1048576
GOTO CHECKSIZE
:FILESIZE
  SET SIZE=%~z1
  EXIT /b 0
:CHECKSIZE
IF [%SIZE%]==[] GOTO NOTCOMPAT1
:BOOTDRV
SET "s="
FOR %%s IN (I J K L M N O P Q) DO (
IF NOT EXIST %%s: SET "BOOTDRV=%%s" && GOTO PROGDRV
)
:PROGDRV
SET "t="
FOR %%t IN (R S T U V W X Y Z) DO (
IF NOT EXIST %%t: SET "PROGDRV=%%t" && GOTO INIT1
)
:INIT1
CLS
ECHO        Bob.Omb's USB Creation Tool
ECHO --------------------------------------------
IF EXIST "%~dp0TempUSB" DEL /S /Q "%~dp0TempUSB\*.*" >nul
MD "%~dp0TempUSB" >nul
ECHO list disk >"%~dp0TempUSB\list.txt"
diskpart /s "%~dp0TempUSB\list.txt"
ECHO.
DEL "%~dp0TempUSB\list.txt"
SET /p disk="Select the disk number for your USB Drive (e.g. 2): "
IF [%DISK%]==[] GOTO CHOOSEABORT
ECHO.
IF %DISK%==0 ECHO THIS IS USUALLY YOUR SYSTEM DRIVE! ARE YOU SURE? & ECHO.
ECHO --WARNING-- This will FORMAT the selected disk and ERASE ALL DATA
ECHO.
ECHO   MAKE SURE YOU ARE SELECTING THE CORRECT DISK!!
ECHO.
ECHO You selected disk ---^> %disk%
ECHO.
CHOICE /C YN /M "Is this correct "
IF %ERRORLEVEL%==1 GOTO INIT2
IF %ERRORLEVEL%==2 GOTO INIT1
:ABORT
CLS
ECHO -Cleaning Up-
CD /D %~dp0
IF EXIST "%~dp0TempUSB\*.*" DEL /S /Q "%~dp0TempUSB\*.*" >nul
IF EXIST "%~dp0TempUSB" RD "%~dp0TempUSB" >nul
POWERSHELL.EXE "Dismount-DiskImage ""%1""" >nul
ECHO Process Aborted, No changes have been made...
ECHO.
PAUSE
EXIT
:INIT2
ECHO select disk %disk% >"%~dp0TempUSB\init.txt"
ECHO attribute disk clear readonly >>"%~dp0TempUSB\init.txt"
ECHO clean >>"%~dp0TempUSB\init.txt"
ECHO exit >>"%~dp0TempUSB\init.txt"
ECHO select disk %disk% >"%~dp0TempUSB\initdata.txt"
ECHO clean >>"%~dp0TempUSB\initdata.txt"
ECHO convert mbr >>"%~dp0TempUSB\initdata.txt"
ECHO create partition primary >>"%~dp0TempUSB\initdata.txt"
ECHO shrink minimum=%SIZE% >>"%~dp0TempUSB\initdata.txt"
ECHO format quick fs=ntfs label="WinPE Data" >>"%~dp0TempUSB\initdata.txt"
ECHO assign letter=%PROGDRV% >>"%~dp0TempUSB\initdata.txt"
ECHO exit >>"%~dp0TempUSB\initdata.txt"
ECHO select disk %disk% >"%~dp0TempUSB\initboot.txt"
ECHO create partition primary>>"%~dp0TempUSB\initboot.txt"
ECHO format quick fs=fat32 label="BOOTFILES" >>"%~dp0TempUSB\initboot.txt"
ECHO assign letter=%BOOTDRV% >>"%~dp0TempUSB\initboot.txt"
ECHO active >>"%~dp0TempUSB\initboot.txt"
ECHO exit >>"%~dp0TempUSB\initboot.txt"
:RUNMBR
CLS
ECHO        Bob.Omb's USB Creation Tool
ECHO --------------------------------------------
ECHO.
CD /D "%~dp0"
ECHO Preparing Disk %disk%...
ECHO.
diskpart /s "%~dp0TempUSB\init.txt" >nul
ECHO.
ECHO Formatting Data Section of Disk %disk%...
ECHO.
diskpart /s "%~dp0TempUSB\initdata.txt" >nul
ECHO.
ECHO Formatting Boot Section of Disk %disk%...
diskpart /s "%~dp0TempUSB\initboot.txt" >nul
ECHO.
ECHO -Preparing FileCopy-
:COPYBOOTFILES
CD /D %SOURCE%:
IF EXIST "%~dp0TempUSB\isod.txt" DEL "%~dp0TempUSB\isod.txt"
IF EXIST "%~dp0TempUSB\isodirs.txt" DEL "%~dp0TempUSB\isodirs.txt"
DIR /B /A:D>"%~dp0TempUSB\isod.txt"
FINDSTR /v /i /c:"efi" /c:"boot" /c:"sources" "%~dp0TempUSB\isod.txt">>"%~dp0TempUSB\isodirs.txt"
DEL "%~dp0TempUSB\isod.txt" >nul
IF EXIST "%~dp0TempUSB\isof.txt" DEL "%~dp0TempUSB\isof.txt"
IF EXIST "%~dp0TempUSB\isofiles.txt" DEL "%~dp0TempUSB\isofiles.txt"
DIR /B /A-D>"%~dp0TempUSB\isof.txt"
FINDSTR /v /i /c:"bootmgr" /c:"menu" "%~dp0TempUSB\isof.txt">>"%~dp0TempUSB\isofiles.txt"
DEL "%~dp0TempUSB\isof.txt" >nul
ECHO.
ECHO -Copying Boot Files-
XCOPY %SOURCE%:\BOOT %BOOTDRV%:\BOOT /i /s /e /r /v /h /y
XCOPY %SOURCE%:\EFI %BOOTDRV%:\EFI /i /s /e /r /v /h /y
ECHO THE SOURCES FOLDER MAY TAKE A WHILE - PLEASE BE PATIENT
ECHO USB 3.0 = Approx 1-3 minutes
ECHO USB 2.0 = Approx 5-15 minutes
XCOPY %SOURCE%:\sources %BOOTDRV%:\sources /i /s /e /r /v /h /y
IF EXIST %SOURCE%:\BOOTMGR. XCOPY %SOURCE%:\BOOTMGR. %BOOTDRV%:\ /r /v /h /y
IF EXIST %SOURCE%:\bootmgr.efi XCOPY %SOURCE%:\bootmgr.efi %BOOTDRV%:\ /r /v /h /y
IF EXIST %SOURCE%:\bootmgr.exe XCOPY %SOURCE%:\bootmgr.exe %BOOTDRV%:\ /r /v /h /y
IF EXIST %SOURCE%:\menu.lst XCOPY %SOURCE%:\menu.lst %BOOTDRV%:\ /r /v /h /y
ECHO.
ECHO -Copying Program Files-
CD /D %~dp0
pushd "%~dp0TempUSB"
SET "a="
for /f "tokens=* delims=" %%a in ('TYPE ISODIRS.TXT') do xcopy /isehrvy "%SOURCE%:\%%a" "%PROGDRV%:\%%a"
popd
DEL /S /Q "%~dp0TempUSB\isodirs.txt" >nul
pushd "%~dp0TempUSB"
SET "a="
for /f "tokens=* delims=" %%a in ('TYPE ISOFILES.TXT') do xcopy /hrvy "%SOURCE%:\%%a" "%PROGDRV%:\"
popd
DEL /S /Q "%~dp0TempUSB\isofiles.txt" >nul
ECHO.
ECHO -Cleaning Up-
ENDLOCAL
CD /D %~dp0
IF EXIST "%~dp0TempUSB\*.*" DEL /S /Q "%~dp0TempUSB\*.*" >nul
IF EXIST "%~dp0TempUSB" RD "%~dp0TempUSB" >nul
POWERSHELL.EXE "Dismount-DiskImage ""%1""" >nul
ECHO.
ECHO The USB drive is now prepared for Legacy and UEFI boot (Macs Too)
ECHO.
ECHO.
PAUSE
EXIT
:IMPROPERUSE
CLS
ECHO.
ECHO =============================================
ECHO.
ECHO            IMPROPER USE DETECTED
ECHO.
ECHO  CLOSE THE PROGRAM AND DRAG AND DROP THE ISO 
ECHO            ONTO THE TOOL TO BEGIN
ECHO.
ECHO       THIS TOOL CANNOT BE RUN DIRECTLY
ECHO =============================================
ECHO.
ECHO.
ECHO.
PAUSE
EXIT
:CHOOSEABORT
ECHO.
CHOICE /C YN /M "Would you like to abort? "
IF %ERRORLEVEL%==1 GOTO ABORT
) ELSE (
GOTO INITMBR
)
EXIT
:NOTCOMPAT1
CLS
CD /D %~dp0
IF EXIST "%~dp0TempUSB\*.*" DEL /S /Q "%~dp0TempUSB\*.*" >nul
IF EXIST "%~dp0TempUSB" RD "%~dp0TempUSB" >nul
POWERSHELL.EXE "Dismount-DiskImage ""%1""" >nul
ECHO.
ECHO ==============================================
ECHO.
ECHO               INCOMPATIBLE ISO
ECHO.
ECHO   THIS TOOL IS FOR ISO's CREATED BY PESE/XPE 
ECHO            BOOT.WIM MUST BE PRESENT
ECHO.
ECHO ==============================================
ECHO.
ECHO.
ECHO.
PAUSE
EXIT
:NOTCOMPAT2
CLS
CD /D %~dp0
IF EXIST "%~dp0TempUSB\*.*" DEL /S /Q "%~dp0TempUSB\*.*" >nul
IF EXIST "%~dp0TempUSB" RD "%~dp0TempUSB" >nul
POWERSHELL.EXE "Dismount-DiskImage ""%1""" >nul
ECHO.
ECHO ==============================================
ECHO.
ECHO               INCOMPATIBLE ISO
ECHO.
ECHO  THIS TOOL IS FOR ISO's CREATED BY PESE/XPE 
ECHO            CdUsb.Y MUST BE PRESENT
ECHO.
ECHO ==============================================
ECHO.
ECHO.
ECHO.
PAUSE
EXIT
END LOCAL

 

 

Edited by bobomb
Link to comment
Share on other sites

I feel like if I am making something to put a bootable ISO onto a USB there really shouldnt be any questions for the user... They shouldnt have to decide the partition layout, cluster size... I dont even want people to have to select an ISO.. Thats why the program will only run if you drop and ISO directly on the EXE, or CLI the full path to an ISO.. 

Drop the ISO on the tool to open it, if the program is open the ISO is already selected:

2 steps to use, Pick your USB/Disk number, click 'Burn'... and it burns as fast as possible, no options, no choices.. and at the other end a bootable usb(or fixed disk) compatible with Legacy/UEFI PC's and Macs pops out every time, and you can focus on why u needed to burn the ISO and not burning the ISO lol...

I cant remember exactly why preferred this method over what Rufus would achieve. There was a reason Im sure, other than the advanced interface. (It may have been that a MBR fat32 partition was necessary to boot on macs? Rufus creates a single MBR NTFS partition with an EFI structure to allow for CSM/UEFI dual boot, which works, but not on macs...i dont remember I think there was something else too) Also the disk layout had to have the data partition first and the boot partition second as Windows 7 would only recognize the "First" partition on a USB with multiple partitions..  I dont mean to leave such a long winded explanation, Rufus is the king for sure for burning bootable USB's..  

Edited by bobomb
Link to comment
Share on other sites

Aye, the dos functions will be quicker, so for simple things it maybe worthwhile keeping those. I have done another function to fill the list which doesn't use a file write and read and runs diskpart directly. You can swap it with the DiskList and remove the 3 lines after DirCreate(GetCachePath())

Func GetDiskListings()
    Local $i_PID = Run('diskpart.exe', @SystemDir, @SW_HIDE, BitOR($STDIN_CHILD, $STDOUT_CHILD))
    StdinWrite($i_PID, 'list disk')
    StdinWrite($i_PID)

    Local $s_STDOUT = ''
    Local $s_Ret = ''

    While 1
        $s_STDOUT = StdoutRead($i_PID)
         If @error Then ExitLoop

        ; clean up the string and add it to the return if it has disk info
        If StringRegExp($s_STDOUT, '(?i)Disk [\d]+') Then $s_Ret &= StringReplace(StringRegExpReplace($s_STDOUT, '[\s|]*$', ''), @crlf, '') & '|'
    WEnd

    Return $s_Ret
EndFunc

 

Link to comment
Share on other sites

@benners I found this elsewhere on the forum for disk checking and it looks a LOT better than what I'm using.  Is there any way to make this parse with this type of look and only be able to select the "Disk" line but still show the partition line? I cannot even get it to wrap(got it) when I add it to my disk function but it will display all on 1 line with return 

Example MsgBox from the forum:

#include <WinAPIFiles.au3>
#include <Array.au3>

GetDriveList()

Func GetDriveList()
Local $aDriveInfo, $iLastDevNumber = -1
Local $aFixed = DriveGetDrive('FIXED'), $aRemovable = DriveGetDrive('REMOVABLE')
Local $aDrives[  (IsArray($aFixed) ? $aFixed[0] : 0) + (IsArray($aRemovable) ? $aRemovable[0] : 0) ][3]

Local $iDrive = 0
For $i = 1 To UBound($aFixed) - 1
    $aDrives[$iDrive][0] = $aFixed[$i]
    $aDriveInfo = _WinAPI_GetDriveNumber($aFixed[$i])
    If Not @error Then
        $aDrives[$iDrive][1] = $aDriveInfo[1]
        $aDrives[$iDrive][2] = $aDriveInfo[2]
    EndIf
    $iDrive += 1
Next
For $i = 1 To UBound($aRemovable) - 1
    $aDrives[$iDrive][0] = $aRemovable[$i]
    $aDriveInfo = _WinAPI_GetDriveNumber($aRemovable[$i])
    If Not @error Then
        $aDrives[$iDrive][1] = $aDriveInfo[1]
        $aDrives[$iDrive][2] = $aDriveInfo[2]
    EndIf
    $iDrive += 1
Next


_ArraySort($aDrives, 0, 0, 0, 1)

Local $sDrivesInfo = "Drive list :" & @CRLF
For $i = 0 To UBound($aDrives) - 1
    If IsNumber($aDrives[$i][1]) Then
        If $aDrives[$i][1] <> $iLastDevNumber Then
            $sDrivesInfo &= @CRLF & "Disk #" & $aDrives[$i][1] & " [" & _GetDiskNameByNumber($aDrives[$i][1]) & "]" & @CRLF
            $iLastDevNumber = $aDrives[$i][1]
        EndIf
        $sDrivesInfo &= " - Partition #" & $aDrives[$i][2] & "  " & DriveGetLabel($aDrives[$i][0]) & " - " & $aDrives[$i][0] & @CRLF
    EndIf
Next

MsgBox(0, "", $sDrivesInfo)
EndFunc

Func _GetDiskNameByNumber($iDiskNumber)
    Local $iCount = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum", "Count")
    Local $sDiskKey = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum", String($iDiskNumber))
    If @error Then Return SetError(1, 0, 0)

    Local $sDiskName = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" & $sDiskKey, "FriendlyName")
    If $sDiskName = "" Then $sDiskName = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" & $sDiskKey, "DeviceDesc")

    Return $sDiskName
EndFunc

Located here

https://www.autoitscript.com/forum/topic/184895-get-diskname-without-diskpart-wmi-wmic/page/3/?tab=comments#comment-1329548

With my attempt to integrate it.. This displays in reverse, the partitions in their own group and the disk list is also in its own grouped together, the partitions being out of place I cant tell which disk they belong to.. 

#NoTrayIcon
#RequireAdmin
#include <AutoItConstants.au3>
#include <WinAPIFiles.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include <File.au3>
#include <Array.au3>
#include <String.au3>

Global $DiskList, $Selection, $IsoFile, $MountedDrive = ""
Global $finalfiles, $finaldirs, $wimSize, $bootDrive, $dataDrive

ProperUse()
MountIso()
GetISODriveLetter()
BootWim_Check()
Cleanup()

DirCreate(GetCachePath())

Opt("GUIOnEventMode", 1)
MainMenu()

Cleanup()
Exit

Func MainMenu()
    GUICreate('Burn Tool (XPE/SE) v2.0', 300, 298)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents")
    GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents")
    GUISetIcon(@WorkingDir & '\USBTool.ico', 1)
    GUISetBkColor(0x797979)
    GUICtrlCreateLabel('1: Select a disk use...', 20, 10, 280)
    $DiskList = GUICtrlCreateList('', 20, 30, 260, 150)
    GUICtrlSetData(-1, GetDiskList())
    $Refresh = GUICtrlCreateButton('Refresh List', 110, 185, 80, 25)
    GUICtrlSetOnEvent(-1, "RefreshPressed")
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlCreateLabel('________________________________________', 30, 210, 280, 30)
    $Burn = GUICtrlCreateButton('Burn', 90, 232, 120, 40)
    GUICtrlSetOnEvent(-1, "BurnPressed")
    GUICtrlCreateLabel('( * ) Disk is Currently GPT', 160, 278, 130, 30)
    GUISetState()
    ; Just idle around
    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>MainMenu

Func RefreshPressed()
    GUICtrlSetData($DiskList, "")
    GUICtrlSetData($DiskList, GetDiskList())
EndFunc   ;==>RefreshPressed

Func BurnPressed()
    If GUICtrlRead($DiskList) = '' Then
        MsgBox( _
                $MB_ICONERROR, _
                "Notice: ", _
                "No disk has been selected")
    Else
        Local $s_DiskNumber = StringRegExp(GUICtrlRead($DiskList), '(?<=Disk\s)[0-9]+', $STR_REGEXPARRAYMATCH)[0]

        If @error Then
            MsgBox( _
                    $MB_ICONERROR, _
                    "Notice: ", _
                    "An error occured retrieving the disk number")
        Else
            If MsgBox( _
                    BitOR($MB_TOPMOST, $MB_ICONWARNING, $MB_YESNO, $MB_DEFBUTTON2), _
                    'This will FORMAT Disk ' & $s_DiskNumber, _
                    'ALL DATA WILL BE ERASED FROM DISK ' & $s_DiskNumber & @CRLF & 'Are you sure you want to proceed?') = $IDYES Then
                GUISetState(@SW_HIDE)
                ProgressOn("Applying ISO...", "Creating Bootable Media... ", "0%")
                PrepFormat($s_DiskNumber)
                ProgressSet(5 & "%", "Formatting Disk " & $s_DiskNumber)
                Format()
                ProgressSet(25 & "%", "Analyzing ISO Structure ")
                CleanDirList()
                CleanFileList()
                ProgressSet(26 & "%", "Copying Boot Partition ")
                CopyBootFiles()
                ;Progress in function; start at 55%
                CopyDataFilesF()
                ;Progress in function; start at 65%
                CopyDataFilesD()
                ProgressSet(100, "Finished", "ISO Applied!!")
                Sleep(2750)
                ProgressOff()
                Cleanup()
                UnmountIso()
                MsgBox($MB_ICONINFORMATION, "", " Enjoy! ")
                Exit
            EndIf
        EndIf
    EndIf
EndFunc   ;==>BurnPressed

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Code below for actions on Close
            Cleanup()
            UnmountIso()
            Exit
        Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE
            ; Code below for actions on Minimize
        Case @GUI_CtrlId = $GUI_EVENT_RESTORE
            ; Code below for actions on Restore
    EndSelect
EndFunc   ;==>SpecialEvents

Func ProperUse()
    If Not ($CmdLine[0]) = 0 Then ;Something was dropped on the EXE file or CLI was used with a flag(s)
        $IsoFile = ($CmdLine[1]) ;Sets $IsoFile var to the full path of whatever was dropped onto the EXE file or the 1st CLI flag that was used
    Else
        MsgBox($MB_ICONERROR, "Notice: ", "This program cannot be run directly!" & @CRLF & "Please drag an ISO onto" & @CRLF & "the program to begin...")
        Exit
    EndIf
EndFunc   ;==>ProperUse


Func BootWim_Check() ; check for the boot wim file
    If Not FileExists($MountedDrive & ':\sources\boot.wim') Then
        MsgBox($MB_ICONERROR, "Notice: ", "BOOT.WIM NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        UnmountIso()
        Exit
    EndIf
EndFunc   ;==>BootWim_Check

Func BootWim_GetSize() ; get the boot wim size and add 200 megabytes for headroom on boot partition
    Return Round((FileGetSize($MountedDrive & ':\sources\boot.wim') + 209715200) / 1048576)
EndFunc   ;==>BootWim_GetSize

Func MountIso()
    RunWait('cmd /c powershell.exe ' & '"Mount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>MountIso

Func UnmountIso()
    RunWait('cmd /c powershell.exe ' & '"Dismount-DiskImage "' & '"' & $IsoFile & '"' & '"' & '"' & ' >nul', @WorkingDir, @SW_HIDE)
EndFunc   ;==>UnmountIso

Func Cleanup()
    If FileExists(GetCachePath()) Then
        DirRemove(GetCachePath(), $DIR_REMOVE)
    EndIf
EndFunc   ;==>Cleanup

Func GetISODriveLetter()
    Local $findiso = StringSplit("CDEFGHIJKLMNOPQRSTUVWXYZ", "", 1)
    For $i = 1 To $findiso[0] Step +1
        $isoExists = FileExists($findiso[$i] & ":\CdUsb.Y")
        If $isoExists Then
            If PathIsWritable($findiso[$i] & ":\") = False Then
                $MountedDrive = ($findiso[$i])
            EndIf
        EndIf
    Next
    If $MountedDrive = "" Then
        MsgBox($MB_ICONERROR, "Notice: ", "CdUsb.Y NOT DETECTED!!!" & @CRLF & "This tool is designed for SE" & @CRLF & "and XPE projects only.")
        Exit
    EndIf
EndFunc   ;==>GetISODriveLetter

Func PathIsWritable($sFile)
    Local $aRet = DllCall('kernel32.dll', 'handle', 'CreateFileW', _
            'wstr', $sFile, _
            'dword', 2, _
            'dword', 7, _
            'struct*', 0, _
            'dword', 3, _
            'dword', 0x02000000, _
            'handle', 0)
    If @error Or $aRet[0] = Ptr(-1) Or $aRet[0] = 0 Then Return False
    DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $aRet[0])
    Return True
EndFunc   ;==>PathIsWritable

Func GetDiskList()
    Local $aDriveInfo, $iLastDevNumber = -1
    Local $aFixed = DriveGetDrive('FIXED'), $aRemovable = DriveGetDrive('REMOVABLE')
    Local $aDrives[(IsArray($aFixed) ? $aFixed[0] : 0) + (IsArray($aRemovable) ? $aRemovable[0] : 0)][3]

    Local $iDrive = 0
    For $i = 1 To UBound($aFixed) - 1
        $aDrives[$iDrive][0] = $aFixed[$i]
        $aDriveInfo = _WinAPI_GetDriveNumber($aFixed[$i])
        If Not @error Then
            $aDrives[$iDrive][1] = $aDriveInfo[1]
            $aDrives[$iDrive][2] = $aDriveInfo[2]
        EndIf
        $iDrive += 1
    Next
    For $i = 1 To UBound($aRemovable) - 1
        $aDrives[$iDrive][0] = $aRemovable[$i]
        $aDriveInfo = _WinAPI_GetDriveNumber($aRemovable[$i])
        If Not @error Then
            $aDrives[$iDrive][1] = $aDriveInfo[1]
            $aDrives[$iDrive][2] = $aDriveInfo[2]
        EndIf
        $iDrive += 1
    Next

    _ArraySort($aDrives, 0, 0, 0, 1)

    Local $sDrivesInfo, $s_Drives
    For $i = 0 To UBound($aDrives) - 1
        If IsNumber($aDrives[$i][1]) Then
            If $aDrives[$i][1] <> $iLastDevNumber Then
                $sDrivesInfo &= "Disk " & $aDrives[$i][1] & " [" & _GetDiskNameByNumber($aDrives[$i][1]) & "]" & "|" & @CRLF
                $iLastDevNumber = $aDrives[$i][1]
            EndIf
            $sDrivesInfo &= " - Partition #" & $aDrives[$i][2] & "  " & DriveGetLabel($aDrives[$i][0]) & " - " & $aDrives[$i][0] & "|" & @CRLF
        EndIf
    Next
Return $sDrivesInfo
EndFunc   ;==>GetDiskList

Func _GetDiskNameByNumber($iDiskNumber)
    Local $iCount = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum", "Count")
    Local $sDiskKey = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum", String($iDiskNumber))
    If @error Then Return SetError(1, 0, 0)

    Local $sDiskName = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" & $sDiskKey, "FriendlyName")
    If $sDiskName = "" Then $sDiskName = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" & $sDiskKey, "DeviceDesc")

    Return $sDiskName
EndFunc   ;==>_GetDiskNameByNumber

Func GetCachePath()
    Local Static $s_CachePath = IniRead(@WorkingDir & '\USBTool.ini', "Settings", "CachePath", @WorkingDir & '\cache') & '\'
    Return $s_CachePath
EndFunc   ;==>GetCachePath

Func PrepFormat($Drive)
    GetDriveLetters()
    createDiskPartScriptFile(GetCachePath() & 'clean.dat', 'Sel Dis ' & $Drive & @CRLF & 'clean' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'attrib.dat', 'Sel Dis ' & $Drive & @CRLF & 'attribute disk clear readonly' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'scrubber.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=NTFS label=scrubber' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'convert.dat', 'Sel Dis ' & $Drive & @CRLF & 'convert mbr' & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'initdata.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'shrink minimum=' & BootWim_GetSize() & @CRLF & 'format quick fs=ntfs label="WinPE Data"' & @CRLF & 'assign letter=' & $dataDrive & @CRLF & 'Exit')
    createDiskPartScriptFile(GetCachePath() & 'initboot.dat', 'Sel Dis ' & $Drive & @CRLF & 'cre par pri' & @CRLF & 'format quick fs=fat32 label="BOOTFILES"' & @CRLF & 'assign letter=' & $bootDrive & @CRLF & 'Active' & @CRLF & 'Exit')
EndFunc   ;==>PrepFormat

Func CopyBootFiles()
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOT ' & $bootDrive & ':\BOOT /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(27 & "%", "Copying Boot Partition ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\EFI ' & $bootDrive & ':\EFI /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(40 & "%", "Copying Boot.wim, this may take a while... ")
    RunWait('cmd /c xcopy ' & $MountedDrive & ':\sources ' & $bootDrive & ':\sources /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE)
    ProgressSet(50 & "%", "Copying Boot Files ")
    If FileExists($MountedDrive & ":\BOOTMGR.") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\BOOTMGR. ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.efi") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.efi ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\bootmgr.exe") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\bootmgr.exe ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
    If FileExists($MountedDrive & ":\menu.lst") Then RunWait('cmd /c xcopy ' & $MountedDrive & ':\menu.lst ' & $bootDrive & ':\ /h /r /v /y', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CopyBootFiles

Func CopyDataFilesF()
    Local $GoFiles = (GetCachePath() & $finalfiles), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 55
    For $i = 1 To UBound($aArray) - 1
        ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i])
        RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & ' /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
        $StartProgAt = ($StartProgAt + 1)
    Next
EndFunc   ;==>CopyDataFilesF

Func CopyDataFilesD()
    Local $GoFiles = (GetCachePath() & $finaldirs), $StartProgAt, $xcopycmd, $line = ""
    FileOpen($GoFiles, 0)
    Local $aArray[1000]
    ReDim $aArray[_FileCountLines($GoFiles) + 1]
    For $i = 1 To _FileCountLines($GoFiles)
        $newline = FileReadLine($GoFiles, $i)
        $aArray[$i] = $newline
    Next

    _ArraySort($aArray)
    $StartProgAt = 65

    For $i = 1 To UBound($aArray) - 1
        If $aArray[$i] = "Programs" Then
            ProgressSet($StartProgAt & "%", "Copying Programs Folder, this may take a while...")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
            $StartProgAt = ($StartProgAt + 15)
        Else
            ProgressSet($StartProgAt & "%", "Copying " & $aArray[$i] & " Folder")
            RunWait('cmd /c xcopy ' & $MountedDrive & ':\' & $aArray[$i] & ' ' & $dataDrive & ':\' & $aArray[$i] & ' /i /s /e /h /r /v /y', @WorkingDir, @SW_HIDE, 2)
            $StartProgAt = ($StartProgAt + 1)
        EndIf
    Next
EndFunc   ;==>CopyDataFilesD

Func createDiskPartScriptFile($fileName, $message)
    $CacheFile = ''
    $CacheFile = FileOpen($fileName, 2)
    FileWrite($CacheFile, $message)
    FileClose($CacheFile)
EndFunc   ;==>createDiskPartScriptFile

Func GetDriveLetters()
    Local $allDriveLetters = "CDEFGHIJKLMNOPQRSTUVWXYZ", $AvailDriveLetters
    Local $aArray = DriveGetDrive($DT_ALL)
    If @error Then
        ; An error occurred when retrieving the drives.
        MsgBox($MB_SYSTEMMODAL, "", "An Error Occurred! Unable to retrieve " & @CRLF & "available drive letters! Exiting Program...")
        Cleanup()
        UnmountIso()
        Exit
    Else
        For $i = 1 To $aArray[0]
            $driveLetter = StringLeft(StringUpper($aArray[$i]), 1)
            $allDriveLetters = StringReplace($allDriveLetters, $driveLetter, "")
        Next
    EndIf
    $AvailDriveLetters = StringSplit($allDriveLetters, "")
    $bootDrive = $AvailDriveLetters[1] ;Get first available letter
    $dataDrive = $AvailDriveLetters[2] ;Get second available letter
EndFunc   ;==>GetDriveLetters

Func CleanDirList()
    Local $rawlist = 'isod.dat'
    $finaldirs = 'isodirs.dat'
    RunWait('cmd /c DIR /B /A:D ' & $MountedDrive & ':\>' & '"' & GetCachePath() & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'efi' & '"' & ' /c:' & '"' & 'boot' & '"' & ' /c:' & '"' & 'sources' & '"' & ' "' & GetCachePath() & $rawlist & '"' & '>>' & '"' & GetCachePath() & $finaldirs & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanDirList

Func CleanFileList()
    Local $rawlist = 'isof.dat'
    $finalfiles = 'isofiles.dat'
    RunWait('cmd /c DIR /B /A-D ' & $MountedDrive & ':\>' & '"' & GetCachePath() & $rawlist & '"', @WorkingDir, @SW_HIDE)
    RunWait('cmd /c FINDSTR /v /i /c:' & '"' & 'bootmgr' & '"' & ' /c:' & '"' & 'menu' & '"' & ' "' & GetCachePath() & $rawlist & '"' & '>>' & '"' & GetCachePath() & $finalfiles & '"', @WorkingDir, @SW_HIDE)
EndFunc   ;==>CleanFileList

Func Format()
    Local $aArray[7][3] = [ _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'clean.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'scrub.dat' & '"'], _
            ["Cleaning Drive", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'clean.dat' & '"'], _
            ["Resetting Disk Attributes", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'attrib.dat' & '"'], _
            ["Converting Layout to MBR", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'convert.dat' & '"'], _
            ["Creating Data Partition", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'initdata.dat' & '"'], _
            ["Creating Boot Partition", 'cmd /c diskpart /s ' & '"' & GetCachePath() & 'initboot.dat' & '"'] _
            ]

    For $i = 0 To UBound($aArray) - 1
        ProgressSet($i * 2 & "%", $aArray[$i][0])
        ;MsgBox($MB_ICONINFORMATION, "Troubleshooting.. ", $aArray[$i][1]) ;Troubleshoot Array Data
        RunWait($aArray[$i][1], @WorkingDir, @SW_HIDE)
        Sleep(750)
    Next

EndFunc   ;==>Format

Should I open a new thread for this? I dont want to crosspost too much for the same app but also I do not want to drag several questions down an incorrectly titled thread.. (update thread name maybe?)

Edited by bobomb
Link to comment
Share on other sites

  • bobomb changed the title to Progress Bar options, and disk list

I'll have a look, I'm sure we can manipulate the results to the programs need but I doubt you will be able to get the list to function like that. Some ideas would be

  • Change the list to a listview or combo box. The listview could have columns for the drive info and partition info ( a bit fiddly if there's loads or partitions). A combo would just have the drive info for selection and add another control to display the partition info.
  • Keep the list but add a label or other control to display the partition info.

If you're going to want to display file names, copy progress etc you will have to alter the gui or create another one anyway.

As for the topic, It's your topic. You could add different tags for the topic and\or change the title to USB Burning Tool, this would encompass all the different changes to the program and would be a better description of the topic content.

Link to comment
Share on other sites

Maybe I will take the partitions out if needed.  I would prefer if the correct partitions showed under their respective disks, i could just set a msgbox to instruct the user to choose a line containing a disk... or figure out a way to have the selection associated with the appropriate disk if a partition is selected. idk depends on if it is a pain or not, btw you are awesome. I am still going to make use of your STDout example with other sections I just need to review it a few times and run some tests..

Really reversing the array would be enough for me to get unstuck..

Edited by bobomb
Link to comment
Share on other sites

  • bobomb changed the title to USB Burning tool for PE projects - (Progress Bar options, and disk list)

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...