Skip to content

Instantly share code, notes, and snippets.

@lawndoc
Last active April 23, 2024 17:51
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.
#>
# Define parameters and their defaults
param([string]$DrivePath = "C:\ProgramData\Custom Dev Drive",
[string]$DriveSize = "100GB",
[string]$DriveLetter = "V"
)
# Parse drive size
function Convert-ToMegabytes {
param (
[string]$sizeString
)
# Extract the numeric part of the size string
$number = [double]($sizeString -replace '[^\d.]+')
# Determine the unit (GB, TB, MB) and convert accordingly
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
# Test to make sure we don't already have a Dev Drive overlapping with the provided configuration
if (Test-Path "$DrivePath\drive.vhdx") {
Write-Warning "ERROR: $DrivePath\drive.vhdx already exists! Aborting..."
exit
}
if (Test-Path "${DriveLetter}:") {
Write-Warning "ERROR: Drive letter ${DrivePath}: is already in use! Aborting..."
exit
}
# Set up diskpart script with the provided parameters or defaults
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=V" | Out-File -Encoding ascii -Append -FilePath C:\Temp\diskpart_devdrive.txt
# Create the Dev Drive
Write-Output "[*] Creating Dev Drive..."
if (!(Test-Path "$DrivePath")) {
mkdir $DrivePath
}
diskpart /s C:\Temp\diskpart_devdrive.txt
Format-Volume -DriveLetter $DriveLetter -DevDrive
# Output Dev Drive trusted status (should be trusted by default)
Write-Output "[*] Verifying Dev Drive trust..."
fsutil devdrv query ${DriveLetter}:
# Label Dev Drive
cd ${DriveLetter}:
label Dev Drive
# Setup scheduled task to re-mount dev drive after reboots
$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"
# Cleanup
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 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 and run unit tests on large projects, this is 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.

One 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.

Another policy that pairs nicely with Dev Drive is "Controlled Folder Access". With this policy, you can allow only dev programs to use the Dev Drive file system. This both protects the code from theft and prevents malware from abusing the Dev Drive's performance AV mode.

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