[OPTIONS] Installing Windows on UEFI System with install.wim over 4 GB

Discussion in 'Windows 10' started by freddie-o, Mar 13, 2019.

  1. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,440
    1,420
    60
    #2 rpo, Mar 13, 2019
    Last edited: Mar 13, 2019
    This can be done by running the following script :
    Code:
    rem    This script must be executed with admin privilege
    (
    echo #    This script must be executed with admin privilege
    echo #    Test Administrator privileges
    echo If ^(-NOT ^([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent^(^)^).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"^)^)
    echo {
    echo #    Restart the script to get Administrator privileges and exit
    echo     Start-Process 'powershell.exe' -Verb runAs -ArgumentList ^("-NoLogo -WindowStyle Maximized -noprofile -file " + """" + $PSCommandPath + """"^)
    echo     exit
    echo }
    echo #    We have Administrator privileges
    echo [console]::ForegroundColor = "Yellow"
    echo [console]::BackgroundColor = "blue"
    echo clear-host
    echo $wshell=New-Object -ComObject Wscript.Shell
    echo $wshell.Popup^("Mount the USB stick",0,"USB stick"^) ^| Out-Null
    echo #    Select the USB stick
    echo $usb = ^(Get-Disk ^| Where-Object {^($_.BusType -eq "USB"^) -and ^($_.OperationalStatus -eq "Online"^)} ^| Out-GridView -Title 'Select USB Drive to Format' -OutputMode Single^).number
    echo if ^($usb -eq $null^) {$wshell.Popup^("No USB stick online or operation cancelled",0,"Erro"^) ^| Out-Null;exit}
    echo #    Clear the USB stick
    echo Clear-Disk $usb -RemoveData -RemoveOEM -Confirm:$false
    echo Stop-Service ShellHWDetection
    echo #    Create the fat32 boot partition
    echo $usbfat32=^(New-Partition -DiskNumber $usb -Size 1GB -AssignDriveLetter -IsActive ^| Format-Volume -FileSystem FAT32 -NewFileSystemLabel "BOOTFAT"^).DriveLetter + ":"
    echo #    Create the ntfs intall partition
    echo $usbntfs=^(New-Partition -DiskNumber $usb -UseMaximumSize -AssignDriveLetter ^| Format-Volume -FileSystem NTFS -NewFileSystemLabel "INSTALL"^).DriveLetter + ":"
    echo Start-Service ShellHWDetection
    echo $wshell.Popup^("Mount the iso image",0,"ISO image"^) ^| Out-Null
    echo $ISO = ^(get-volume^| Where-Object {^($_.DriveType -eq "CD-ROM"^) -and ^($_.filesystemlabel -ne ""^) -and ^($_.OperationalStatus -eq "OK"^)} ^|Out-GridView -Title 'Select Cd-Rom image' -OutputMode Single^).DriveLetter + ":"
    echo robocopy $iso $usbntfs /e
    echo robocopy $iso"\" $usbfat32"\" bootmgr bootmgr.efi
    echo robocopy $iso"\boot" $usbfat32"\boot" /e
    echo robocopy $iso"\efi" $usbfat32"\efi" /e
    echo robocopy $iso"\sources" $usbfat32"\sources" boot.wim
    echo # Eject the mounted iso image
    echo ^(New-Object -ComObject Shell.Application^).Namespace^(17^).ParseName^($ISO^).InvokeVerb^("Eject"^)
    echo Remove-item ^($env:TEMP + "\script.ps1"^)    
    )>"%temp%\script.ps1"
    powershell "%temp%\script.ps1" -ExecutionPolicy Bypass
    
     
  2. freddie-o

    freddie-o MDL Expert

    Jul 29, 2009
    1,358
    2,267
    60
    I tried the script and got this.
    F:\>rem This script must be executed with admin privilege

    F:\>(
    echo # This script must be executed with admin privilege
    echo # Test Administrator privileges
    echo If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
    echo {
    echo # Restart the script to get Administrator privileges and exit
    echo Start-Process 'powershell.exe' -Verb runAs -ArgumentList ("-NoLogo -WindowStyle Maximized -noprofile -file " + """" + $PSCommandPath + """")
    echo exit
    echo }
    echo # We have Administrator privileges
    echo [console]::ForegroundColor = "Yellow"
    echo [console]::BackgroundColor = "blue"
    echo clear-host
    echo $wshell=New-Object -ComObject Wscript.Shell
    echo $wshell.Popup("Mount the USB stick",0,"USB stick") | Out-Null
    echo # Select the USB stick
    echo $usb = (Get-Disk | Where-Object {($_.BusType -eq "USB") -and ($_.OperationalStatus -eq "Online")} | Out-GridView -Title 'Select USB Drive to Format' -OutputMode Single).number
    echo if ($usb -eq $null) {$wshell.Popup("No USB stick online or operation cancelled",0,"Erro") | Out-Null;exit}
    echo # Clear the USB stick
    echo Clear-Disk $usb -RemoveData -RemoveOEM -Confirm:$false
    echo Stop-Service ShellHWDetection
    echo # Create the fat32 boot partition
    echo $usbfat32=(New-Partition -DiskNumber $usb -Size 1GB -AssignDriveLetter -IsActive | Format-Volume -FileSystem FAT32 -NewFileSystemLabel "BOOTFAT").DriveLetter + ":"
    echo # Create the ntfs intall partition
    echo $usbntfs=(New-Partition -DiskNumber $usb -UseMaximumSize -AssignDriveLetter | Format-Volume -FileSystem NTFS -NewFileSystemLabel "INSTALL").DriveLetter + ":"
    echo Start-Service ShellHWDetection
    echo $wshell.Popup("Mount the iso image",0,"ISO image") | Out-Null
    echo $ISO = (get-volume| Where-Object {($_.DriveType -eq "CD-ROM") -and ($_.filesystemlabel -ne "") -and ($_.OperationalStatus -eq "OK")} |Out-GridView -Title 'Select Cd-Rom image' -OutputMode Single).DriveLetter + ":"
    robocopy $iso $usbntfs /e
    robocopy $iso"\" $usbfat32"\" bootmgr bootmgr.efi
    robocopy $iso"\boot" $usbfat32"\boot" /e
    robocopy $iso"\efi" $usbfat32"\efi" /e
    robocopy $iso"\sources" $usbfat32"\sources" boot.wim
    echo # Eject the mounted iso image
    echo (New-Object -ComObject Shell.Application).Namespace(17).ParseName($ISO).InvokeVerb("Eject")
    echo Remove-item ($env:TEMP + "\script.ps1")
    ) 1>"C:\Users\ADMINI~1\AppData\Local\Temp\script.ps1"

    F:\>powershell "C:\Users\ADMINI~1\AppData\Local\Temp\script.ps1" -ExecutionPolicy Bypass
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:29 char:80
    + ... ---------------------------------------------------------------------
    + ~
    Missing expression after unary operator '-'.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:30 char:4
    + ROBOCOPY :: Robust File Copy for Windows
    + ~~~~~~~~
    Unexpected token 'ROBOCOPY' in expression or statement.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:31 char:80
    + ... ---------------------------------------------------------------------
    + ~
    Missing expression after unary operator '-'.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:33 char:3
    + Started : Wednesday, March 13, 2019 9:26:53 PM
    + ~~~~~~~
    Unexpected token 'Started' in expression or statement.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:43 char:12
    + 2019/03/13 21:26:53 ERROR 2 (0x00000002) Accessing Source Directory F ...
    + ~~~~~~~~
    Unexpected token '21:26:53' in expression or statement.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:47 char:80
    + ... ---------------------------------------------------------------------
    + ~
    Missing expression after unary operator '-'.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:48 char:4
    + ROBOCOPY :: Robust File Copy for Windows
    + ~~~~~~~~
    Unexpected token 'ROBOCOPY' in expression or statement.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:49 char:80
    + ... ---------------------------------------------------------------------
    + ~
    Missing expression after unary operator '-'.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:51 char:3
    + Started : Wednesday, March 13, 2019 9:26:53 PM
    + ~~~~~~~
    Unexpected token 'Started' in expression or statement.
    At C:\Users\Administrator\AppData\Local\Temp\script.ps1:61 char:12
    + 2019/03/13 21:26:53 ERROR 123 (0x0000007B) Accessing Source Directory ...
    + ~~~~~~~~
    Unexpected token '21:26:53' in expression or statement.
    Not all parse errors were reported. Correct the reported errors and try again.
    + CategoryInfo : ParserError: :)) [], ParseException
    + FullyQualifiedErrorId : MissingExpressionAfterOperator
     
  3. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,440
    1,420
    60
    My bad… It wasn't the correct version of the script. The statements beginning with robocopy should beging with echo robocopy. I updated my previous post.
     
  4. rpo

    rpo MDL Expert

    Jan 3, 2010
    1,440
    1,420
    60
    Yes, you can.
     
  5. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    534
    926
    30
    #8 GodHand, Mar 14, 2019
    Last edited: Mar 14, 2019
    Should rely entirely on disk objects when formatting or structuring any type of storage

    Code:
    Function New-WinBootUSB
    {
    <#
        .SYNOPSIS
            Create a bootable USB drive.
     
        .DESCRIPTION
            Create a bootable USB drive using using a disk object.
         
            Create a Windows installation file structure and copy the full installation media directly to the disk making it bootable on both GPT/UEFI and MBR/BIOS systems
     
        .PARAMETER Disk
            Create a disk object using the Get-Disk cmdlet that identifies the USB drive by its index number.
            Example: $USB = Get-Disk -Number 6
     
        .PARAMETER MediaPath
            The full path to a Windows installation media.  This can either be an ISO or directory.
     
        .PARAMETER DiskLayout
            The disk firmware layout of the device being booted by the USB.
     
        .PARAMETER DiskLabel
            An optional volume label to easily identify the USB drive.
     
        .EXAMPLE
            PS C:\> New-WinBootUSB -Disk $USB -MediaPath "E:\Windows 10\WIN_10_ENTERPRISE_LTSC.iso" -DiskLayout UEFI
            PS C:\> New-WinBootUSB -Disk $USB -MediaPath "E:\Windows 10\WIN_10_ENTERPRISE_LTSC" -DiskLayout UEFI -DiskLabel "WIN10LTSC"
    #>
        [CmdletBinding(ConfirmImpact = 'High',
            SupportsShouldProcess = $true)]
        [OutputType([PSCustomObject])]
        Param
        (
            [Parameter(Mandatory = $true,
                HelpMessage = 'A disk object that identifies the USB drive.')]
            [ValidateNotNullOrEmpty()]
            [object]$Disk,
            [Parameter(Mandatory = $true,
                HelpMessage = 'The full path to a Windows installation media.  This can either be an ISO or directory.')]
            [ValidateScript( { Test-Path $(Resolve-Path -Path $_) })]
            [string]$MediaPath,
            [Parameter(Mandatory = $true,
                HelpMessage = 'The disk firmware layout of the device being booted by the USB.')]
            [ValidateNotNullOrEmpty()]
            [ValidateSet('UEFI', 'BIOS')]
            [string]$DiskLayout,
            [Parameter(HelpMessage = 'An optional volume label to easily identify the USB drive.')]
            [string]$DiskLabel
        )
     
        Process
        {
            If ($PSCmdlet.ShouldProcess("$($Disk.FriendlyName), All data will be lost"))
            {
                Try
                {
                    $DiskNumber = $Disk.Number
                    $Disk | Set-Disk -IsReadOnly $false
                    $Disk | Get-Partition -ErrorAction SilentlyContinue | Remove-Partition -Confirm:$false -PassThru -ErrorAction SilentlyContinue | Clear-Disk -RemoveData -Confirm:$false -ErrorAction SilentlyContinue
                    Switch ($DiskLayout)
                    {
                        'UEFI' { $PartitionStyle = 'GPT' }
                        'BIOS' { $PartitionStyle = 'MBR' }
                    }
                    If ($Disk.PartitionStyle -eq 'RAW')
                    {
                        $Disk | Initialize-Disk -PartitionStyle $PartitionStyle -ErrorAction Stop
                    }
                    Else
                    {
                        $Disk | Set-Disk -PartitionStyle $PartitionStyle -ErrorAction Stop
                    }
                    If ($DiskLayout.Equals('UEFI'))
                    {
                        If ($Disk.Size -gt 32GB)
                        {
                            $Partition = $Disk | New-Partition -Size 32GB -ErrorAction Stop
                        }
                        Else
                        {
                            $Partition = $Disk | New-Partition -UseMaximumSize -ErrorAction Stop
                        }
                    }
                    ElseIf ($DiskLayout.Equals('BIOS'))
                    {
                        If ($Disk.Size -gt 32GB)
                        {
                            $Partition = $Disk | New-Partition -Size 32GB -IsActive -ErrorAction Stop
                        }
                        Else
                        {
                            $Partition = $Disk | New-Partition -UseMaximumSize -IsActive -ErrorAction Stop
                        }
                    }
                    If ($DiskLabel)
                    {
                        $Format = Format-Volume -Partition $Partition -NewFileSystemLabel $DiskLabel -FileSystem FAT32 -Force -Confirm:$false -ErrorAction Stop
                    }
                    Else
                    {
                        $Format = Format-Volume -Partition $Partition -FileSystem FAT32 -Force -Confirm:$false -ErrorAction Stop
                    }
                    $Partition | Add-PartitionAccessPath -AssignDriveLetter -ErrorAction Stop
                    $Disk = Get-Disk -Number $DiskNumber | Get-Disk
                    $DiskPath = (($Disk | Get-Partition).AccessPaths[0]).SubString(0, 2)
                    If ($null -eq $DiskPath)
                    {
                        $DiskPath = (($Disk | Get-Partition).AccessPaths[1]).SubString(0, 2)
                    }
                }
                Catch
                {
                    Write-Warning $($_.Exception.Message)
                    Break
                }
                Try
                {
                    If (([IO.FileInfo]$MediaPath).Extension -eq '.ISO')
                    {
                        $SourcePath = (Mount-DiskImage -ImagePath $MediaPath -StorageType ISO -PassThru | Get-Volume).DriveLetter + ':'
                        $SourcePath = Get-Item -Path $SourcePath -Force -ErrorAction Stop
                    }
                    ElseIf (Test-Path -Path $MediaPath -PathType Container)
                    {
                        $SourcePath = Get-Item -Path $MediaPath -Force -ErrorAction Stop
                    }
                    If (Test-Path -Path "$($SourcePath)\sources\install.wim") { $InstallWim = Get-Item -Path "$($SourcePath)\sources\install.wim" -Force -ErrorAction Stop }
                    If ($InstallWim.Length -gt 4GB)
                    {
                        Write-Host "Splitting WIM to SWM will take some time. Please be patient..." -NoNewline -ForegroundColor Cyan
                        [void](New-Item -Path $DiskPath -Name 'sources' -ItemType Directory -Force -ErrorAction Stop)
                        Start-Process -FilePath Dism -ArgumentList ("/Split-Image /ImageFile:`"${InstallWim}`" /SWMFile:`"${DiskPath}\sources\install.swm`" /FileSize:4096") -WindowStyle Hidden -Wait -ErrorAction Stop
                        Write-Host "[Completed]" -ForegroundColor Cyan
                        $FileList = Get-ChildItem -Path $($SourcePath.FullName) -Recurse -Exclude install.wim -Force -ErrorAction SilentlyContinue
                    }
                    Else
                    {
                        $FileList = Get-ChildItem -Path $($SourcePath.FullName) -Recurse -Force -ErrorAction SilentlyContinue
                    }
                    If ($FileList)
                    {
                        $Progress = 0
                        ForEach ($File In $FileList)
                        {
                            $FileName = $File.FullName.Replace($SourcePath, $null)
                            $DestinationFilePath = Join-Path -Path $DiskPath -ChildPath $FileName
                            Switch ($File.Length)
                            {
                                { $_ -lt 1MB } { $FileSize = ($_ / 1KB).ToString("0.00 KB"); Break }
                                { $_ -lt 1GB } { $FileSize = ($_ / 1MB).ToString("0.00 MB"); Break }
                                { $_ -lt 1TB } { $FileSize = ($_ / 1GB).ToString("0.00 GB"); Break }
                            }
                            Write-Progress -Activity "Copying media from $(Split-Path -Path $MediaPath -Leaf)" -Status "Copying File: $($File.FullName), Size: $FileSize" -PercentComplete (($Progress / $($FileList.Count)) * 100)
                            Copy-Item $($File.FullName) -Destination $DestinationFilePath -Force -ErrorAction Stop
                            $Progress++
                        }
                        $Bootsect = Join-Path -Path $SourcePath -ChildPath 'boot\bootsect.exe'
                        If (!(Test-Path -Path $Bootsect)) { $Bootsect = 'bootsect.exe' }
                        $Run = Start-Process -FilePath $Bootsect -ArgumentList ("/NT60 `"${DiskPath}`"") -WindowStyle Hidden -Wait -PassThru
                        If ($Run.ExitCode -eq 0) { $IsBootable = $true }
                        Else { $IsBootable = $false }
                        $USBInfo = [PSCustomObject]@{
                            'USB Name'    = $Disk.FriendlyName
                            'Access Path' = $DiskPath + '\'
                            'File System' = $Format.FileSystem
                            'Is Bootable' = $IsBootable.ToString()
                        } | Format-List
                    }
                }
                Catch
                {
                    Write-Warning $($_.Exception.Message)
                    Break
                }
                Finally
                {
                    Dismount-DiskImage -ImagePath $MediaPath -ErrorAction SilentlyContinue
                    $Progress = $null
                }
            }
        }
        End
        {
            If ($USBInfo) { Return $USBInfo }
        }
    }
    Here's a small advanced function I quickly wrote that will return your disk index number by inputting the drive letter it's attached to:

    Code:
    Function Get-USBIndex
    {
        [CmdletBinding()]
        Param
        (
            [Parameter(Mandatory = $true)]
            [string]$DriveLetter
        )
       
        Begin
        {
            $DriveLetter = $DriveLetter.Substring(0, 1).ToUpper()
        }
        Process
        {
            Try
            {
                Get-WmiObject -Class Win32_DiskDrive -ErrorAction Stop | Where-Object { ($_.InterfaceType -eq 'USB') -and ($_.MediaType -eq 'Removable Media') } | ForEach-Object -Process {
                    If ((Get-Partition -DiskNumber $_.Index -ErrorAction Stop).DriveLetter -eq $DriveLetter)
                    {
                        $DiskNumber = $_.Index
                        $DiskSize = [Math]::Round($_.Size / 1GB)
                        Return $DiskNumber
                    }
                }
            }
            Catch
            {
                Write-Warning ('Failed to locate USB drive "{0}"' -f $DriveLetter)
            }
        }
    }
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  6. spedia

    spedia MDL Senior Member

    Jul 13, 2009
    310
    121
    10
    Wonderful!

    [rantcode] Microsoft should not make oversized WIM in the first place!! [/rantcode]
     
  7. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    534
    926
    30
    The PowerShell function works with both ISOs and already expanded installation media. I use it pretty regularly since I can just execute it directly from any location as opposed to using an executable. I literally just used it to install LTSC 2019 on a friend's new Dell Latitude laptop in UEFI mode with CSM disabled maybe 15 minutes ago.

    I have not tried the batch files posted.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  8. sebus

    sebus MDL Guru

    Jul 23, 2008
    6,354
    2,026
    210
    Or use 2 separate media, one for boot & one for install of large .wims
    The media holding .wims can be usb stick, usb hd, network share etc
     
  9. uffbros

    uffbros MDL Senior Member

    Aug 9, 2010
    447
    58
    10
    Option 4 using Rufus...I use Rufus all the time. I don't see any options with Rufus to do what you are saying in option 4. I select the .iso..then what do you select for the partition scheme? Can you give me a blow by blow of what to select in this scenario. Thanks.
     
  10. Chigz_

    Chigz_ MDL Novice

    Oct 4, 2017
    47
    29
    0
    Thanks for sharing the WinPE method. This will make installing Windows a whole lot easier. ( :

    Rather than using the ones shown on the MDL page, I actually went ahead and made my own from the ADK, included some basic tools in it too; first a basic Explorer window to find the ISO on my HDD and second a ISO mounter to mount and run Setup.exe as to install Windows from, all from following the documentation on the Microsoft site.

    -

    I did try out the ones on the MDL page to begin but there were too many tools for my liking, for the time being installing Windows (usually every 6 months) is all i'll use my PE for.
    If I need, I can add more things to my PE image perhaps using some of the tools from the MDL page and integrating them in : p
     
  11. freddie-o

    freddie-o MDL Expert

    Jul 29, 2009
    1,358
    2,267
    60
    Do you mean the tools here WinPE [Build Your Own] ?
    You can just check the Apps you want to integrate and uncheck the ones you don't need.
    I found it much simpler and it already has the basics such as the GUI (Explorer) and the option to mount your ISO.
    Plus there's a whole lot more you can do in WinPE than just installing Windows. :)
     
  12. Chigz_

    Chigz_ MDL Novice

    Oct 4, 2017
    47
    29
    0
    #20 Chigz_, Mar 18, 2019
    Last edited: Mar 18, 2019
    Yeah that’s the one.

    Honestly I just found it a bit too bloated for my personal use. I’m sure all the tools included in it are great.

    -

    It was a fun weekend project and learning experience about finding out what WinPE is and what it can do for me ( :

    -

    Edit: spelling and added some words