Brilliant little tool Hrisan Dzhankardashliyski at Powershell.com
http://powershell.com/cs/media/p/49052.aspx
Edit: updated the script block to enable copy & paste 😀
# Author: Hrisan Dzhankardashliyski # Date: 20/05/2015 # Inspiration from # # http://blogs.msdn.com/b/opticalstorage/archive/2010/08/13/writing-optical-discs-using-imapi-2-in-powershell.aspx</a> # # and # # http://tools.start-automating.com/Install-ExportISOCommand/</a> # # with help from # # http://stackoverflow.com/a/9802807/223837</a> $InputFolder = "" function WriteIStreamToFile([__ComObject] $istream, [string] $fileName) { # NOTE: We cannot use [System.Runtime.InteropServices.ComTypes.IStream], # since PowerShell apparently cannot convert an IStream COM object to this # Powershell type. (See <a href="http://stackoverflow.com/a/9037299/223837">http://stackoverflow.com/a/9037299/223837</a> for # details.) # # It turns out that .NET/CLR _can_ do this conversion. # # That is the reason why method FileUtil.WriteIStreamToFile(), below, # takes an object, and casts it to an IStream, instead of directly # taking an IStream inputStream argument. $cp = New-Object CodeDom.Compiler.CompilerParameters $cp.CompilerOptions = "/unsafe" $cp.WarningLevel = 4 $cp.TreatWarningsAsErrors = $true Add-Type -CompilerParameters $cp -TypeDefinition @" using System; using System.IO; using System.Runtime.InteropServices.ComTypes; namespace My { public static class FileUtil { public static void WriteIStreamToFile(object i, string fileName) { IStream inputStream = i as IStream; FileStream outputFileStream = File.OpenWrite(fileName); int bytesRead = 0; int offset = 0; byte[] data; do { data = Read(inputStream, 2048, out bytesRead); outputFileStream.Write(data, 0, bytesRead); offset += bytesRead; } while (bytesRead == 2048); outputFileStream.Flush(); outputFileStream.Close(); } unsafe static private byte[] Read(IStream stream, int toRead, out int read) { byte[] buffer = new byte[toRead]; int bytesRead = 0; int* ptr = &bytesRead; stream.Read(buffer, toRead, (IntPtr)ptr); read = bytesRead; return buffer; } } } "@ [My.FileUtil]::WriteIStreamToFile($istream, $fileName) } # The Function defines the ISO parameturs and writes it to file function createISO([string]$VolName,[string]$Folder,[bool]$IncludeRoot,[string]$ISOFile){ # Constants from <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa364840.aspx">http://msdn.microsoft.com/en-us/library/windows/desktop/aa364840.aspx</a> $FsiFileSystemISO9660 = 1 $FsiFileSystemJoliet = 2 $FsiFileSystemUDF = 4 $fsi = New-Object -ComObject IMAPI2FS.MsftFileSystemImage #$fsi.FileSystemsToCreate = $FsiFileSystemISO9660 + $FsiFileSystemJoliet $fsi.FileSystemsToCreate = $FsiFileSystemUDF #When FreeMediaBlocks is set to 0 it allows the ISO file to be with unlimited size $fsi.FreeMediaBlocks = 0 $fsi.VolumeName = $VolName $fsi.Root.AddTree($Folder, $IncludeRoot) WriteIStreamToFile $fsi.CreateResultImage().ImageStream $ISOFile } Function Get-Folder($initialDirectory) { [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") $foldername = New-Object System.Windows.Forms.FolderBrowserDialog $foldername.rootfolder = "MyComputer" if($foldername.ShowDialog() -eq "OK") { $folder += [string]$foldername.SelectedPath } return $folder } # Show an Open Folder Dialog and return the directory selected by the user. function Read-FolderBrowserDialog([string]$Message, [string]$InitialDirectory, [switch]$NoNewFolderButton) { $browseForFolderOptions = 0 if ($NoNewFolderButton) { $browseForFolderOptions += 512 } $app = New-Object -ComObject Shell.Application $folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory) if ($folder) { $selectedDirectory = $folder.Self.Path } else { $selectedDirectory = '' } [System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null return $selectedDirectory } #Prompts the user to save the ISO file, if the files does not exists it will create it otherwise overwrite without prompt Function Get-SaveFile($initialDirectory) { [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog $SaveFileDialog.CreatePrompt = $false $SaveFileDialog.OverwritePrompt = $false $SaveFileDialog.initialDirectory = $initialDirectory $SaveFileDialog.filter = "ISO files (*.iso)| *.iso" $SaveFileDialog.ShowHelp = $true $SaveFileDialog.ShowDialog() | Out-Null $SaveFileDialog.filename } # Show message box popup and return the button clicked by the user. function Read-MessageBoxDialog([string]$Message, [string]$WindowTitle, [System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::None) { Add-Type -AssemblyName System.Windows.Forms return [System.Windows.Forms.MessageBox]::Show($Message, $WindowTitle, $Buttons, $Icon) } # GUI interface for the PowerShell script [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") #loading the necessary .net libraries (using void to suppress output) $Form = New-Object System.Windows.Forms.Form #creating the form (this will be the "primary" window) $Form.Text = "ISO Creator Tool:" $Form.Size = New-Object System.Drawing.Size(600,300) #the size in px of the window length, height $Form.FormBorderStyle = 'FixedDialog' $Form.MaximizeBox = $false $Form.MinimizeBox = $false $objLabel = New-Object System.Windows.Forms.Label $objLabel.Location = New-Object System.Drawing.Size(20,20) $objLabel.Size = New-Object System.Drawing.Size(120,20) $objLabel.Text = "Please select a Folder:" $Form.Controls.Add($objLabel) $InputBox = New-Object System.Windows.Forms.TextBox $InputBox.Location = New-Object System.Drawing.Size(150,20) $InputBox.Size = New-Object System.Drawing.Size(300,20) $InputBox.Enabled = $false $Form.Controls.Add($InputBox) $objLabel2 = New-Object System.Windows.Forms.Label $objLabel2.Location = New-Object System.Drawing.Size(20,80) $objLabel2.Size = New-Object System.Drawing.Size(120,20) $objLabel2.Text = "ISO File Name:" $Form.Controls.Add($objLabel2) $InputBox2 = New-Object System.Windows.Forms.TextBox $InputBox2.Location = New-Object System.Drawing.Size(150,80) $InputBox2.Size = New-Object System.Drawing.Size(300,20) $InputBox2.Enabled = $false $Form.Controls.Add($InputBox2) $objLabel3 = New-Object System.Windows.Forms.Label $objLabel3.Location = New-Object System.Drawing.Size(20,50) $objLabel3.Size = New-Object System.Drawing.Size(120,20) $objLabel3.Text = "ISO Volume Name:" $Form.Controls.Add($objLabel3) $InputBox3 = New-Object System.Windows.Forms.TextBox $InputBox3.Location = New-Object System.Drawing.Size(150,50) $InputBox3.Size = New-Object System.Drawing.Size(150,20) $Form.Controls.Add($InputBox3) $objLabel4 = New-Object System.Windows.Forms.Label $objLabel4.Location = New-Object System.Drawing.Size(20,120) $objLabel4.Size = New-Object System.Drawing.Size(120,20) $objLabel4.Text = "Status Msg:" $Form.Controls.Add($objLabel4) $InputBox4 = New-Object System.Windows.Forms.TextBox $InputBox4.Location = New-Object System.Drawing.Size(150,120) $InputBox4.Size = New-Object System.Drawing.Size(200,20) $InputBox4.Enabled = $false $InputBox4.Text = "Set ISO Parameters..." $InputBox4.BackColor = "LimeGreen" $Form.Controls.Add($InputBox4) $Button = New-Object System.Windows.Forms.Button $Button.Location = New-Object System.Drawing.Size(470,20) $Button.Size = New-Object System.Drawing.Size(80,20) $Button.Text = "Browse" $Button.Add_Click({ $InputBox.Text=Read-FolderBrowserDialog $InputBox4.Text = "Set ISO Parameters..." }) $Form.Controls.Add($Button) $Button2 = New-Object System.Windows.Forms.Button $Button2.Location = New-Object System.Drawing.Size(470,120) $Button2.Size = New-Object System.Drawing.Size(80,80) $Button2.Text = "CreateISO" $Button2.Add_Click({ if(($InputBox.Text -eq "") -or ($InputBox3.Text -eq "")){ Read-MessageBoxDialog "You have to select folder and specify ISO Volume Name" "Error: No Parameters entered!" } else{ $SaveDialog = Get-SaveFile #If you click cancel when save file dialog is called if ($SaveDialog -eq ""){ return } $InputBox2.Text= $SaveDialog $InputBox2.Refresh() if($checkBox1.Checked){ $includeRoot=$true } else{ $includeRoot=$false } $InputBox4.BackColor = "Red" $InputBox4.Text = "Generating ISO File!" $InputBox4.Refresh() createISO $InputBox3.Text $InputBox.Text $includeRoot $InputBox2.Text $InputBox4.BackColor = "LimeGreen" $InputBox4.Text = "ISO Creation Finished!" $InputBox4.Refresh() } }) $Form.Controls.Add($Button2) $objLabel5 = New-Object System.Windows.Forms.Label $objLabel5.Location = New-Object System.Drawing.Size(20,160) $objLabel5.Size = New-Object System.Drawing.Size(280,20) $objLabel5.Text = "Check the box if you want to include the top folder:" $Form.Controls.Add($objLabel5) $checkBox1 = New-Object System.Windows.Forms.CheckBox $checkBox1.Location = New-Object System.Drawing.Size(300,156) $Form.Controls.Add($checkBox1) $Form.Add_Shown({$Form.Activate()}) [void] $Form.ShowDialog()
Enjoy!
Dan
Glen Flint
Hi Dan,
Thanks for this helpful post!
Is there a way to set the Copyright File Identifier and Volume Modification Date and Time?
These are part of the ECMA-119 standard, but are not filled by the default IMAPI2FS.MsftFileSystemImage.
Dan
Hi Glen
Can’t answer that one sorry 🙁
I would be interested to know how you went with it though so feel free to post back your findings
Cheers
Dan
John
Any chance you could put this up in a gist or something so we can download the file without the html formatting?
Dan
Hi John,
I’ve changed the script block method I use. Others try to encourage me to use GitHub etc but in some ways I am still a bit old fashioned 😀
This should work for you
Cheers
Dan