Written by James McDonald

June 17, 2024

Usage

New-IsoFile -NewIsoFilePath C:\tmp\Hyper-V.iso-sources -ImageName Hyper-V -SourceFilePath 'C:\tmp\Hyper-V'

New-IsoFile -NewIsoFilePath C:\tmp\W2K3SP2CD1.iso -ImageName W2K3SP2CD1 -SourceFilePath 'C:\tmp\Windows 2003 Server R2 Std Edition SP2 CD1'
New-IsoFile -NewIsoFilePath C:\tmp\W2K3SP2CD2.iso -ImageName W2K3SP2CD2 -SourceFilePath 'C:\tmp\Windows 2003 Server R2 Std Edition SP2 CD2'
function New-IsoFile
{
  param
  (
    # path to local folder to store in 
    # new ISO file (must exist)
    [Parameter(Mandatory)]
    [String]
    $SourceFilePath,

    # name of new ISO image (arbitrary, 
    # turns later into drive label)
    [String]
    $ImageName = 'MyCDROM',

    # path to ISO file to be created
    [Parameter(Mandatory)]
    [String]
    $NewIsoFilePath,

    # if specified, the source base folder is
    # included into the image file
    [switch]
    $IncludeRoot
  )
    
  # use this COM object to create the ISO file:
  $fsi = New-Object -ComObject IMAPI2FS.MsftFileSystemImage

  # use this helper object to write a COM stream to a file:
  # compile the helper code using these parameters:
  $cp = [CodeDom.Compiler.CompilerParameters]::new()
  $cp.CompilerOptions = '/unsafe'
  $cp.WarningLevel = 4
  $cp.TreatWarningsAsErrors = $true
  $code = '
    using System;
    using System.IO;
    using System.Runtime.InteropServices.ComTypes;

    namespace CustomConverter
    {
     public static class Helper 
     {
      // writes a stream that came from COM to a filesystem file
      public static void WriteStreamToFile(object stream, string filePath) 
      {
       // open output stream to new file
       IStream inputStream = stream as IStream;
       FileStream outputFileStream = File.OpenWrite(filePath);
       int bytesRead = 0;
       byte[] data;

       // read stream in chunks of 2048 bytes and write to filesystem stream:
       do 
       {
        data = Read(inputStream, 2048, out bytesRead);  
        outputFileStream.Write(data, 0, bytesRead);
       } while (bytesRead == 2048);

       outputFileStream.Flush();
       outputFileStream.Close();
      }

      // read bytes from stream:
      unsafe static private byte[] Read(IStream stream, int byteCount, out int readCount) 
      {
       // create a new buffer to hold the read bytes:
       byte[] buffer = new byte[byteCount];
       // provide a pointer to the location where the actually read bytes are reported:
       int bytesRead = 0;
       int* ptr = &bytesRead;
       // do the read:
       stream.Read(buffer, byteCount, (IntPtr)ptr);   
       // return the read bytes by reference to the caller:
       readCount = bytesRead;
       // return the read bytes to the caller:
       return buffer;
      } 
     }
  }'

  Add-Type -CompilerParameters $cp -TypeDefinition $code

  # define the ISO file properties:

  # create CDROM, Joliet and UDF file systems
  $fsi.FileSystemsToCreate = 7 
  $fsi.VolumeName = $ImageName
  # allow larger-than-CRRom-Sizes
  $fsi.FreeMediaBlocks = -1    

  $msg = 'Creating ISO File - this can take a couple of minutes.'
  Write-Host $msg -ForegroundColor Green
    
  # define folder structure to be written to image:
  $fsi.Root.AddTreeWithNamedStreams($SourceFilePath,$IncludeRoot.IsPresent)
        
  # create image and provide a stream to read it:
  $resultimage = $fsi.CreateResultImage()
  $resultStream = $resultimage.ImageStream

  # write stream to file
  [CustomConverter.Helper]::WriteStreamToFile($resultStream, $NewIsoFilePath)

  Write-Host 'DONE.' -ForegroundColor Green

}

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.

You May Also Like…

List local disks

GET-CimInstance -query "SELECT * from Win32_DiskDrive" DeviceID Caption Partitions Size Model -------- -------...