Create an ISO file with PowerShell!
- Ben Liebowitz
- 34
- 43094
I received a request at work to transfer 5+gb from the internal network, to a server in the DMZ. Our DMZ networks are locked down, so I cannot copy the files directly. I have the trial version of UltraISO that I’ve used for tasks like this in the past, but it’s limited to 300mb in the trial version. Previously, we’ve used a “swing VMDK” that we’d mount on an internal VM, copy the data to it, take this VMDK and download it to my PC with something like WinSCP, then upload it to a DMZ datastore, mount it to the VM, etc. This can get messy, especially if you don’t remember to remove and delete the “swing VMDK”.
I decided to do some research online to see if I could use something like 7-zip or another tool to create the ISO. I happened upon a function that someone wrote for PowerShell to create an ISO via Microsoft’s Technet Script Center. I took the function, read through it to verify it wasn’t going to do anything malicious (which you should ALWAYS do before just blatantly running someone else’s code) and decided to try it.
Here’s the function itself:
function New-IsoFile { <# .Synopsis Creates a new .iso file .Description The New-IsoFile cmdlet creates a new .iso file containing content from chosen folders .Example New-IsoFile "c:\tools","c:Downloads\utils" This command creates a .iso file in $env:temp folder (default location) that contains c:\tools and c:\downloads\utils folders. The folders themselves are included at the root of the .iso image. .Example New-IsoFile -FromClipboard -Verbose Before running this command, select and copy (Ctrl-C) files/folders in Explorer first. .Example dir c:\WinPE | New-IsoFile -Path c:\temp\WinPE.iso -BootFile "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\efisys.bin" -Media DVDPLUSR -Title "WinPE" This command creates a bootable .iso file containing the content from c:\WinPE folder, but the folder itself isn't included. Boot file etfsboot.com can be found in Windows ADK. Refer to IMAPI_MEDIA_PHYSICAL_TYPE enumeration for possible media types: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366217(v=vs.85).aspx .Notes NAME: New-IsoFile AUTHOR: Chris Wu LASTEDIT: 03/23/2016 14:46:50 #> [CmdletBinding(DefaultParameterSetName='Source')]Param( [parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true, ParameterSetName='Source')]$Source, [parameter(Position=2)][string]$Path = "$env:temp\$((Get-Date).ToString('yyyyMMdd-HHmmss.ffff')).iso", [ValidateScript({Test-Path -LiteralPath $_ -PathType Leaf})][string]$BootFile = $null, [ValidateSet('CDR','CDRW','DVDRAM','DVDPLUSR','DVDPLUSRW','DVDPLUSR_DUALLAYER','DVDDASHR','DVDDASHRW','DVDDASHR_DUALLAYER','DISK','DVDPLUSRW_DUALLAYER','BDR','BDRE')][string] $Media = 'DVDPLUSRW_DUALLAYER', [string]$Title = (Get-Date).ToString("yyyyMMdd-HHmmss.ffff"), [switch]$Force, [parameter(ParameterSetName='Clipboard')][switch]$FromClipboard ) Begin { ($cp = new-object System.CodeDom.Compiler.CompilerParameters).CompilerOptions = '/unsafe' if (!('ISOFile' -as [type])) { Add-Type -CompilerParameters $cp -TypeDefinition @' public class ISOFile { public unsafe static void Create(string Path, object Stream, int BlockSize, int TotalBlocks) { int bytes = 0; byte[] buf = new byte[BlockSize]; var ptr = (System.IntPtr)(&bytes); var o = System.IO.File.OpenWrite(Path); var i = Stream as System.Runtime.InteropServices.ComTypes.IStream; if (o != null) { while (TotalBlocks-- > 0) { i.Read(buf, BlockSize, ptr); o.Write(buf, 0, bytes); } o.Flush(); o.Close(); } } } '@ } if ($BootFile) { if('BDR','BDRE' -contains $Media) { Write-Warning "Bootable image doesn't seem to work with media type $Media" } ($Stream = New-Object -ComObject ADODB.Stream -Property @{Type=1}).Open() # adFileTypeBinary $Stream.LoadFromFile((Get-Item -LiteralPath $BootFile).Fullname) ($Boot = New-Object -ComObject IMAPI2FS.BootOptions).AssignBootImage($Stream) } $MediaType = @('UNKNOWN','CDROM','CDR','CDRW','DVDROM','DVDRAM','DVDPLUSR','DVDPLUSRW','DVDPLUSR_DUALLAYER','DVDDASHR','DVDDASHRW','DVDDASHR_DUALLAYER','DISK','DVDPLUSRW_DUALLAYER','HDDVDROM','HDDVDR','HDDVDRAM','BDROM','BDR','BDRE') Write-Verbose -Message "Selected media type is $Media with value $($MediaType.IndexOf($Media))" ($Image = New-Object -com IMAPI2FS.MsftFileSystemImage -Property @{VolumeName=$Title}).ChooseImageDefaultsForMediaType($MediaType.IndexOf($Media)) if (!($Target = New-Item -Path $Path -ItemType File -Force:$Force -ErrorAction SilentlyContinue)) { Write-Error -Message "Cannot create file $Path. Use -Force parameter to overwrite if the target file already exists."; break } } Process { if($FromClipboard) { if($PSVersionTable.PSVersion.Major -lt 5) { Write-Error -Message 'The -FromClipboard parameter is only supported on PowerShell v5 or higher'; break } $Source = Get-Clipboard -Format FileDropList } foreach($item in $Source) { if($item -isnot [System.IO.FileInfo] -and $item -isnot [System.IO.DirectoryInfo]) { $item = Get-Item -LiteralPath $item } if($item) { Write-Verbose -Message "Adding item to the target image: $($item.FullName)" try { $Image.Root.AddTree($item.FullName, $true) } catch { Write-Error -Message ($_.Exception.Message.Trim() + ' Try a different media type.') } } } } End { if ($Boot) { $Image.BootImageOptions=$Boot } $Result = $Image.CreateResultImage() [ISOFile]::Create($Target.FullName,$Result.ImageStream,$Result.BlockSize,$Result.TotalBlocks) Write-Verbose -Message "Target image ($($Target.FullName)) has been created" $Target } }
With that, I was able to create a variable for my source data, and use get-childitem to get that location and pipe that to creating the ISO. See below:
$source_dir = "Z:\Install\App123" get-childitem "$source_dir" | New-ISOFile -path e:\iso\app123.iso
34 thoughts on “Create an ISO file with PowerShell!”
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Very Very cool. thanks for sharing.
No problem!
Reddit has taken to your code. https://www.reddit.com/r/PowerShell/comments/8r57pi/create_an_iso_file_with_powershell/
I think this ability should have been native a long time ago. thank you for your work and time with bringing this up.
It’s not my code, I found it somewhere and I’m sharing it because I found it useful!
Strongly Agree with “you should ALWAYS do before just blatantly running someone else’s code” thanks for mentioning it. Awesome work.
IMGBurn can also create an ISO from a folder or list of files.
Rather than uploading ISOs to datastores if it is a one-time thing, I open the console to the VM with VRMC and you can mount a local ISO direct from your computer. Once done, just unmount the iso or close the VRMC window and nothing left behind to clean up.
Yeah, I’ve done it that way too. I have an ISO folder on our file server that I share via NFS and present to my VMware hosts. This lets me put the ISOs on a network drive and still access them via my hosts. 🙂
Can I modify it to create a standard ISO 9660 ?
Yes, it creates a standard ISO file.
Great – worked like a charm!
Hi Ben,
nice Tool! I’m sitting in the Homeoffice and have to get some files into my VMs but they dont have internet access or some other local stuff. (Its an cutted development environment)
So i “ISO” the files i need, and bind the iso to the host where i can just use it as a CD.
Nice sharing!
but, there is a little grammar Error and could newbies think it wont work:
You call the Function with “New-ISOFile -path …
The Function itself is New-IsoFile.
I see how that could be confusing. I didn’t create the function and that’s just how I named MY script, you can save it with whatever name you wish. 🙂
Thank you very much for this!
It works, but I cannot boot from the created ISO file. I copied the content from a windows 10 x64 iso into a local folder, added the autounattend.xml and executed your script to create the ISO file. It doesn’t get detected in the VM as bootable media. What might the error be?
This script won’t create a boot able iso. I’m not sure what has to be done to do that. Sorry.
Hi! What PS version should I have installed? On PS 6.2.2 the script doesn’t work. There’s error:
Add-Type : A parameter cannot be found that matches parameter name ‘CompilerParameters’.
At E:\work\MSPV\New_ISOfile.psm1:99 char:16
+ Add-Type -CompilerParameters $cp -TypeDefinition @’
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Add-Type], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.AddTypeCommand
Unable to find type [ISOFile].
At E:\work\MSPV\New_ISOfile.psm1:157 char:5
+ [ISOFile]::Create($Target.FullName,$Result.ImageStream,$Result.Bl …
+ ~~~~~~~~~
+ CategoryInfo : InvalidOperation: (ISOFile:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
Note: I’ve saved your script as .psm1 file and referencing to it from main script using Import-Module for modularity sake. ) I’m on Windows 10 x64 Pro if that’s matter.
Sorry, I don’t have a lot of experience with .psm1 files. My script was saved as .ps1 and I was able to execute it in various PS versions. For me, most of the time, it was run on a Windows 2016 server running PS version 5.
Hi Ben,
Nice Post! Thank you so much for sharing this valuable post on Create an ISO file with PowerShell!. The code is working great! Keep sharing… Keep Sharing…
Cheers,
Abhay
Hi Ben,
Awesome Post! Thank you so much for sharing this informative post on creating an iso file with powershell. And it really works great & creates a standard ISO file. And I also want to suggest to add a section like this —> https://bit.ly/createiso .Keep up the Good Work… Keep Sharing…
Hope it helps 🙂
Thanks,
Abhay
It looks great, create the iso and all, but when I try to use theiso inside a VM, I get an error saying it’s not ISO 9660 standard, is there a way to fix and make it standard |?
I think it depends on what you’re looking to do with the ISO. Take a look at the Q&A tab from the URL below. This is the person I originally took the script from, as I called out in my post.
https://gallery.technet.microsoft.com/scriptcenter/New-ISOFile-function-a8deeffd/view/Discussions#content
Thanks for sharing
I have a problem to remove sorce folder after ISO has created (access dineid)
Did you run the command to unmount the ISO folder?
Works like a charm…
Thanks for sharing
Hi Ben,
Thank you for sharing such a nice tool,
I am not expert in PowerShell, so I could not get any result when I apply below two line of command
after I created the Skript and saved as CreatesIsoImage.ps1
Could you please help me how to make this script run in a way that it will create an iso file form the given path.
$source_dir=$source_dir=”D:\Zenon\V8.00.53129″
Get-ChildItem “$source_dir” | C:\Users\Guendogdu\Documents\PowerShellScripts\CreatesIsoImage.ps1 -path D:\ISO\V8.00.53129.iso
Here in my example D is portable SSD which is connected through USB 3.0 port.
Br
Volkan Gündogdu
You have to have the function New-IsoFile code at the top of the script for the New-ISOFile command to work.
$source_dir = “D:\Zenon\V8.00.53129”
get-childitem “$source_dir” | New-ISOFile -path d:\ISO\V8.00.53129.iso
very nice thank you. So usefull.
I can’t get the code to work…
Im on standard Windows 10.
I’ve created a file “New-IsoFile.ps1″ at my desktop”.
Originally I tryed to write the execure code in the bottom of the script to just point to my E-drive where my dvds show up, but could not get that to work.
Now I’ve made a seperate script file on my desktop called “Convert E-Drive to ISO.ps1” with the execute code in, but I can’t figure out how to run it like that.
Running the execute code in PS terminal produces an error:
—————–
New-IsoFile : The term ‘New-IsoFile’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.
At C:\Users\power\OneDrive\Skrivebord\Convert E-Drive to ISO.ps1:4 char:31
+ get-childitem “$source_dir” | New-IsoFile -path e:\iso\app123.iso
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (New-IsoFile:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
————————-
I’ve never done powershell before and I’m honestly a bit lost.
Is it possible to make a runnable script that will just grab the contents of the E-drive and create an .ISO-file at the same location as the script? I belive that would indeed be ease of use. 😉
First, I would combine the function and the execution of the function into the same script and save it.
function New-IsoFile
{
<# .Synopsis Creates a new .iso file .Description The New-IsoFile cmdlet creates a new .iso file containing content from chosen folders .Example New-IsoFile "c:\tools","c:Downloads\utils" This command creates a .iso file in $env:temp folder (default location) that contains c:\tools and c:\downloads\utils folders. The folders themselves are included at the root of the .iso image. .Example New-IsoFile -FromClipboard -Verbose Before running this command, select and copy (Ctrl-C) files/folders in Explorer first. .Example dir c:\WinPE | New-IsoFile -Path c:\temp\WinPE.iso -BootFile "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\efisys.bin" -Media DVDPLUSR -Title "WinPE" This command creates a bootable .iso file containing the content from c:\WinPE folder, but the folder itself isn't included. Boot file etfsboot.com can be found in Windows ADK. Refer to IMAPI_MEDIA_PHYSICAL_TYPE enumeration for possible media types: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366217(v=vs.85).aspx .Notes NAME: New-IsoFile AUTHOR: Chris Wu LASTEDIT: 03/23/2016 14:46:50 #>
[CmdletBinding(DefaultParameterSetName=’Source’)]Param(
[parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true, ParameterSetName=’Source’)]$Source,
[parameter(Position=2)][string]$Path = “$env:temp\$((Get-Date).ToString(‘yyyyMMdd-HHmmss.ffff’)).iso”,
[ValidateScript({Test-Path -LiteralPath $_ -PathType Leaf})][string]$BootFile = $null,
[ValidateSet(‘CDR’,’CDRW’,’DVDRAM’,’DVDPLUSR’,’DVDPLUSRW’,’DVDPLUSR_DUALLAYER’,’DVDDASHR’,’DVDDASHRW’,’DVDDASHR_DUALLAYER’,’DISK’,’DVDPLUSRW_DUALLAYER’,’BDR’,’BDRE’)][string] $Media = ‘DVDPLUSRW_DUALLAYER’,
[string]$Title = (Get-Date).ToString(“yyyyMMdd-HHmmss.ffff”),
[switch]$Force,
[parameter(ParameterSetName=’Clipboard’)][switch]$FromClipboard
)
Begin {
($cp = new-object System.CodeDom.Compiler.CompilerParameters).CompilerOptions = ‘/unsafe’
if (!(‘ISOFile’ -as [type])) {
Add-Type -CompilerParameters $cp -TypeDefinition @’
public class ISOFile
{
public unsafe static void Create(string Path, object Stream, int BlockSize, int TotalBlocks)
{
int bytes = 0;
byte[] buf = new byte[BlockSize];
var ptr = (System.IntPtr)(&bytes);
var o = System.IO.File.OpenWrite(Path);
var i = Stream as System.Runtime.InteropServices.ComTypes.IStream;
if (o != null) {
while (TotalBlocks– > 0) {
i.Read(buf, BlockSize, ptr); o.Write(buf, 0, bytes);
}
o.Flush(); o.Close();
}
}
}
‘@
}
if ($BootFile) {
if(‘BDR’,’BDRE’ -contains $Media) { Write-Warning “Bootable image doesn’t seem to work with media type $Media” }
($Stream = New-Object -ComObject ADODB.Stream -Property @{Type=1}).Open() # adFileTypeBinary
$Stream.LoadFromFile((Get-Item -LiteralPath $BootFile).Fullname)
($Boot = New-Object -ComObject IMAPI2FS.BootOptions).AssignBootImage($Stream)
}
$MediaType = @(‘UNKNOWN’,’CDROM’,’CDR’,’CDRW’,’DVDROM’,’DVDRAM’,’DVDPLUSR’,’DVDPLUSRW’,’DVDPLUSR_DUALLAYER’,’DVDDASHR’,’DVDDASHRW’,’DVDDASHR_DUALLAYER’,’DISK’,’DVDPLUSRW_DUALLAYER’,’HDDVDROM’,’HDDVDR’,’HDDVDRAM’,’BDROM’,’BDR’,’BDRE’)
Write-Verbose -Message “Selected media type is $Media with value $($MediaType.IndexOf($Media))”
($Image = New-Object -com IMAPI2FS.MsftFileSystemImage -Property @{VolumeName=$Title}).ChooseImageDefaultsForMediaType($MediaType.IndexOf($Media))
if (!($Target = New-Item -Path $Path -ItemType File -Force:$Force -ErrorAction SilentlyContinue)) { Write-Error -Message “Cannot create file $Path. Use -Force parameter to overwrite if the target file already exists.”; break }
}
Process {
if($FromClipboard) {
if($PSVersionTable.PSVersion.Major -lt 5) { Write-Error -Message ‘The -FromClipboard parameter is only supported on PowerShell v5 or higher’; break }
$Source = Get-Clipboard -Format FileDropList
}
foreach($item in $Source) {
if($item -isnot [System.IO.FileInfo] -and $item -isnot [System.IO.DirectoryInfo]) {
$item = Get-Item -LiteralPath $item
}
if($item) {
Write-Verbose -Message “Adding item to the target image: $($item.FullName)”
try { $Image.Root.AddTree($item.FullName, $true) } catch { Write-Error -Message ($_.Exception.Message.Trim() + ‘ Try a different media type.’) }
}
}
}
End {
if ($Boot) { $Image.BootImageOptions=$Boot }
$Result = $Image.CreateResultImage()
[ISOFile]::Create($Target.FullName,$Result.ImageStream,$Result.BlockSize,$Result.TotalBlocks)
Write-Verbose -Message “Target image ($($Target.FullName)) has been created”
$Target
}
}
$source_dir = “Z:\Install\App123”
get-childitem “$source_dir” | New-ISOFile -path e:\iso\app123.iso
Then, open a powershell window, and execute the file:
.\New-IsoFile.ps1
Excellent
Thanks for sharing. The original link is dead now but this was really helpful.
Also someone suggested creating bootable ISOs,
This will do that. (Windows boot ISOs in my case)
Instructions in the script comments up the top.
I’m glad to hear this script is still useful!
Thank you for your efforts.
Unfortunately, this one works for 5.1 only.
I’m using PS 7.
I’ve found a more universal script that works with both of them.
https://thedotsource.com/2021/03/16/building-iso-files-with-powershell-7/
Thanks for sharing.