Last active
July 20, 2024 19:10
-
-
Save marnix/3944688 to your computer and use it in GitHub Desktop.
Demo for PowerShell script to create ISO using IMAPI COM component, as a simplification for StackOverflow answer http://stackoverflow.com/a/8325316/223837
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Inspiration from | |
# | |
# http://blogs.msdn.com/b/opticalstorage/archive/2010/08/13/writing-optical-discs-using-imapi-2-in-powershell.aspx | |
# | |
# and | |
# | |
# http://tools.start-automating.com/Install-ExportISOCommand/ | |
# | |
# with help from | |
# | |
# http://stackoverflow.com/a/9802807/223837 | |
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 http://stackoverflow.com/a/9037299/223837 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) | |
} | |
# Constants from http://msdn.microsoft.com/en-us/library/windows/desktop/aa364840.aspx | |
$FsiFileSystemISO9660 = 1 | |
$FsiFileSystemJoliet = 2 | |
$fsi = New-Object -ComObject IMAPI2FS.MsftFileSystemImage | |
$fsi.FileSystemsToCreate = $FsiFileSystemISO9660 + $FsiFileSystemJoliet | |
$fsi.VolumeName = "demo image" | |
$fsi.Root.AddTree("my folder", $true) | |
WriteIStreamToFile $fsi.CreateResultImage().ImageStream "demo.iso" |
@newkit Apologies for the delay, I missed this comment completely. This code is in the public domain.
Doesn't work in PS 6.2.2:
Add-Type : A parameter cannot be found that matches parameter name 'CompilerParameters'.
At E:\work\MSPV\New_ISOfile.ps1:19 char:11
+ Add-Type -CompilerParameters $cp -TypeDefinition @"
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Add-Type], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.AddTypeCommand
Unable to find type [My.FileUtil].
At E:\work\MSPV\New_ISOfile.ps1:52 char:2
+ [My.FileUtil]::WriteIStreamToFile($istream, $fileName)
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (My.FileUtil:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
Corresponding (see just above) question on Stack Overflow:
https://stackoverflow.com/questions/57754249/code-works-perfectly-in-powershell-5-but-not-in-powershell-6
@AbdElraoufSabri, thanks. That's good. More universal approach. I'll give it a go.
As for above it's working as well. We only need to check PS Version and use corresponding Compiler Options/Parameters. Works like a charm and pretty fast.
$PSV = $PSVersionTable.PSVersion.Major
if ($PSV -ge 6) {
$cp = "/unsafe"
Add-Type -CompilerOptions $cp -TypeDefinition $typedef
}
elseif ($PSV -le 5 -and $PSV -ge 3) {
$cp = New-Object CodeDom.Compiler.CompilerParameters
$cp.CompilerOptions = "/unsafe"
$cp.WarningLevel = 4
$cp.TreatWarningsAsErrors = $true
Add-Type --CompilerParameters $cp -TypeDefinition $typedef
}
....
Write IStream to File here.
....
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Under which license is this code?