Skip to content

feat: say before anything is created that BitLocker is mandatory here - #72

Merged
ALERTua merged 1 commit into
mainfrom
bugfix/65
Aug 24, 2026
Merged

feat: say before anything is created that BitLocker is mandatory here#72
ALERTua merged 1 commit into
mainfrom
bugfix/65

Conversation

@ALERTua

@ALERTua ALERTua commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Closes #65, and closes #3, which it turns from a mystery into a line in the plan.

The fact behind it

HKLM\SYSTEM\CurrentControlSet\Policies\Microsoft\FVE
FDVDenyWriteAccess : 1

"Deny write access to fixed drives not protected by BitLocker". While it is 1, Windows mounts every unencrypted fixed data drive read-only. @Eagle3386's run proved it end to end: the volume refused writes while unencrypted and accepted them once encryption completed.

That path, not HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\BitLocker, which was empty on his machine. The effective location is the one to read, whatever delivered the setting.

What the run does with it now

  • Read before the BitLocker question, and whatever the answer. The four other machine facts (domain, Entra, system drive, mode) are read only once BitLocker has been chosen. This one decides whether declining leaves an unusable drive, so it cannot wait for that. A test pins both the order and that the read is unconditional.
  • The question carries it, so nobody answers without knowing:
    This machine denies write access to fixed drives that BitLocker does not protect (FDVDenyWriteAccess is 1).
    So a Dev Drive without BitLocker would mount read-only here, with nothing able to be written to it.
    
  • The plan says it as a consequence of the answer given, still before anything exists:
    * Skip BitLocker encryption
      - This machine denies write access to fixed drives that BitLocker does not protect (FDVDenyWriteAccess is 1).
      - So this Dev Drive will mount read-only, and nothing can be written to it.
      - The run will stop at the write check once the drive exists. Enable BitLocker, or change that setting first.
    
    The two are worded differently on purpose: before the menu nobody has decided to skip anything, so the consequence is stated as a condition rather than as a fact.
  • The write check, if it still comes to that, names a cause instead of listing suspects:
    This machine denies write access to fixed drives that BitLocker does not protect, and E: is not encrypted. That is almost certainly the cause.
    Encrypt this volume to make it writable, without creating it again: Enable-BitLocker -MountPoint E: -RecoveryPasswordProtector -UsedSpaceOnly
    

The other half of the report

On such a machine Windows opens its own prompt to encrypt the new volume while this run is already encrypting it. He answered it, got BitLocker encryption already enabled, deleted the partition and started over; on the second run he left it alone and it closed by itself. The BitLocker notes now say so before encryption starts - and say it on an unreadable setting too, because a read that failed is not evidence the setting is off.

Verification

dev_drive.ps1 was not executed, deliberately. Parse OK, PSScriptAnalyzer recursive with no findings, Pester 560 passed / 0 failed (532 before this branch). On this machine the setting reads as Allow, so none of the new lines appear here.

Reviewed

Reviewed independently before this was opened. Applied:

  • A dead branch. Resolve-WriteAccessPolicyAdvice -BitLockerChosen was never passed by either call site, so a tested, green branch could not run in production. Replaced by -Skipping, which both call sites now use to tell the two moments apart.
  • The same three lines printed verbatim twice in one run, at the question and in the plan. Now worded for the moment each is printed in.
  • Test-Path without -ErrorAction Stop: a key that exists but cannot be read answered $false, which the function then reported as "not set" - the exact confusion its docstring promises to avoid.
  • A value of an unexpected type made an [int] cast throw, and the docstring claimed only a failed read answers Unknown. The type is checked now, and a string value and a DWORD 2 each have a test.
  • The Windows-prompt warning was gated on Deny, so a machine whose setting could not be read got no warning at all - which is precisely the situation that cost the reporter a partition. Gated on "not known to be off" instead.
  • The registry path was written out three times. One constant now, with a test forbidding a second literal, matching the discipline already applied to the label length cap.
  • The Allow branch acquitted the setting too confidently on the strength of one key; it now says it does not look like the cause rather than that it cannot be.
  • The Deny branch dropped the partition read-only check that a comment three lines above promises is offered in every branch, and told the user to run the script again - wrong, because the Dev Drive already exists by then and a rerun would repeat its creation. It names Enable-BitLocker on the existing volume instead.
  • Two test defects of my own: a Mock Test-Path inside an It was still active during AfterEach, making cleanup print a red error over a key that test never created; and an assertion on a parameter's ParameterAttribute was vacuous - it passes for any parameter of any function. The suite also left HKCU:\Software\DevDriveTests behind; it now removes the whole branch, verified.

Not resolved, and worth saying: whether FDVDenyWriteAccess applies to a volume inside a .vhdx the same way it does to a physical partition could not be established without a test machine. The plan note is passed in that mode too. If it does not apply there, the line is harmlessly early rather than wrong - it says the drive is read-only until encryption finishes, which resolves either way.

A single setting decides whether a Dev Drive is usable at all:
FDVDenyWriteAccess under HKLM\SYSTEM\CurrentControlSet\Policies\Microsoft
\FVE. While it is 1, Windows mounts every unencrypted fixed data drive
read-only, so declining BitLocker leaves a drive nothing can be written
to. Until now that was invisible until the write check stopped the run,
with the partition already made.

It is read before the BitLocker question and whatever the answer, unlike
the four other machine facts, which are read only once BitLocker has
been chosen. The question then carries it, the plan repeats it as a
consequence of skipping, and the write check, if it still comes to that,
names the setting instead of listing suspects.

The other half of the report: on such a machine Windows opens its own
prompt to encrypt the new drive while this run is already encrypting it.
Answering it produces "BitLocker encryption already enabled". The run now
says to leave it alone, and says so on an unreadable setting too, since a
failed read is not evidence the setting is off.

Closes #65
Closes #3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ALERTua
ALERTua merged commit 970eee6 into main Aug 24, 2026
3 checks passed
@ALERTua
ALERTua deleted the bugfix/65 branch August 24, 2026 18:52
Comment thread dev_drive.ps1
Comment thread dev_drive.ps1
@kilo-code-bot

kilo-code-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 2
Issue Details (click to expand)

SUGGESTION

File Line Issue
dev_drive.ps1 423 Narrow numeric-type gate (-isnot [int] -and -isnot [long]) can misclassify a legible non-int/long numeric DWORD as "could not be read"
dev_drive.ps1 427 Broad catch { return 'Unknown' } masks any unexpected programming error as an unreadable registry setting
Files Reviewed (3 files)
  • dev_drive.ps1 - 2 issues
  • dev_drive.Tests.ps1 - 0 issues
  • README.md - 0 issues

Fix these issues in Kilo Cloud


Reviewed by free · Input: 88.2K · Output: 17.6K · Cached: 397.6K

@Eagle3386

Eagle3386 commented Aug 27, 2026

Copy link
Copy Markdown

Not resolved, and worth saying: whether FDVDenyWriteAccess applies to a volume inside a .vhdx the same way it does to a physical partition could not be established without a test machine.

Did the real-world test for you - compiled creation plan:

===============================================================================
                        DEV DRIVE CREATION PLAN
===============================================================================

* Create a 50 GB Dynamic virtual hard disk at C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx
* Initialize the new virtual disk with a GPT partition table
* Format the attached virtual disk as a Dev Drive using ReFS
* Register the virtual disk to be mounted on every Windows startup
* Name the Dev Drive DevDriveTest.vhdx
* Mark Dev Drive as trusted for Windows Defender performance
* Skip BitLocker encryption
  - This machine denies write access to fixed drives that BitLocker does not protect (FDVDenyWriteAccess is 1).
  - So this Dev Drive will mount read-only, and nothing can be written to it.
  - The run will stop at the write check once the drive exists. Enable BitLocker, or change that setting first.
* Skip deduplication and compression setup

===============================================================================

Results:

  1. Dialog popped up, although BitLocker was set to be skipped & did not disappear automatically.
  2. Yes, the virtual drive's label was really set to DevDriveTest.vhdx. 😅🤣
  3. Lots of errors, here's the script's full output (German messages manually translated & prepended with §, missing empty lines were already missing in the original output):
    Starting Dev Drive creation...
    Creating a 50 GB Dynamic virtual hard disk at C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx
    Attaching C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx
    Attached C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx as disk 1
    Windows will mount C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx automatically on every startup.
    Initializing disk 1 with a GPT partition table
    Creating a partition spanning the whole virtual disk
    Formatting the newly created partition drive E: to a Dev Drive
    
    Dev Drive created at E:, named DevDriveTest.vhdx.
    Marking Dev Drive E: as trusted for Defender performance
    Could not mark E: as trusted (fsutil exited with code 1).
    fsutil devdrv query E: said:
      §This is a trusted Dev Drive.
      §Dev Drives are protected by anti-virus filters.
      §Currently attached dev drive filters:
      WdFilter
    The Dev Drive will still work, but without the Defender performance mode trust enables.
    Retry by hand with: fsutil devdrv trust /f E:
    Skipping BitLocker encryption as requested.
    Checking that E: can be written to
    
    Drive E: was created, but nothing can be written to it.
    §Windows said: Media is write-protected: 'E:\.devdrive-write-test'.
    This machine denies write access to fixed drives that BitLocker does not protect, and E: is not encrypted. That is almost certainly the cause.
    Encrypt this volume to make it writable, without creating it again: Enable-BitLocker -MountPoint E: -RecoveryPasswordProtector -UsedSpaceOnly
    Check whether the partition itself is marked read-only: Get-Partition -DriveLetter E | Format-List IsReadOnly, DiskNumber
    Drive E: stays as it is. Nothing more can be set up on it while it refuses writes.
    An error occurred during Dev Drive creation:
    Drive E: is read-only. See the explanation above.
    Left behind: C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx, still attached.
    It is also registered to attach on every startup. Dismounting clears that.
    To remove it: Dismount-DiskImage -ImagePath 'C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx'; Remove-Item -LiteralPath 'C:\Users\[REDACTED]\Documents\DevDriveTest.vhdx'
    Check the error above, undo whatever this run already changed, and only then run it again.
    This script does not resume: every run starts from the beginning.
    DriveLetter FriendlyName      FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining     Size
    ----------- ------------      -------------- --------- ------------ ----------------- -------------     ----
    E           DevDriveTest.vhdx ReFS           Fixed     Healthy      OK                     48.75 GB 49.94 GB

Suggestions:

  1. Only ask for the folder path of the Dev Drive instead of its file path & use the provided Dev Drive's name later in the "questionnaire" (maybe with removal of any special chars and/or whitespaces) as file name.
  2. After running Dismount-DiskImage to remove the leftovers, it stated LogicalSectorSize : 512 - virtual disks, if stored on a flash memory partition, should follow the general rule of thumb which - at least to my knowledge - is 4096 bytes, not those 512 bytes which are common for an HDD.

@ALERTua

ALERTua commented Aug 27, 2026

Copy link
Copy Markdown
Owner Author

Thank you — it settles an open question and found a defect in the same output.

The question it settles

Whether FDVDenyWriteAccess reaches inside a virtual disk, or only applies to real partitions, could not be established without a machine that has the setting on. Your run answers it: the write check refused with "Media is write-protected", exactly as it would on a physical partition.

So the warning you saw in the plan was right, and it was right to appear before anything was created. That is now recorded as measured rather than assumed.

Your run is also the first end-to-end confirmation of that whole path on somebody else's machine: warned in the plan, stopped at the write check, named the .vhdx it left attached and how to remove it. All three behaved as intended.

The defect you found

Look at what the script told you:

Could not mark E: as trusted (fsutil exited with code 1).
fsutil devdrv query E: said:
  This is a trusted Dev Drive.

The first line says it failed. The next says it worked. You should not have to decide which half of our message to believe — that is our job, and we got it wrong.

What happened is that the script trusted the error code and ignored the answer it had just read back. There is a rule in this repository against exactly that, and it was written the other way round: never call something a success on an error code alone. Calling it a failure on one is the same mistake facing the other way.

Filed as #105. The fix is to say what happened — fsutil returned an error — show what the volume answered, and stop there, instead of concluding the drive is untrusted when it plainly is not.

Your drive is fine. It is trusted, Defender is running in performance mode on it, and WdFilter being the only filter attached is the proof of that.

Why fsutil returned 1 at all

I do not know. It has now been seen exactly once, on your machine. The likeliest explanation is that formatting with Format-Volume -DevDrive already marks the volume trusted, so the call had nothing left to do — but that is a guess, and it is not going into the fix.

The label

That one is not the script's doing. It asks for a name and offers DevDrive if you just press Enter; DevDriveTest.vhdx is what was typed at the prompt. 😄

It is a fair trap to fall into, though — the question comes moments after you have typed a file path, and nothing in it says it wants a display name rather than a file name. Worth a clearer prompt. Already fixed — #106:

The Dev Drive carries a name, which is what File Explorer shows beside its letter, like "Projects (D:)".
This is not the file name; the ".vhdx" keeps the name you gave it.
Enter a name for the Dev Drive, or press Enter for "DevDrive":

The middle line appears only in virtual disk mode; the other two modes have no file to confuse it with.

Your own suggestion — ask for the folder and build the file name from the drive name — is the better shape, and it is filed as #107.

I nearly answered that the two names have different rules and that deriving one from the other would silently rewrite what you typed. Checking before saying it: the name question already refuses every character Windows forbids in a file name, so a name that passes it is already a legal file name. Nothing needs stripping, and the file can be called exactly what you typed.

What is left is narrower and more interesting: CON, NUL, LPT1 and their siblings are perfectly good volume labels and impossible file names. That question would have to start refusing them. Once #107 lands, #106's extra sentence goes with it — there will be nothing left to warn about.

The 512-byte sector

I checked this rather than trust either of our instincts, and the rule hangs on something other than flash. From Microsoft's Hyper-V storage tuning guidance:

You can configure VHDX files to expose as a 4-KB logical-sector size disk. This implementation is an optimal configuration for performance for disks hosted on a 4-KB native physical device. However, make sure the 4-KB logical-sector size supports both the guest and application that use the virtual disk.

and, on the same page:

We recommend you avoid using 4-KB native disks with VHD and VHDX files, as it can cause performance degradation.

By default, the system creates VHDX disks with a 4-KB physical sector size to optimize their performance profile on regular disks and larger sector disks.

The condition is the logical sector size your physical disk reports, not whether it is flash. Nearly every consumer SSD and NVMe is 512e: 512-byte logical sectors over 4096-byte physical ones. So LogicalSectorSize : 512 sitting over a 4096-byte physical sector is the aligned pairing for an ordinary drive, and it is what a VHDX gets by default. The script never asks for anything else.

One command settles it for your machine:

fsutil fsinfo sectorinfo C:

LogicalBytesPerSector is the line to read. 512 means the default is already right for your disk. 4096 means you have a genuine 4K-native drive — that is the case the guidance is about, and then there is something worth building.

Never tried either way: whether a Dev Drive can be formatted at all inside a 4K-logical VHDX.

The dialog that stayed open

Noted, and it is the second time you have seen it. On your first run it closed by itself; this time it did not. That is Windows' own encryption prompt, not something the script opens, and it appears on machines with your setting whether or not BitLocker is being skipped. #65 will warn about it before anything starts.

The line at the very end

The stray table after "This script does not resume" is #82 — a command whose output was never silenced. Harmless, but it lands as the last thing you read after a failure, which is the worst possible place for it. Your output is the first time anyone has seen it there.

@Eagle3386

Eagle3386 commented Aug 27, 2026

Copy link
Copy Markdown

Always glad to help you help me! 🥳

That one is not the script's doing. It asks for a name and offers DevDrive if you just press Enter; DevDriveTest.vhdx is what was typed at the prompt. 😄

I could swear I just typed DevDriveTest - but "in the heat of the moment", it might have slipped & got my adding .vhdx at the end.. 🙈
So, I definitely agree on your explanation of "typed at the prompt". 😅🙈

I checked this rather than trust either of our instincts, and the rule hangs on something other than flash. From Microsoft's Hyper-V storage tuning guidance:

You can configure VHDX files to expose as a 4-KB logical-sector size disk. This implementation is an optimal configuration for performance for disks hosted on a 4-KB native physical device. However, make sure the 4-KB logical-sector size supports both the guest and application that use the virtual disk.

and, on the same page:

We recommend you avoid using 4-KB native disks with VHD and VHDX files, as it can cause performance degradation.

How can they possibly think this is sufficient to make a reasonable decision? 🙈
First, they say 4k give better performance. Then they warn about "performance degradation"?

The condition is the logical sector size your physical disk reports, not whether it is flash. Nearly every consumer SSD and NVMe is 512e: 512-byte logical sectors over 4096-byte physical ones. So LogicalSectorSize : 512 sitting over a 4096-byte physical sector is the aligned pairing for an ordinary drive, and it is what a VHDX gets by default. The script never asks for anything else.

I'd have come up with an advanced parameter for overriding that choice, i.e., purposely not adding another question while still providing a choice - however…

One command settles it for your machine:

fsutil fsinfo sectorinfo C:

… resulted in this (manually translated):

Logical bytes per sector:                                  512
Physical bytes per sector for indivisibility:              4096
Physical bytes per sector for performance:                 4096
Eff. phys. bytes/sector for indivisibility in file system: 4096
Device alignment:                                          Aligned (0x000)
Partition alignment on device:                             Aligned (0x000)
No deduction for searches
Shortening is supported
Not DAX-capable
Not provided with slim storage allocation

… which makes me think the laptop was setup with 512e on a 4 kB NVMe storage drive.

LogicalBytesPerSector is the line to read. 512 means the default is already right for your disk. 4096 means you have a genuine 4K-native drive — that is the case the guidance is about, and then there is something worth building.

I still think: most development files do exceed 4 kB of actual disk usage, hence having all "bytes per sector" values set to 4096 bytes would increase performance - but: I'll leave it entirely up to your final decision. 😎

Never tried either way: whether a Dev Drive can be formatted at all inside a 4K-logical VHDX.

"Never say never".. 😉

The stray table after "This script does not resume" is #82 — a command whose output was never silenced. Harmless, but it lands as the last thing you read after a failure, which is the worst possible place for it. Your output is the first time anyone has seen it there.

Yes, that indeed confused me the most. 😅

@ALERTua

ALERTua commented Aug 27, 2026

Copy link
Copy Markdown
Owner Author

Your measurement settles it, and your suggestion is filed.

Logical bytes per sector:                        512
Physical bytes per sector for performance:       4096

That is 512e — the ordinary case, and the pairing the default already matches. Nothing on your machine needed changing.

Your idea, reshaped: #113. Not a hidden switch, though — a question asked only in virtual disk mode, showing your disk's own figure beside it, so the answer is informed rather than guessed. And the two values are not written into our script: they are read out of what Windows itself will accept, so the question grows by itself if that ever changes.

One thing has to be measured before it ships: whether a Dev Drive can be formatted at all inside a 4-KB-logical .vhdx. Nobody here has tried it either way, and if it cannot, the second option is a trap rather than a choice.

First, they say 4k give better performance. Then they warn about "performance degradation"?

Both are true and they are about different disks. 4 KB logical is faster on a disk that is itself 4 KB native, and slower on everything else — which is nearly everything. The page never says which sentence applies to you, and that is a fair complaint.

most development files do exceed 4 kB of actual disk usage

That argument is right, but it lands on a different knob: the cluster size, which is what the format dialog's "allocation unit size" sets. ReFS offers 4 KB and 64 KB there. It is a separate question from the sector size and is not part of #113.

#82

Closed, not planned. The stray output stays as it is.

@Eagle3386

Copy link
Copy Markdown

One thing has to be measured before it ships: whether a Dev Drive can be formatted at all inside a 4-KB-logical .vhdx. Nobody here has tried it either way, and if it cannot, the second option is a trap rather than a choice.

Did the test real quick - result (manually translated):

format E: /FS:ReFS /A:4096 /DevDrv /Q /V:DevDriveTest

The file system type is REFS.
Enter the current volume label for drive E: DevDriveTest

ATTENTION: ALL DATA ON THE
HARD DISK DRIVE E: WILL BE LOST!
Execute format (Y/N)? y
Format with quick format 50.0 GB
The BitLocker encryption and the encrypted data of the volume were removed.
You can reactivate BitLocker after format completed.
Creating file system structure.
Format finished.
      50.0 GB space total.
      50.0 GB are available.

NOTE: Upon creation of the .vhdx Dev Drive via dev_drive.ps1 (version fetched this morning from your repo), I got the BitLocker dialog once again & it did not vanished automatically.
I therefore suspect it never auto-closes, I just dismissed it back then via X & forgot about that click. I sincerely apologize for that misinformation, Alexey!

That argument is right, but it lands on a different knob: the cluster size, which is what the format dialog's "allocation unit size" sets. ReFS offers 4 KB and 64 KB there. It is a separate question from the sector size and is not part of #113.

While I do get the message & understand the technical stuff behind it. I did think cluster size equals logical size & even allocation unit size. So, thanks for that clarification as well!

@Eagle3386

Copy link
Copy Markdown

Forgot 1 question: how to completely revert anything the .vhdx Dev Drive creation created, including the recovery key stored in AD?

@ALERTua

ALERTua commented Aug 27, 2026

Copy link
Copy Markdown
Owner Author

Forgot 1 question: how to completely revert anything the .vhdx Dev Drive creation created, including the recovery key stored in AD?

Right mouse button on the drive, "Eject", delete the .vhdx, and forget about it.

@Eagle3386

Eagle3386 commented Aug 28, 2026

Copy link
Copy Markdown

Right mouse button on the drive, "Eject", delete the .vhdx, and forget about it.

For .vhdx Dev Drives, there's not a single leftover & even the AD-stored recovery for the virtual drive gets deleted then? 😳

BTW: Due to restricted rights & the way that darn Admin By Request works, I can't go the Eject route.
Any PS cmdlet I could execute to achieve the save?

@ALERTua

ALERTua commented Aug 28, 2026

Copy link
Copy Markdown
Owner Author

Get-DiskImage -Volume (Get-Volume -DriveLetter D) | Dismount-DiskImage

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Read FDVDenyWriteAccess and say in the plan that BitLocker is mandatory on this machine Created Dev Drive volume ends up write-protected

2 participants