Win10+ Setup Disk (Works with UEFI Secure Boot / BIOS / Install.wim over 4 GB)

Discussion in 'Scripting' started by freddie-o, Mar 21, 2019.

  1. freddie-o

    freddie-o MDL Expert

    Jul 29, 2009
    1,165
    1,574
    60
    #361 freddie-o, Nov 23, 2021
    Last edited: Nov 23, 2021
    (OP)
    Meanwhile I updated the thread title to Win10+ Setup Disk, the OP and the script to 2.5
     
  2. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,305
    1,256
    60
    #362 rpo, Nov 24, 2021
    Last edited: Nov 24, 2021
    This is the script is tested :
    Code:
    <# : standard way of doing hybrid batch + powershell scripts
    @title Win10+ Setup Disk 3.0 &color 3E
    @set "__ARGS__=%*" &powershell -noprofile "$ScriptPath='%~f0';iex((Get-Content('%~f0') -Raw))" &exit/b
    #>
    #
    #   Homepage: https://forums.mydigitallife.net/threads/win10-setup-disk-works-with-uefi-with-secure-boot-bios-install-wim-over-4-gb.79268/
    #   Credits: @rpo, @freddie-o, @BAU & @abbodi1406
    #
    #   This script must be executed with admin privilege
    #
    #   Test Administrator privileges
    If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
    {
        $uac_error="Elevating UAC for Administrator Privileges failed"
        #   The following test is to avoid infinite looping if elevating UAC for Administrator Privileges failed
        if ($env:__ARGS__ -eq $uac_error) {
        read-host "$uac_error`r`nRight click on the script and select ""Run as administrator""`r`nPress Enter to exit...";exit}
    #   Restart the script to get Administrator privileges and exit
                                                                                       
        Start-Process "$ScriptPath" $uac_error -Verb runAs; exit
    }
    $pswindow = $host.ui.rawui          # create a reference to the console’s UI.RawUI child object
    $pswindow.windowtitle = ([string]($pswindow.windowtitle -split "^.*  ")).trim() ; $ShortTitle=($pswindow.windowtitle -split " @ .*")[0]
    #
    Add-Type -AssemblyName System.Windows.Forms # Load the class System.Windows.Forms
    # Filebrowser dialog object
    $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{
        Multiselect = $false # One file can be chosen
        Filter = 'ISO images (*.iso)|*.iso' # Select only iso files
    }
    #
    Function MsgBox {[System.Windows.Forms.MessageBox]::Show($Args[0],$ShortTitle,$Args[1],$Args[2])}
    #
    Function Update_bcd
    {
    param ($iso, $usbpartition)
    "Set bootmenupolicy Legacy for $usbpartition"
    Copy-Item "$iso\boot\bcd" "$usbpartition\boot\bcd" -Force
    Copy-Item "$iso\EFI\Microsoft\boot\bcd" "$usbpartition\EFI\Microsoft\boot\bcd" -Force
    & bcdedit /store "$usbpartition\boot\bcd" /set '{default}' bootmenupolicy Legacy |Out-Null
    & bcdedit /store "$usbpartition\EFI\Microsoft\boot\bcd" /set '{default}' bootmenupolicy Legacy |Out-Null
    Set-ItemProperty -Path "$usbpartition\boot\bcd" -Name IsReadOnly -Value $true
    Set-ItemProperty -Path "$usbpartition\EFI\Microsoft\boot\bcd" -Name IsReadOnly -Value $true
    remove-item "$usbpartition\boot\bcd.*" -force
    remove-item "$usbpartition\EFI\Microsoft\boot\bcd.*" -force
    }
    #
    clear-host
    $swmsize=4000
    $USB=$Null
    $Form=New-Object System.Windows.Forms.Form # Create the screen form (window)
    $Form.TopMost = $True
    # Set the title and size of the window:
    $Form.Text=$ShortTitle
    $Form.Font='Consolas,9'                    
    $Form.Width=420 ; $Form.Height=315
    $Form.StartPosition = "CenterScreen"
    $Form.SizeGripStyle = "Hide"
    [System.Windows.Forms.Application]::EnableVisualStyles();
    #
    $USBDisk=New-Object System.Windows.Forms.Label # Put Selected USB Disk label on the form
    $USBDisk.Location=New-Object System.Drawing.Point(20,20)
    $USBDisk.Text="Selected USB Disk"
    $USBDisk.Size=New-Object System.Drawing.Size(200,20)
    $Form.Controls.Add($USBDisk)
    #
    $USBDiskList=New-Object System.Windows.Forms.ComboBox # Create a drop-down list and fill it
    $USBDiskList.DropDownStyle=[System.Windows.Forms.ComboBoxStyle]::DropDownList;
    $USBDiskList.Location=New-Object System.Drawing.Point(20,40)
    $USBDiskList.Size=New-Object System.Drawing.Size(363,22)
    $Form.Controls.Add($SelectUSBDiskList)
    $USBDisks=@() # array with USB disk number
    #
    $Disks=$Null;While (!$Disks){
        If(!($Disks=Get-Disk | Where-Object {($_.BusType -eq "USB") -and ($_.OperationalStatus -eq "Online")})){
            if((MsgBox "Plug in your USB disk first. `n`nClick OK to continue." "OKCancel" "Information") -eq "Cancel") {exit}}}
    #
    $SelectProcedure=New-Object System.Windows.Forms.Label # Put Selected Procedure for creating Setup disk on the form
    $SelectProcedure.Location=New-Object System.Drawing.Point(20,85)
    $SelectProcedure.Size=New-Object System.Drawing.Size(380,20)
    $SelectProcedure.text="Selected Procedure if Install Wim is more than 4GB"
    $Form.Controls.Add($SelectProcedure)
    #
    $ProcedureList=New-Object System.Windows.Forms.ComboBox # Create a procedure drop-down list and fill it
    $ProcedureList.DropDownStyle=[System.Windows.Forms.ComboBoxStyle]::DropDownList;
    $ProcedureList.Location=New-Object System.Drawing.Point(20,105)
    $ProcedureList.Size=New-Object System.Drawing.Size(363,22)
    [void] $ProcedureList.Items.Add("Create a FAT32 and NTFS partition")
    [void] $ProcedureList.Items.Add("Split the Install.wim (single fat32 partition)")
    $Form.Controls.Add($ProcedureList)
    #
    $ProcedureList.SelectedIndex=0
    #
    $ISOImage=New-Object System.Windows.Forms.Label # Put the ISO Image label on the form
    $ISOImage.Location=New-Object System.Drawing.Point(20,150)
    $ISOImage.Size=New-Object System.Drawing.Size(200,20)
    $ISOImage.text="Selected ISO Image"
    $Form.Controls.Add($ISOImage)
    #
    $ISOFile=New-Object System.Windows.Forms.Label # Put the ISO file name on the form
    $ISOFile.Location=New-Object System.Drawing.Point(20,170)
    $ISOFile.Text=" "
    $ISOFile.Size=New-Object System.Drawing.Size(364,24)
    $ISOFile.Backcolor = [System.Drawing.Color]::White
    $ISOFile.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
    $Form.Controls.Add($ISOFile)
    #
    $CancelButton=New-Object System.Windows.Forms.Button # Put the Cancel button on the form
    $CancelButton.Location=New-Object System.Drawing.Point(270,230)
    $CancelButton.Text="Cancel"
    $CancelButton.Size=New-Object System.Drawing.Size(115,26)
    $Form.Controls.Add($CancelButton)
    $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    #
    $SelectISOButton=New-Object System.Windows.Forms.Button # Put the Select ISO button on the form
    $SelectISOButton.Location=New-Object System.Drawing.Point(145,230)
    $SelectISOButton.Text="Select ISO"
    $SelectISOButton.Size=New-Object System.Drawing.Size(115,26)
    $Form.Controls.Add($SelectISOButton)
    #
    $CreateDiskButton=New-Object System.Windows.Forms.Button # Put the Create Disk button on the form
    $CreateDiskButton.Location=New-Object System.Drawing.Point(20,230)
    $CreateDiskButton.Text="Create Disk"
    $CreateDiskButton.Size=New-Object System.Drawing.Size(115,26)
    $Form.Controls.Add($CreateDiskButton)
    $CreateDiskButton.Enabled = $false
    $CreateDiskButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    #
    $SelectISOButton.Add_Click({
        If ($FileBrowser.ShowDialog() -ne "Cancel"){ # if Cancel, just ignore
            $Global:ImagePath = $FileBrowser.filename    # return the file name
            $ISOFile.Text= Split-Path -Path $ImagePath -leaf # extract filename and extension (iso)
            if (($ISOFile.Text).length -gt 44) {$ISOFile.Text = $ImagePath.PadRight(100," ").substring(0,49)+"..."}
            $CreateDiskButton.Enabled = $true
            $CreateDiskButton.Focus()}})
    #
    Foreach ($USBDisk in $Disks) {
        $FriendlyName=($USBDisk.FriendlyName).PadRight(40," ").substring(0,39)
        $USBDisks+=$USBDisk.DiskNumber
        $USBDiskList.Items.Add(("{0,-39}{1:n2} GB" -f $FriendlyName,($USBDisk.Size/1GB)))|out-null
        $Partitions = Get-Partition | Where-Object { $_.DiskNumber -eq $USBDisk.DiskNumber}
        If ($Partitions) {
            Foreach ($Partition in $Partitions) {
            If(!$Partition.DriveLetter){$AccessPath="  "} Else {$AccessPath=$Partition.DriveLetter+":"}  
            $Volumes=get-volume | Where-Object {$Partition.AccessPaths -contains  $_.path }
                Foreach ($Volume in $Volumes) {
                    $USBDisks+=$USBDisk.DiskNumber
                    $USBDiskList.Items.Add(("{0,0}({1,2}){2,-32}[{3:n2} GB]" -f " ", ($AccessPath), $Volume.FileSystemLabel.PadRight(25," ").substring(0,25), ($Partition.Size/1GB)))|out-null
                }
            }
        }
    }
    $form.Controls.Add($USBDiskList)
    $USBDiskList.SelectedIndex=0
    #
    $Groupbox=New-Object System.Windows.Forms.Groupbox # Add a group box on the form
    $Groupbox.Location=New-Object System.Drawing.Point(7,0)
    $Groupbox.Text=""
    $Groupbox.Size=New-Object System.Drawing.Size(390,270)
    $Form.Controls.Add($Groupbox)
    #
    @"
    Select your USB Disk, the procedure (how you want your Setup disk created) and your ISO image.
    Your $ShortTitle will start as soon as you click the 'Create Disk' button.
    
    When install.wim is <= 4 GB, a fat32 partition is created
    When install.wim is >  4 GB, two cases :
        If you opt for splitting intall.wim, a single fat32 partition is created
        Otherwide a fat32 and a ntfs partitions are created
       
    "@| Write-Host
    #
    if($form.ShowDialog() -eq "Cancel") {MsgBox "The script was cancelled." "OK" "Information"|out-Null;exit}
    #
    # At this point the mounted USB disk and the iso image file path are defined
    #
    $USB=$USBDisks[$USBDiskList.SelectedIndex]
    #
    If ($ProcedureList.SelectedIndex -eq 0){$splitwim=0}Else{$splitwim=1}
    #
    If((MsgBox "WARNING! `n`nYour USB disk will be converted to MBR scheme, repartitioned and reformatted.`n`nAll partitions and data currently stored in the USB disk will be erased.`r`n`r`nAre you sure you want to continue?" "YESNO" "Warning") -eq "NO"){exit}
    # Mount the image file if not already mounted and get the drive letter
    #
    #   Check if iso already mounted by getting driveletter
    If($ISO=(Get-DiskImage -ImagePath $ImagePath | Get-Volume).DriveLetter){$Mounted=$True}    Else
    #    Mount iso and get drive letter
        {$Mounted=$False; Mount-DiskImage -ImagePath $ImagePath -StorageType ISO |out-null
         If(!($ISO=(Get-DiskImage -ImagePath $ImagePath | Get-Volume).DriveLetter)){Exit}}
    $ISO=$ISO+":"
    Clear-Host
    if (Test-Path "$iso\sources\install.wim"){$WimFile="install.wim"}
    if (Test-Path "$iso\sources\install.esd"){$WimFile="install.esd"}
    $NTFS=1
    If((Get-Item "$iso\Sources\$WimFile").Length/1MB -le $swmsize){
    $NTFS=0}
    else{
    If ((Test-Path "$iso\sources\install.wim") -and ($Splitwim -gt 0)){$NTFS=0}
    }
    #    Clear the USB stick
    Clear-Disk $usb -RemoveData -RemoveOEM -Confirm:$false
    set-disk $usb -partitionstyle mbr
    Stop-Service ShellHWDetection -erroraction silentlycontinue|out-null
    #####################################################################
    #    Create partition(s)
    #
    IF ($NTFS -gt 0){
    $usbfat32=(New-Partition -DiskNumber $usb -Size  1GB -AssignDriveLetter | Format-Volume -FileSystem FAT32 -NewFileSystemLabel "BOOT").DriveLetter + ":"
    #    Create the NTFS intall partition
    $usbntfs=(New-Partition -DiskNumber $usb -UseMaximumSize -AssignDriveLetter -IsActive | Format-Volume -FileSystem NTFS -NewFileSystemLabel "SETUP").DriveLetter + ":"}
    else {
    $usbfat32=(New-Partition -DiskNumber $usb -UseMaximumSize -AssignDriveLetter -IsActive| Format-Volume -FileSystem FAT32 -NewFileSystemLabel "SETUP").DriveLetter + ":"}
    Start-Service ShellHWDetection -erroraction silentlycontinue|out-null
    #####################################################################
    IF ($NTFS -gt 0){
    #
    #    One fat32 partition and one ntfs partition
    #
    #    Copy needed files to the fat32 boot partition
    robocopy $iso"\" $usbfat32"\" bootmgr bootmgr.efi
    robocopy $iso"\boot" $usbfat32"\boot" /e /xf $iso\boot\bcd
    robocopy $iso"\efi" $usbfat32"\efi" /e /xf $iso\efi\microsoft\boot\bcd
    Update_BCD $iso $usbfat32
    robocopy $iso"\sources" $usbfat32"\sources" boot.wim
    #     Remove the drive letter to hide the device
    Get-Volume -DriveLetter $usbfat32.substring(0,$usbfat32.Length-1) | Get-Partition | Remove-PartitionAccessPath -accesspath $usbfat32
    #
    #
    #    Copy needed files to the NTFS install partition
    robocopy $iso $usbntfs /e /xf $iso\boot\bcd $iso\efi\microsoft\boot\bcd
    Update_BCD $iso $usbntfs
    }
    #####################################################################
    else{
    #
    #    One fat32 partition
    #
    robocopy $iso $usbfat32 /e /xf $iso\boot\bcd $iso\efi\microsoft\boot\bcd $iso\sources\install.wim
    Update_BCD $iso $usbfat32
    If((Get-Item "$iso\Sources\install.wim").Length/1MB -le $swmsize){
    robocopy "$iso\sources" "$usbfat32\sources" install.wim}
    else
    {Dism /Split-Image /ImageFile:"$iso\sources\install.wim" /SWMFile:"$usbfat32\sources\install.swm" /FileSize:$swmsize}
    }
    #####################################################################
    #
    # Eject the mounted iso image if it was loaded by the script
    If(!$Mounted){DisMount-DiskImage -ImagePath $ImagePath |out-null}
    MsgBox (($ShortTitle -split " @.*")[0]+" was created successfully.") "OK" "Information" |Out-Null
    #

    If install.wim <= 4 GB, only a fat32 partition is created; install.wim is not splitted
    If install.wim > 4 GB, by default a fat32 and a ntfs partitions are created, othewise a single fat32 partition is created and install.wim is splitted.
    All three configurations have been successfully tested.
     
  3. Pl correct a typo :)
     
  4. freddie-o

    freddie-o MDL Expert

    Jul 29, 2009
    1,165
    1,574
    60
    How about?
    If install.wim < 4 GB only a fat32 partition is created
    If install.wim > 4 GB a fat32 and an ntfs partitions are created

    Can the script detect the size of the install.wim?
     
  5. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,305
    1,256
    60
    #365 rpo, Nov 24, 2021
    Last edited: Nov 24, 2021
    Yes, it can :
    (Get-Item "$iso\Sources\$WimFile").Length/1MB : size in megabytes
     
  6. freddie-o

    freddie-o MDL Expert

    Jul 29, 2009
    1,165
    1,574
    60
    #366 freddie-o, Nov 25, 2021
    Last edited: Nov 25, 2021
    (OP)
    I prefer this

    to this
     
  7. TigTex

    TigTex MDL Senior Member

    Oct 5, 2009
    382
    303
    10
    Split wim files have extra install steps (wim file needs to be combined). So if possible keep with the fat32 boot + ntfs partition
     
  8. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,305
    1,256
    60
    fat32 boot + ntfs partition is the default option
     
  9. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,305
    1,256
    60
    And what if install.win=4GB?
     
  10. ericgl

    ericgl MDL Member

    Mar 10, 2011
    230
    169
    10
    Just looked at the latest script (v2.7).
    I may be missing something, but it seems that the script does not copy the main install.wim to the NTFS partition...?
    The only copy procedure to the NTFS partition that I see is:
    Code:
     robocopy $iso $usbntfs /e /xf $iso\boot\bcd $iso\efi\microsoft\boot\bcd 
     
  11. ericgl

    ericgl MDL Member

    Mar 10, 2011
    230
    169
    10
    Oh, sorry, I wasn't thinking. It copies everything except the bcd files.
    I must have been tired from work or something...my bad.