New-ISO: Remaster Windows Installation ISO files.

Discussion in 'Scripting' started by GodHand, Dec 21, 2018.

  1. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    427
    473
    10
    #1 GodHand, Dec 21, 2018
    Last edited: Dec 21, 2018
    An easy to use advanced function that will remaster (create) bootable Windows ISO files. The only required parameter is the media path which is the location of the Windows installation media content that will be remastered into an ISO. This allows for easy pipeline processing by simply typing "Path to Media" | New-ISO

    A PS Custom Object is then returned upon the creation of the ISO that displays the ISO Name, the ISO Label, the path the ISO was saved to, and a Boolean value signifying whether the ISO prompts the user during boot-up or not.

    [​IMG]

    [​IMG]

    [​IMG]

    Code:
    Function New-ISO
    {
        <#
        .SYNOPSIS
            Create a new remastered bootable Windows Installation Media ISO.
        
        .DESCRIPTION
            This function remasters and creates bootable Windows Installation Media ISO files automatically without having to input the paths to the Windows ADK boot files.
            It does this by querying the registry keys that contain the path the Windows ADK is saved to, and then creating absolute paths to any required boot files for ISO creation.
        
        .PARAMETER MediaPath
            The full path to the Windows media content to be remastered into a new ISO.
        
        .PARAMETER SavePath
            An optional full path to the location where the new remastered ISO is to be saved.
        
        .PARAMETER ISOName
            An optional name of the new ISO file. If no name is supplied, the media name will be used.
        
        .PARAMETER ISOLabel
            An optional label for the new ISO file.
        
        .PARAMETER BootType
            Will create an ISO that prompts for user input upon boot-up, or an ISO that starts automatically with no user prompt.
            The default setting is no user prompt
        
        .EXAMPLE
            PS C:\> New-ISO -MediaPath "D:\WIN_10_PRO_WORKSTATIONS_17763.194" -SavePath "D:\" -ISOName "Win 10 Pro for Workstations" -ISOLabel "Windows 10 Pro for Workstations"
            PS C:\> New-ISO -MediaPath "D:\WIN_10_PRO_WORKSTATIONS_17763.194" -BootType "Prompt"
            PS C:\> "D:\WIN_10_PRO_WORKSTATIONS_17763.194" | New-ISO
        
        .NOTES
            Accepts pipe-line arguments for the media path for quick ISO remastering.
            The default save location is the user's temporary directory (%TEMP% or $Env:TEMP).
    #>
        
        [CmdletBinding()]
        [OutputType([PSCustomObject])]
        Param
        (
            [Parameter(Mandatory = $true,
                ValueFromPipeline = $true,
                ValueFromPipelineByPropertyName = $true,
                Position = 1,
                HelpMessage = 'The full path to the Windows media content to be remastered into a new ISO.')]
            [ValidateScript( { Test-Path $(Resolve-Path -Path $_) })]
            [string]$MediaPath,
            [Parameter(Mandatory = $false,
                HelpMessage = 'The full path to the location where the new remastered ISO is to be saved.')]
            [string]$SavePath = "$Env:TEMP\$((Get-Date).ToString('MMddyyyy-HHmmss')).iso",
            [Parameter(Mandatory = $false,
                HelpMessage = 'An optional name for the new ISO file.')]
            [ValidateNotNullOrEmpty()]
            [string]$ISOName = (Get-Date).ToString("MM.dd.yyyy-HHmmss"),
            [Parameter(Mandatory = $false,
                HelpMessage = 'An optional label for the new ISO File.')]
            [string]$ISOLabel = (Get-Date).ToString("MM.dd.yyyy-HHmmss"),
            [Parameter(HelpMessage = 'Determines whether the ISO requires a key-press during boot-up or not.')]
            [ValidateSet('Prompt', 'No-prompt')]
            [string]$BootType = "No-Prompt"
        )
        
        Begin
        {
            @("HKLM:\Software\Wow6432Node\Microsoft\Windows Kits\Installed Roots", "HKLM:\Software\Microsoft\Windows Kits\Installed Roots") | ForEach {
                If (Test-Path -Path $($_)) { $ADK_ROOT = Get-ItemProperty -Path $($_) -Name KitsRoot10 -ErrorAction SilentlyContinue | Select -ExpandProperty KitsRoot10 | Where { $($_) } }
            }
            $DEPLOYMENT_TOOLS = Join-Path -Path $ADK_ROOT -ChildPath ("Assessment and Deployment Kit" + '\' + "Deployment Tools")
            $OSCDIMG = Join-Path -Path $DEPLOYMENT_TOOLS -ChildPath ($Env:PROCESSOR_ARCHITECTURE + '\' + "Oscdimg")
        }
        Process
        {
            $BootFiles = (Get-ChildItem -Path $OSCDIMG -ErrorAction SilentlyContinue)
            If ($ISOName.EndsWith('.iso')) { $ISOName = $ISOName.Replace(' ', '_') }
            Else { $ISOName = $ISOName.Replace(' ', '') + '.iso' }
            If ($SavePath.EndsWith('.iso')) { $ISOName = [System.IO.Path]::GetFileNameWithoutExtension($SavePath).Replace(' ', '_') + '.iso'; $SavePath = Split-Path -Path $SavePath -Parent }
            $ISODest = Join-Path -Path $SavePath -ChildPath $ISOName
            Switch ($BootType)
            {
                'Prompt' { $BootCode = "efisys.bin"; $BootPrompt = $true }
                'No-Prompt' { $BootCode = "efisys_noprompt.bin"; $BootPrompt = $false }
            }
            If ((Test-Path -Path "$MediaPath\boot\etfsboot.com") -and (Test-Path -Path "$MediaPath\efi\Microsoft\boot\$BootCode")) { $BootData = '2#p0,e,b"{0}"#pEF,e,b"{1}"' -f "$MediaPath\boot\etfsboot.com", "$MediaPath\efi\Microsoft\boot\$BootCode" }
            ElseIf ($BootFiles.Name.Contains('etfsboot.com') -and $BootFiles.Name.Contains($BootCode)) { $BootData = '2#p0,e,b"{0}"#pEF,e,b"{1}"' -f "$OSCDIMG\etfsboot.com", "$OSCDIMG\$BootCode" }
            Else { Write-Warning "Missing required boot files."; Break }
            If ($ISOLabel) { $OscdimgArgs = @("-bootdata:${BootData}", "-u2", "-udfver102", "-l`"${ISOLabel}`"", "`"${MediaPath}`"", "`"${ISODest}`"") }
            Else { $OscdimgArgs = @("-bootdata:${BootData}", "-u2", "-udfver102", "`"${MediaPath}`"", "`"${ISODest}`"") }
            Try
            {
                Write-Host "Creating a Bootable ISO..." -NoNewline -ForegroundColor Cyan
                $Run = Start-Process -FilePath "$OSCDIMG\oscdimg.exe" -ArgumentList $OscdimgArgs -WindowStyle Hidden -Wait
                Write-Host "[Complete]" -ForegroundColor Cyan
            }
            Catch
            {
                $Run = "Failed to create $($ISOName), Error $($_)"
                Write-Warning $Run
                Break
            }
        }
        End
        {
            If ($?)
            {
                [PSCustomObject]@{
                    "ISO Name"    = $ISOName
                    "ISO Label"   = $ISOLabel
                    "Save Path"   = $SavePath
                    "Boot Prompt" = $BootPrompt
                } | Format-List
            }
        }
    }