Since the release of Windows Server 2022, discussions and reviews have been abundant. One day, I might write my own review, but for now, let’s focus on something more practical—creating a bootable USB for installation. In today’s guide, I’ll share updated scripts for creating and formatting bootable USB drives for Windows Server.
Introduction
This guide was inspired by an article by Thomas Maurer on creating bootable USB drives for Windows Server 2019. While his approach was solid, I’ve improved upon his scripts with updated methods and additional enhancements.
DISCLAIMER: You may use the scripts in this guide, but you are responsible for any consequences that result from running them.
Look at your hardware first
OS installation can sometimes be challenging, especially when selecting and creating a bootable device. Although there are multiple ways to create installation media, using a USB drive remains the most convenient. Tools like Rufus are available, but knowing an alternative method—one that doesn’t rely on third-party software—is always beneficial.
Before proceeding, ensure that your hardware is compatible with the chosen boot method. Devices with MBR partition type can only boot on systems that support BIOS, whereas GPT partition types require UEFI.
The toolkit used
To create a bootable USB, you will need:
- A Windows 11 or Windows Server 2022 system to run the scripts.
- An 8GB or larger USB drive (Windows Server 2022 requires at least 4GB, but extra space is recommended).
- A Windows Server 2022 installation ISO.
- A target system for testing (PC, server, or VM).
Creating a bootable USB for Windows Server 2022
First, obtain a Windows Server 2022 installation ISO. You can download it from the official Microsoft website.
Steps Overview:
- The script scans connected drives and lists only USB devices with at least 8GB of storage.
- You select the USB drive to use.
- The selected drive is formatted and converted into a bootable USB (all existing data will be erased).
- The Windows Server 2022 image is mounted.
- Files are copied from the mounted image to the USB drive.
- If the install.wim file exceeds 4GB, it is split into smaller chunks.
- Once complete, the image is automatically unmounted.
Running the Script
Save the following script as Create-USB-Drive.ps1 and execute it in PowerShell as an administrator:
PS>.\Create-USB-Drive.ps1 -ISOImg "C:\Temp\Win_Srv_2022.iso" -DriveName "New Usb Drive Name" -BootType "Boot Type"
Script Parameters:
- ISOImg: Path to the Windows Server 2022 ISO file.
- DriveName: Name assigned to the USB drive (default: Boot-Drive).
- BootType: Specifies whether the USB is bootable via UEFI (default) or BIOS.
Select the necessary disk afterward. Or, you can exit the script.
Now, finally, the script comes. Once it finishes, you can start installing the OS.
<#
.SYNOPSIS A script to create an installation USB for Windows 2019 Server.
.PARAMETER ISOImg The path to the Windows Server 2019 image.
.PARAMETER DriveName The flash drive name. "Boot-Drive" is set by default.
.PARAMETER BootType The boot type for the flash drive (UEFI or BIOS). UEFI is set by default.
.EXAMPLE PS> .\Create-USB-Drive.ps1 -ISOImg "C:\Temp\Win_Srv_2022.iso" -DriveName "New Usb Drive" -BootType "UEFI"
#>
# Specify parameters passed to the script as variables
param
(
[Parameter (Mandatory = $true)]
[String]$ISOImg,
[Parameter (Mandatory = $false)]
[String]$DriveName = "Boot-Drive",
[Parameter (Mandatory = $false)]
[ValidateSet("BIOS","UEFI")]
[String]$BootType = "UEFI"
)
#Confirmation of the privileges to run the script.
#requires –RunAsAdministrator
# Variable definition based on the boot type
if ($BootType -eq "UEFI")
{
$PartStyle="GPT"
$FSType="FAT32"
$IsPartActive=$false
}
else
{
$PartStyle="MBR"
$FSType="NTFS"
$IsPartActive=$true
}
# Clean the console to get started
Clear-Host
# Check whether a USB drive is connected to the system
if (!(Get-Disk | Where BusType -eq "USB" ))
{
# Get the list of all drives
Get-Disk | Format-Table -AutoSize Number,FriendlyName,BusType,@{Name="Size (GB)"; Expression={[int]($_.Size/1GB)}},PartitionStyle
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
# Pause before closing the console
Write-Error "Flash drive not found! Please connect an appropriate one and run the script again!" | Pause | Clear-Host
exit
}
else
{
# Get the list of USB drives
Get-Disk | Where BusType -eq "USB" | Format-Table -AutoSize Number,FriendlyName,@{Name="Size (GB)"; Expression={[int]($_.Size/1GB)}},PartitionStyle
# The cycle variable initialization
$Choice1=0
# Create the first input cycle
while (($Choice1).Equals(0))
{
# Get the number of the required USB drive from the user
$NumOfDisk = Read-Host 'Type the number of the required disk from the list as a number. To exit the script, enter "Exit"'
# Validation of entered data
if (($NumOfDisk).Equals("E") -or ($NumOfDisk).Equals("e") -or ($NumOfDisk).Equals("Exit") -or ($NumOfDisk).Equals("exit") )
{
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
# Pause before closing the console
Write-Warning "You have successfully terminated the script!" | Pause | Clear-Host
Exit
}
# Get from the user the value for the variable name of the required USB drive
$USBDrive = Get-Disk | Where Number -eq "$NumOfDisk"
# Check if disk variable has been input correctly
if (($USBDrive).BusType -eq "USB" -and ($USBDrive).Number -notlike $null -and ($USBDrive).Number -gt "0" -and ([int]($USBDrive.Size/1GB)) -ge "7" )
{
# The cycle variable initialization
$Choice2=0
# Create the second input cycle
while (($Choice2).Equals(0))
{
# Reading data from the console to a variable
$Confirm = Read-Host "You have selected the disk ("($USBDrive).FriendlyName" ). All data on this disk will be deleted! Continue (Yes(Y) / No(N) / Exit(E))"
# Validation of the entered data
if (($Confirm).Equals("Y") -or ($Confirm).Equals("y") -or ($Confirm).Equals("Yes") -or ($Confirm).Equals("yes") )
{
$Choice1=1
break
}
# Validation of the entered data
elseif (($Confirm).Equals("N") -or ($Confirm).Equals("n") -or ($Confirm).Equals("No") -or ($Confirm).Equals("no") )
{
Write-Warning "Please choose another drive number!"
$Choice2=1
continue
}
# Validation of the entered data
elseif (($Confirm).Equals("E") -or ($Confirm).Equals("e") -or ($Confirm).Equals("Exit") -or ($Confirm).Equals("exit") )
{
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
# Pause before closing the console
Write-Warning "You have successfully terminated the script!" | Pause | Clear-Host
exit
}
else
{
Write-Warning "An invalid or unrecognizable input received! Please reenter the value."
}
}
}
else
{
Write-Warning "An invalid or unrecognized value was received, or the selected drive volume is less than 8GB! Please re-enter the value!"
}
}
# Delete data from the flash drive. Assign a partition style
$USBDrive | Clear-Disk -RemoveData -Verbose:$true -Confirm:$false -PassThru | Set-Disk -PartitionStyle $PartStyle -WarningAction SilentlyContinue
# Create the partition. Formatting in a new file system
$DrivePart = $USBDrive | New-Partition -Verbose:$true -UseMaximumSize -AssignDriveLetter -WarningAction SilentlyContinue | Format-Volume -Verbose:$true -Force:$true -FileSystem $FSType -NewFileSystemLabel $DriveName
# Make a partition active
$USBDrive | Get-Partition -Verbose:$true | Set-Partition -Confirm:$false -Verbose:$true -IsActive $IsPartActive
# Mount the installation image
$MntImg = Mount-DiskImage -ImagePath $ISOImg -StorageType ISO -PassThru
# Mount an image letter
$MntImgLetter = ($MntImg | Get-Volume).DriveLetter
# Assign a drive letter
$DriveLetter = ($DrivePart).DriveLetter
# Assign an installation disk letter
$InstFSize = Get-Childitem -Path $MntImgLetter":\sources\install.wim" | select length
if ( ($BootType).Equals("BIOS") -and [int](($InstFSize).Length/1GB) -le "4")
{
# Copy all files to the USB drive.
Copy-Item -Verbose:$true -Force:$true -Recurse -Path ($MntImgLetter+":\*") -Destination ($DriveLetter+":\")
}
else
{
# Copy all files to the USB drive except install.wim
Copy-Item -Verbose:$true -Exclude "install.wim" -Recurse -Path ($MntImgLetter+":\*") -Destination ($DriveLetter+":\")
# Initialize the temporary directory variable on the PC and Create a temporary directory on the PC
($TmpPcDir = $env:TEMP+"\DISMTMP\") | new-item -Path $TmpPcDir -Force:$true -Verbose:$true -itemtype directory | Out-Null
# Split a Windows image file (install.wim)
Dism /Split-Image /ImageFile:$MntImgLetter":\sources\install.wim" /SWMFile:$TmpPcDir\install.swm /FileSize:3000 /English /Quiet
# Transfer files to the flash drive
Move-Item -Verbose:$true -Force:$true -Path ($TmpPcDir+"*") -Destination ($DriveLetter+":\sources\")
# Delete the temporary directory
Remove-Item $TmpPcDir -Force:$true -Verbose:$true -Recurse
}
# Unmount the installation image
Dismount-DiskImage -Verbose:$true -ImagePath $ISOImg
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
}
# Pause before closing the console
Write-Warning "The script has been successfully completed! Your bootable flash drive is ready to use!" | Pause | Clear-Host
Reformatting the drive after Windows installation
After installing Windows Server, you may want to reformat the USB drive for regular use. The following script accomplishes this by allowing you to:
- Select the USB drive.
- Format it to GPT or MBR.
- Choose a file system format (FAT32, exFAT, or NTFS).
Save the script as Return-USB-Drive.ps1 and run it using:
PS>.\Return-USB-Drive.ps1 -DriveName " New Usb Drive Name " -PartStyle " Partition style " -FSType "File system format"
Script Parameters:
- DriveName: Name for the USB drive (default: My Flash Drive).
- PartStyle: Partition format (GPT or MBR; default: GPT).
- FSType: File system format (NTFS by default).
Select the disk which you want to reformat. Otherwise, you can exit the script.
Here’s the script that I was talking about. Once it finishes, the disk is ready.
<#
.SYNOPSIS A script for cleaning and reformatting a flash drive after installing Windows
.PARAMETER DriveName A new flash drive name. My Flash Drive is set by default!
.PARAMETER PartStyle The partition style for the flash drive (MBR or GPT). GPT is set by default!
.PARAMETER FSType The flash disk file system format type. NTFS is set by default!
.EXAMPLE PS> .\Return-USB-Drive.ps1 -DriveName "New Usb Drive" -PartStyle "GPT" -FSType "FAT32"
#>
# Parameters passed to the script as variables
param
(
[Parameter (Mandatory = $false)]
[String]$DriveName = "My Flash Drive",
[Parameter (Mandatory = $true)]
[ValidateSet("exFAT","FAT","FAT32","NTFS")]
[String]$FSType = "NTFS",
[Parameter (Mandatory = $true)]
[ValidateSet("MBR","GPT")]
[String]$PartStyle = "GPT"
)
#Cleaning the console to get started
Clear-Host
#Confirmation of the privileges to run the script.
#requires –RunAsAdministrator
# Check whether a USB drive is connected to the system
if (!(Get-Disk | Where BusType -eq "USB" ))
{
# Get the list of all drives
Get-Disk | Format-Table -AutoSize Number,FriendlyName,BusType,@{Name="Size (GB)"; Expression={[int]($_.Size/1GB)}},PartitionStyle
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
# Pause before closing the console
Write-Error "Flash drive not found! Please connect an appropriate one and run the script again!" | Pause | Clear-Host
exit
}
else
{
# Get a list of USB drives
Get-Disk | Where BusType -eq "USB" | Format-Table -AutoSize Number,FriendlyName,@{Name="Size (GB)"; Expression={[int]($_.Size/1GB)}},PartitionStyle
# The cycle variable initialization
$Choice1=0
# Creating the first input cycle
while (($Choice1).Equals(0))
{
# Get the number of the required USB drive from the user
$NumOfDisk = Read-Host 'Type the number of the required disk from the list as a number. To exit the script, enter "Exit"'
# Validation of the entered data
if (($NumOfDisk).Equals("E") -or ($NumOfDisk).Equals("e") -or ($NumOfDisk).Equals("Exit") -or ($NumOfDisk).Equals("exit") )
{
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
# Pause before closing the console
Write-Warning "You have successfully terminated the script!" | Pause | Clear-Host
exit
}
# Get from the user the value for the variable name of the required USB drive
$USBDrive = Get-Disk | Where Number -eq "$NumOfDisk"
# Checking whether the disk variable has been input correctly
if (($USBDrive).BusType -eq "USB" -and ($USBDrive).Number -notlike $null -and ($USBDrive).Number -gt "0")
{
# The cycle variable initialization
$Choice2=0
# Creating the second input cycle
while (($Choice2).Equals(0))
{
# Reading the data from the console to a variable
$Confirm = Read-Host "You have selected the disk ("($USBDrive).FriendlyName" ). All data on this disk will be deleted! Continue (Yes(Y) / No(N) / Exit(E))"
# Validation of the entered data
if (($Confirm).Equals("Y") -or ($Confirm).Equals("y") -or ($Confirm).Equals("Yes") -or ($Confirm).Equals("yes") )
{
$Choice1=1
break
}
# Validation of the entered data
elseif (($Confirm).Equals("N") -or ($Confirm).Equals("n") -or ($Confirm).Equals("No") -or ($Confirm).Equals("no") )
{
Write-Warning "Please choose another drive Number!"
$Choice2=1
continue
}
# Validation of the entered data
elseif (($Confirm).Equals("E") -or ($Confirm).Equals("e") -or ($Confirm).Equals("Exit") -or ($Confirm).Equals("exit") )
{
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
# Pause before closing the console
Write-Warning "You have successfully terminated the script!" | Pause | Clear-Host
exit
}
else
{
Write-Warning "An invalid or unrecognizable answer received! Please re-enter the value!"
}
}
}
else
{
Write-Warning "An invalid or unrecognized value was entered! Please re-enter the value!"
}
}
# Delete data from the flash drive. Assign a partition style
$USBDrive | Clear-Disk -RemoveData -Verbose:$true -Confirm:$false -PassThru | Set-Disk -PartitionStyle $PartStyle -WarningAction SilentlyContinue
# Create the partition and format it to a new file system
$DrivePart = $USBDrive | New-Partition -Verbose:$true -UseMaximumSize -AssignDriveLetter -WarningAction SilentlyContinue | Format-Volume -Verbose:$true -Force:$true -FileSystem $FSType -NewFileSystemLabel $DriveName
# Delete local variables
Remove-Variable -Name * -Force -ErrorAction SilentlyContinue
}
# Pause before closing the console
Write-Warning "The script has been successfully completed! Your flash drive is ready to use!" | Pause | Clear-Host
Conclusion
These scripts provide an efficient way to create a bootable USB for installing Windows Server 2022. Instead of relying on third-party tools, this PowerShell-based approach ensures a streamlined process. I hope this guide proves useful!