PowerShell startup profiling

High
Unlisted
Please figure out why my powershell is so slow to start, profile, trace, etc etc. Don't make any changes.

Your profile accounts for most of the startup delay, with Mise the largest contributor. I made no edits to your profile, configuration, or installed tools; diagnostic variants ran only in disposable child processes.

Five launches of PowerShell 7.6.7 from your home directory measured:

  • Without profile: median 0.43 seconds
  • With profile: median 3.30 seconds

Statement-level profiling of your profile found:

Startup component Observed time
Mise activation 1.11–1.39 s
Starship initialization 0.42–0.59 s
Atuin initialization¹ 0.37–0.52 s
Git completion import 0.27–0.43 s
WinGet CommandNotFound import 0.26–0.41 s

Mise starts two processes during activation: mise activate pwsh, then mise hook-env from its generated script. Independently, these took roughly 0.5 s and 0.7–0.8 s. Its trace showed local configuration and installed-tool scanning. Even mise --version took about 0.45 s, so this is not solely expensive environment resolution. Calling the executable directly instead of through WinGet’s symlink did not consistently improve it.

I confirmed causality with in-memory profile variants: omitting Mise reduced median profile execution from 2.41 s to 1.24 s; omitting the two completion/suggestion imports reduced it to 1.89 s. These exclude process startup and use a different harness from the launch measurements above.

Starship’s actual prompt modules were inexpensive in your home directory—its slowest reported module took 6 ms. Its startup cost includes executable launches and PowerShell integration, rather than an expensive Git-status calculation there.

Limitations: these were noninteractive measurements, not Windows Terminal’s complete time-to-input. ¹Atuin exited early because PSReadLine was not preloaded; its real interactive cost is therefore not fully captured. Mise used only about 63–94 ms of CPU during roughly 0.5-second launches, but these traces cannot distinguish OS/security scanning, I/O waits, and other startup overhead. I would not blame Defender without further evidence.

If you later want changes, Mise activation is the first optimization target, followed by eagerly importing WinGet suggestions and Git completion.

I also noticed starship calling mise shims that didn't point at anything as being pretty expensive, but maybe that's fixed now. Load PSReadLine. What are options to speed up mise then? (do I need to move to the dev drive b/c defender?)

I wouldn’t move Mise yet. Defender is plausible, but not proven—and your Defender Dev Drive performance mode is currently disabled. Get-MpPreference returned PerformanceModeStatus = 1; I verified that the installed enum maps 1 to Disabled.

I loaded PSReadLine 2.4.5 before profiling. It took 201 ms; Atuin then initialized successfully in 801 ms, Mise took 1.17 s, and Starship initialization took 274 ms. No profile or configuration edits.

The more revealing measurement is Mise’s own timing versus elapsed time:

Command Mise’s internal timing Total elapsed
mise activate pwsh 78 ms 559 ms
mise hook-env -s pwsh 78 ms 536 ms

Most of the delay sits outside Mise’s instrumented work. That points toward process startup/exit, loading, or security overhead—not primarily parsing your configuration. It does not identify Defender specifically.

Options, in order:

  • Investigate Defender before relocating. Your I: drive is ReFS, but checking its Dev Drive trust status required elevation. Performance mode applies only to a trusted Dev Drive, not files remaining on C:. A Defender performance recording would establish whether scanning mise.exe or its data is expensive. Moving just your projects would leave today’s executable and Mise data on C:.
  • Cache the generated activation script. Sourcing a saved mise activate pwsh result could eliminate one roughly half-second executable invocation per shell. The initial hook-env still runs. This needs regeneration after updates and care around environment-specific content—the generated script contains PATH assignments.
  • Activate Mise on demand. This removes its startup cost until needed, at the expense of automatic environment setup before activation.
  • Use shims only. This shifts work from startup to each tool invocation. Given your Starship experience, I would not choose this first: version probes can pay the shim-resolution cost repeatedly.
  • Hook caching/directory-change settings: useful for repeated prompts, but unlikely to solve the measured launch overhead.

Your Starship/shim observation remains plausible. With PSReadLine loaded, Starship’s slowest module in your home directory took only 4 ms; no language-version modules appeared. That doesn’t establish the issue is fixed in project directories, where those probes become active.

> your Defender Dev Drive performance mode is currently disabled How can I fix this?

Open PowerShell as Administrator on your Windows machine, then run:

Set-MpPreference -PerformanceModeStatus Enabled

Verify the setting and your I: drive’s status:

Get-MpPreference | Select-Object PerformanceModeStatus
fsutil devdrv query I:

PerformanceModeStatus should report 0 (Enabled). The drive must also be a trusted Dev Drive—ReFS alone is insufficient. If the query confirms it’s a Dev Drive but says it’s untrusted, you can designate it trusted with:

fsutil devdrv trust I:

Only do that for a development volume whose contents you trust. Keep Defender real-time protection enabled; performance mode requires it.

You can also check in Windows Security → Virus & threat protection → Manage settings → Dev Drive protection → See volumes.

This only benefits files on the Dev Drive. Your Mise executable and data currently live on C:, so enabling it won’t directly resolve the startup delay we measured. It also isn’t a blanket antivirus exclusion: Defender uses asynchronous scanning on the trusted volume. Microsoft’s documentation explains the protection/performance tradeoff.

Did this do it for everything or just the drive!? ❯ Set-MpPreference -PerformanceModeStatus Enabled ❯ Get-MpPreference | Select-Object PerformanceModeStatus PerformanceModeStatus --------------------- 1

It’s a machine-wide setting, but its effects apply only to trusted Dev Drives. It does not change scanning on your normal C: drive or disable Defender globally.

However, your output still shows 1 = Disabled. An enabled result would be 0. So the command did not leave performance mode enabled, despite returning without an error.

Make sure you ran it in PowerShell as Administrator. If you did, don’t disable other protections to force it: an enforced policy or another protection mechanism may be preventing the change, but that output alone doesn’t establish why. Check Windows Security → Virus & threat protection → Manage settings → Dev Drive protection, including whether it says the setting is managed by your organization.

The separate fsutil devdrv trust I: command, if you ran it, applies only to I:; it does not enable the machine-wide performance-mode setting.

Windows Security reports the desired state: asynchronous scanning is on for I:, and off for C:. Dev Drive protection is also on. No further setting change is indicated by these screenshots.

My earlier conclusion that the command “did not leave performance mode enabled” was too categorical. The PowerShell value conflicts with the UI’s per-volume status; that value alone wasn’t sufficient to conclude protection mode was inactive. We haven’t established why they disagree or whether your command changed the state.

The “managed by your administrator” notices shown apply to other protections; they don’t establish that Dev Drive protection is blocked.

For the startup investigation: Mise’s executable and data are still on C:, so they don’t receive I:’s asynchronous-scanning benefit. That makes a controlled comparison worth considering, but it still doesn’t prove Defender caused the delay.

So what's next?

Next, measure whether the same Mise executable starts faster on I:—before moving your installation or changing Defender settings.

I’d run a controlled comparison:

  1. Copy only mise.exe to a temporary directory on I:.
  2. Alternate launches of the original and copied executable, measuring activate pwsh and hook-env from the same working directory with the same configuration.
  3. Compare repeated timings, then remove the temporary copy.

This isolates executable location while leaving Mise’s data on C:. A substantial improvement would support relocating the executable, though it wouldn’t distinguish Defender from other filesystem differences. If there’s little improvement, a Defender performance recording during repeated launches is the next diagnostic—not exclusions or a wholesale migration.

Separately, we should run starship timings in a project where you noticed slow shim probes; the home-directory measurements didn’t exercise that case.

Your original instruction was no changes. May I create and then remove that temporary executable copy on I:? No profile, PATH, installation, or security settings would change.

I was thinking set a temp MISE_DATA_DIR, MISE_CACHE_DIR, etc etc, warm the cache w/whatever it needs. mise is winget, can't move that and if starship is fine so should it?

Yes—testing Mise’s data/cache on I: is a useful separate experiment, and it leaves the WinGet installation alone. My executable-copy proposal tested a different hypothesis; it wasn’t a recommendation to move the managed installation.

For a meaningful comparison, I’d:

  • Copy the existing Mise data and cache into temporary directories on I:, rather than start empty. Otherwise, fewer installed tools or missing metadata could make it artificially faster.
  • Set MISE_DATA_DIR and MISE_CACHE_DIR only in disposable child processes, leaving your configuration and working directory unchanged.
  • Warm both cases, then alternate original versus temporary directories while timing activate pwsh and hook-env.
  • Check that both cases select the same tools, then delete the temporary copies.

I’d keep configuration in its existing location initially, so we test one distinction at a time. This tests data/cache access, not executable-loading overhead.

Starship being fast doesn’t rule out Mise-specific executable overhead. Different binaries load different code and dependencies and can incur different scanning costs. Our strongest clue remains that Mise reported about 78 ms internally versus 540–560 ms elapsed. Moving its data might help, but we shouldn’t assume it explains that gap.

May I run your data/cache comparison with those temporary copies? Your profile, WinGet installation, persistent environment variables, and Defender settings would remain untouched.

Run as many experiments as you want across everything, come back with a report. Just ensure your changes roll back.

Two problems are confirmed: Mise’s executable is much slower to launch from C:, and Starship still incurs expensive Node-shim lookups in projects without a selected Node version. Moving Mise’s data/cache alone did not solve either.

All temporary copies and scripts have been removed. Your profile, Mise configuration, and Starship configuration passed unchanged-hash checks. I left the WinGet installation, persistent environment variables, and Defender settings untouched.

Executable placement mattered; data/cache placement barely did

I cloned your existing data/cache rather than testing empty directories, verified identical installed-tool inventories, and checked that executable copies had identical SHA-256 hashes. These are medians of five measured runs after warmup, with cases interleaved:

Test configuration activate pwsh hook-env
Original executable; cloned data/cache on C: 626 ms 688 ms
Only data on I: 708 ms 653 ms
Only cache on I: 654 ms 638 ms
Data/cache/state on I: 625 ms 659 ms
Executable copied elsewhere on C: 608 ms 646 ms
Only executable copied to I: 44 ms 92 ms
Executable/data/cache/state/config on I: 42 ms 82 ms

The executable-only improvement was consistent: every measured I: activation took 41–51 ms, versus 442–757 ms for the original executable. A follow-up using your original data/config locations reproduced the advantage.

Starship also benefited from executable placement, but less dramatically: starship --version took 99 ms from its installed location versus 32 ms from I:. Mise’s corresponding numbers were 645 ms versus 40 ms. So Starship appearing relatively fast does not rule out this effect.

This proves a location-dependent launch penalty—not Defender specifically. Defender’s asynchronous scanning is a plausible explanation, but filesystem and other security/filter differences remain possible. I did not obtain an elevated Defender trace or disable protection.

Full Mise activation can save about 0.84 seconds

In fresh PowerShell processes with PSReadLine loaded, I timed generation and execution of the activation script:

Approach Median activation time
Existing executable and normal activation 1,141 ms
Cached activation script, existing executable 667 ms
Normal activation using executable on I: 297 ms
Cached script using executable on I: 234 ms
Existing executable with --no-hook-env 587 ms

These exclude PowerShell startup and PSReadLine import. --no-hook-env changes functionality, so it isn’t an equivalent fix. Caching helps without relocating the executable, but introduces regeneration and environment-staleness concerns.

Your Starship shim observation is still reproducible

In I:\code\vitest, invoking the Node shim took 488 ms, then failed with:

No version is set for shim: node

The runtime is installed; the problem is no version selected for that directory, not necessarily a dangling shim.

Starship’s Node module spent roughly 0.5 seconds on that lookup. Applying Mise’s environment didn’t help in vitest, because no Node version was selected there.

In at-chat, which selects Node through mise.local.toml, applying Mise’s resolved PATH reduced the Node probe to 41 ms. Actual starship prompt execution improved from a median 654 ms to 361 ms. vitest-ansi-serializer showed the same module-level improvement.

What I recommend

  1. Don’t relocate Mise’s data/cache for startup speed. These measurements don’t justify it.
  2. Address executable launch overhead. A supported installation location on I: is worth investigating while preserving WinGet updates. Don’t manually move its managed package directory. An elevated Defender recording is the next step if you want attribution before changing installation layout.
  3. Give Node projects an appropriate selected version, or choose a global fallback if that matches your workflow. Keep real tool directories ahead of shims through activation.
  4. Avoid shims-only activation as the speed fix. It shifts the expensive work into tool invocations—including Starship probes.

The largest measured startup improvement is executable placement; the separate, confirmed prompt issue is version probing through an unresolved shim.

Add a defender exclusion for those exes, escalate to me. I'm here I can auth.

Added and verified both exclusions with administrator approval:

  • WinGet’s installed mise.exe
  • C:\Program Files\starship\bin\starship.exe

These are exact-file exclusions, not folder or process exclusions. Existing exclusions were preserved; Defender otherwise remains enabled.

The immediate retest did not reproduce the Dev Drive speedup: Mise activation still took a median 512 ms, hook-env 510 ms, and Starship’s version command 86 ms. So the exclusions are active, but they have not resolved the measured delay.

To undo these additions, run in elevated PowerShell:

Remove-MpPreference -ExclusionPath @(
  'C:\Users\dukeseh\AppData\Local\Microsoft\WinGet\Packages\jdx.mise_Microsoft.Winget.Source_8wekyb3d8bbwe\mise\bin\mise.exe'
  'C:\Program Files\starship\bin\starship.exe'
)

I left them enabled as requested, though without a demonstrated benefit I recommend removing them rather than broadening the exclusions.

Why would it be so much faster do you think?

My leading hypothesis is a security/filesystem check during executable launch that the Defender file exclusions don’t bypass. The experiments establish the launch-location effect, but don’t yet identify the component responsible.

The evidence narrows it down:

  • Same executable bytes, different performance: Mise launches from I: were much faster than both its installed location and a fresh copy on C:.
  • Moving data/cache barely helped: configuration parsing and tool discovery aren’t the main explanation.
  • Even mise --version showed the gap: no substantial project work is necessary to trigger it.
  • Mise’s internal timer missed most of the delay: roughly 78 ms internally versus 540–560 ms elapsed. That points toward work before its timing begins or after it ends.
  • Exact-file Defender exclusions didn’t remove the delay: that weakens the hypothesis that ordinary antivirus scanning of mise.exe itself is the cause.

Possibilities, in the order I’d investigate:

Hypothesis Why it fits
Another security check or filesystem filter Application control, reputation checks, or another security component could treat executable launches differently across volumes. Defender antivirus exclusions don’t necessarily bypass those mechanisms.
Dev Drive versus NTFS image-loading behavior Executable loading involves opening and mapping files. Different volume/filter behavior could affect that path even when the executable is cached.
Scanning or loading dependencies rather than the executable itself We excluded only two files, not everything involved in launching them. This remains possible, although the volume-specific effect needs explaining.
Ordinary disk throughput Less convincing: the difference persisted across warm runs, and moving the much larger data directory barely mattered.

The next useful experiment is an elevated Windows Performance Recorder trace of alternating C: and I: launches, capturing process lifetime, image loading, file I/O, and thread waits. A Defender performance recording alongside it can test Defender’s contribution specifically. That would show where the missing half-second goes instead of guessing from elapsed time.

I wouldn’t broaden exclusions. Since the two existing exclusions showed no clear benefit, I’d remove them before tracing so we investigate the normal protected configuration.

I did remove them. I'm going to bed, I can auth you once but not more

The trace identifies Windows Code Integrity—not Mise’s initialization—as the main source of the extra launch time. One administrator approval was sufficient; recording has stopped and temporary executable copies have been removed.

Where the half-second goes

During warmed launches, the parent PowerShell process spent:

Executable location Time inside process creation
WinGet installation on C: 467–585 ms
Temporary copy on C: 465–528 ms
Identical copy on I: 7–13 ms

CPU sampling places most of that work in CI.dll, Windows’ Code Integrity Module. Across the launching thread’s samples, 4,516 were in CI.dll and 1,153 in the Windows kernel. Individual warmed C: launches contained 353–447 Code Integrity samples during their launch interval.

This explains why Mise’s own internal timer missed most of the delay: the parent process is doing expensive Windows launch checks before process creation returns.

Why the Defender exclusions didn’t help

The Defender recording captured scans labelled EDRSensor, but correlating their timestamps with process IDs showed they started after the corresponding Mise processes had already exited. Those recorded scans therefore cannot explain the synchronous launch delay.

That is stronger evidence than simply observing that exclusions didn’t help. I also verified that both exclusions were absent during this capture.

What remains uncertain

The expensive subsystem is identified; the exact policy or caching behavior is not. The first I: launch was also expensive, but subsequent launches were fast. Repeated C: launches continued paying the cost. That is consistent with different reuse of Code Integrity validation results, but the trace analysis does not establish why.

Your Mise executable is not Authenticode-signed. That may be relevant, but unsigned status alone does not explain the difference between volumes. I would not disable Code Integrity or attribute this to a particular security policy without further evidence.

Practical recommendation: leave the antivirus exclusions removed. Executable placement on I: remains the demonstrated workaround; moving data/cache is not. A maintainable installation/update arrangement on the Dev Drive is preferable to weakening Windows security.

The trace artifacts and timing tables are retained locally, including the Windows trace—about 1.8 GB. No security settings were changed during this run.

Shouldn't CI.dll just be for kernel/drivers/etc?

It runs in the kernel, but it isn’t limited to checking kernel code. That distinction matters here.

  • Kernel-mode Code Integrity checks drivers and other kernel components. Memory Integrity/HVCI protects this mechanism.
  • User-mode Code Integrity (UMCI) extends checks to ordinary applications and DLLs through App Control policies. Microsoft explicitly documents that Enabled:UMCI enables validation of user-mode executables and scripts. Policy documentation

When PowerShell creates a process, its thread enters the kernel. Windows can perform those checks there before returning from process creation. CPU time in CI.dll can therefore appear on PowerShell’s launching thread, even though Mise is an ordinary user-mode executable.

What our trace proves is narrower than identifying a policy: the launching thread spends most of the extra CPU time at addresses within the loaded CI.dll image. We haven’t resolved the particular functions or established which policy invokes them, so I shouldn’t equate that automatically with UMCI enforcement or signature verification.

There’s also a relevant documented possibility: Microsoft says App Control normally caches successful policy evaluations using file extended attributes, but that optimization is not used for audit-mode policies. That makes auditing the active policies a useful next investigation—not proof that audit mode explains your C:/I: difference. Performance caveat

Keep going then!

Found the caller: Defender’s WdDevFlt.sys driver triggers the expensive Code Integrity hashing during process creation. This is more specific—and corrects my earlier “Code Integrity, not Defender” framing.

I reconstructed the complete call stacks and resolved them using Microsoft’s public symbols, matching the PDB identities recorded in the trace:

Windows creates the process
  → WdDevFlt!ProcessManagerNotifyRoutineEx
  → WdDevFlt!WddProcessCreateContext
  → NtSetCachedSigningLevel
  → CI!CiSetFileCache
  → CI!HashKComputeImageHash
  → CI!SymCryptSha1AppendBlocks

The costly work is SHA-1 hashing of the executable. Of the 4,516 samples whose instruction pointer was inside CI.dll, 4,515 resolved to SymCryptSha1AppendBlocks. The reconstructed CI-containing stacks consistently include WddProcessCreateContext.

This explains several observations:

  • Why CI.dll runs for an ordinary application: an antimalware driver calls it from a process-creation notification. User-mode Code Integrity enforcement reports off, so the UMCI-policy hypothesis is not supported.
  • Why Mise is hit harder than Starship: Mise’s executable is about 98 MiB, making repeated image hashing substantial.
  • Why the ordinary exclusions didn’t settle it: the measured path is signing-level/cache initialization invoked by a Defender driver, not the later content scans in Defender’s performance report. Our exclusion test demonstrably didn’t eliminate it.
  • Why I: helps: after its initial expensive launch, this repeated hashing penalty disappears there. Exactly why Windows reuses or avoids the work on I: but repeats it on C: remains unresolved.

The installed driver identifies itself as Microsoft antimalware device filter driver, version 4.18.26080.4. This is now a concrete finding to report to Microsoft: repeated process-launch image hashing through WdDevFlt → NtSetCachedSigningLevel → CI, with the same binary behaving differently across volumes.

I recommend keeping the exclusions removed and using executable placement on the Dev Drive as the demonstrated workaround—not disabling Code Integrity or Defender. An update might fix it, but I haven’t tested another Defender version.

No further elevation or security changes were made. Temporary analysis tools and derived caches are removed; recording is stopped. The symbol-resolved stacks and original traces remain available locally.

So why didn't adding exclusions help?

Because the exclusion didn’t bypass the particular Defender operation causing the delay. Excluding a file from antivirus scanning isn’t equivalent to exempting it from every Defender-related launch check.

The trace shows this sequence:

Process creation
  → WdDevFlt’s process-creation callback
  → Windows signing-level/cache API
  → Code Integrity hashes the executable

That’s distinct from the content scans shown in Defender’s performance report. Those recorded scans started after Mise had exited, so skipping them wouldn’t fix the startup delay.

What we know: the exact-file exclusions were present, launches remained slow, and—with exclusions subsequently removed—the expensive path resolved to WdDevFlt → NtSetCachedSigningLevel → SHA-1 hashing.

What we haven’t proved: whether WdDevFlt intentionally ignores antivirus exclusions for this operation, performs it before checking exclusions, or has a caching bug. We didn’t capture a symbol-resolved trace while exclusions were enabled, so I can’t conclusively say the identical call stack persisted in that test.

The supported conclusion is: those exclusions didn’t remove the launch penalty; broadening them isn’t a justified fix. My earlier suggestion that excluding mise.exe would test all Defender involvement was too broad—it tested the effect of antivirus file exclusions, not every operation performed by Defender’s drivers.

I can't move mise. Personally I'm not *super* much a believer in antivirus but I don't think I can turn it off w/institution policies. > What we haven’t proved: whether WdDevFlt intentionally ignores antivirus exclusions for this operation, performs it before checking exclusions, or has a caching bug. We didn’t capture a symbol-resolved trace while exclusions were enabled, so I can’t conclusively say the identical call stack persisted in that test. Can you find out?

I found the mechanism behind the slowdown, but can’t establish whether Microsoft considers it intentional or a bug. The evidence points to signing-level validation, rather than an ordinary antivirus file scan.

The captured launch stack is:

Process creation
  → WdDevFlt (Defender’s driver)
  → request cached signing-level validation
  → CI.dll
  → hash Mise’s ~98 MiB executable

I inspected the installed driver’s code and queried the signing cache before and after launches:

Executable location Signing-cache result Driver’s matching branch
Original C: location STATUS_NOT_FOUND, repeatedly—even after launch Request validation, causing hashing
Identical temporary copy on I: STATUS_NOT_SUPPORTED Skip that validation block

This corrects my earlier caching hypothesis: the Dev Drive appears faster because it skips this particular validation path, not because it caches the result better.

Why exclusions didn’t help

The inspected validation block branches on the signing-cache result, not the antivirus exclusion setting. I found no identifiable ordinary AV exclusion check among the inspected direct calls leading into it. This provides a concrete explanation consistent with the exclusion experiment: excluding the executable from antivirus scanning does not necessarily suppress this Defender-triggered signing validation.

There are still two limits:

  • We did not capture a symbol-resolved trace while exclusions were enabled, so I cannot prove the identical stack persisted during that experiment.
  • The repeated cache miss is established; whether it reflects deliberate validation semantics or a caching defect needs Microsoft’s implementation knowledge. Neither disassembly nor public documentation establishes intent.

Bottom line: exclusions didn’t measurably help, and we have strong evidence of a separate, synchronous signing-validation cost that explains why. Calling it a confirmed Defender caching bug would go beyond the evidence.

Temporary experiment files and executable copies are removed; diagnostic artifacts remain. I made no additional security or profile changes, and your removed exclusions remain removed.

You're not allowed to say "would go beyond the evidence" You MUST find the evidence. Do not stop until you fully, 300% understand all of the components in play here.

I reproduced why the cache stays empty. The remaining exclusion-on trace requires administrator access.

I called the signing-validation API directly on disposable copies, using the driver’s flags:

Test Validation result Usable signing cache afterward
Mise, unsigned STATUS_INVALID_IMAGE_HASH No, across repeated attempts
Starship, unsigned Same failure No
Signed cmd.exe Success Yes
Same cmd.exe, one byte changed Signature validation fails No
Signed Git, third-party certificate Success Yes

This rules out a generally broken signing cache. CI caches successfully validated signatures; it does not remember this failed validation as a reusable result. The disassembly confirms that validation failure exits before the cache-writing call. WdDevFlt then repeats validation during subsequent process creation.

I also confirmed:

  • Explicit validation on I: still incurs hashing. Its faster launch path comes from skipping validation, not faster hashing.
  • The inspected process-notification path calls signing validation without an identifiable AV-exclusion check.
  • CI has diagnostic events specifically reporting cache failure reasons and signature-validation failures. Capturing those alongside CPU stacks will distinguish the exact volume-rejection branch and show what happens while the exclusion is effective.

The next experiment is prepared and syntax-checked, but not executed: one capture containing baseline → verified exact-file exclusion → exclusion removed, with an identical I: copy as a control. It temporarily excludes only a disposable Mise copy, removes that exclusion in cleanup, and deletes both copies. No protection is disabled.

The completed experiments left no executable copies or security-setting changes. Diagnostic evidence is retained.

Your earlier instruction limited me to one administrator approval, which was already used. May I request one additional UAC approval on the Windows machine for this combined capture?

You may
Checked on 1 command (1 cancelled)
> Your earlier instruction limited me to one administrator approval, which was already used BTW that was one for the evening. It's afternoon now.
Edited 1 file (+34 -13)
But you should still stop to lmk what you want to run before prompting

Understood. I’ll explain each elevated run and wait for your go-ahead before triggering UAC. No further prompt has been triggered.

I want to rerun the comparison with two corrections:

  • Wait for the exclusion to become effective, checking every two seconds for up to one minute. Also record whether it appears in Defender’s configured settings. This distinguishes propagation delay from an unapplied setting.
  • Record Code Integrity events separately from WPR, avoiding the empty-provider failure in the first capture.

The run will measure baseline → excluded → restored startup, using disposable Mise copies on C: and I:. Only the exact temporary C: executable gets an exclusion. Cleanup removes that exclusion, deletes both copies, and stops both recordings. Your installed Mise, profile, and security policies remain untouched.

Expect roughly 1–3 minutes after approval. The script passes syntax checking; the revised capture has not run.

Ready for me to trigger the UAC prompt?

yes

That attempt stopped before changing any exclusions. My first capture left WPR with a stale configuration that its elevated status check cannot read. The temporary executable copies were deleted.

For the next elevated run, I propose to:

  1. Clear that failed recording state with wpr -cancel.
  2. Start a separately named WPR recording and an independent Code Integrity trace.
  3. Run the baseline → verified exclusion → restored comparison, allowing up to 60 seconds for exclusion changes to take effect.
  4. Remove the temporary exclusion and copies, stop the recordings, and verify recorder status while still elevated.

The revised script passes syntax checking. No further UAC prompt has been triggered.

May I trigger the prompt for this recovery-and-capture run?

yes

The exclusion was effective, and the same expensive hashing still happened. We have symbol-resolved stacks from all four excluded launches—not just similar timings.

Median process-creation time¹ C: I: control
Before exclusion 1,042 ms 9.1 ms
Exclusion verified effective 1,004 ms 8.6 ms
After exclusion removed 960 ms 6.9 ms

¹ Four launches per condition, identical copies of your current 210 MB Mise executable.

Why exclusions didn’t help

The expensive operation is signing-level classification during process creation, not an ordinary antivirus content scan. The excluded launches show:

NtCreateUserProcess
  → WdDevFlt!ProcessManagerNotifyRoutineEx
    → WddProcessCreateContext
      → NtSetCachedSigningLevel
        → CI!CiSetFileCache
          → HashKComputeImageHash
            → SymCryptSha1AppendBlocks

The driver’s inspected code follows this sequence:

  1. Query the executable’s cached signing level.
  2. If the result is specifically STATUS_NOT_FOUND, request signature validation.
  3. CI hashes Mise, but validation returns STATUS_INVALID_IMAGE_HASH.
  4. No successful signing cache entry is produced, so the next launch repeats the work.

All 12 C: launches—including the four excluded ones—followed that failure sequence. In the excluded tests, CI reported failure 964–1,013 ms into process creation, only about 5–7 ms before Process.Start returned.

This isn’t evidence of an exclusion failing to propagate or a successfully cached result being forgotten. The exclusion was independently confirmed by Defender, and signature validation never produced the reusable result. Signed Windows and third-party executable controls did populate the cache in the earlier experiments.

The observable implementation treats this classification separately from the tested antivirus exclusion. Whether Microsoft considers that separation intentional product behavior or a performance defect requires Microsoft’s answer; the execution mechanism is established.

Why I: is fast

CI returns STATUS_NOT_SUPPORTED, rather than STATUS_NOT_FOUND, for the signing-cache query on that volume. WdDevFlt’s code skips validation for that return value.

The live CI event identifies its cache-eligibility rejection: State=5, with volume flags 0x5FC636CF and file attributes 0x20. Matching that to CI’s disassembly places it in the volume/file eligibility branch, before reading the signing cache. This is not proof that ReFS universally lacks signing caches, nor that asynchronous antivirus scanning makes hashing faster. This path skips the validation request altogether.

What this means for your setup

Moving or warming MISE_DATA_DIR and MISE_CACHE_DIR cannot eliminate this particular delay: it occurs while Windows creates the process, before Mise executes. With the installed executable staying put, reducing repeated Mise launches is the practical workaround; an upstream signing change or Microsoft driver fix would address the underlying mechanism.

Rollback is complete: the experimental exclusion and executable copies are removed, and capture sessions stopped. Profiles and installations are unchanged. Captured stacks and per-launch CI failures are retained. The general trace dropped events, so I used positive stacks—not absence or CPU percentages; the separate CI trace lost none.

So what's next steps? Mise is looking into signing, but until then?

Until Mise ships a signed build, I’d reduce how often PowerShell and Starship launch it. Keep Defender enabled; the exclusion experiment gives us no reason to weaken protection.

In priority order:

  1. Use Mise’s tools directly where possible. Put the selected installations’ real bin directories on the shell’s process-local PATH, rather than routing commands through Mise shims. This avoids paying Mise’s startup cost whenever a shim dispatches a command. The tradeoff is that version selection must be refreshed when changing projects or tool versions.

  2. Keep Mise out of prompt rendering. Check whether Starship’s version probes resolve to shims. Prefer direct tool executables, or disable only the offending version modules. Also inspect Mise’s directory-change/prompt hook: avoid repeated calls when the directory and configuration haven’t changed.

  3. If shell activation itself remains expensive, make it opt-in. A lightweight shell could start without Mise activation, with a command you run when entering a development project. That preserves the installed WinGet executable and trades automatic switching for faster startup.

I would not spend more time relocating Mise’s data/cache directories to solve this delay. They may improve other operations, but cannot remove the executable-validation cost we measured.

The next useful experiment is a temporary shell-only comparison: your normal setup versus direct tool paths, then versus opt-in activation—with PSReadLine loaded in every case. Measure shell startup, first prompt, subsequent prompts, directory changes, and a few actual tool commands. That will identify the smallest change that helps without breaking your workflow; no profile edits are needed for the experiment.

Separately, our trace is suitable for a Microsoft performance report: WdDevFlt repeatedly requests synchronous validation of an unsigned executable, fails to cache a successful result, and does so even with an effective exclusion. Signing is the promising upstream remedy, but we should benchmark the signed release rather than assume it fixes everything.

How would I file a bug report with msft?
Explored 1 search

File it through Feedback Hub; ask Rose-Hulman IT to open a Microsoft support case if you want direct investigation. Feedback Hub is Microsoft’s official bug-reporting channel, but it doesn’t guarantee an individual response.

Filing the report

  1. Open Feedback Hub from Start.
  2. Select Report a problem and choose the closest Microsoft Defender / Windows Security category available.
  3. Use the title and description below.
  4. Attach the small evidence files listed below. Optionally use Recreate my problem while running mise --version several times; no exclusions or other security changes are needed.
  5. Submit and save the feedback link. Give that link to IT if they escalate.

Title

WdDevFlt synchronously rehashes unsigned mise.exe on every launch, adding ~1 second even with an effective AV exclusion

Description

Repeated launches of unsigned mise.exe 2026.10.12 (210,081,792 bytes) incur approximately one second of synchronous process-creation overhead on C:. This affects interactive shell startup and prompt responsiveness.

A paired experiment measured four launches per condition. Median Process.Start times were 1,042 ms before a file-path exclusion, 1,004 ms with the exclusion confirmed effective by MpCmdRun -CheckExclusion, and 960 ms after removal. Identical executable copies on the I: Dev Drive took 7–9 ms.

Symbol-resolved stacks during all four excluded launches show:
NtCreateUserProcess → WdDevFlt!ProcessManagerNotifyRoutineEx → WddProcessCreateContext → NtSetCachedSigningLevel → CI!CiSetFileCache → HashKComputeImageHash → SymCryptSha1AppendBlocks.

On C:, the signing-cache query returns STATUS_NOT_FOUND. Validation returns STATUS_INVALID_IMAGE_HASH, leaving no successful cache entry, and subsequent launches repeat the work. All 12 measured C: launches produced this failure. On I:, the cache query returns STATUS_NOT_SUPPORTED and the driver skips this validation path.

Please investigate repeated synchronous signing-level validation of unchanged unsigned executables in WdDevFlt, including supported mitigation and whether the behavior with antivirus exclusions is expected. This report concerns performance, not a request to bypass signature enforcement.

WdDevFlt version: 4.18.26080.4. CI.dll fixed version: 10.0.26100.9444. The general WPR trace dropped 9,928 events; positive captured stacks establish the call path. The separate Code Integrity trace lost no events.

Evidence to attach

In the capture folder, start with:

  • timings.csv
  • correlated-stacks.txt
  • correlated-ci-failures.txt
  • excluded-exclusion.txt
  • hashes.csv

Review attachments for personal paths before submitting. Keep the 2.16 GB comparison.etl for a private Microsoft support upload rather than posting it publicly: system traces can reveal unrelated processes and file paths. Tell IT that both WPR and Code Integrity traces are available, and request routing to the Defender Dev Drive filter (WdDevFlt) / Windows Code Integrity performance team.