murphy78 DiskPart and Apply Image Script

Discussion in 'Scripting' started by murphy78, Apr 2, 2014.

  1. Proph

    Proph MDL Junior Member

    May 2, 2007
    56
    64
    0
    My mod is almost finished. The only portion I think I need help with is using the script in Vista. Since in Vista the script does not create a "System" W Drive. I have tried making the "Windows" drive as ACTIVE and running bcdboot C:\Windows on it but I get registry errors when Vista boots. I have also tried it using bcdboot X:\Windows before the drive letter changes and still get the same registry errors. In Windows 7 and Windows 8 the "System" W drive is created and the drive is made ACTIVE correctly. I'm sure it is me missing a step to ensure the Windows drive is properly pointed to for booting. Any ideas?
     
  2. Proph

    Proph MDL Junior Member

    May 2, 2007
    56
    64
    0
    After speaking with murphy78 I have decided not to support Vista. I can't seem to figure out how to get it to work properly. If I find a way to support it later I'll do it... but for now my scripts will not support Vista either. I'm sure most users won't mind it anyways. ;)

    I do have another minor question... Is there any downside to turning NOSYSPART on? NOSYSPART=1

    I assume it would be needed for multiboot os setups... but there is no downside to turning off the creation of the 100/300MB System drive for a single os install is there?
     
  3. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    I still haven't had proper time to go over proph's script, but in the meantime I changed a few minor things and updated mine to v1.2.6:

    Changed it so the DISK menu actually tells you what disk number is currently targeted (helpful, right?)
    Changed the winrecfg stuff so that you add the packages from packages i put in package folders instead of leaving them in by default.
    This is because kb2934018 will update these files if you actually add the package, and that's a good thing. Plus using the actual packages makes things a little more future-proof.
    I also added a menu.cmd in the system32 folder for the use-existing-setup files so people can just shift-f10 and type "MENU" like in my monthly releases to open the diskpart/apply script

    I still want to clean things up and re-design the script and the over-all methodology a bit.
    Although I'd be happier with a gui using WMIapi stuff, I'm happy enough with the diskpart /s importing method using the ramdrive for now.
    I do want to re-design the functionality of the script to be more like the Windows Setup in the future, excepting of course the things that aren't supported by default like split-wim without an autounattend, multi-boot, and the recovery image stuff.

    Sometimes letting your mind work in the background while you do other things is a good way to problem solve things when you are designing or re-designing something complex.
    I also am a firm believer in trying to simplify things if it's possible to simplify.
    I also want to de-duplicate some of the code if necessary. Multiple disk menus and prompts can be confusing, so I'd like to consolidate that stuff into a one-time selection with options process.
    I don't want the script to be confusing to the user. I want it to do what windows setup does, except also support multi-boot, recovery partition, and split-wim images without an autounattend to skip the eula setup failure.

    Anyway, OP updated to v1.2.6
     
  4. sam3971

    sam3971 MDL Guru

    Nov 14, 2008
    2,235
    311
    90
    Really nice script but just one question, once setup with the recovery option how does one actually enter the recovery environment? I have been playing around and I know there is the DART options if you boot the CD but cannot figure out how to get into the recovery. Any info would be really appreciated, I cannot find anything anywhere lol.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  5. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    #65 murphy78, Jul 10, 2014
    Last edited by a moderator: Apr 20, 2017
    (OP)
    Windows has most of the recovery stuff automated in win8+
    There are many ways to do the various features in the winre.wim

    Windows 8 also has a pseudo recovery environment. if you do a shutdown /r /o /t 0 it will logout and enter that pseudo recovery environment.
    It will have the default recovery options but it won't have anything that you've added to winre.wim like dart8.1

    To access dart8.1 from the winre.wim you need to run
    Code:
    reagentc /boottore
    shutdown /r /t 0
    Alternatively you can do a:
    Code:
    bcdedit /set {default} bootmenupolicy legacy
    and try to press f8 during boot. I find that this is damn near impossible though, so I usually recommend only doing that if you need to enter safe mode or something on the fly.
     
  6. sam3971

    sam3971 MDL Guru

    Nov 14, 2008
    2,235
    311
    90
    As far as windows 8 I know there is a lot of built in recovery but I was not 100% what all was entailed in the recovery partition your script creates. TBH I thought it was something similar that will bring you back to factory based with nothing installed like an OEM recovery partition lmfao.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  7. Flipp3r

    Flipp3r MDL Expert

    Feb 11, 2009
    1,965
    908
    60
    That's because the function keys aren't available in Win8+ anymore... MS disabled...
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  8. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    Yes that's why I mentioned setting bootmenupolicy to legacy, so it re-enables.
     
  9. Flipp3r

    Flipp3r MDL Expert

    Feb 11, 2009
    1,965
    908
    60
    What WHat WHAT!!! How come I didn't know about that? :eek:
    Does that also mean you could assign a function key to boot WinRE???
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  10. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    #70 murphy78, Jul 11, 2014
    Last edited by a moderator: Apr 20, 2017
    (OP)
    indeed. in my script I use f1.
    The actual command is:
    Code:
    winrecfg /setreimage /path W:\Recovery\WindowsRE /target Z:\Windows /bootkey 3b00
    that's for winrecfg (the winpe version of reagentc) but you can just sub all the arguments for reagentc.

    I just left it at 3b00 because I don't know which ones do what, but that's f1 and it seems good enough for me.
     
  11. Flipp3r

    Flipp3r MDL Expert

    Feb 11, 2009
    1,965
    908
    60
    #71 Flipp3r, Jul 11, 2014
    Last edited by a moderator: Apr 20, 2017
    I was planning on looking up what winrecfg actually did as I've never used it. I've used reagentc for everything - even in winpe/re...
    For notebooks all my Win7 images follow whatever the default manufacturer uses, ie MSI uses F3 which is 0x3d00.

    Wow this has made my day! Can't wait to try stuff out on the weekend! Thanks m8tty!!!
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  12. taviruni

    taviruni MDL Senior Member

    May 8, 2010
    261
    248
    10
    #72 taviruni, Jul 11, 2014
    Last edited: Jul 11, 2014
  13. generalmx

    generalmx MDL Novice

    Apr 15, 2014
    34
    21
    0
    #73 generalmx, Nov 4, 2014
    Last edited by a moderator: Apr 20, 2017
    Hey murphy78, sorry I haven't been getting back the code I put out...I do have a lot of unfinished projects laying around that I just don't have time to work on by myself anymore, one of them being helping more with your awesome DiskPart and Apply Image Script. I did want to at least post the AutoIT script I started a while ago to interact with diskpart:

    Code:
    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_Version=Beta
    #AutoIt3Wrapper_Run_After=%out%
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
    ; By Gen 4-22-2014
    
    #RequireAdmin
    
    #include <Constants.au3>
    #include <StaticConstants.au3>
    #include <GuiConstantsEx.au3>
    #include <MsgBoxConstants.au3>
    #include <FileConstants.au3>
    #include <WindowsConstants.au3>
    #include <Array.au3>
    #include <ButtonConstants.au3>
    #include <GUIButton.au3>
    
    ; If this option is used then all variables must be pre-declared with Local, Global or in some cases Dim before
    ; they can be used - removes the chance for misspelled variables causing bugs.
    Opt( "MustDeclareVars", 1 )
    
    ;Local Const $wbemFlagReturnImmediately = 0x10
    ;Local Const $wbemFlagForwardOnly = 0x20
    
    Local Const $sProgName = "WinNTPart v0.1"
    Local Const $iSizeOfAllDiskInfo = 7
    
    Local $iComboBox1, $iSysCheckBox, $iGPTCheckBox, $iWinRECheckBox, $iRecoveryCheckBox, $iGoButton, $aAllDiskInfo
    Local $bIsUEFIBooted
    Local $iWindowWidth = 500
    Local $iWindowHeight = 300
    Local $sessionid = String( Random(0,32768,1) )
    Local $tempfile = @TempDir & 'winntpart.' & $sessionid & '.txt'
    
    ; Get the WMI object
    ;Local $oWMI = ObjGet("winmgmts:\\" & @ComputerName & "\root\CIMV2")
    
    ; Try to figure out if we have a Camera
    ; http://smsug.ca/blogs/garth_jones/archive/2013/04/02/find-all-webcam-wql.aspx
    ; Local $aItems = $oWMI.ExecQuery('SELECT * FROM SMS_R_System', "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    ;Local $aItems = $oWMI.ExecQuery('SELECT CS.Name0,SD.Name0,SD.DeviceID0 FROM dbo.v_GS_COMPUTER_SYSTEM CS join dbo.v_GS_SYSTEM_DEVICES SD on CS.ResourceID = SD.ResourceID Where SD.Name0 like "%Webcam%"', "SQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    ;If IsObj($aItems) then
    ;    For $elements In $aItems
    ;        MsgBox(0, "", $elements.Name0)
    ;    Next
    ;Else
    ;    Msgbox(0,"","No WMI Objects Found For Selection" )
    ;EndIf
    
    ; Call main function
    main()
    
    ; Returns an array of size 2.
    ; Example of Diskpart Format: "Disk 0 Online 133GB 11GB * *"
    Func DPParseListDisk( $string )
        Local $aListDisk[2], $match
        If $string Then
            $match = StringRegExp( $string, "^[[:space:]]+Disk [0-9]+[[:space:]]+[^[:space:]]+[[:space:]]+([0-9]+ [[:alpha:]]+)[[:space:]]+([0-9]+ [[:alpha:]]+)", 1)
            If Not @error Then
                $aListDisk[0] = $match[0] ; Disk Size
                $aListDisk[1] = $match[1] ; Free Space
                ;$aListDisk[2] = $match[3] ; Dynamic (may be empty)
                ;$aListDisk[3] = $match[4] ; GPT (may be empty)
            EndIf
        EndIf
    
        ; Sanity checks
        If Not $aListDisk[0] Then
            $aListDisk[0] = "ERROR"
        EndIf
        If Not $aListDisk[1] Then
            $aListDisk[1] = "ERROR"
        EndIf
    
        Return $aListDisk
    EndFunc
    
    ; Returns an array of size 5
    Func DPParseDiskDetail($iDisk, $sListdisk)
        Local $aDiskInfo[5], $match, $file, $iPID, $sOutput, $aArray, $bNameNext
        $file = FileOpen( $tempfile, $FO_OVERWRITE )
        FileWrite( $file, "select disk " & $iDisk & @CRLF & "detail disk" )
        FileClose( $file )
        $iPID = Run(@ComSpec & ' /c diskpart /s "' & $tempfile & '"',"", @SW_HIDE, $STDOUT_CHILD)
        ProcessWaitClose($iPID)
        $sOutput = StdoutRead($iPID)
        $aArray = StringSplit(StringTrimRight(StringStripCR($sOutput), StringLen(@CRLF)), @CRLF)
        If Not @error Then
            For $string In $aArray
                If StringLen( $string ) > 2 Then ; skip empty lines
                    If Not $bNameNext Then
                        If StringRegExp( $string, "^\s*Disk " & $iDisk & " is.*selected disk.*$" ) Then
                            $bNameNext = True ; two lines down is name all by itself
                        Else ; all other info
                            If Not $aDiskInfo[4] Then
                                $match = StringRegExp( $string, "Location Path[^:]*:\s?([^[:space:]]+)", 1)
                                If Not @error Then
                                    $aDiskInfo[4] = $match[0] ; Location Path (IE, "PCIROOT(0)#PCI(1F02)#ATA(C00T00L00)")
                                    ContinueLoop
                                EndIf
                            EndIf
                            If Not $aDiskInfo[3] Then
                                $match = StringRegExp( $string, "Status[^:]*:\s?([[:alnum:]]+)", 1)
                                If Not @error Then
                                    $aDiskInfo[3] = $match[0] ; Disk Status
                                    ContinueLoop
                                EndIf
                            EndIf
                            If Not $aDiskInfo[2] Then
                                $match = StringRegExp( $string, "Type[^:]*:\s?([[:alnum:]]+)", 1)
                                If Not @error Then
                                    $aDiskInfo[2] = $match[0] ; Disk (Bus) Type
                                    ContinueLoop
                                EndIf
                            EndIf
                            If Not $aDiskInfo[1] Then
                                $match = StringRegExp( $string, "Disk ID[^:]*:\s?([[:alnum:]]+)", 1)
                                If Not @error Then
                                    $aDiskInfo[1] = $match[0] ; Disk ID
                                    ContinueLoop
                                EndIf
                            EndIf
                        EndIf
                    ElseIf StringRegExp( $string, "[[:alnum:]]+" ) Then ; skip empty lines
                        $aDiskInfo[0] = $string
                        $bNameNext = False
                        ;MsgBox(0, "", "Name is : " & $aDiskInfo[0])
                    EndIf
                EndIf
            Next
            ;_ArrayDisplay($aArray)
        EndIf
    
        ; Sanity checks
        If Not $aDiskInfo[0] Then
            $aDiskInfo[0] = "UNKNOWN DISK " & $iDisk
        EndIf
        If Not $aDiskInfo[1] Then
            $aDiskInfo[1] = "UNKNOWN"
        EndIf
        If Not $aDiskInfo[2] Then
            $aDiskInfo[2] = "UNKNOWN"
        EndIf
        If Not $aDiskInfo[3] Then
            $aDiskInfo[3] = "UNKNOWN"
        EndIf
        If Not $aDiskInfo[4] Then
            $aDiskInfo[4] = "UNKNOWN"
        EndIf
    
        Return $aDiskInfo
    EndFunc
    
    ; Returns a 2D array with info on all disks.
    Func DPGetAllDiskInfo()
        Local $aAllInfo, $iPID, $sOutput, $aArray, $match, $aDiskInfo, $aDiskInfo2, $size, $i
    
        $iPID = Run(@ComSpec & ' /c echo list disk | diskpart',"", @SW_HIDE, $STDOUT_CHILD)
        ProcessWaitClose($iPID)
        $sOutput = StdoutRead($iPID)
    
        ; Use StringSplit to split the output of StdoutRead to an array. All carriage returns (@CRLF) are stripped and @CRLF (line feed) is used as the delimiter.
        $aArray = StringSplit(StringTrimRight(StringStripCR($sOutput), StringLen(@CRLF)), @CRLF)
        If @error Then
            MsgBox($MB_SYSTEMMODAL, "", "It appears there was an error trying to run diskpart.")
        Else
            For $string In $aArray
                $match = StringRegExp($string, "^\s+Disk ([0-9]+) .+", 1)
                If Not @error Then
                    $aDiskInfo = DPParseDiskDetail( $match[0], $string )
                    $aDiskInfo2 = DPParseListDisk( $string )
                    _ArrayConcatenate( $aDiskInfo, $aDiskInfo2 )
                    ; Need to do some weird stuff here because of 2D arrays
                    If UBound($aAllInfo) == 0 Then
                        Dim $aAllInfo[1][$iSizeOfAllDiskInfo]
                        $size = 0
                    Else
                        $size = UBound($aAllInfo, 1)
                        ReDim $aAllInfo[$size + 1][$iSizeOfAllDiskInfo]
                    EndIf
                    For $i = 0 To (UBound($aDiskInfo)-1)
                        $aAllInfo[$size][$i] = $aDiskInfo[$i]
                    Next
                EndIf
            Next
        EndIf
    
        Return $aAllInfo
    EndFunc
    
    Func DPRepartition( $iDisk )
        ; DEBUG DEBUG DEBUG DEBUG!!!
        MsgBox(0, "DEBUG", "All ur data r belong 2 uz")
    EndFunc
    
    Func IsUEFIPEBooted()
        Local $val = RegRead("HKLM\System\CurrentControlSet\Control", "PEFirmwareType")
        If Not @error Then
            If $val == 0x2 Then
                Return True
            ElseIf $val == 0x1 Then
                Return False
            EndIf
        EndIf
    
        Return Null
    EndFunc
    
    Func Init()
        Local $i
        Local $sComboItems = "-- Select Disk --"
        $bIsUEFIBooted = IsUEFIPEBooted()
    
        GUICreate($sProgName, $iWindowWidth, $iWindowHeight)
        If $bIsUEFIBooted Then
            GUICtrlCreateLabel("* UEFI Detected   ", $iWindowWidth - 120, 5, 120, 20, $SS_RIGHT)
        Else
            GUICtrlCreateLabel("* MBR Detected   ", $iWindowWidth - 120, 5, 120, 20, $SS_RIGHT)
        EndIf
        GUICtrlCreateLabel($sProgName, 5, 5)
        Opt("GUICoordMode", 2) ; Switch to relative positioning
        GUICtrlCreateLabel("Select Disk For Partitioning", -1, 20, $iWindowWidth - 10)
        $iComboBox1 = GUICtrlCreateCombo("", -1, 2, $iWindowWidth - 10)
    
        $aAllDiskInfo = DPGetAllDiskInfo()
        For $i = 0 To (UBound($aAllDiskInfo,1)-1)
            $sComboItems = $sComboItems & '|' & "Disk " & $i & ": " & $aAllDiskInfo[$i][0] & " (" & $aAllDiskInfo[$i][5] & ")"
        Next
        GUICtrlSetData(-1, $sComboItems, "-- Select Disk --")
    
        $iSysCheckBox = GUICtrlCreateCheckBox("Add System Partition", -1, 2)
        GUICtrlSetState(-1, $GUI_CHECKED)
        $iWinRECheckBox = GUICtrlCreateCheckBox("Copy over WinRE", -1, 2)
        GUICtrlSetState(-1, $GUI_CHECKED)
        $iRecoveryCheckBox = GUICtrlCreateCheckBox("Add Recovery Partition", -1, 2)
        GUICtrlSetState(-1, $GUI_CHECKED)
        $iGPTCheckBox = GUICtrlCreateCheckBox("Use GPT", -1, 2)
        GUICtrlSetState(-1, $GUI_UNCHECKED)
    
        Opt("GUICoordMode", 1) ; Default (absolute)
        $iGoButton = GUICtrlCreateButton("Go!", 10, $iWindowHeight - 40, 80)
    EndFunc
    
    Func Cleanup()
        FileDelete( $tempfile )
    EndFunc
    
    Func Go()
        Local $iOKORCANCEL, $match, $iDisk
    
        $match = StringRegExp( GUICtrlRead( $iComboBox1 ), "^Disk ([0-9]+):", 1 )
        If Not @error Then
            $iDisk = $match[0]
            $iOKORCANCEL = MsgBox($MB_OKCANCEL, "Does this look right?", _
                "Repartition drive " & $iDisk & "?" & @CRLF & _
                @CRLF & _
                $aAllDiskInfo[$iDisk][0] & @CRLF & _
                "ID: " & $aAllDiskInfo[$iDisk][1] & @CRLF & _
                "Type: " & $aAllDiskInfo[$iDisk][2] & @CRLF & _
                "Location: " & $aAllDiskInfo[$iDisk][4] & @CRLF & _
                @CRLF & _
                "Unallocated Space: " & $aAllDiskInfo[$iDisk][6] & @CRLF & _
                "Total Size: " & $aAllDiskInfo[$iDisk][5] & @CRLF & _
                @CRLF & _
                "Status: " & $aAllDiskInfo[$iDisk][3] & @CRLF )
            If $iOKORCANCEL == $IDOK Then
                $iOKORCANCEL = MsgBox($MB_OKCANCEL, "WARNING!", _
                    "ALL DATA ON DRIVE " & $iDisk & " WILL BE LOST!" & @CRLF & _
                    @CRLF & _
                    "Continue?" )
                If $iOKORCANCEL == $IDOK Then
                    DPRepartition($iDisk)
                EndIf
            EndIf
        Else
            MsgBox(0, "", "Please select a disk!")
        EndIf
    EndFunc
    
    Func main()
        Local $state
    
        Init()
    
        ; GUI MESSAGE LOOP
        GUISetState(@SW_SHOW)
        While 1
            Switch GUIGetMsg()
                Case $GUI_EVENT_CLOSE
                    Cleanup()
                    Exit
                Case $iGoButton
                    Go()
                Case $iGPTCheckBox
                    ;$state = GUICtrlRead( $iGPTCheckBox )
                    ;If $state == $GUI_CHECKED Then
                        ;GUICtrlSetState( $iSysCheckBox, $GUI_CHECKED)
                    ;    _GUICtrlButton_SetState( $iSysCheckBox, $BST_INDETERMINATE )
                    ;Else
                    ;    _GUICtrlButton_SetState( $iSysCheckBox, $BST_CHECKED )
                    ;EndIf
                Case $iSysCheckBox
                    $state = GUICtrlRead( $iSysCheckBox )
                    If $state == $GUI_CHECKED Then
                        GUICtrlSetState( $iWinRECheckBox, $GUI_SHOW)
                    Else
                        GUICtrlSetState( $iWinRECheckBox, $GUI_HIDE)
                    EndIf
            EndSwitch
        WEnd
    EndFunc
    
    It's not totally absent of commenting and will at least show you the drives and volumes. It's a start that I hope to use to fully GUI-ify your script or at least complement WinNTSetup (which doesn't do partitioning or recovery creation). We can even have it call batch files for some processing, if you don't want to work with AutoIT. In fact, I'd rather modularize at least dealing with diskpart into a shared script, so it's easily updated and used in other projects.
     
  14. hypedave

    hypedave MDL Member

    Oct 14, 2014
    129
    30
    10
    Has anyone had success getting this to work with a PC or laptop that has a hybrid hard drive? It throws an error when copying the bcdboot files.
     
  15. Chibi ANUBIS

    Chibi ANUBIS MDL Chibi Developer

    Apr 28, 2014
    1,238
    911
    60
    Is compatible for Windows 10 ? :)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  16. Chibi ANUBIS

    Chibi ANUBIS MDL Chibi Developer

    Apr 28, 2014
    1,238
    911
    60
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  17. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    Updated script to v1.2.8 in the OP
     
  18. crashnburn

    crashnburn MDL Addicted

    Mar 18, 2010
    574
    25
    30
    What options would you suggest for a Windows Enterprise based WTG Windows to Go 8.x or 10?

    Especially if done on a .VHD/ .VHDX?
     
  19. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    Windows to go images are created from within Windows.
    I'm not entirely sure how exactly they form the images.
    If you want Enterprise to be installed as intended, you should use a stock Enterprise image as a source.

    I haven't played with .vhd booting, but as far as the size goes, it really doesn't matter unless you're using a recovery image.
    Normal setup will make the vhd roughly the same size as dism apply does.
     
  20. Chibi ANUBIS

    Chibi ANUBIS MDL Chibi Developer

    Apr 28, 2014
    1,238
    911
    60
    Tested with Windows 10 Enterprise French and work perfectly !
    But I see two errors :
    • I use fast setup, after partition no index available, but I tape "1" and the index ready
    • At the end, the script rebuild and error in 42% "the system already exists"

    Thanks for your work :)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...