VDI Assessment Pack v1.0.0

.NET 8.0 · C# 12 · Automated VDI environment assessment tool
6Projects
30Rules
9Commands
158Tests
~7.4KLOC

Architecture

Dependency Graph
VdiAssess.Model
Entities, Interfaces, Enums
VdiAssess.Rules
30 Rules, RuleRunner, Scoring
VdiAssess.Connectors.Citrix
PowerShell, Mock, Mapper
VdiAssess.Core
Orchestrators, SQLite, Locks, Secrets
VdiAssess.Reporting
HTML & PDF Renderers
VdiAssess.Cli
System.CommandLine, 9 Commands
Project Breakdown (6 source + 2 test)
ProjectFilesPurposeKey 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
Data Flow Pipeline
config.yaml
IConnector
SQLite
RuleRunner
Findings
HTML / PDF

ConfigLoader parses YAML → Connector collects inventory + telemetry → SqliteRepository persists snapshots → RuleRunner evaluates 30 rules against RuleContext → ScoringEngine grades by domain → Renderers produce reports

Key Interfaces

IConnector — VdiAssess.Model

interface IConnector
  string Platform { get; }
  string PlatformVariant { get; }
  Task<InventorySnapshot> CollectInventoryAsync(ConnectorConfig, CancellationToken)
  Task<TelemetryInterval> CollectTelemetryAsync(ConnectorConfig, DateTime, DateTime, int, CancellationToken)

Platform abstraction: CitrixConnector (PowerShell, Windows-only) or MockConnector (cross-platform dev/test)

ISecretsStore — VdiAssess.Model

interface ISecretsStore
  string? Get(string key)
  void Set(string key, string value)
  void Delete(string key)
  IReadOnlyList<string> ListKeys()

Impl: DpapiSecretsStore — DPAPI encryption on Windows, base64 fallback for dev

IRule — VdiAssess.Rules

interface IRule
  string RuleId { get; }
  string RuleVersion { get; }
  FindingDomain Domain { get; }
  string Description { get; }
  IReadOnlyList<Finding> Evaluate(RuleContext)

RuleContext provides Controllers, Catalogs, DeliveryGroups, VDAs, PolicySettings, SessionBuckets, LogonBuckets, FailureBuckets

IReportRenderer — VdiAssess.Reporting

interface IReportRenderer
  string OutputFileName { get; }
  void Render(ReportData, string outputPath)

Impls: HtmlReportRenderer (self-contained HTML) and PdfReportRenderer (QuestPDF)

IScheduledTaskManager — VdiAssess.Core

interface IScheduledTaskManager
  void CreateBaselineTask(string runId, string configPath, int intervalMinutes)
  void RemoveBaselineTask(string runId)
  bool TaskExists(string runId)

Impls: WindowsScheduledTaskManager (schtasks.exe) and NoopScheduledTaskManager (non-Windows)

IClock — VdiAssess.Model

interface IClock
  DateTime UtcNow { get; }

Impls: SystemClock (production) and FakeClock (test, with Advance/Set methods for time manipulation)

Implementation Phases

#PhaseDescriptionKey DeliverablesStatus
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

Rules Engine (30 Rules)

Domain Distribution

UX
10 rules
Capacity
9 rules
Resilience
6 rules
Security
5 rules
UX — 10 rules
Rule IDClassDescription
UX-AVG-LOGONHighAvgLogonRuleFlags when the overall average logon duration exceeds threshold
UX-LOGON-P95LogonP95RuleFlags delivery groups where p95 logon duration exceeds threshold
UX-LOGON-P99LogonP99RuleFlags extreme logon outliers where p99 exceeds threshold
UX-PROFILE-LOADLogonProfileLoadRuleFlags when profile load phase dominates logon duration
UX-GPO-LOADLogonGpoRuleFlags when GPO processing phase is excessive during logon
UX-BROKER-RESPONSEBrokerResponseTimeRuleFlags when broker response time contributes excessively to logon duration
UX-DISCONNECT-RATEDisconnectRateRuleFlags elevated disconnect-to-reconnect ratios indicating session instability
UX-RECONNECT-RATEHighReconnectRateRuleFlags elevated reconnection rates indicating network instability or client issues
UX-FAILURE-HOTSPOTFailureHotspotRuleFlags delivery groups with elevated connection failure rates
UX-RECURRING-ERRORRecurringErrorCodeRuleFlags when the same error code recurs across multiple telemetry buckets
Capacity — 9 rules
Rule IDClassDescription
CAP-CONCURRENCYConcurrencyHeadroomRuleFlags when peak concurrent sessions approach available VDA capacity
CAP-EMPTY-DGEmptyDeliveryGroupRuleFlags delivery groups with no associated VDAs
CAP-LARGE-DGLargeDeliveryGroupRuleFlags delivery groups with a very large number of VDAs (blast radius concern)
CAP-SMALL-CATALOGSmallCatalogRuleFlags catalogs with very few VDAs (potential consolidation opportunity)
CAP-POOL-IMBALANCEPoolImbalanceRuleFlags delivery groups with significantly uneven VDA distribution across catalogs
CAP-OS-MIXOsTypeHomogeneityRuleFlags delivery groups mixing desktop and server OS VDAs (unusual configuration)
CAP-SERVER-DENSITYServerOsDensityRuleAssesses session density on server OS VDAs for capacity planning
CAP-PROV-TYPEMcsProvisioningRuleReports provisioning type distribution for capacity planning awareness
CAP-STATIC-MACHINESStaticMachineTypeRuleReports proportion of static (persistent) vs pooled VDAs for lifecycle management awareness
Resilience — 6 rules
Rule IDClassDescription
RES-SINGLE-DDCSingleControllerRuleFlags environments with only a single Delivery Controller (SPOF)
RES-DDC-VERSIONControllerVersionMismatchRuleFlags when controllers have different roles that may indicate incomplete upgrades
RES-SINGLE-CATALOGSingleCatalogRuleFlags delivery groups backed by a single machine catalog (SPOF for image updates)
RES-SESSION-RELIABILITYSessionReliabilityRuleFlags when session reliability is not enabled
RES-NO-DGNoDeliveryGroupsRuleFlags environments with no delivery groups configured
RES-NO-VDASNoVdasRuleFlags environments with no VDAs discovered
Security — 5 rules
Rule IDClassDescription
SEC-USBUsbRedirectionRuleFlags when USB redirection is enabled (malware introduction risk)
SEC-CLIPBOARDClientClipboardRedirectionRuleFlags when client clipboard redirection is enabled (data exfiltration risk)
SEC-CLIENT-DRIVEClientDriveRedirectionRuleFlags when client drive redirection is enabled (data exfiltration risk)
SEC-PRINTERPrinterRedirectionRuleFlags when client printer redirection is enabled with auto-create (potential data exfiltration via print-to-file)
SEC-AUDIO-QUALITYAudioRedirectionRuleFlags when audio quality is set to high, consuming excessive bandwidth

CLI Commands (9)

Workflow

init
validate
snapshot
report
export
cleanup

Optional: baseline (multi-interval collection) · secrets (credential management) · lock-clear (recovery)

CommandDescriptionKey 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

Security Architecture

Secrets Management

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.

Assessment Key Derivation

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.

File Locking

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.

Audit Trail

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.

Atomic Operations

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.

Input Validation

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.

Policy Rules

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.

Connector Isolation

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.

Test Coverage

158 total tests
140 unit
18 integration
0 failures
Test Breakdown by Category
CategoryTest FileTestsType
RulesRuleTests.cs11Unit
ExpandedRuleTests.cs16Unit
Core InfraFileLockManagerTests.cs7Unit
DpapiSecretsStoreTests.cs13Unit
ValidateOrchestratorTests.cs10Unit
SqliteRepositoryTests.cs6Unit
RunManagerTests.cs5Unit
ConfigLoaderTests.cs2Unit
ScheduledTaskManagerTests.cs3Unit
ReportingReportTests.cs9Unit
PdfReportTests.cs4Unit
ModelCsvTests.cs12Unit
RunStatusTests.cs26Unit
AssessmentKeyTests.cs2Unit
ConnectorsCitrixMapperTests.cs12Unit
SmokeSmokeTest.cs (unit)1Unit
IntegrationBaselineTests.cs11Integration
ReportEndToEndTests.cs3Integration
SnapshotEndToEndTests.cs2Integration
ExportTests.cs1Integration
SmokeTest.cs (integration)1Integration
E2E Validation Results (Mock Connector)
ScenarioCommandResultStatus
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

What Remains

ItemDetailStatus
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

NuGet Dependencies

PackageUsed ByPurpose
System.CommandLineCliCLI argument parsing and command routing
Microsoft.Extensions.DependencyInjectionCliService container for DI
Microsoft.Extensions.LoggingCliLogging infrastructure
Microsoft.Extensions.Logging.ConsoleCliConsole log output
Microsoft.Extensions.Logging.AbstractionsModel, Rules, Core, Connectors, ReportingILogger abstraction
Microsoft.Extensions.DependencyInjection.AbstractionsCoreDI abstractions
Microsoft.Data.SqliteCoreSQLite data persistence
YamlDotNetCoreYAML configuration parsing
System.Security.Cryptography.ProtectedDataCoreWindows DPAPI support
QuestPDFReportingPDF report generation
xunitTestsTest framework
FluentAssertionsTestsAssertion library
NSubstituteTestsMocking framework
coverlet.collectorTestsCode coverage collection
Microsoft.NET.Test.SdkTestsTest SDK infrastructure