Skip to content

download required oscdimg.exe as first step - #604

Open
rofl0r wants to merge 1 commit into
ntdevlabs:mainfrom
rofl0r:patch-1
Open

download required oscdimg.exe as first step#604
rofl0r wants to merge 1 commit into
ntdevlabs:mainfrom
rofl0r:patch-1

Conversation

@rofl0r

@rofl0r rofl0r commented Apr 22, 2026

Copy link
Copy Markdown

else it could happen that after hours of work the entire process fails if no internet connection is available at that moment. also keep the local copy, once downloaded.

else it could happen that after hours of work the entire process fails if no internet connection is available at that moment.
also keep the local copy, once downloaded.
@rofl0r

rofl0r commented Apr 22, 2026

Copy link
Copy Markdown
Author

the same should be done in tinycore.ps1.
or even better both scripts should be merged into one so one doesn't have to copy/paste every change to a second location. just add a command line parameter e.g. -c to build the core version, else the normal version.

@miticollo

Copy link
Copy Markdown

IMO, there is a better solution: not using oscdimg.exe.

#Requires -Version 5.1

#region Constants
Set-Variable -Name 'bootFiles' -Option Constant -Scope Global -Value @(
[PSCustomObject]@{
    'PlatformLabel'   = 'x86'
    'PlatformId'      = 0 # PlatformId.PlatformX86
    'File'            = 'boot\etfsboot.com'
},
[PSCustomObject]@{
    'PlatformLabel'   = 'EFI/UEFI'
    'PlatformId'      = 0xef # PlatformId.PlatformEFI
    'File'            = 'efi\microsoft\boot\efisys.bin'
}
)
#endregion

#region Functions
function New-Iso {
<#
.SYNOPSIS
    .

.DESCRIPTION
    .

.PARAMETER SourceDirectory
    Directory of files to burn.

.PARAMETER IsoPath
    .

.PARAMETER Label
    The volume name for this file system image.

.EXAMPLE
     New-Iso "$ScratchDisk\tiny11" "$PSScriptRoot\tiny11.iso"

.INPUTS
   None. You can't pipe objects to New-Iso.

.NOTES
    Author:  Lorenzo Ferron
    Twitter: @miticollo

.LINK
    https://learn.microsoft.com/en-us/windows/win32/imapi/creating-a-multisession-disc

.LINK
    https://learn.microsoft.com/en-us/windows/win32/api/imapi2fs/

.LINK
    https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/new-object?view=powershell-5.1

.LINK
    https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/stream-object-ado-reference

.LINK
    https://learn.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-istream#:~:text=Release

.LINK
    https://devblogs.microsoft.com/scripting/powertip-release-com-object-in-powershell/#post-7721
#>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        [Parameter(Mandatory=$true,Position=0)]
        [ValidateScript({
            if(Test-Path "$_" -PathType Container) {
                return $true
            }
            elseif(Test-Path "$_" -PathType Leaf) {
                throw 'The SourceDirectory parameter must be a folder. File paths are not allowed.'
            }
            throw 'Invalid File Path'
        })]
        [string]$SourceDirectory,
        [Parameter(Mandatory=$true,Position=1)]
        [ValidateNotNullOrEmpty()]
        [string]$IsoPath,
        [ValidatePattern('^[a-z0-9_\.]{0,15}$', Options = 'IgnoreCase')]
        [string]$Label = 'tiny11'
    )

    $code = @"
using System;
using System.IO;
using System.Runtime.Interop`Services;
using System.Runtime.Interop`Services.ComTypes;

public class dir2iso {
    [DllImport("shlwapi.dll", CharSet=CharSet.Unicode, PreserveSig=false)]
    internal static extern void SHCreateStreamOnFileEx(string pszFile, uint grfMode, uint dwAttributes, bool fCreate, IStream pstmTemplate, out IStream ppstm);

    public static int Create(string file, ref object stream, int bs, int tb) {
        IStream dir = (IStream)stream, iso;

        try {
            SHCreateStreamOnFileEx(file, 0x1001, 0x80, true, null, out iso);
        } catch(Exception e) {
            Console.WriteLine(e.Message);
            return 1;
        }

        int d=tb>1024 ? 1024 : 1, pad=tb%d, block=bs*d, total=(tb-pad)/d, c=total>100 ? total/100 : total, i=1, MB=(bs/1024)*tb/1024;
        Console.Write("\r\n{0,2}%  {1}MB  MakeISO", 0, MB);
        if (pad > 0) dir.CopyTo(iso, pad * block, Int`Ptr.Zero, Int`Ptr.Zero);
        while (total-- > 0) {
            dir.CopyTo(iso, block, Int`Ptr.Zero, Int`Ptr.Zero);
            if (total % c == 0) Console.Write("\r{0,2}%",i++);
        }
        iso.Commit(0);
        Console.WriteLine("\r{0,2}%  {1}MB  MakeISO", 100, MB);
        return 0;
    }
}
"@
    & {
        # https://github.com/PowerShell/PowerShell/issues/21070
        $CompilerParameters = [System.CodeDom.Compiler.CompilerParameters]::new("System.dll")
        $CompilerParameters.TempFiles = [System.CodeDom.Compiler.TempFileCollection]::new($env:TEMP, $false)
        $CompilerParameters.GenerateInMemory = $true #:: ` used to silence ps eventlog
        (New-Object Microsoft.CSharp.CSharpCodeProvider).CompileAssemblyFromSource($CompilerParameters, $code)

        $BOOT = @()

        # -------- Adding Boot Image Code -----
        $bootFiles | ForEach-Object -Process {
            Write-Output "Creating BootOptions ($(${_}.PlatformLabel))"
            $bootOptions = New-Object -ComObject 'IMAPI2FS.BootOptions'
            $bootOptions.Manufacturer = "Microsoft"
            $bootOptions.PlatformId   = ${_}.PlatformId

            # Need a stream for the boot image file
            $bootStream = New-Object -ComObject 'ADODB.Stream'
            # Path and filename of boot image
            $bootFile = Join-Path ${SourceDirectory} -child ${_}.File
            Write-Output "Creating IStream for file $bootFile"
            $bootStream.Mode = 3 # adModeReadWrite
            $bootStream.Type = 1 # adTypeBinary
            $bootStream.Open()
            # Load the file into the stream
            $bootStream.LoadFromFile("$bootFile")

            $bootOptions.AssignBootImage($bootStream.psobject.BaseObject)

            # Override the previously assigned EmulationType value
            $bootOptions.Emulation    = 0 # EmulationType.EmulationNone

            $BOOT += $bootOptions.psobject.BaseObject
        }

        # Create a new file system image object
        $FSI = New-Object -ComObject 'IMAPI2FS.MsftFileSystemImage'
        $FSI.ChooseImageDefaultsForMediaType(0xc) # IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK

        # Add the boot directories and their contents to the file system
        $FSI.BootImageOptionsArray = $BOOT

        # Add the directory and its contents to the file system
        Write-Output "Adding $SourceDirectory directory to the disc..."
        $FSI.Root.AddTree($SourceDirectory, $false)

        $FSI.VolumeName = "${Label}"

        # Create an image from the file system image object
        $result = $FSI.CreateResultImage()

        $BOOT | ForEach-Object -Process {
            ${_}.BootImage.Close()
            $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject(${_}.BootImage)
            $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject(${_})
        }

        $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($FSI)
        Remove-Variable FSI

        $stream = $result.ImageStream

        Write-Output ' '
        Write-Output "Saving $IsoPath..."

        if ($PSCmdlet.ShouldProcess('Create File', "Destination: $IsoPath")) {
            $ret = [dir2iso]::Create($IsoPath, [ref]$stream, $result.BlockSize, $result.TotalBlocks)
        } else {
            $ret = 0
        }

        $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($stream)
        Remove-Variable stream

        $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($result)
        Remove-Variable result
    }
    # call garbage collection to free up memory
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
    return $ret
}
#endregion

@rofl0r

rofl0r commented Aug 1, 2026

Copy link
Copy Markdown
Author

can you compress your finding into one or two sentences that dont require to read 100 lines of code?

@miticollo

Copy link
Copy Markdown

$FSI is the ISO content and to be bootable we must add boot options. So we have $BOOT, an array with two options for UEFI and BIOS legacy. The advantage is that oscdimg.exe is no more necessary because we can use Image Mastering API. This is the main example. But it is not complete because filesystem is not bootable in the example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants