| Project | Files | Purpose | Key Classes |
|---|---|---|---|
VdiAssess.Model |
10 | Domain entities, interfaces, enums | IConnector, ISecretsStore, IClock, AssessmentKey, FindingDomain |
VdiAssess.Rules |
34 | Assessment rules engine | IRule, RuleRunner, ScoringEngine, DefaultRules, 30 rule classes |
VdiAssess.Core |
13 | Orchestration, persistence, infrastructure | SnapshotOrchestrator, FileLockManager, DpapiSecretsStore, AuditLogger |
VdiAssess.Connectors.Citrix |
4 | Citrix CVAD data collection | CitrixConnector, CitrixPowerShellRunner, MockConnector, CitrixMapper |
VdiAssess.Reporting |
4 | Report generation (HTML + PDF) | IReportRenderer, HtmlReportRenderer, PdfReportRenderer, ReportDataBuilder |
VdiAssess.Cli |
10 | CLI entry point and command handlers | Program, InitCommand, SnapshotCommand, SecretsCommand |
VdiAssess.Tests |
16 | Unit tests (xUnit + FluentAssertions) | RuleTests, FileLockManagerTests, DpapiSecretsStoreTests |
VdiAssess.IntegrationTests |
5 | End-to-end integration tests | SnapshotEndToEndTests, BaselineTests, ExportTests |
ConfigLoader parses YAML → Connector collects inventory + telemetry → SqliteRepository persists snapshots → RuleRunner evaluates 30 rules against RuleContext → ScoringEngine grades by domain → Renderers produce reports
Platform abstraction: CitrixConnector (PowerShell, Windows-only) or MockConnector (cross-platform dev/test)
Impl: DpapiSecretsStore — DPAPI encryption on Windows, base64 fallback for dev
RuleContext provides Controllers, Catalogs, DeliveryGroups, VDAs, PolicySettings, SessionBuckets, LogonBuckets, FailureBuckets
Impls: HtmlReportRenderer (self-contained HTML) and PdfReportRenderer (QuestPDF)
Impls: WindowsScheduledTaskManager (schtasks.exe) and NoopScheduledTaskManager (non-Windows)
Impls: SystemClock (production) and FakeClock (test, with Advance/Set methods for time manipulation)
| # | Phase | Description | Key Deliverables | Status |
|---|---|---|---|---|
| 0 | Foundation | Solution scaffold, projects, CI-ready structure | 8 csproj files, Directory.Build.props, .editorconfig | Complete |
| 1 | Domain Model | Core entities, enums, value objects | Entities, Buckets, Snapshots, Findings, RunInfo, Enums | Complete |
| 2 | Interfaces & Config | Abstractions and YAML configuration | IConnector, ISecretsStore, IClock, ConfigLoader, AssessmentKey | Complete |
| 3 | Rules Engine | 30 assessment rules across 4 domains | IRule, RuleRunner, ScoringEngine, 30 rule implementations | Complete |
| 4 | Data Layer | SQLite persistence and file locking | SqliteRepository, SchemaBootstrap, FileLockManager, AuditLogger | Complete |
| 5 | Connectors | Citrix CVAD data collection via PowerShell | CitrixConnector, CitrixPowerShellRunner, MockConnector, CitrixMapper | Complete |
| 6 | Orchestration | Snapshot and baseline workflow orchestrators | SnapshotOrchestrator, BaselineOrchestrator, ValidateOrchestrator, RunManager | Complete |
| 7 | Reporting | HTML and PDF report generation | HtmlReportRenderer, PdfReportRenderer, ReportDataBuilder | Complete |
| 8 | CLI & Secrets | System.CommandLine CLI with DPAPI secrets store | 9 commands, DpapiSecretsStore, WindowsScheduledTaskManager | Complete |
| 9 | Export & Cleanup | ZIP export, manifest, cleanup with retention | ExportCommand, CleanupCommand, ManifestBuilder, LockClearCommand | Complete |
| Rule ID | Class | Description |
|---|---|---|
UX-AVG-LOGON | HighAvgLogonRule | Flags when the overall average logon duration exceeds threshold |
UX-LOGON-P95 | LogonP95Rule | Flags delivery groups where p95 logon duration exceeds threshold |
UX-LOGON-P99 | LogonP99Rule | Flags extreme logon outliers where p99 exceeds threshold |
UX-PROFILE-LOAD | LogonProfileLoadRule | Flags when profile load phase dominates logon duration |
UX-GPO-LOAD | LogonGpoRule | Flags when GPO processing phase is excessive during logon |
UX-BROKER-RESPONSE | BrokerResponseTimeRule | Flags when broker response time contributes excessively to logon duration |
UX-DISCONNECT-RATE | DisconnectRateRule | Flags elevated disconnect-to-reconnect ratios indicating session instability |
UX-RECONNECT-RATE | HighReconnectRateRule | Flags elevated reconnection rates indicating network instability or client issues |
UX-FAILURE-HOTSPOT | FailureHotspotRule | Flags delivery groups with elevated connection failure rates |
UX-RECURRING-ERROR | RecurringErrorCodeRule | Flags when the same error code recurs across multiple telemetry buckets |
| Rule ID | Class | Description |
|---|---|---|
CAP-CONCURRENCY | ConcurrencyHeadroomRule | Flags when peak concurrent sessions approach available VDA capacity |
CAP-EMPTY-DG | EmptyDeliveryGroupRule | Flags delivery groups with no associated VDAs |
CAP-LARGE-DG | LargeDeliveryGroupRule | Flags delivery groups with a very large number of VDAs (blast radius concern) |
CAP-SMALL-CATALOG | SmallCatalogRule | Flags catalogs with very few VDAs (potential consolidation opportunity) |
CAP-POOL-IMBALANCE | PoolImbalanceRule | Flags delivery groups with significantly uneven VDA distribution across catalogs |
CAP-OS-MIX | OsTypeHomogeneityRule | Flags delivery groups mixing desktop and server OS VDAs (unusual configuration) |
CAP-SERVER-DENSITY | ServerOsDensityRule | Assesses session density on server OS VDAs for capacity planning |
CAP-PROV-TYPE | McsProvisioningRule | Reports provisioning type distribution for capacity planning awareness |
CAP-STATIC-MACHINES | StaticMachineTypeRule | Reports proportion of static (persistent) vs pooled VDAs for lifecycle management awareness |
| Rule ID | Class | Description |
|---|---|---|
RES-SINGLE-DDC | SingleControllerRule | Flags environments with only a single Delivery Controller (SPOF) |
RES-DDC-VERSION | ControllerVersionMismatchRule | Flags when controllers have different roles that may indicate incomplete upgrades |
RES-SINGLE-CATALOG | SingleCatalogRule | Flags delivery groups backed by a single machine catalog (SPOF for image updates) |
RES-SESSION-RELIABILITY | SessionReliabilityRule | Flags when session reliability is not enabled |
RES-NO-DG | NoDeliveryGroupsRule | Flags environments with no delivery groups configured |
RES-NO-VDAS | NoVdasRule | Flags environments with no VDAs discovered |
| Rule ID | Class | Description |
|---|---|---|
SEC-USB | UsbRedirectionRule | Flags when USB redirection is enabled (malware introduction risk) |
SEC-CLIPBOARD | ClientClipboardRedirectionRule | Flags when client clipboard redirection is enabled (data exfiltration risk) |
SEC-CLIENT-DRIVE | ClientDriveRedirectionRule | Flags when client drive redirection is enabled (data exfiltration risk) |
SEC-PRINTER | PrinterRedirectionRule | Flags when client printer redirection is enabled with auto-create (potential data exfiltration via print-to-file) |
SEC-AUDIO-QUALITY | AudioRedirectionRule | Flags when audio quality is set to high, consuming excessive bandwidth |
Optional: baseline (multi-interval collection) · secrets (credential management) · lock-clear (recovery)
| Command | Description | Key Options |
|---|---|---|
init |
Generate starter config.yaml for an assessment | --output, --platform |
validate |
Validate config.yaml and test connectivity | --config |
snapshot |
Single-point assessment: collect, analyze, report | --config, --data-root, --mock |
baseline |
Multi-interval baseline collection over time | start, collect, finish subcommands |
report |
Regenerate reports from existing run data | --run-id, --data-root |
export |
Package run artifacts into distributable ZIP | --run-id, --output |
cleanup |
Remove old runs based on retention policy | --older-than, --dry-run |
lock-clear |
Force-remove stale lock files | --assessment-key |
secrets |
Manage encrypted credentials (DPAPI) | set, get, list, delete subcommands |
DpapiSecretsStore uses Windows DPAPI (ProtectedData.Protect via PowerShell interop) for
CurrentUser-scoped encryption. Falls back to base64 encoding on non-Windows (dev only).
Individual files per key in secrets/ directory. Atomic writes via temp-then-rename.
Key validation prevents path traversal via InvalidFileNameChars check.
SHA-256 hash of normalized JSON payload: platform, variant, site_guid,
sorted controllers (lowercased FQDNs), and sorted scope (include/exclude DG and catalog IDs).
Deterministic — same environment always produces the same key. Used for lock files, run directories, and audit correlation.
FileLockManager: atomic acquire via File.Move(overwrite: false), 60-second heartbeat timer,
5-minute stale threshold, 24-hour absolute timeout, PID validation on same host.
Supports async wait with configurable timeout. Lock files are JSON with assessment_key, run_id, PID, hostname, timestamps.
AuditLogger: structured JSONL output with fields ts_utc, level, event,
run_id, assessment_key, details. Thread-safe via lock.
Levels: INFO, WARN, ERROR. All orchestrator lifecycle events logged.
Temp-then-rename pattern used across the codebase: run.json updates, lock file creation/heartbeat,
evidence CSV writes, secrets storage. Prevents partial-write corruption on crash or power loss.
Secret key names validated against Path.GetInvalidFileNameChars() (prevents path traversal).
PowerShell string escaping via single-quote doubling (' → '') in DPAPI interop.
Config validation via ValidateOrchestrator with 10 checks before any data collection.
5 security rules inspect Citrix policy settings: USB redirection (malware vector), clipboard redirection (data exfiltration),
client drive mapping (data exfiltration), printer auto-create (print-to-file risk), and audio quality (bandwidth abuse).
Each maps to specific PolicySetting entries from the connector.
CitrixConnector checks OperatingSystem.IsWindows() and throws PlatformNotSupportedException
on non-Windows. PowerShell commands run as isolated child processes with RedirectStandardOutput/Error
and configurable timeout enforcement via Process.WaitForExit.
| Category | Test File | Tests | Type |
|---|---|---|---|
| Rules | RuleTests.cs | 11 | Unit |
| ExpandedRuleTests.cs | 16 | Unit | |
| Core Infra | FileLockManagerTests.cs | 7 | Unit |
| DpapiSecretsStoreTests.cs | 13 | Unit | |
| ValidateOrchestratorTests.cs | 10 | Unit | |
| SqliteRepositoryTests.cs | 6 | Unit | |
| RunManagerTests.cs | 5 | Unit | |
| ConfigLoaderTests.cs | 2 | Unit | |
| ScheduledTaskManagerTests.cs | 3 | Unit | |
| Reporting | ReportTests.cs | 9 | Unit |
| PdfReportTests.cs | 4 | Unit | |
| Model | CsvTests.cs | 12 | Unit |
| RunStatusTests.cs | 26 | Unit | |
| AssessmentKeyTests.cs | 2 | Unit | |
| Connectors | CitrixMapperTests.cs | 12 | Unit |
| Smoke | SmokeTest.cs (unit) | 1 | Unit |
| Integration | BaselineTests.cs | 11 | Integration |
| ReportEndToEndTests.cs | 3 | Integration | |
| SnapshotEndToEndTests.cs | 2 | Integration | |
| ExportTests.cs | 1 | Integration | |
| SmokeTest.cs (integration) | 1 | Integration |
| Scenario | Command | Result | Status |
|---|---|---|---|
| Version check | --version |
Output: 1.0.0 | Pass |
| Config generation | init |
config.yaml generated with defaults | Pass |
| Snapshot assessment | snapshot --mock |
30 rules ran, 7 findings, 4 scorecards, HTML + PDF | Pass |
| Report regeneration | report |
HTML report regenerated from existing run | Pass |
| Export packaging | export |
170KB ZIP with 13 files | Pass |
| Secrets CRUD | secrets set/get/list/delete |
Full lifecycle verified | Pass |
| Cleanup dry-run | cleanup --dry-run |
Detected eligible run, no deletion | Pass |
| Item | Detail | Status |
|---|---|---|
| Live Citrix testing | Requires Citrix CVAD SDK and a live Citrix environment for real PowerShell collection | Blocked |
| MSI installer build | Requires WiX Toolset v4 on Windows (dotnet build -c Release) |
Ready to build |
| Cross-compile for Windows | dotnet publish -r win-x64 --self-contained produces single-file EXE |
Ready to build |
| DPAPI encryption on Windows | Base64 fallback working on Linux/macOS; real DPAPI encryption activates automatically on Windows | Ready |
| Package | Used By | Purpose |
|---|---|---|
System.CommandLine | Cli | CLI argument parsing and command routing |
Microsoft.Extensions.DependencyInjection | Cli | Service container for DI |
Microsoft.Extensions.Logging | Cli | Logging infrastructure |
Microsoft.Extensions.Logging.Console | Cli | Console log output |
Microsoft.Extensions.Logging.Abstractions | Model, Rules, Core, Connectors, Reporting | ILogger abstraction |
Microsoft.Extensions.DependencyInjection.Abstractions | Core | DI abstractions |
Microsoft.Data.Sqlite | Core | SQLite data persistence |
YamlDotNet | Core | YAML configuration parsing |
System.Security.Cryptography.ProtectedData | Core | Windows DPAPI support |
QuestPDF | Reporting | PDF report generation |
xunit | Tests | Test framework |
FluentAssertions | Tests | Assertion library |
NSubstitute | Tests | Mocking framework |
coverlet.collector | Tests | Code coverage collection |
Microsoft.NET.Test.Sdk | Tests | Test SDK infrastructure |