Skip to content

Instantly share code, notes, and snippets.

@lawndoc
Last active February 20, 2025 14:53
Show Gist options
  • Save lawndoc/ea03e2ee0f4d64162669d1b5e997ec77 to your computer and use it in GitHub Desktop.
Save lawndoc/ea03e2ee0f4d64162669d1b5e997ec77 to your computer and use it in GitHub Desktop.
Scripted Dev Drive Setup
<#
.SYNOPSIS
Script to create a new Dev Drive
.DESCRIPTION
This script will create a new Dev Drive on a Windows system. By default, it will create a 100GB dynamically sized VHDX file located in C:\ProgramData\Custom Dev Drive\drive.vhdx that will be mounted to the V: letter drive. For more information about Dev Drives, please see https://learn.microsoft.com/en-us/windows/dev-drive/
.EXAMPLE
.\New-DevDrive.ps1
or
.\New-DevDrive.ps1 -DrivePath "C:\Temp\testing" -DriveSize 200GB -DriveLetter "T"
.PARAMETER Drive Path
This optional parameter specifies the path that the VHDX file will be saved to. A default path of 'C:\ProgramData\Custom Dev Drive' is provided.
.PARAMETER Drive Letter
This optional parameter defines the drive letter that the Dev Drive will be mounted to. A default letter of 'V' is provided.
.PARAMETER Drive Size
This optional parameter defines the maximum size of the Dev Drive's dynamically sized volume. A default size of '100GB' is provided.
#>
param([string]$DrivePath = "C:\ProgramData\Custom Dev Drive",
[string]$DriveSize = "100GB",
[string]$DriveLetter = "B"
)
function Convert-ToMegabytes {
param (
[string]$sizeString
)
$number = [double]($sizeString -replace '[^\d.]+')
switch -Regex ($sizeString) {
'MB' {
$numberInMB = $number
break
}
'GB' {
$numberInMB = $number * 1024
break
}
'TB' {
$numberInMB = $number * 1024 * 1024
break
}
default {
throw "Unsupported unit. Please use MB, GB, or TB."
}
}
return $numberInMB
}
$SizeInMB = Convert-ToMegabytes -sizeString $DriveSize
if (Test-Path "$DrivePath\drive.vhdx") {
Write-Warning "ERROR: $DrivePath\drive.vhdx already exists! Aborting..."
exit 1
}
if (Test-Path "${DriveLetter}:") {
Write-Warning "ERROR: Drive letter ${DrivePath}: is already in use! Aborting..."
exit 1
}
Write-Output "[*] Setting disk configuration settings..."
Write-Output "create vdisk file='${DrivePath}\drive.vhdx' maximum=$SizeInMB type=expandable" | Out-File -Encoding ascii -FilePath C:\Temp\diskpart_devdrive.txt
Write-Output "select vdisk file='${DrivePath}\drive.vhdx'" | Out-File -Encoding ascii -Append -FilePath C:\Temp\diskpart_devdrive.txt
Write-Output "attach vdisk" | Out-File -Encoding ascii -Append -FilePath C:\Temp\diskpart_devdrive.txt
Write-Output "create partition primary" | Out-File -Encoding ascii -Append -FilePath C:\Temp\diskpart_devdrive.txt
Write-Output "format fs=refs label='Dev Drive' quick" | Out-File -Encoding ascii -Append -FilePath C:\Temp\diskpart_devdrive.txt
Write-Output "assign letter=${DriveLetter}" | Out-File -Encoding ascii -Append -FilePath C:\Temp\diskpart_devdrive.txt
Write-Output "[*] Creating Dev Drive..."
if (!(Test-Path "$DrivePath")) {
mkdir $DrivePath
}
diskpart /s C:\Temp\diskpart_devdrive.txt
Format-Volume -DriveLetter $DriveLetter -DevDrive
if (!(Test-Path "${DriveLetter}:")) {
Write-Warning "ERROR: Failed to create ReFS vdisk for Dev Drive..."
exit 1
}
Write-Output "[*] Verifying Dev Drive trust..."
fsutil devdrv query ${DriveLetter}:
cd ${DriveLetter}:
label Dev Drive
# dev drive doesn't re-mount after reboots without a scheduled task
$Script = "diskpart.exe /s '$DrivePath\devdrivetask.txt' > '$DrivePath\tasklog.txt'"
Write-Output "select vdisk file='$DrivePath\drive.vhdx'" | Out-File -Encoding ascii -FilePath $DrivePath\devdrivetask.txt
Write-Output "attach vdisk" | Out-File -Encoding ascii -Append -FilePath $DrivePath\devdrivetask.txt
Write-Output $Script | Out-File -Encoding ascii -FilePath $DrivePath\devdrivetask.ps1
Write-Output "cd ${DriveLetter}:" | Out-File -Encoding ascii -Append -FilePath $DrivePath\devdrivetask.ps1
Write-Output "label Dev Drive" | Out-File -Encoding ascii -Append -FilePath $DrivePath\devdrivetask.ps1
$taskname = "Mount Dev Drive"
$taskdescription = "Make sure Dev Drive is mounted after reboots"
$taskTrigger = New-ScheduledTaskTrigger -AtStartup
$taskAction = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass .\devdrivetask.ps1" -WorkingDirectory $DrivePath
$taskSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName $taskname -Description $taskdescription -Action $taskAction -Trigger $taskTrigger -Settings $taskSettings -User "System"
Write-Output "[*] Cleaning up..."
Remove-Item C:\Temp\diskpart_devdrive.txt
Write-Output "[*] Done."
@lawndoc
Copy link
Author

lawndoc commented Mar 12, 2024

Dev Drive is a dynamically expanding, ReFS-formatted, virtual drive that allows Defender AV to run in "Performance Mode". This means that file scans run asynchronously and don't delay file opens. For developers who use git, run unit tests, and build apps on large projects, Dev Drive offers a huge performance benefit.

In addition to the performance gains, keeping all of your code in a Dev Drive enables security engineers to create policies they wouldn't be able to otherwise.

An example of a policy that Dev Drive enables is the "Untrusted Executable" ASR rule. This ASR rule is impossible to put into block mode if your developers compile custom, unsigned programs all over the C:\ drive. Having a drive dedicated to custom programs allows for more predictable exclusions.

@lawndoc
Copy link
Author

lawndoc commented Feb 18, 2025

To expand the max size of the VHDX:

$DriveLetter = "B"
$FileName = "C:\Temp\diskpart_devdrive.txt"
Write-Output "select vdisk file='C:\ProgramData\Custom Dev Drive\drive.vhdx'" | Out-File -Encoding ascii -FilePath $FileName
Write-Output "detach vdisk" | Out-File -Encoding ascii -Append -FilePath $FileName
Write-Output "expand vdisk maximum=256000" | Out-File -Encoding ascii -Append -FilePath $FileName
Write-Output "attach vdisk" | Out-File -Encoding ascii -Append -FilePath $FileName
Write-Output "select volume $DriveLetter" | Out-File -Encoding ascii -Append -FilePath $FileName
Write-Output "extend" | Out-File -Encoding ascii -Append -FilePath $FileName
diskpart /s $FileName

You cannot reduce the max size of a VHDX file, but you can reclaim unused space and shrink the physical size on disk.

To shrink the physical size of the VHDX (requires unused space):

$FileName = "C:\Temp\diskpart_devdrive.txt"
Write-Output "select vdisk file='C:\ProgramData\Custom Dev Drive\drive.vhdx'" | Out-File -Encoding ascii -FilePath $FileName
Write-Output "detach vdisk" | Out-File -Encoding ascii -Append -FilePath $FileName
Write-Output "compact vdisk" | Out-File -Encoding ascii -Append -FilePath $FileName
Write-Output "attach vdisk" | Out-File -Encoding ascii -Append -FilePath $FileName
diskpart /s $FileName

@lawndoc
Copy link
Author

lawndoc commented Feb 19, 2025

To change the drive letter of the Dev Drive:

$OldLetter = "B"
$NewLetter = "V"
$FileName = "C:\Temp\diskpart_devdrive.txt"
Write-Output "select volume $OldLetter" | Out-File -Encoding ascii -FilePath $FileName
Write-Output "assign letter=$NewLetter" | Out-File -Encoding ascii -Append -FilePath $FileName
diskpart /s $FileName
(Get-Content -Path 'C:\ProgramData\Custom Dev Drive\devdrivetask.ps1' -Raw) -replace "cd $OldLetter", "cd $NewLetter" | Set-Content -Path "C:\ProgramData\Custom Dev Drive\devdrivetask.ps1"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment