mirror of https://github.com/raandree/NTFSSecurity
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
15 KiB
15 KiB
| status | last-verified | owner | source |
|---|---|---|---|
| current | 2026-10-08 | active-agent | repository evidence |
Tech context
Stack
- C# class libraries, old-style
.csproj, .NET Framework 4.5.2, solutionNTFSSecurity.sln(Visual Studio 2017 format). - Projects:
NTFSSecurity(cmdlets),Security2(ACL object model, Win32 interop),PrivilegeControlandProcessPrivileges(token privileges),Log,TestClient,NTFSSecurityTest(MSTest, minimal coverage). - NuGet (
packages.config): AlphaFS 2.2.x for long paths;System.Management.Automation.dll10.0.10586.0. For a drive or volume root, AlphaFSDirectoryInforeaches the device object, whileDirectory.Get/SetAccessControl('C:\')reaches the root folder (#41). - Module:
NTFSSecurity.psd1loadsNTFSSecurity.psm1(aliasesdir2,gi2,rm2,del2),NTFSSecurity.Init.ps1(Add-Type of the helper assemblies, prependsNTFSSecurity.format.ps1xml), andNTFSSecurity.dll. - Documentation: Markdown in
DocsandREADME.md, rendered by GitHub and published to the wiki by CI; no documentation site (Decisions 9 and 11). Cmdlet pages are platyPS 0.14 markdown (schema 2.0.0) inDocs/Cmdlets. - Help:
NTFSSecurity\en-US\NTFSSecurity.dll-Help.xml, generated fromDocs/Cmdletsand committed (Decision 8). - Tests: Pester 5 in
Tests, one file per area, against the Release build;Wiki.Tests.ps1(wiki conversion) runs without a build. - CI: GitHub Actions,
.github/workflows/ci.ymlwith the scripts in.github/scripts(Decision 11).
Environment
- Windows only (NTFS, Win32 security APIs).
- The Debug build writes straight into
C:\Program Files\WindowsPowerShell\Modules\NTFSSecurity\. - No Visual Studio MSBuild or .NET Framework targeting pack on the
workstation. A local build works with the .NET Framework MSBuild
(
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe) plus/p:CscToolPathto the Roslyncsc.exeof theMicrosoft.Net.Compilerspackage; the legacy C# 5 compiler fails with CS0136.dotnet msbuildfails on the binary resources inResources.resx(MSB3822, MSB3823). - platyPS 0.14.2, Pester 5.7.1, PSScriptAnalyzer, and powershell-yaml are
installed only for PowerShell 7. Windows PowerShell 5.1, started from
PowerShell 7, imports platyPS and Pester by full path
(
~\OneDrive\Documents\PowerShell\Modules\platyPS\0.14.2,C:\Program Files\PowerShell\Modules\Pester\5.7.1). Leave$env:PSModulePathalone: PowerShell 7 hands the child the Windows PowerShell default path, and clearing it leaves Windows PowerShell without its core modules (Pester fails:Add-Membernot found). - MarkdownLinkCheck is not installed, and
Save-Modulecrashed (FailFast) in PowerShell 7.6 on 2026-10-04. Download the 0.2.0 package fromhttps://www.powershellgallery.com/api/v2/package/MarkdownLinkCheck/0.2.0into$env:TEMP, extract it, and import it by path. - The first workstation is ARM64; PowerShell 7 runs as x64 under emulation.
- The NuGet cache (
~\.nuget\packages) holds every build dependency: copyalphafs\2.2.1,system.management.automation.dll\10.0.10586, andmicrosoft.netframework.referenceassemblies.net452\1.0.3intopackages\<Id>.<Version>, and pointCscToolPathatmicrosoft.net.compilers\4.2.0\tools. - The second workstation (x64, used since 2026-10-05) runs the agent
session elevated, so the tests that need privileges run there as in CI.
It has no NuGet cache with these packages: download each from
https://api.nuget.org/v3-flatcontainer/<id>/<version>/<id>.<version>.nupkg, extract the first three intopackages\<Id>.<Version>and the compilers into$env:TEMP; Pester 5.7.1 comes from the Gallery package API the same way, its folder first on$env:PSModulePathof the test process. The GitHub CLI is inC:\Program Files\GitHub CLI, outside the PATH of sessions started before its installation. - The third workstation (
ExHost, a Windows Server 2025 VM, x64, used since 2026-10-07) runs the agent session elevated and hosts the AutomatedLab labWindowsAccessControlLab(Decision 20) with Hyper-V and AutomatedLab 5.61.704. It has no NuGet cache or platyPS: check each nuget.org package against the SHA-512packageHashof its catalog entry (https://api.nuget.org/v3/registration5-semver1/<id>/<version>.json, thencatalogEntry), and each Gallery package againstPackageHashofapi/v2/Packages(Id='<id>',Version='<version>'). Pester 5.7.1 is inV:\Git\WindowsAccessControl\output\RequiredModules. The GitHub CLI 2.102.0 is inC:\Program Files\GitHub CLI, outside the PATH, and signed in asraandreesince 2026-10-08;Block-RemoteMutationdenies its mutating commands, so the agent uses it read-only. The lab domainsa.forest1.netandb.forest1.nethad a maximum password age of 42 days, so the password ofinstallexpired on 2026-09-15 and AutomatedLab got access denied; it never expires since 2026-10-07, as inforest1.net.
Constraints
ModuleVersionis5.0.0with the prerelease labelrc6on the branchai/release-5.0.0-rc6(rc5onmaster). The latest stable tag and Gallery release is4.2.6. The manifest requires PowerShell 5.1 and .NET Framework 4.5.2, usesRootModule, and lists exactly 36 cmdlets;Test-ModuleManifestpasses in Windows PowerShell 5.1 and PowerShell 7.6.- The module source at
masterdiffers from tag4.2.6by the changes thatCHANGELOG.mdlists under[Unreleased], the release notes of each 5.0.0 prerelease. - PowerShell Gallery versions (publish dates): 4.0.0 (2015-08-19), 4.2.2 (2016-05-18), 4.2.3 (2016-05-19), 4.2.4 (2018-08-13), 4.2.5 (2019-07-11), 4.2.6 (2019-07-12), none with release notes; 5.0.0-rc1 (2026-10-04), 5.0.0-rc2 (2026-10-05), 5.0.0-rc3 and 5.0.0-rc4 (2026-10-06), 5.0.0-rc5 (2026-10-08), published by CI. Older versions were released on CodePlex only, and their dates are lost. The git history starts on 2016-10-10, when the project moved from CodePlex.
- Releases up to 4.2.6 were Debug builds published by hand, with the whole
output folder; their tags carry the previous version. From 5.0.0 on, CI
publishes on a version tag (Decision 12). GitHub releases attach
NTFSSecurity.zip. - CI: GitHub Actions on pull requests, pushes to
master, and version tags (Decision 11); AppVeyor and Read the Docs aren't used (Decision 9). CHANGELOG.mdlists user-visible changes only; CI and build-only changes get no entry (Decision 7).- Remote mutations are the maintainer's: the user-level preToolUse hook
Block-RemoteMutation.ps1deniesgit pushand mutatingghcommands (pr create,pr close, and others) from the agent session, even after an explicit request. Its override,COPILOT_ATELIER_ALLOW_REMOTE=1, is read from the environment that VS Code starts the hook with; setting it inside an agent command has no effect (verified 2026-10-04). The hook matches the whole command text, so a commit message that quotes such a command is blocked too. Prepare the commands and descriptions; the maintainer runs them. Hand over each command as its own fenced code block at the end of the reply, which the chat shows with a copy button, and end the turn there; the maintainer reports back in the chat. The question dialog joins the lines of its text, has no copy button, and covers the reply before it (maintainer, 2026-10-06). A long question also hides its choices, so that it can't be answered: keep it to a few short sentences (2026-10-07). A pull request description names an issue without a closing keyword (fixes, closes, resolves) unless the merge should close it: "fixes #34" in #112 closed #34. Simulatedghcommands in offline tests must print what the real ones print, such as the URL of a new comment.
Validation
- CI (
.github/workflows/ci.yml): jobbuildonwindows-2025installs platyPS 0.14.2, MarkdownLinkCheck 0.2.0, and Pester 5.7.1 for all users, restorespackages.configper project plusMicrosoft.NETFramework.ReferenceAssemblies.net4521.0.3, buildsNTFSSecurity.csprojin Release with the MSBuild thatvswherefinds, then: 01Update-MarkdownHelpand fail ongit diff -- Docs/Cmdlets; 02Get-MarkdownLink -BrokenOnly; 03 regenerate the help file and fail ongit status --porcelain -- NTFSSecurity/en-US; 04Invoke-Tests.ps1in Windows PowerShell 5.1 and in PowerShell 7, thenInvoke-TestsAsBasicUser.ps1in both editions (since 5.0.0-rc6). Jobwikionubuntu-latest(read-only) clones the wiki (gh auth setup-gitwith the built-in token), runsExport-WikiContent.ps1, and lists the changed pages in the job summary; jobpublish-wiki(contents: write) repeats that and publishes, formasteronly. After the tests,buildrunsNew-ModulePackage.ps1and uploads the artifactpackages(nupkg andNTFSSecurity.zip). Jobreleaseruns only for tags matching[0-9]+.[0-9]+.[0-9]+or[0-9]+.[0-9]+.[0-9]+-*, in the environmentpowershell-gallery(secretPSGALLERY_API_KEY); see Decision 12. Actions are pinned by commit SHA:actions/checkoutv7.0.1,actions/upload-artifactv7.0.1,actions/download-artifactv8.0.1; Dependabot proposes updates weekly, one week after a release. - Packaging needs PSResourceGet (
Compress-PSResource, PowerShell 7.4 or later); its tests skip in Windows PowerShell. Dry run locally: runNew-ModulePackage.ps1againstNTFSSecurity\bin\Releaseinto$env:TEMP, then extract the nupkg into a folder and import it there. - Read CI runs with
gh run list --repo raandree/NTFSSecurity --workflow ci.yml,gh pr checks <number>, andgh run view <id> --log-failed(read-only). - Workflow lint: actionlint (download the release zip into
$env:TEMPand check its SHA-256 against the checksum file; 1.7.12 on 2026-10-08); PowerShell steps check$LASTEXITCODEafter every native command, because GitHub checks only the last one. - Run platyPS in Windows PowerShell 5.1 to avoid PowerShell 7.4+
-ProgressActionnoise. - Placeholder check: no
{{left inDocs/Cmdlets/*.md. - Help file:
New-ExternalHelp -Path .\Docs\Cmdlets -OutputPath .\NTFSSecurity\en-US -Forcemust leavegit statusunchanged. - Pester: run detached (
Start-DetachedPowerShell.ps1) in Windows PowerShell 5.1: the launcher startspwsh, and its payload runspowershell.exe -NoProfile -EncodedCommandwith Pester imported by full path. A run withoutbin\Release\en-USmust fail. - Tests that run only without a privilege skip in an elevated session.
.github\scripts\Invoke-TestsAsBasicUser.ps1runs the suite from an elevated session with a token of the SAFER level Normal User, likerunas /trustlevel:0x20000, and CI runs it in both editions. For a single file,runas /trustlevel:0x20000works too; give Windows PowerShell its ownPSModulePath, and note thatrunasreturns at once, so the script it starts writes its own log. Both tokens hold only the privilege to bypass traverse checking. Pester reports a skipped-ForEachtest under its template name, such as<_> should ..., and a test that ran under the expanded name: compare runs by template. - C# coverage (Decision 21): AltCover 9.0.145 (
tools\net472\AltCover.exeof the nuget.org package) instruments a copy of the local Release build, which has the PDB files that the published package lacks:--reportFormat=OpenCover, AlphaFS andSystem.Management.Automationexcluded with--assemblyFilter, and no--save: then every process writes its hits into the report when it exits. With--save, each process writes a recorder file, andrunner --collectkeeps only the first one (verified 2026-10-08), so the numbers measured that way held only the main process of the elevated Windows PowerShell run. Put the instrumented module inNTFSSecurity\bin\Releaseof agit worktree, run.github\scripts\Invoke-Tests.ps1elevated andInvoke-TestsAsBasicUser.ps1in both editions, thenAltCover.exe runner --collect --recorderDirectory=<the instrumented folder>, which recalculates the summary of the report from the hits. All four configurations, 2026-10-08: the rc5 tree 58.1% of the lines (2,020 of 3,476) and 38.0% of the branches (711 of 1,873), 62.5% without 244 lines in classes that no cmdlet calls; the rc6 candidate (1b9edbb) 68.1% of the lines (2,412 of 3,540) and 44.3% of the branches (850 of 1,918), 73.2% without those classes, theNTFSSecurityassembly 78.1%. The earlier figures, 55.9% for rc5 and 65.6% for rc6, used--save. - Live tests (Decision 20): in an elevated Windows PowerShell 5.1 session
on the lab host,
Tests\Lab\Invoke-NTFSSecurityLabTest.ps1with-Versionfor Gallery packages or-ModulePathfor a build; it writes the results to$env:TEMP\NTFSSecurityLab\Results. A run of two versions in both editions takes about 30 minutes;-RemoveFixtureremoves its accounts, share, and folders from the lab. For a check on the client as an account without administrator rights, useNtfsLiveServerAdmin(Remote Management Users on the client, CredSSP by IP address like the controller): reset its password on the PDC emulator to a random value in memory; the next run of the controller sets a new one anyway. - Lab acceptance of a candidate (modeled on the WindowsAccessControl
handoff 07): build once, package it with
New-ModulePackage.ps1, and record the SHA-256 of the packages and module files; check WinRM, LDAP (RootDSE), Kerberos (klist get), the secure channel, and the clock of the six VMs; take a Production checkpoint namedntfs-<label>-<commit>-before-acceptanceofF1ADC1,F1BDC1,F2DC1,F3DC1,F1AFile1, andF1AFile2; run the controller with-ModulePathof the extractedNTFSSecurity.zipin both editions; then-RemoveFixtureand check that the accounts, share, folders, group memberships, and profiles are gone. Get-NTFSEffectiveAccess -ServerName: the authorization manager of the named computer answers only its administrators and the members of its group Access Control Assistance Operators (S-1-5-32-579); others get "Access is denied" (5). Lab probe of 2026-10-08 onF1AFile2.- Markdown lint:
npx markdownlint-cli2withMD013limited to prose (tables, code, and headings excluded) on the conceptual pages; forCHANGELOG.mdalsoMD024withsiblings_only: true, because every version repeats the category headings. - Gallery packages: download
https://www.powershellgallery.com/api/v2/package/NTFSSecurity/<version>into$env:TEMPand extract it; dates come from the OData endpointapi/v2/FindPackagesById()?id='NTFSSecurity'. Import each version in its own process: every version'sNTFSSecurity.dllhas assembly version 4.2.1.0, so a second version in the same process reuses the first DLL. - YAML:
ConvertFrom-Yaml(powershell-yaml) on.github/workflows/ci.yml. - Links: the CI step 02 (MarkdownLinkCheck 0.2.0) checks only relative
links in
Docs; it strips anchors and skips absolute URLs.Wiki.Tests.ps1checks the wiki links with their anchors; check the links inREADME.mdandCHANGELOG.mdwith a script.