Information
The way Windows operating system is delivered and installed has changed quite a lot from days when Windows 3.0 was delivered on 6 floppy disks. To install, you booted PC from floppy 1, which in its turn asked you to eject it and insert floppy 2 to continue, and so on. Fully installed, Windows 3.0 took 5 MB (no, that's not a typo!) space on hard disk.
Windows 95, although also available as a set of 13 Distribution Media Formatted floppies (DMF to allow each floppy to store more than then standard 1.44MB) was first one to be distributed on CD, Windows XP last one on CD and Vista first one on DVD, size of install media jumping from XP's under 650 MB to Vista's over 3 GB thus forcing the change of media.
With Windows 10 Microsoft took a big step towards fully electronic distribution; although you can still order Windows 10 on USB flash drive, most of its delivery is done through downloaded ISO images.
When a user earlier got the physical install media in a box, today the box usually only contains a license, product key and download instructions. To make the install media is left for users themselves.
Windows Media Creation Tool (
tutorial) can create a USB install media but for instance users downloading
Windows Insider ISO images or wanting a custom install media need to create USB install media by themselves.
This tutorial contains a
PowerShell script for creating a bootable USB Windows 10 install media. No additional third party tools is required. Tutorial will continue where
PowerShell Scripting - The Basics General Tips Tutorials ended, breaking the script in parts explaining how it was made.
Please notice that script in tutorial is for creating install media for UEFI based computers with GPT partitioning.
Contents
Use links below to go to any part, back button of your browser to return to this list.
Note
The
Quick Start, first part of tutorial is for those who found here searching a quick way to create Windows 10 install USB. If you are not interested in "
under the hood" stuff, how the script works and how it's built simply get the script and run it as told in Quick Start and forget the rest of the tutorial.
The other parts labelled as
Making a script are then for those users interested in how to plan and start making scripts. Tutorial will not detail every line in sample script in question, instead it will show how to get started. Going through these parts is not required in any way to be able to use the script for what's it made for, to create USB install media.
If you get interested in PS scripting, you can find excellent sample scripts and instructions on
Microsoft TechNet Script Center and PowerShell pages on
docs.microsoft.com:
-
Windows PowerShell Scripting
-
PowerShell Scripting | Microsoft Docs
1: Quick Start
Save the script & run it
1.1) The script:
Code:
##########################################################
# Creating a bootable USB drive for installing Windows
# on UEFI / GPT systems
##########################################################
##########################################################
# Start by clearing the screen, tell user how to start
##########################################################
cls
Write-Host
Write-Host ' Plug in a USB flash (thumb) drive, recommended'
Write-Host ' size (standard W10 install media) 6 GB or more.'
Write-Host
Write-Host ' Notice: Remove all other USB flash drives'
Write-Host ' leaving only the one to be used connected.'
Write-Host
Write-Host ' If more than 1 USB flash drives are connected'
Write-Host ' this process will fail.'
Write-Host
Write-Host ' External USB hard disks may remain connected,'
Write-Host ' just remove all additional USB flash drives.'
Write-Host
##########################################################
# Pause to wait a key to be pressed, then check connected
# disks showing their name and ID asking user to select
# the USB flash drive to be used. Showing clear warning to
# user with magenta text color to be sure user understands
# risks involved, cleaning wrong disk will cause issues!
##########################################################
pause
cls
Write-Host
Write-Host 'Checking connected disks. This might take a while...'
Write-Host
Get-Disk | Format-Table Number, Friendlyname, HealthStatus, PartitionStyle,
@{n='Size';e={[int]($_.Size/1GB)}}
Write-Host
Write-Host ' Above is a list of all your connected disks.'
Write-Host ' Size is given in full gigabytes (GB).'
Write-Host
Write-Host ' Enter the Disk Number (left column) for USB'
Write-Host ' flash (thumb) drive to be made as bootable'
Write-Host ' Windows install media.'
Write-Host
Write-Host '############################################################' -ForeGround Magenta
Write-Host '# Be extremely careful! #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# Selected disk will be wiped clean and formatted. #' -ForeGround Magenta
Write-Host '# Selecting wrong disk, you will lose any data on it. #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# Accidentally selecting disk containing Windows, you will #' -ForeGround Magenta
Write-Host '# make it unbootable, in which case you will lose all your #' -ForeGround Magenta
Write-Host '# installed software and personal user files and folders! #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# If you are unsure, press CTRL + C to abort now. #' -ForeGround Magenta
Write-Host '############################################################' -ForeGround Magenta
Write-Host
##########################################################
# Getting the USB ID number from user, asking one more
# time if user is sure and wants to proceed. To avoid any
# liability issues, user is asked not only to press a key
# but clearly type YES. If a wrong disk fill be cleaned
# and formatted after this, it's caused by user not script
##########################################################
$USBNUMBER = Read-Host -Prompt ' Enter your selection, and press Enter'
cls
Write-Host
Write-Host ' Are you sure?'
Write-Host
Write-Host ' Selected disk will be completely wiped and formatted!'
Write-Host
Write-Host ' Please type YES (not case sensitive) and press Enter'
Write-Host ' to confirm, any other key or string + Enter to exit.'
Write-Host
$AreYouSure = Read-Host -Prompt ' Type YES and press Enter to confirm'
if ($AreYouSure -ne 'YES')
{exit}
cls
Write-Host
Write-Host ' Wiping USB flash drive clean & formatting it'
Clear-Disk -Number $USBNUMBER -RemoveData
New-Partition -DiskNumber $USBNUMBER -UseMaximumSize -AssignDriveLetter
$USBDrive = Get-WmiObject Win32_Volume -Filter "DriveType='2'"
$USBDrive = $USBDrive.DriveLetter
Format-Volume -NewFileSystemLabel "W10 USB" -FileSystem FAT32 -DriveLetter $USBDrive.Trim(":", " ")
$USBDrive = ($USBDrive + '\')
##########################################################
# USB flash drive cleaned and formatted, asking user to
# mount ISO and enter its drive letter. Entered drive
# letter or path will be written to variable $ISOFolder
##########################################################
cls
Write-Host
Write-Host ' Right click a Windows 10 ISO image and select "Mount".'
Write-Host
Write-Host ' When done, enter the drive letter of mounted ISO'
Write-Host ' below and press Enter.'
Write-Host
Write-Host ' If you want to add additional files and folders to USB,'
Write-Host ' copy the the contents of mounted ISO to a folder. Copy'
Write-Host ' additional content for instance customised "autounattend.xml"'
Write-Host ' for unattended "Hands-Free" installation, driver installers'
Write-Host ' and such to same folder, enter the path to that folder'
Write-Host ' and press Enter.'
Write-Host
Write-Host ' Examples:'
Write-Host ' - ISO mounted as drive F:, no additional content required, enter F'
Write-Host ' - ISO contents copied to "D:\ISO_Files", enter D:\ISO_Files'
Write-Host ' - ISO contents copied to "X:\MyStuff\ISO", enter X:\MyStuff\ISO'
Write-Host
$ISOFolder = Read-Host -Prompt ' Enter path to source folder, press Enter'
##########################################################
# Check if path entered by user is a drive letter by
# checking its length. If length is a single character,
# it is a drive letter for mounted ISO in which case we
# add a colon (:) to variable value, X becoming X:
##########################################################
if ($ISOFolder.length -eq 1)
{$ISOFolder = $ISOFolder + ":"}
##########################################################
# Check if entered mounted ISO or path to folder contains
# \Sources\install.wim (or install.esd) file (single bit
# architecture ISO), or in case of dual architecture ISO
# if install.wim (or install.esd) file can be found either
# in \x86\Sources or \x64\Sources folder or both of them.
#
# If install.wim or install.esd file is not found, given
# mounted ISO or folder path does not contain valid
# W10 install files in which case script is aborted.
##########################################################
$WimCount = 0
if ((Test-Path $ISOFolder\Sources\install.wim) -or
(Test-Path $ISOFolder\x86\Sources\install.wim) -or
(Test-Path $ISOFolder\x64\Sources\install.wim) -or
(Test-Path $ISOFolder\Sources\install.esd) -or
(Test-Path $ISOFolder\x86\Sources\install.esd) -or
(Test-Path $ISOFolder\x64\Sources\install.esd))
{$WimCount = 1}
else
{
cls
Write-Host
Write-Host ' No Windows 10 installation files found.'
Write-Host ' Please check mounted ISO letter or path'
Write-Host ' to folder containing installation files'
Write-Host ' and run script again.'
Write-Host
Pause
Exit
}
##########################################################
# Copying ISO content to USB flash drive
##########################################################
cls
$Files = Get-ChildItem -Path $ISOFolder -Recurse
$FileCount = $Files.count
$i=0
Foreach ($File in $Files) {
$i++
Write-Progress -activity "Copying files to USB. Get a cup of java or shot of single malt, this will take a few minutes..." -status "$File ($i of $FileCount)" -percentcomplete (($i/$FileCount)*100)
if ($File.psiscontainer) {$SourcefileContainer = $File.parent} else {$SourcefileContainer = $File.directory}
$RelativePath = $SourcefileContainer.fullname.SubString($ISOFolder.length)
Copy-Item $File.fullname ($USBDrive + $RelativePath)
}
##########################################################
# Telling user a bootable USB flash drive has been created
# and showing "Free to share" plus credits
##########################################################
cls
Write-Host
Write-Host ' Bootable Windows 10 USB drive for installing'
Write-Host ' Windows 10 on UEFI / GPT computers created.'
Write-Host
Write-Host ' You are free to edit and share this script'
Write-Host ' as long as source TenForums.com is mentioned'
Write-Host
Write-Host ' More Windows 10 tips, tricks, videos & tutorials at'
Write-Host ' https://www.tenforums.com'
Write-Host
Write-Host ' Twitter.com/TenForums -- Facebook.com/TenForums'
Write-Host
Write-Host ' Script by Kari'
Write-Host ' - TenForums.com/members/kari.html'
Write-Host ' - Twitter.com/KariTheFinn'
Write-Host ' - YouTube.com/KariTheFinn'
Write-Host
Write-Host
1.2) Open an elevated (Run as administrator)
PowerShell ISE:
- Click Start > W > Windows PowerShell
- Right click Windows PowerShell ISE
- Select Run as administrator
1.3 Open the
Script pane:
1.4) Copy the code from 1.1, paste it in script editor. You can resize script editor as you wish (#1 in screenshot), show / hide it (#2). If the
Command Add-on at right is taking too much place you can resize it or hide it completely (#3):
1.5) Save the script (File > Save as) as
CreateUSB.ps1. The extension .ps1 tells Windows it is a PowerShell script
Tip
I recommend creating a folder for your PS scripts. In my case I have it on OneDrive in folder %userprofile%\OneDrive\PS Scripts to allow me to share and use scripts on all connecting devices.
1.6) If you'd rather download the script, download from here:
- As a PS script file:
CreateUSB.ps1
- As a text file:
CreateUSB.txt
Note
Notice if downloading script as
PS script (.ps1) file: Running downloaded third party scripts in PowerShell by default requires execution policy being changed from default
Restricted mode. See step 2.2 in this tutorial for more information:
PowerShell Scripting - The Basics General Tips Tutorials
If you download script as a text file, open in
Notepad, copy all text and paste it in PS ISE script editor as told in
1.4, then save it as told in
1.5, it will be a local script which can be run simply by changing local script policy:
(Screenshot from step 2.2 in this tutorial:
PowerShell Scripting - The Basics General Tips Tutorials )
1.7) You can now hide script pane (see 1.4) and run the script simply by pressing
F5 or selecting
Run from
File menu. Follow the on-screen instructions to create a bootable Windows 10 install media on USB flash drive:
1.8) In the future when you want to run the script, open elevated (admin)
PS ISE, open the script (File > Open), hide the script pane and press
F5
1.9) To manually run this script on an elevated normal PowerShell or PowerShell ISE, type
& sign followed by a space and full path in quotes and hit
Enter:
& "D:\My PS Scripts\CreateUSB.ps1"
If script is in current PS or PS ISE working folder it can also be started by typing
.\<ScriptName.ps1>:
.\CreateUSB.ps1
1.10) Notice that when running the script, Windows will detect newly cleaned USB flash drive and will prompt you to format it. Click
Cancel to close the prompt,
do not in any case click Format!
When script has formatted USB drive, Windows Explorer will open showing it. You can close Explorer immediately when it happens
2: Making a script - Think ahead
Plan what and in which order will be done
2.1) Of course you can just start typing your code without any advanced planning, but the longer and more complicated the script will be, the better to spend some time outlining it first
2.2) In this sample case I wrote myself a short synopsis in Notepad, listing what should be done and in which order. My plan:
- Opening greetings (explain purpose)
- Check connected disks, ask user which one is target (USB flash drive)
- Wipe USB clean, format it
- Ask source (mounted W10 ISO or folder where ISO contents is copied to)
- Check if valid W10 install media (simple check > if install.wim / install.esd exists)
- If not valid > abort
- If valid > copy ISO or folder contents to USB
- End > tell user USB install media has been created
2.3) It looks simple, not worth even telling but I promise you, making a script this long without a plan, just starting to type is much more difficult. It is also easier to stay focused when you have split the script in advance in modules. A good outline helps you stay oriented and can surprisingly often help you to debug it; finding errors in script is easier when you calm down and check your outline
3: Making a script - Start coding
From plan to action
3.1) Open elevated PS ISE. Some scripts do not require elevation but as this sample one will wipe and format a USB drive, elevation is required. For simple file handling scripts you can use a normal user mode PS.
3.2) Expand script pane. In this script, I started simply by entering code to clear the screen and show the user general purpose of the script:
Code:
cls
Write-Host
Write-Host ' Plug in a USB flash (thumb) drive, recommended'
Write-Host ' size (standard W10 install media) 6 GB or more.'
Write-Host
Write-Host ' Notice: Remove all other USB flash drives'
Write-Host ' leaving only the one to be used connected.'
Write-Host
Write-Host ' If more than 1 USB flash drives are connected'
Write-Host ' this process will fail.'
Write-Host
Write-Host ' External USB hard disks may remain connected,'
Write-Host ' just remove all additional USB flash drives.'
Write-Host
pause
3.3) When done, I can check if it works and looks as I wanted by pressing
F5:
3.4) OK, it works. Next step: check all connected disks using
Get-Disk cmdlet, show them in formatted table with disk number, name, status, partition system and size in GB. Notice that because I want output to end user remaining as clear as possible, I again clear the screen first with cls and use additional Write-Host cmdlets without any output to create empty lines to make text more readable:
Code:
cls
Write-Host
Write-Host 'Checking connected disks. This might take a while...'
Write-Host
Get-Disk | Format-Table Number, Friendlyname, HealthStatus, PartitionStyle,
@{n='Size';e={[int]($_.Size/1GB)}}
3.5) Again I'll check if it works, pressing
F5 runs the script:
3.6) The next steps, following lines in script include cleaning, wiping the USB flash drive user selects empty. Because this involves risks, an accidentally selected Windows system disk would effectively ruin Windows installation and remove user data, I want to explain to user what's happening and add a warning using a different text colour (magenta looks alarming enough on blue background!).
Code from above in 3.4 plus explanation and warning added, finally reading user input (USB flash drive number) to variable
$USBNUMBER:
Code:
cls
Write-Host
Write-Host 'Checking connected disks. This might take a while...'
Write-Host
Get-Disk | Format-Table Number, Friendlyname, HealthStatus, PartitionStyle,
@{n='Size';e={[int]($_.Size/1GB)}}
Write-Host
Write-Host ' Above is a list of all your connected disks.'
Write-Host ' Size is given in full gigabytes (GB).'
Write-Host
Write-Host ' Enter the Disk Number (left column) for USB'
Write-Host ' flash (thumb) drive to be made as bootable'
Write-Host ' Windows install media.'
Write-Host
Write-Host '############################################################' -ForeGround Magenta
Write-Host '# Be extremely careful! #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# Selected disk will be wiped clean and formatted. #' -ForeGround Magenta
Write-Host '# Selecting wrong disk, you will lose any data on it. #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# Accidentally selecting disk containing Windows, you will #' -ForeGround Magenta
Write-Host '# make it unbootable, in which case you will lose all your #' -ForeGround Magenta
Write-Host '# installed software and personal user files and folders! #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# If you are unsure, press CTRL + C to abort now. #' -ForeGround Magenta
Write-Host '############################################################' -ForeGround Magenta
Write-Host
$USBNUMBER = Read-Host -Prompt ' Enter your selection, and press Enter'
3.7) Again, pressing
F5 to run script to see if OK:
(Click to enlarge.)
3.8) Following my outline step by step I will add all modules until the script is done, doing what I want it to do
4: Making a script - Remarks
Using remarks in scripts
4.1) PS ignores every line in script starting with a hash (#) sign. It is similar than
REM (remark) lines in other coding / scripting languages. To include notes and remarks in script, simply start a line with
#, everything after it will be ignored when script is run
4.2) In my opinion you can't add too many remarks! Even if the script is solely for your personal use, remarks make it easy to see and understand what a long forgotten and found again script does. It also helps to find and extract various parts of scripts as modules to be reused in other scripts
4.3) Let's look at two examples. The first part of my sample shown in step
3.2 script tells user what it is about. I added the following remark before it (yellow highlight)
Code:
##########################################################
# Start by clearing the screen, tell user how to start
##########################################################
cls
Write-Host
Write-Host ' Plug in a USB flash (thumb) drive, recommended'
Write-Host ' size (standard W10 install media) 6 GB or more.'
Write-Host
Write-Host ' Notice: Remove all other USB flash drives'
Write-Host ' leaving only the one to be used connected.'
Write-Host
Write-Host ' If more than 1 USB flash drives are connected'
Write-Host ' this process will fail.'
Write-Host
Write-Host ' External USB hard disks may remain connected,'
Write-Host ' just remove all additional USB flash drives.'
Write-Host
4.4) Next remarks were added before the part checking connected disks and before asking user to enter disk number for USB flash drive (highlighted)
Code:
##########################################################
# Pause to wait a key to be pressed, then check connected
# disks showing their name and ID asking user to select
# the USB flash drive to be used. Showing clear warning to
# user with magenta text color to be sure user understands
# risks involved, cleaning wrong disk will cause issues!
##########################################################
pause
cls
Write-Host
Write-Host 'Checking connected disks. This might take a while...'
Write-Host
Get-Disk | Format-Table Number, Friendlyname, HealthStatus, PartitionStyle,
@{n='Size';e={[int]($_.Size/1GB)}}
Write-Host
Write-Host ' Above is a list of all your connected disks.'
Write-Host ' Size is given in full gigabytes (GB).'
Write-Host
Write-Host ' Enter the Disk Number (left column) for USB'
Write-Host ' flash (thumb) drive to be made as bootable'
Write-Host ' Windows install media.'
Write-Host
Write-Host '############################################################' -ForeGround Magenta
Write-Host '# Be extremely careful! #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# Selected disk will be wiped clean and formatted. #' -ForeGround Magenta
Write-Host '# Selecting wrong disk, you will lose any data on it. #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# Accidentally selecting disk containing Windows, you will #' -ForeGround Magenta
Write-Host '# make it unbootable, in which case you will lose all your #' -ForeGround Magenta
Write-Host '# installed software and personal user files and folders! #' -ForeGround Magenta
Write-Host '# #' -ForeGround Magenta
Write-Host '# If you are unsure, press CTRL + C to abort now. #' -ForeGround Magenta
Write-Host '############################################################' -ForeGround Magenta
Write-Host
##########################################################
# Getting the USB ID number from user, asking one more
# time if user is sure and wants to proceed. To avoid any
# liability issues, user is asked not only to press a key
# but clearly type YES. If a wrong disk fill be cleaned
# and formatted after this, it's caused by user not script
##########################################################
$USBNUMBER = Read-Host -Prompt ' Enter your selection, and press Enter'
4.5) There are no rules regarding use of remarks. Some advanced coders do not note / remark their code at all, some want to add a remark before each line of code. Do as I you prefer, what feels correct. Personally I would not even dream about writing code without remarks
5: Making a script - Instructions
Adding on-screen instructions
5.1) We have all seen software, batch files and scripts with bad on-screen instructions and illogical output. In my opinion, however much I hate typing, it is essential to be sure that user clearly understands what's done, what will happen and what is expected from user
5.2) In this sample script, wiping the USB flash drive empty is the one place where everything can go wrong; if user accidentally enters wrong disk number, that disk will be wiped instead of the USB drive. Therefore even using other text color as I did in that part (see steps 3.6 & 3.7) is not overreacting and can be justified
5.3) Another important part in this script where user needs to know exactly what is expected from user is the step that follows wiping and formatting USB drive, when user needs to tell where Windows installation files are located. In my case, not being a native English speaker, I had to think quite a lot about how to formulate the instructions to make them as clear as possible yet short enough to be sure user will read them:
Code:
##########################################################
# USB flash drive cleaned and formatted, asking user to
# mount ISO and enter its drive letter. Entered drive
# letter or path will be written to variable $ISOFolder
##########################################################
cls
Write-Host
Write-Host ' Right click a Windows 10 ISO image and select "Mount".'
Write-Host
Write-Host ' When done, enter the drive letter of mounted ISO'
Write-Host ' below and press Enter.'
Write-Host
Write-Host ' If you want to add additional files and folders to USB,'
Write-Host ' copy the the contents of mounted ISO to a folder. Copy'
Write-Host ' additional content for instance customised "autounattend.xml"'
Write-Host ' for unattended "Hands-Free" installation, driver installers'
Write-Host ' and such to same folder, enter the path to that folder'
Write-Host ' and press Enter.'
Write-Host
Write-Host ' Examples:'
Write-Host ' - ISO mounted as drive F:, no additional content required, enter F'
Write-Host ' - ISO contents copied to "D:\ISO_Files", enter D:\ISO_Files'
Write-Host ' - ISO contents copied to "X:\MyStuff\ISO", enter X:\MyStuff\ISO'
Write-Host
$ISOFolder = Read-Host -Prompt ' Enter path to source folder, press Enter'
5.4) I had run the script several times, not trusting that what I saw in script pane is correct, what I want to, but run it to see how the output looks, editing it certainly 15 - 20 times:
5.5) A script giving not enough information to user increases the risk user does something wrong. Be sure your users understand what they are doing by providing clear instructions
6: Making a script - Error handling
How to handle possible errors
6.1) In this sample error handling is only used once and in very simple way. When user has entered the drive letter for mounted ISO or path to folder where user has copied ISO files to, script checks if given mounted ISO or folder really contains Windows setup files.
6.2) This check is done by checking if given ISO or folder contains an
install.wim or
install.esd file. The idea here is, if
WIM or
ESD file is not found, the ISO or folder can't contain everything required for Windows installation, therefore script will be aborted:
Code:
##########################################################
# Check if entered mounted ISO or path to folder contains
# \Sources\install.wim (or install.esd) file (single bit
# architecture ISO), or in case of dual architecture ISO
# if install.wim (or install.esd) file can be found either
# in \x86\Sources or \x64\Sources folder or both of them.
#
# If install.wim or install.esd file is not found, given
# mounted ISO or folder path does not contain valid
# W10 install files in which case script is aborted.
##########################################################
$WimCount = 0
if ((Test-Path $ISOFolder\Sources\install.wim) -or
(Test-Path $ISOFolder\x86\Sources\install.wim) -or
(Test-Path $ISOFolder\x64\Sources\install.wim) -or
(Test-Path $ISOFolder\Sources\install.esd) -or
(Test-Path $ISOFolder\x86\Sources\install.esd) -or
(Test-Path $ISOFolder\x64\Sources\install.esd))
{$WimCount = 1}
else
{
cls
Write-Host
Write-Host ' No Windows 10 installation files found.'
Write-Host ' Please check mounted ISO letter or path'
Write-Host ' to folder containing installation files'
Write-Host ' and run script again.'
Write-Host
Pause
Exit
}
6.3) An ideal script would check each and every possible error situation and contains "Plan B" for each of them
That's it geeks! Plan and outline your script, be sure you add enough remarks for you and others to better understand its functions, be sure the on-screen output gives end user enough clear instructions to use your script.
Kari