Introduction
Since Windows Server 2019 release, the Internet is booming with its reviews. Someday, I maybe write my own one too. Till then, why don’t we focus on something more important than just listing new Windows Server features? In today’s post, I share the scripts for creating and formatting bootable USB disks for Windows Server.
I came up with the idea of this short guide after reading the following article:
https://www.thomasmaurer.ch/2018/07/create-a-usb-drive-for-windows-server-2019-installation.
In fact, Thomas did a great job, but his scripts can be improved! With this being said, today, I present my universal scripts based on ones developed by Thomas and improved with my experience and comments to his post in mind.
DISCLAIMER: You can try out the scripts form this article, but you are the only person responsible for the consequences!
Look at your hardware first
OS installation may sometimes be a challenging task. Especially, when it comes to selecting and creating a bootable device. By the way, did you know that apart from USB, there are at least 3 other storage media that can be used as Windows installation disks? USB is more convenient for that purpose, IMHO, so let’s just stick to it. Of course, you can use Rufus to create a bootable USB. But, it is always good to know an alternative, right? And, it is better NOT to rely on some weird 3rd party software…
Picking a bootable disk partition type that is compatible with your hardware is not that straightforward too. Before creating such device, you need to think whether OS can be installed on your hardware afterward. For instance, a device with MBR partition type can be started only on a PC or server that supports BIOS. Devices with GPT partition type, in turn, require UEFI. So, take a closer look at your hardware first!
The Toolkit used
Here are things needed to create a bootable USB:
- Windows 10 PC. You need it to run the scripts. Note that several PowerShell commands may be unavailable.
- 8 GB USB drive. Windows Server consumes at least 4 GB, but it is always good to have some extra space. So, obviously, you cannot create a bootable USB of lower capacity.
- Installation image (*.iso) for copying Windows Server 2019 distributive files.
- A device to test the bootable USB. It can be a PC, server, or VM.
Creating a bootable USB for Windows Server 2019
Initially, find a Windows Server 2019 installation image. You can download it and read about the OS itself at the official website:
https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2019.
The script for creating a bootable USB described here is good for older Windows Server versions too. I tried it for Windows Server 2016, it worked good. Do you remember that I said at the beginning that I made universal scripts?
Here’s briefly how my script for creating a Windows Server bootable USB works:
- All drives connected to the system are scanned after starting the script. I have fine-tuned it such that only USBs are listed. One more time, you can use one only if its volume exceeds 8GB.
- Select any USB disk from that list.
- The disk you choose becomes a bootable USB. Note that all data are wiped out from that drive! By default, a GPT volume formatted as FAT32 is created. But, you can also create an MBR volume formatted as NTFS.
- Mounting Windows Server 2019 bootable image.
- Copying files and directories from the mounted image to the USB.
- While being written to a GTP disk, the image will be automatically split into 3GB chunks if the image keeping install.wim files is larger than 4GB. File splitting involves a temporary folder creation, so you need from 4 through 8GB of free space on the system disk therefor.
- Once script finishes, the disk where the image resides gets automatically unmounted.
To run the script, save its body locally as “Create-USB-Drive.ps.1”.
Next, start PowerShell as Administrator. Run the script with this cmdlet:
1 |
PS>.\Create-USB-Drive.ps1 -ISOImg "C:\Temp\Win_Srv_2019.iso" -DriveName "New Usb Drive Name" -BootType "Boot Type" |
I guess it is good to discuss each piece of this command.
- .\Create-USB-Drive.ps1 stands for the script name.
- -ISOImg “C:\Temp\Win_Srv_2019.iso” represents the path to the *.iso image. Keep the script in that directory (it is just more convenient).
- -DriveName “New Usb Drive Name” – the new USB drive name. By default, it is called Boot-Drive.
- -BootType “Boot Type” allows setting the firmware interface for booting (UEFI or BIOS). UEFI is set by default.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
<# .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_2019.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
Now, let’s take a look at my script for reformatting a USB. Here’s briefly how it works:
- Once the script is started, all disks connected to the system are scanned, but only USBs are listed. This script works for USB disks of any size.
- WARNING: IF YOU DO RUN THIS SCRIPT, DATA ON THE SELECTED USB IS WIPED OUT! You can create either a GPT volume or MBR one. Also, you can format the file system as FAT32, exFAT, FAT, or NTFS. Just input the appropriate parameter.
Save locally the body of the script provided below as Return-USB-Drive.ps1 file. Next, open PowerShell console as administrator, and you can run the script with the command below:
1 |
<em> PS>.\Return-USB-Drive.ps1 -DriveName " New Usb Drive Name " -PartStyle " Partition style " -FSType "File system format"</em> |
Let’s discuss what each part of the command stands for.
- -DriveName “New Usb Drive Name” the new name of the USB disk. By default, it is called My Flash Drive.
- -PartStyle ” Partition style ” – the partition table format (GPT or MBR). It is set to GPT by default.
- -FSType “File system format” allows changing the type of file system formatting.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
<# .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
The scripts discussed in this post allow creating a bootable USB drive for installing Windows Server 2019 or Windows Server 2016. I did not reinvent the wheel here. I just improved the existing scripts considering both what people say and my experience. I hope that my way to create a Windows Server installation disk comes in handy!