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!