PSProxmoxVE Module Review Report
Reviewer: Claude Code (Opus 4.6)
Module Version: 0.1.0-preview
Repository: PSProxmoxVE (C# binary PowerShell module)
Executive Summary
Delta since last scan: 16 fixed | 5 new findings | 0 regressed | 9 still open
API drift: 194 endpoints with version_changes | 466 PVE endpoints unimplemented (72.1% uncovered) | 42 🆕 PVE 9.0 endpoints
- 169 cmdlets (up from 148) — all fully exported, sealed, with OutputType attributes. New: 21 additional cmdlets since prior scan.
- 14 prior findings resolved: All 4 infinite-loop WaitForTask methods (CQ1–CQ4) now use
TaskService.WaitForTask. Guest exec timeout added (CQ5). OutputType on all cmdlets (CQ9). Firewall VmId nullable (CQ10). Bare catches replaced with filtered exceptions (CQ11–CQ14). RemovePveRole/SuspendPveVm/RestartPveVm ConfirmImpact fixed (CQ17/CQ19/CQ20). Cmdlets sealed (CQ18). Dual JSON attrs removed (CQ21). Magic strings extracted to constants (CQ22). Guest password now SecureString (S1). Debug script secrets redacted (S2).
- Remaining Critical: 5 cmdlets still have
while(true) task-polling loops with no timeout — 3 container snapshot cmdlets plus InvokePveStorageDownloadCmdlet and SendPveFileCmdlet.
- 100% Pester unit test coverage maintained across all 169 cmdlets. Integration test coverage is ~62% (105 of 169).
- 27.9% API endpoint coverage (180 of 646 endpoints). Major uncovered areas unchanged: Ceph (40), HA (21), cluster config (10), disks (18), ACME (15), certificates (8).
- Security posture solid: All prior security findings resolved (S1–S3). URL encoding now consistent across all services. HTTPS enforced, SecureString used consistently.
- PSGallery-ready: No publication blockers. IconUri still missing (cosmetic). Manifest CmdletsToExport fully enumerates all 169 cmdlets.
- net9.0 target is EOL (May 2025) — should upgrade to net10.0.
- Pool/CephPool parameter conflict in New-PveStorage resolved: runtime validation now throws if both specified.
- 42 new PVE 9.0 endpoints available (HA rules, SDN fabrics, bulk actions, OCI registry). None yet implemented.
Phase 1 — Repository Inventory & Structure
Directory Tree (depth ≤ 4)
Project Layout
| Item |
Value |
| Solution |
PSProxmoxVE.sln |
| Main project |
src/PSProxmoxVE/PSProxmoxVE.csproj |
| Core library |
src/PSProxmoxVE.Core/PSProxmoxVE.Core.csproj |
| Test project (xUnit) |
tests/PSProxmoxVE.Core.Tests/PSProxmoxVE.Core.Tests.csproj |
| Test project (Pester) |
tests/PSProxmoxVE.Tests/ |
| Target Frameworks |
netstandard2.0, net9.0, net48 |
| Language Version |
C# 10.0 |
| Nullable |
Enabled |
| Assembly Names |
PSProxmoxVE, PSProxmoxVE.Core |
CI/CD Workflows
| Workflow |
Purpose |
build.yml |
Build + xUnit tests on net48 (Windows) and net9.0 (Windows + Ubuntu) |
unit-tests.yml |
Build + Pester tests across PS 5.1/7.5 on Windows/Ubuntu/macOS |
integration-tests.yml |
Full integration tests against nested PVE 8 + PVE 9 instances |
publish.yml |
Tag-triggered publish to PSGallery + GitHub Release creation |
Inventory Checklist
| Item |
Present |
Prior Status |
Solution file (.sln) |
Yes |
Open |
Module manifest (.psd1) |
Yes |
Open |
Format definitions (.format.ps1xml) |
Yes |
Open |
MAML help (.dll-Help.xml) |
Yes |
Open |
.editorconfig |
Yes |
Open |
.gitignore |
Yes |
Open |
.gitattributes |
Yes |
Open |
LICENSE (MIT) |
Yes |
Open |
CHANGELOG.md |
Yes |
Open |
README.md |
Yes |
Open |
CONTRIBUTING.md |
Yes |
Open |
CODE_OF_CONDUCT.md |
Yes |
Open |
SECURITY.md |
Yes |
Open |
.github/ISSUE_TEMPLATE/ |
Yes |
Open |
.github/pull_request_template.md |
Yes |
Open |
| PSGallery publish workflow |
Yes |
Open |
docs/PVE_API_COVERAGE.md |
Yes |
Open |
docs/cmdlets/ (75 files) |
Yes |
Open |
What's Missing
Phase 2 — PVE API Coverage Audit
Source of truth: ~/Source/pve_api/pve-api.json (646 endpoints). Spec generated 2026-03-21.
Latest tracked PVE version: 9.0 (42 new endpoints, 56 changed endpoints)
Implemented Cmdlets (169 total)
Connection (3)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Connect-PveServer |
/access/ticket |
POST |
Open |
Disconnect-PveServer |
(session teardown) |
— |
Open |
Test-PveConnection |
/version |
GET |
Open |
Nodes (8)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveNode |
/nodes |
GET |
Open |
Get-PveNodeStatus |
/nodes/{node}/status |
GET |
Open |
Get-PveNodeConfig |
/nodes/{node}/config |
GET |
Open |
Set-PveNodeConfig |
/nodes/{node}/config |
PUT |
Open |
Get-PveNodeDns |
/nodes/{node}/dns |
GET |
Open |
Set-PveNodeDns |
/nodes/{node}/dns |
PUT |
Open |
Start-PveNodeVms |
/nodes/{node}/startall |
POST |
Open |
Stop-PveNodeVms |
/nodes/{node}/stopall |
POST |
Open |
VMs / QEMU (19)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveVm |
/nodes/{node}/qemu |
GET |
Open |
New-PveVm |
/nodes/{node}/qemu |
POST |
Open |
Remove-PveVm |
/nodes/{node}/qemu/{vmid} |
DELETE |
Open |
Start-PveVm |
/nodes/{node}/qemu/{vmid}/status/start |
POST |
Open |
Stop-PveVm |
/nodes/{node}/qemu/{vmid}/status/stop |
POST |
Open |
Restart-PveVm |
/nodes/{node}/qemu/{vmid}/status/reboot |
POST |
Open |
Suspend-PveVm |
/nodes/{node}/qemu/{vmid}/status/suspend |
POST |
Open |
Resume-PveVm |
/nodes/{node}/qemu/{vmid}/status/resume |
POST |
Open |
Reset-PveVm |
/nodes/{node}/qemu/{vmid}/status/reset |
POST |
Open |
Copy-PveVm |
/nodes/{node}/qemu/{vmid}/clone |
POST |
Open |
Move-PveVm |
/nodes/{node}/qemu/{vmid}/migrate |
POST |
Open |
Get-PveVmConfig |
/nodes/{node}/qemu/{vmid}/config |
GET |
Open |
Set-PveVmConfig |
/nodes/{node}/qemu/{vmid}/config |
PUT |
Open |
Resize-PveVmDisk |
/nodes/{node}/qemu/{vmid}/resize |
PUT |
Open |
Import-PveVmDisk |
/nodes/{node}/storage/{storage}/upload |
POST |
Open |
Import-PveOva |
Multiple (upload + config + import) |
POST |
Open |
Move-PveVmDisk |
/nodes/{node}/qemu/{vmid}/move_disk |
POST |
Open |
Remove-PveVmDisk |
/nodes/{node}/qemu/{vmid}/unlink |
PUT |
Open |
New-PveVmFromTemplate |
/nodes/{node}/qemu/{vmid}/clone |
POST |
Open |
Guest Agent (9)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Test-PveVmGuestAgent |
/nodes/{node}/qemu/{vmid}/agent/ping |
POST |
Open |
Get-PveVmGuestNetwork |
/nodes/{node}/qemu/{vmid}/agent/network-get-interfaces |
GET |
Open |
Invoke-PveVmGuestExec |
/nodes/{node}/qemu/{vmid}/agent/exec + .../exec-status |
POST/GET |
Open |
Get-PveVmGuestOsInfo |
/nodes/{node}/qemu/{vmid}/agent/get-osinfo |
GET |
Open |
Get-PveVmGuestFsInfo |
/nodes/{node}/qemu/{vmid}/agent/get-fsinfo |
GET |
Open |
Read-PveVmGuestFile |
/nodes/{node}/qemu/{vmid}/agent/file-read |
GET |
Open |
Write-PveVmGuestFile |
/nodes/{node}/qemu/{vmid}/agent/file-write |
POST |
Open |
Set-PveVmGuestPassword |
/nodes/{node}/qemu/{vmid}/agent/set-user-password |
POST |
Open |
Invoke-PveVmGuestFsTrim |
/nodes/{node}/qemu/{vmid}/agent/fstrim |
POST |
Open |
Containers / LXC (20)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveContainer |
/nodes/{node}/lxc |
GET |
Open |
New-PveContainer |
/nodes/{node}/lxc |
POST |
Open |
Remove-PveContainer |
/nodes/{node}/lxc/{vmid} |
DELETE |
Open |
Start-PveContainer |
/nodes/{node}/lxc/{vmid}/status/start |
POST |
Open |
Stop-PveContainer |
/nodes/{node}/lxc/{vmid}/status/stop |
POST |
Open |
Restart-PveContainer |
/nodes/{node}/lxc/{vmid}/status/shutdown |
POST |
Open |
Copy-PveContainer |
/nodes/{node}/lxc/{vmid}/clone |
POST |
Open |
Move-PveContainer |
/nodes/{node}/lxc/{vmid}/migrate |
POST |
Open |
Get-PveContainerConfig |
/nodes/{node}/lxc/{vmid}/config |
GET |
Open |
Set-PveContainerConfig |
/nodes/{node}/lxc/{vmid}/config |
PUT |
Open |
Suspend-PveContainer |
/nodes/{node}/lxc/{vmid}/status/suspend |
POST |
Open |
Resume-PveContainer |
/nodes/{node}/lxc/{vmid}/status/resume |
POST |
Open |
Resize-PveContainerDisk |
/nodes/{node}/lxc/{vmid}/resize |
PUT |
Open |
New-PveContainerTemplate |
/nodes/{node}/lxc/{vmid}/template |
POST |
Open |
Move-PveContainerVolume |
/nodes/{node}/lxc/{vmid}/move_volume |
POST |
Open |
Get-PveContainerInterface |
/nodes/{node}/lxc/{vmid}/interfaces |
GET |
Open |
Get-PveContainerSnapshot |
/nodes/{node}/lxc/{vmid}/snapshot |
GET |
Open |
New-PveContainerSnapshot |
/nodes/{node}/lxc/{vmid}/snapshot |
POST |
Open |
Remove-PveContainerSnapshot |
/nodes/{node}/lxc/{vmid}/snapshot/{name} |
DELETE |
Open |
Restore-PveContainerSnapshot |
/nodes/{node}/lxc/{vmid}/snapshot/{name}/rollback |
POST |
Open |
Storage (11)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveStorage |
/storage or /nodes/{node}/storage |
GET |
Open |
Get-PveStorageContent |
/nodes/{node}/storage/{storage}/content |
GET |
Open |
Send-PveFile |
/nodes/{node}/storage/{storage}/upload |
POST |
Open |
Invoke-PveStorageDownload |
/nodes/{node}/storage/{storage}/download-url |
POST |
Open |
New-PveStorage |
/storage |
POST |
Open |
Remove-PveStorage |
/storage/{storage} |
DELETE |
Open |
Set-PveStorage |
/storage/{storage} |
PUT |
Open |
Get-PveStorageStatus |
/nodes/{node}/storage/{storage}/status |
GET |
Open |
Remove-PveStorageContent |
/nodes/{node}/storage/{storage}/content/{volume} |
DELETE |
Open |
Set-PveStorageContent |
/nodes/{node}/storage/{storage}/content/{volume} |
PUT |
Open |
New-PveStorageDisk |
/nodes/{node}/storage/{storage}/content |
POST |
Open |
VM Snapshots (4)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveSnapshot |
/nodes/{node}/qemu/{vmid}/snapshot |
GET |
Open |
New-PveSnapshot |
/nodes/{node}/qemu/{vmid}/snapshot |
POST |
Open |
Remove-PveSnapshot |
/nodes/{node}/qemu/{vmid}/snapshot/{name} |
DELETE |
Open |
Restore-PveSnapshot |
/nodes/{node}/qemu/{vmid}/snapshot/{name}/rollback |
POST |
Open |
Networking (5)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveNetwork |
/nodes/{node}/network |
GET |
Open |
New-PveNetwork |
/nodes/{node}/network |
POST |
Open |
Set-PveNetwork |
/nodes/{node}/network/{iface} |
PUT |
Open |
Remove-PveNetwork |
/nodes/{node}/network/{iface} |
DELETE |
Open |
Invoke-PveNetworkApply |
/nodes/{node}/network |
PUT |
Open |
SDN (25)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveSdnZone |
/cluster/sdn/zones |
GET |
Open |
New-PveSdnZone |
/cluster/sdn/zones |
POST |
Open |
Remove-PveSdnZone |
/cluster/sdn/zones/{zone} |
DELETE |
Open |
Set-PveSdnZone |
/cluster/sdn/zones/{zone} |
PUT |
Open |
Get-PveSdnVnet |
/cluster/sdn/vnets |
GET |
Open |
New-PveSdnVnet |
/cluster/sdn/vnets |
POST |
Open |
Remove-PveSdnVnet |
/cluster/sdn/vnets/{vnet} |
DELETE |
Open |
Set-PveSdnVnet |
/cluster/sdn/vnets/{vnet} |
PUT |
Open |
Get-PveSdnSubnet |
/cluster/sdn/vnets/{vnet}/subnets |
GET |
Open |
New-PveSdnSubnet |
/cluster/sdn/vnets/{vnet}/subnets |
POST |
Open |
Remove-PveSdnSubnet |
/cluster/sdn/vnets/{vnet}/subnets/{subnet} |
DELETE |
Open |
Set-PveSdnSubnet |
/cluster/sdn/vnets/{vnet}/subnets/{subnet} |
PUT |
Open |
Get-PveSdnIpam |
/cluster/sdn/ipams |
GET |
Open |
New-PveSdnIpam |
/cluster/sdn/ipams |
POST |
Open |
Remove-PveSdnIpam |
/cluster/sdn/ipams/{ipam} |
DELETE |
Open |
Set-PveSdnIpam |
/cluster/sdn/ipams/{ipam} |
PUT |
Open |
Get-PveSdnDns |
/cluster/sdn/dns |
GET |
Open |
New-PveSdnDns |
/cluster/sdn/dns |
POST |
Open |
Remove-PveSdnDns |
/cluster/sdn/dns/{dns} |
DELETE |
Open |
Set-PveSdnDns |
/cluster/sdn/dns/{dns} |
PUT |
Open |
Get-PveSdnController |
/cluster/sdn/controllers |
GET |
Open |
New-PveSdnController |
/cluster/sdn/controllers |
POST |
Open |
Remove-PveSdnController |
/cluster/sdn/controllers/{controller} |
DELETE |
Open |
Set-PveSdnController |
/cluster/sdn/controllers/{controller} |
PUT |
Open |
Invoke-PveSdnApply |
/cluster/sdn |
PUT |
Open |
Firewall (21)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveFirewallRule |
/cluster/firewall/rules |
GET |
Open |
New-PveFirewallRule |
/cluster/firewall/rules |
POST |
Open |
Set-PveFirewallRule |
/cluster/firewall/rules/{pos} |
PUT |
Open |
Remove-PveFirewallRule |
/cluster/firewall/rules/{pos} |
DELETE |
Open |
Get-PveFirewallGroup |
/cluster/firewall/groups |
GET |
Open |
New-PveFirewallGroup |
/cluster/firewall/groups |
POST |
Open |
Remove-PveFirewallGroup |
/cluster/firewall/groups/{group} |
DELETE |
Open |
Get-PveFirewallAlias |
/cluster/firewall/aliases |
GET |
Open |
New-PveFirewallAlias |
/cluster/firewall/aliases |
POST |
Open |
Set-PveFirewallAlias |
/cluster/firewall/aliases/{name} |
PUT |
Open |
Remove-PveFirewallAlias |
/cluster/firewall/aliases/{name} |
DELETE |
Open |
Get-PveFirewallIpSet |
/cluster/firewall/ipset |
GET |
Open |
New-PveFirewallIpSet |
/cluster/firewall/ipset |
POST |
Open |
Remove-PveFirewallIpSet |
/cluster/firewall/ipset/{name} |
DELETE |
Open |
Get-PveFirewallIpSetEntry |
/cluster/firewall/ipset/{name} |
GET |
Open |
New-PveFirewallIpSetEntry |
/cluster/firewall/ipset/{name} |
POST |
Open |
Set-PveFirewallIpSetEntry |
/cluster/firewall/ipset/{name}/{cidr} |
PUT |
Open |
Remove-PveFirewallIpSetEntry |
/cluster/firewall/ipset/{name}/{cidr} |
DELETE |
Open |
Get-PveFirewallOptions |
/cluster/firewall/options |
GET |
Open |
Set-PveFirewallOptions |
/cluster/firewall/options |
PUT |
Open |
Get-PveFirewallRef |
/cluster/firewall/refs |
GET |
Open |
Backup (6)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
New-PveBackup |
/nodes/{node}/vzdump |
POST |
Open |
Get-PveBackupJob |
/cluster/backup |
GET |
Open |
New-PveBackupJob |
/cluster/backup |
POST |
Open |
Set-PveBackupJob |
/cluster/backup/{id} |
PUT |
Open |
Remove-PveBackupJob |
/cluster/backup/{id} |
DELETE |
Open |
Get-PveBackupInfo |
/cluster/backup-info/not-backed-up |
GET |
Open |
Users / Access (23)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveUser |
/access/users |
GET |
Open |
New-PveUser |
/access/users |
POST |
Open |
Remove-PveUser |
/access/users/{userid} |
DELETE |
Open |
Set-PveUser |
/access/users/{userid} |
PUT |
Open |
Get-PveRole |
/access/roles |
GET |
Open |
New-PveRole |
/access/roles |
POST |
Open |
Remove-PveRole |
/access/roles/{roleid} |
DELETE |
Open |
Set-PveRole |
/access/roles/{roleid} |
PUT |
Open |
Get-PvePermission |
/access/acl |
GET |
Open |
Set-PvePermission |
/access/acl |
PUT |
Open |
Get-PveApiToken |
/access/users/{userid}/token |
GET |
Open |
New-PveApiToken |
/access/users/{userid}/token/{tokenid} |
POST |
Open |
Remove-PveApiToken |
/access/users/{userid}/token/{tokenid} |
DELETE |
Open |
Set-PveApiToken |
/access/users/{userid}/token/{tokenid} |
PUT |
Open |
Get-PveGroup |
/access/groups |
GET |
Open |
New-PveGroup |
/access/groups |
POST |
Open |
Set-PveGroup |
/access/groups/{groupid} |
PUT |
Open |
Remove-PveGroup |
/access/groups/{groupid} |
DELETE |
Open |
Get-PveDomain |
/access/domains |
GET |
Open |
New-PveDomain |
/access/domains |
POST |
Open |
Set-PveDomain |
/access/domains/{realm} |
PUT |
Open |
Remove-PveDomain |
/access/domains/{realm} |
DELETE |
Open |
Set-PvePassword |
/access/password |
PUT |
Open |
Pools (4)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PvePool |
/pools |
GET |
Open |
New-PvePool |
/pools |
POST |
Open |
Set-PvePool |
/pools/{poolid} |
PUT |
Open |
Remove-PvePool |
/pools/{poolid} |
DELETE |
Open |
Templates (4)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveTemplate |
/nodes/{node}/qemu (filtered) |
GET |
Open |
New-PveTemplate |
/nodes/{node}/qemu/{vmid}/template |
POST |
Open |
Remove-PveTemplate |
/nodes/{node}/qemu/{vmid} |
DELETE |
Open |
New-PveVmFromTemplate |
/nodes/{node}/qemu/{vmid}/clone |
POST |
Open |
Cloud-Init (3)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveCloudInitConfig |
/nodes/{node}/qemu/{vmid}/config |
GET |
Open |
Set-PveCloudInitConfig |
/nodes/{node}/qemu/{vmid}/config |
PUT |
Open |
Invoke-PveCloudInitRegenerate |
/nodes/{node}/qemu/{vmid}/cloudinit |
PUT |
Open |
Tasks (4)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveTask |
/nodes/{node}/tasks/{upid}/status |
GET |
Open |
Wait-PveTask |
/nodes/{node}/tasks/{upid}/status (polling) |
GET |
Open |
Get-PveTaskList |
/nodes/{node}/tasks |
GET |
Open |
Stop-PveTask |
/nodes/{node}/tasks/{upid} |
DELETE |
Open |
Cluster (1)
| Cmdlet |
API Endpoint |
Method |
Prior Status |
Get-PveClusterResource |
/cluster/resources |
GET |
Open |
Coverage Summary Per Functional Area
| Area |
Total Endpoints |
Covered |
% |
🆕 PVE 9.0 New |
Prior Status |
| acl |
2 |
2 |
100% |
0 |
Open |
| version |
1 |
1 |
100% |
0 |
Open |
| backup |
6 |
5 |
83% |
0 |
Open |
| access_groups |
5 |
4 |
80% |
0 |
Open |
| roles |
5 |
4 |
80% |
0 |
Open |
| tasks |
5 |
4 |
80% |
0 |
Open |
| firewall |
40 |
31 |
78% |
0 |
Open |
| users |
12 |
9 |
75% |
0 |
Open |
| networking |
7 |
5 |
71% |
0 |
Open |
| pools |
7 |
5 |
71% |
0 |
Open |
| access_domains |
6 |
4 |
67% |
0 |
Open |
| storage_config |
5 |
3 |
60% |
0 |
Open |
| storage |
19 |
8 |
42% |
1 |
Open |
| sdn |
60 |
25 |
42% |
16 |
Open |
| vms |
97 |
35 |
36% |
1 |
Open |
| containers |
62 |
21 |
34% |
1 |
Open |
| access |
15 |
2 |
13% |
1 |
Open |
| nodes |
75 |
8 |
11% |
11 |
Open |
| cluster |
77 |
3 |
4% |
6 |
Open |
| ceph |
40 |
0 |
0% |
0 |
Open |
| ha |
21 |
0 |
0% |
5 |
Open |
| disks |
18 |
0 |
0% |
0 |
Open |
| acme |
15 |
0 |
0% |
0 |
Open |
| cluster_config |
10 |
0 |
0% |
0 |
Open |
| certificates |
8 |
0 |
0% |
0 |
Open |
| apt |
8 |
0 |
0% |
0 |
Open |
| services |
7 |
0 |
0% |
0 |
Open |
| metrics |
7 |
0 |
0% |
0 |
Open |
| replication |
5 |
0 |
0% |
0 |
Open |
| TOTAL |
646 |
180 |
27.9% |
42 |
— |
API Drift — Changed Endpoints (Covered Cmdlets)
| Cmdlet |
Endpoint |
Change Description |
Risk |
Prior Status |
Set-PveBackupJob |
PUT /cluster/backup/{id} |
Removed notification-policy, notification-target params |
Breaking |
Open |
Set-PveNetwork |
PUT /nodes/{node}/network |
Added regenerate-frr, removed skip_frr |
Breaking |
Open |
Get-PveVmConfig |
GET .../qemu/{vmid}/config |
Returns changed in latest version |
Cosmetic |
Open |
Move-PveVm |
POST .../qemu/{vmid}/migrate |
Added with-conntrack-state parameter |
Additive |
Open |
PVE 9.0 New Endpoints (42 total, 0 implemented)
| Area |
Endpoint |
Method |
Description |
| ha |
/cluster/ha/rules |
GET/POST |
HA rules system (new in PVE 9.0) |
| ha |
/cluster/ha/rules/{rule} |
GET/PUT/DELETE |
Individual HA rule management |
| cluster |
/cluster/bulk-action/guest/* |
POST |
Bulk guest start/shutdown/suspend/migrate |
| sdn |
/cluster/sdn/fabrics/* |
GET/POST/PUT/DELETE |
SDN fabrics (13 endpoints) |
| sdn |
/cluster/sdn/lock / rollback |
POST/DELETE |
SDN lock and rollback |
| nodes |
/nodes/{node}/capabilities/qemu/cpu-flags |
GET |
CPU flags query |
| nodes |
/nodes/{node}/capabilities/qemu/migration |
GET |
Migration capabilities |
| nodes |
/nodes/{node}/sdn/fabrics/* |
GET |
Node SDN fabric status |
| nodes |
/nodes/{node}/query-oci-repo-tags |
GET |
OCI repo tag query |
| storage |
/nodes/{node}/storage/{storage}/oci-registry-pull |
POST |
OCI registry pull |
| vms |
/nodes/{node}/qemu/{vmid}/dbus-vmstate |
POST |
D-Bus VM state |
| containers |
GET /nodes/{node}/lxc/{vmid}/migrate |
GET |
Container migration pre-check |
| access |
POST /access/vncticket |
POST |
VNC ticket creation |
High-Value Gaps
Tier 1 — Most impactful for users:
- HA (High Availability) — 21 endpoints, 0% covered. Essential for production clusters. Resources, groups, status, and the new PVE 9.0 rules system (5 🆕 endpoints).
- Cluster configuration — 10 endpoints, 0%. Cluster create/join/node management is fundamental for multi-node setups.
- Ceph — 40 endpoints, 0%. Critical for hyperconverged infrastructure (OSD, MON, pools, status).
- Notifications — 32 cluster endpoints, 0%. New in PVE 8.1+, essential for monitoring/alerting automation.
- Disk management — 18 endpoints, 0%. LVM, ZFS, SMART, wipe — needed for storage provisioning.
Tier 2 — Important operational gaps:
- VM/CT-level firewall — ~44 combined endpoints. Cluster-level IS covered, but per-VM/CT rules are not.
- SDN Fabrics (🆕 PVE 9.0) — 13 new endpoints. Key for advanced SDN.
- Resource mappings (PCI/USB passthrough) — 15 endpoints. Key for GPU passthrough.
- Certificates/ACME — 23 combined endpoints. TLS certificate management.
GET /cluster/nextid — Trivial but frequently needed to allocate VM IDs programmatically.
Phase 3 — Code Quality & Best Practices
3a. PowerShell Module Design
- All cmdlets use approved PowerShell verbs via verb class constants.
- Noun prefix
Pve is consistent across all 169 cmdlets.
- HelpMessage present on virtually all parameters.
- ShouldProcess on all destructive/mutating cmdlets.
- Pipeline support via
ProcessRecord and ValueFromPipelineByPropertyName.
- ValidateRange/ValidateNotNullOrEmpty/ValidateSet used appropriately.
- OutputType on all 169 cmdlets (previously ~54 were missing — now all have it).
- All cmdlets are sealed (previously ~95 were not).
3b. C# Code Quality
- Nullable annotations:
<Nullable>enable</Nullable> in both projects.
- IDisposable:
PveHttpClient correctly implements IDisposable.
- Logging:
WriteVerbose used extensively; WriteProgress in file uploads and task waiting.
- Exception hierarchy: 7 custom exception types with context properties.
- Bare catches eliminated: All
catch { } blocks replaced with filtered catch (Exception ex) when (...).
- Magic strings extracted: Auth header names are now
const string fields.
- Zero TODO/FIXME/HACK markers.
- No commented-out code or dead code.
- Clean code style matching
.editorconfig.
- Dual JSON attributes removed: Only
[JsonProperty] (Newtonsoft) remains; [JsonPropertyName] removed.
Code Quality Findings
| ID |
File |
Line |
Severity |
Description |
Prior Status |
| CQ1 |
NewPveContainerSnapshotCmdlet.cs |
75 |
Critical |
Infinite loop with no timeout in private WaitForTask. while (true) with no timeout or cancellation. If task never completes, cmdlet hangs forever. Should use TaskService.WaitForTask (same pattern that was fixed in VM snapshot cmdlets). |
New |
| CQ2 |
RemovePveContainerSnapshotCmdlet.cs |
67 |
Critical |
Identical infinite loop — same while(true) no-timeout pattern as CQ1. |
New |
| CQ3 |
RestorePveContainerSnapshotCmdlet.cs |
70 |
Critical |
Identical infinite loop — same pattern as CQ1. |
New |
| CQ4 |
InvokePveStorageDownloadCmdlet.cs |
83 |
Critical |
Infinite loop in download task polling. while(true) with no timeout. Should use TaskService.WaitForTask. |
New |
| CQ5 |
SendPveFileCmdlet.cs |
143 |
Critical |
Infinite loop in upload task polling. while(true) with no timeout. Should use TaskService.WaitForTask. |
New |
| CQ6 |
Both .csproj files |
4 |
Medium |
net9.0 target is EOL (May 2025). Should upgrade to net10.0 (LTS). |
Open |
| CQ7 |
PveHttpClient.cs |
~154 sites |
Medium |
Sync-over-async via .GetAwaiter().GetResult() across ~216 call sites. Standard for PS binary modules but carries deadlock risk. |
Open |
| CQ8 |
PveCmdletBase.cs |
149 |
Medium |
Broad catch in status polling. catch (Exception ex) when (...) is filtered but still catches broadly. Improvement over bare catch but could be more specific. |
Open |
| CQ9 |
RestartPveContainerCmdlet.cs |
15 |
Medium |
Missing ConfirmImpact.High — RestartPveVmCmdlet has it but container counterpart does not. Inconsistent. |
New |
| CQ10 |
SuspendPveContainerCmdlet.cs |
14 |
Medium |
Missing ConfirmImpact.High — SuspendPveVmCmdlet has it but container counterpart does not. Inconsistent. |
New |
| CQ11 |
38 cmdlet files |
varies |
Medium |
new PveHttpClient per-operation. 38 cmdlets create their own PveHttpClient instance instead of going through services. Bypasses connection pooling. |
Open |
| CQ12 |
PSProxmoxVE.csproj |
22 |
Low |
System.Management.Automation pinned to 7.4.0. Consider updating if targeting .NET 10. |
Open |
Fixed Since Prior Scan
| Prior ID |
Description |
Status |
| CQ1–CQ4 |
Infinite loop WaitForTask in InvokePveNetworkApply, NewPveSnapshot, RestorePveSnapshot, RemovePveSnapshot |
Fixed — now uses TaskService.WaitForTask |
| CQ5 |
Infinite poll loop in InvokePveVmGuestExec |
Fixed — added Timeout parameter with Stopwatch + TimeoutException |
| CQ7 |
Duplicated WaitForTask methods (4 VM/network cmdlets) |
Fixed — uses TaskService |
| CQ9 |
~54 cmdlets missing OutputType |
Fixed — all 169 cmdlets now have [OutputType] |
| CQ10 |
Firewall VmId defaults to 0 instead of nullable |
Fixed — no longer int default 0 pattern |
| CQ11 |
Bare catch in PveHttpClient.ExtractErrorMessage |
Fixed — proper exception handling |
| CQ12 |
Bare catch in PveCmdletBase status polling |
Fixed — filtered when clause excludes OOM/SOE |
| CQ13 |
Bare catch in VmService + ContainerService |
Fixed — filtered to PveApiException/HttpRequestException |
| CQ14 |
Bare catch in GetPveVmCmdlet |
Fixed — proper exception handling |
| CQ17 |
RemovePveRoleCmdlet missing ConfirmImpact.High |
Fixed — now has ConfirmImpact = ConfirmImpact.High |
| CQ18 |
~95 cmdlets not sealed |
Fixed — all 169 cmdlets are now sealed |
| CQ19 |
SuspendPveVmCmdlet missing ConfirmImpact.High |
Fixed — now has ConfirmImpact.High |
| CQ20 |
RestartPveVmCmdlet missing ConfirmImpact |
Fixed — now has ConfirmImpact.High |
| CQ21 |
Dual JSON serialization attributes |
Fixed — [JsonPropertyName] removed, only [JsonProperty] remains |
| CQ22 |
Auth header magic strings |
Fixed — extracted to const string ApiTokenPrefix and CsrfHeaderName |
| CQ6 (prior) |
Pool/CephPool parameter conflict in NewPveStorageCmdlet |
Fixed — runtime validation with ThrowTerminatingError if both specified |
Phase 4 — Testing Coverage Analysis
Test Projects
| Project |
Framework |
Type |
Runner |
PSProxmoxVE.Core.Tests |
xUnit 2.7 + Moq 4.20 |
Unit tests (models, auth) |
dotnet test |
PSProxmoxVE.Tests |
Pester 5 |
Cmdlet + Integration tests |
Invoke-Pester |
xUnit Tests (Core Library)
15 test files covering authentication (PveSession, PveAuthenticator, PveVersion) and model deserialization (12 model areas including backup, cluster, firewall, SDN) with PVE 8 and PVE 9 JSON fixtures. ~180+ xUnit tests total.
Pester Tests
100% of 169 cmdlets have Pester unit tests covering: command existence, parameter metadata, mandatory checks, parameter types, ShouldProcess presence, ConfirmImpact declarations, and "no session" error behavior.
Integration Tests
- Self-hosted runner provisions nested PVE 8 and PVE 9 via Terraform + auto-install ISO
- Tests check for
PVETEST_* environment variables, skip gracefully when unavailable
- Robust
AfterAll cleanup of VMs, containers, users, roles, firewall rules, backup jobs
- CRUD patterns: create → verify → update → verify → delete → verify
- SDN tests check PVE version and skip if older
Test Coverage Gap List (cmdlets lacking integration tests)
| Cmdlet |
Unit Test |
Integration Test |
Prior Status |
| Nodes |
|
|
|
| Get-PveNodeConfig |
Yes |
No |
Open |
| Set-PveNodeConfig |
Yes |
No |
Open |
| Get-PveNodeDns |
Yes |
No |
Open |
| Set-PveNodeDns |
Yes |
No |
Open |
| Start-PveNodeVms |
Yes |
No |
Open |
| Stop-PveNodeVms |
Yes |
No |
Open |
| VMs |
|
|
|
| Move-PveVm |
Yes |
No |
Open |
| Move-PveVmDisk |
Yes |
No |
Open |
| Remove-PveVmDisk |
Yes |
No |
Open |
| Guest Agent |
|
|
|
| Get-PveVmGuestOsInfo |
Yes |
No |
Open |
| Get-PveVmGuestFsInfo |
Yes |
No |
Open |
| Read-PveVmGuestFile |
Yes |
No |
Open |
| Write-PveVmGuestFile |
Yes |
No |
Open |
| Set-PveVmGuestPassword |
Yes |
No |
Open |
| Invoke-PveVmGuestFsTrim |
Yes |
No |
Open |
| Containers |
|
|
|
| Move-PveContainer |
Yes |
No |
Open |
| Suspend-PveContainer |
Yes |
No |
Open |
| Resume-PveContainer |
Yes |
No |
Open |
| Resize-PveContainerDisk |
Yes |
No |
Open |
| New-PveContainerTemplate |
Yes |
No |
Open |
| Move-PveContainerVolume |
Yes |
No |
Open |
| Get-PveContainerInterface |
Yes |
No |
Open |
| Storage |
|
|
|
| Set-PveStorage |
Yes |
No |
Open |
| Get-PveStorageStatus |
Yes |
No |
Open |
| Remove-PveStorageContent |
Yes |
No |
Open |
| Set-PveStorageContent |
Yes |
No |
Open |
| New-PveStorageDisk |
Yes |
No |
Open |
| SDN |
|
|
|
| Set-PveSdnZone |
Yes |
No |
Open |
| Set-PveSdnVnet |
Yes |
No |
Open |
| Set-PveSdnSubnet |
Yes |
No |
Open |
| New-PveSdnIpam |
Yes |
No |
Open |
| Remove-PveSdnIpam |
Yes |
No |
Open |
| Set-PveSdnIpam |
Yes |
No |
Open |
| New-PveSdnDns |
Yes |
No |
Open |
| Remove-PveSdnDns |
Yes |
No |
Open |
| Set-PveSdnDns |
Yes |
No |
Open |
| New-PveSdnController |
Yes |
No |
Open |
| Remove-PveSdnController |
Yes |
No |
Open |
| Set-PveSdnController |
Yes |
No |
Open |
| Invoke-PveSdnApply |
Yes |
No |
Open |
| Users / Access |
|
|
|
| Set-PveRole |
Yes |
No |
Open |
| Set-PveApiToken |
Yes |
No |
Open |
| Get-PveGroup |
Yes |
No |
Open |
| New-PveGroup |
Yes |
No |
Open |
| Set-PveGroup |
Yes |
No |
Open |
| Remove-PveGroup |
Yes |
No |
Open |
| Get-PveDomain |
Yes |
No |
Open |
| New-PveDomain |
Yes |
No |
Open |
| Set-PveDomain |
Yes |
No |
Open |
| Remove-PveDomain |
Yes |
No |
Open |
| Set-PvePassword |
Yes |
No |
Open |
| Pools |
|
|
|
| Get-PvePool |
Yes |
No |
Open |
| New-PvePool |
Yes |
No |
Open |
| Set-PvePool |
Yes |
No |
Open |
| Remove-PvePool |
Yes |
No |
Open |
| Templates |
|
|
|
| New-PveTemplate |
Yes |
No |
Open |
| Remove-PveTemplate |
Yes |
No |
Open |
| Tasks |
|
|
|
| Get-PveTaskList |
Yes |
No |
Open |
| Stop-PveTask |
Yes |
No |
Open |
| Firewall |
|
|
|
| Get-PveFirewallGroup |
Yes |
No |
Open |
| New-PveFirewallGroup |
Yes |
No |
Open |
| Remove-PveFirewallGroup |
Yes |
No |
Open |
| Set-PveFirewallAlias |
Yes |
No |
Open |
| Set-PveFirewallIpSetEntry |
Yes |
No |
Open |
| Set-PveFirewallOptions |
Yes |
No |
Open |
| Get-PveFirewallRef |
Yes |
No |
Open |
| Backup |
|
|
|
| New-PveBackup |
Yes |
No |
Open |
| Get-PveBackupInfo |
Yes |
No |
Open |
| Cluster |
|
|
|
| Get-PveClusterResource |
Yes |
No |
Open |
Summary: 169/169 unit tested (100%), ~105/169 integration tested (~62%).
Phase 5 — Security Review
5.1 Credential Handling
| Aspect |
Status |
Details |
Prior Status |
| PSCredential usage |
Good |
Connect-PveServer accepts PSCredential |
Open |
| SecureString pattern |
Good |
Consistent Marshal.SecureStringToGlobalAllocUnicode + ZeroFreeGlobalAllocUnicode in try/finally |
Open |
| Set-PveVmGuestPassword |
Good |
Now uses SecureString (was plain string) |
Fixed |
| API token in memory |
Acceptable |
Stored as plain string in PveSession.ApiToken |
Open |
| Credential logging |
Good |
No WriteVerbose/WriteDebug includes credentials |
Open |
| Ticket storage |
Good |
In PveSession only, not written to disk |
Open |
| Session expiry |
Good |
2-hour expiry via IsExpired property |
Open |
5.2 TLS/HTTPS
| Aspect |
Status |
Details |
Prior Status |
| HTTPS enforced |
Good |
BaseUrl always https://, no HTTP fallback |
Open |
| SkipCertificateCheck |
Good |
Explicit opt-in with WriteWarning advisory |
Open |
| TLS version |
Good |
OS/runtime negotiation (no pinning) |
Open |
| CSRF protection |
Good |
Token included on all POST/PUT/DELETE with ticket auth |
Open |
5.3 Input Validation
| Aspect |
Status |
Details |
Prior Status |
| VMID validation |
Good |
[ValidateRange(100, 999999999)] on all VmId params |
Open |
| URL encoding |
Good |
Uri.EscapeDataString() applied consistently across all services (VmService, ContainerService, StorageService, NetworkService, FirewallService, UserService, BackupService, PoolService, TaskService, SnapshotService, ClusterService) |
Fixed |
| API token format |
Good |
Regex validation in PveAuthenticator |
Open |
| Port validation |
Good |
[ValidateRange(1, 65535)] on port parameter |
Open |
5.4 Dependency Security
| Package |
Version |
Pinned |
Notes |
Prior Status |
Newtonsoft.Json |
13.0.3 |
Yes |
Latest stable |
Open |
System.Text.Json |
8.0.5 |
Yes |
Latest 8.x patch |
Open |
SharpCompress |
0.38.0 |
Yes |
OVA/tar extraction |
Open |
PowerShellStandard.Library |
5.1.1 |
Yes |
PrivateAssets=all |
Open |
System.Management.Automation |
7.4.0 |
Yes |
PrivateAssets=all |
Open |
Security Findings
| ID |
Area |
File |
Severity |
Description |
Prior Status |
| S1 |
Hardcoded password |
integration-tests.yml:42 |
Low |
PVE_PASSWORD: "Testpass123!" in workflow env. Masked via ::add-mask::. Disposable test VM. |
Open |
| S2 |
Hardcoded password |
variables.tf:80 |
Low |
Default "Testpass123!" for test VM password. Disposable nested VM. |
Open |
Fixed Since Prior Scan
| Prior ID |
Description |
Status |
| S1 |
SetPveVmGuestPasswordCmdlet.cs Password is string, not SecureString |
Fixed — now uses SecureString |
| S2 |
debug/Capture-UploadDiff.ps1 hardcoded API token and IP |
Fixed — replaced with placeholder tokens <PVE_HOST>, <USER>@<REALM>!<TOKENID>=<TOKEN_UUID> |
| S3 |
URL encoding missing in VmService, ContainerService, StorageService |
Fixed — Uri.EscapeDataString() now used consistently across all services |
Phase 6 — PSGallery Publication Readiness
| # |
Check |
Pass/Fail |
Notes |
Prior Status |
| 1 |
ModuleVersion is SemVer |
Pass |
0.1.0 |
Open |
| 2 |
GUID present and stable |
Pass |
a3f7c2d1-84e5-4b9f-a061-3e2d8c5f1a7b |
Open |
| 3 |
Author |
Pass |
goodolclint |
Open |
| 4 |
CompanyName |
Pass |
Worklab |
Open |
| 5 |
Copyright |
Pass |
(c) 2026 goodolclint. All rights reserved. |
Open |
| 6 |
Description (meaningful) |
Pass |
Mentions PVE 8.x/9.x and feature areas |
Open |
| 7 |
PowerShellVersion minimum |
Pass |
5.1 |
Open |
| 8 |
RequiredAssemblies |
Pass |
PSProxmoxVE.Core.dll, Newtonsoft.Json.dll |
Open |
| 9 |
CmdletsToExport explicit list |
Pass |
Fully enumerated (169 cmdlets), no wildcards |
Open |
| 10 |
FunctionsToExport |
Pass |
Explicitly @() |
Open |
| 11 |
Tags for discoverability |
Pass |
8 tags incl. Proxmox, PVE, Virtualization, IaC |
Open |
| 12 |
ProjectUri |
Pass |
GitHub repo URL |
Open |
| 13 |
LicenseUri |
Pass |
Points to LICENSE |
Open |
| 14 |
IconUri |
Fail |
Not set — cosmetic |
Open |
| 15 |
ReleaseNotes |
Pass |
In PSData |
Open |
| 16 |
Prerelease string |
Pass |
'preview' |
Open |
| 17 |
LICENSE (OSI-approved) |
Pass |
MIT |
Open |
| 18 |
README: Install-Module |
Pass |
Install-Module -Name PSProxmoxVE documented |
Open |
| 19 |
README: Quick-start examples |
Pass |
Multiple scenarios |
Open |
| 20 |
README: Authentication guide |
Pass |
Ticket + API token |
Open |
| 21 |
README: Badges |
Pass |
Build, Unit Tests, License, PSGallery |
Open |
| 22 |
Publish workflow |
Pass |
Tag-triggered via publish.yml |
Open |
| 23 |
Publish: version stamping |
Pass |
Extracts from git tag |
Open |
| 24 |
Publish: smoke test |
Pass |
Loads module, asserts cmdlet count |
Open |
| 25 |
Publish: API key as secret |
Pass |
secrets.PSGALLERY_API_KEY |
Open |
| 26 |
Publish: GitHub Release |
Pass |
Auto-created via softprops/action-gh-release |
Open |
| 27 |
CHANGELOG |
Pass |
Keep a Changelog format + Conventional Commits |
Open |
| 28 |
Publish: single netstandard2.0 |
Warning |
Only builds netstandard2.0. Verify it loads under Win PS 5.1 since manifest declares DotNetFrameworkVersion = '4.8'. |
Open |
Phase 7 — Community & Repo Maintenance Standards
| # |
Check |
Pass/Fail |
Notes |
Prior Status |
| 1 |
Bug report issue template |
Pass |
YAML form with module/PVE/PS version fields |
Open |
| 2 |
Feature request template |
Pass |
Description, use case, API endpoints |
Open |
| 3 |
PR template |
Pass |
Summary, type checkboxes, testing checklist |
Open |
| 4 |
CONTRIBUTING.md |
Pass |
Prerequisites, building, tests, coding standards, PR process |
Open |
| 5 |
CODE_OF_CONDUCT.md |
Pass |
Contributor Covenant 2.1 |
Open |
| 6 |
SECURITY.md |
Pass |
Vulnerability disclosure, 48h SLA |
Open |
| 7 |
Conventional commits |
Pass |
Consistent feat:, fix:, fix(test): in history |
Open |
| 8 |
.gitattributes |
Pass |
Comprehensive: csharp diff, binary markers, LF for .sh |
Open |
| 9 |
Issue template config.yml |
Fail |
No config.yml to control blank issues |
Open |
| 10 |
CODEOWNERS |
Fail |
Not present. Low priority for single maintainer. |
Open |
| 11 |
FUNDING.yml / community links |
Fail |
No Discussions/Discord/Funding references |
Open |
| 12 |
Default branch main |
Pass |
Confirmed |
Open |
Recommended Branch Protection
- Require PR reviews before merge
- Require status checks (build + unit tests + integration tests)
- Require linear history or squash merging
Phase 8 — Prioritized Recommendations
🔴 Critical (blocks PSGallery publication or is a security risk)
| # |
What |
Where |
Why |
Fix |
Prior Status |
| C1 |
Infinite loop in 5 cmdlets' WaitForTask methods |
NewPveContainerSnapshotCmdlet.cs, RemovePveContainerSnapshotCmdlet.cs, RestorePveContainerSnapshotCmdlet.cs, InvokePveStorageDownloadCmdlet.cs, SendPveFileCmdlet.cs |
while(true) with no timeout — cmdlet hangs forever if task stalls. Same pattern that was fixed in VM snapshot cmdlets. |
Replace private WaitForTask with TaskService.WaitForTask (identical fix to CQ1–CQ4 from prior scan) |
New |
| # |
What |
Where |
Why |
Fix |
Prior Status |
| H1 |
HA subsystem (0% coverage) |
Module |
21 endpoints + 5 🆕 PVE 9.0, essential for production clusters |
Implement HA resources, groups, status, and PVE 9.0 rules |
Open |
| H2 |
Ceph subsystem (0% coverage) |
Module |
40 endpoints, critical for hyperconverged infrastructure |
Implement Ceph OSD, MON, pool, status operations |
Open |
| H3 |
net9.0 target is EOL |
Both .csproj files |
.NET 9.0 EOL was May 2025. Should use LTS release. |
Upgrade to net10.0 |
Open |
🟡 Medium (best practice gaps, test coverage holes)
| # |
What |
Where |
Why |
Fix |
Prior Status |
| M1 |
HttpClient per-call pattern |
38 cmdlet files + services |
38 cmdlets create new PveHttpClient per operation, bypassing connection pooling |
Refactor to client-per-session or use IHttpClientFactory pattern |
Open |
| M2 |
64 cmdlets lack integration tests |
Integration tests |
38% of cmdlets untested end-to-end |
Prioritize pools, groups, domains, node ops, container gaps, guest agent extensions |
Open |
| M3 |
VM/CT-level firewall (0% coverage) |
Module |
~44 endpoints. Cluster/node-level covered but per-VM/CT rules are not. |
Add VM/CT firewall cmdlets using existing firewall service patterns |
Open |
| M4 |
Cluster config (0% coverage) |
Module |
10 endpoints for cluster create/join/node management |
Implement for multi-node cluster automation |
Open |
| M5 |
PVE 9.0 endpoints (0% coverage) |
Module |
42 new endpoints in latest PVE version. Users on PVE 9 will expect support. |
Prioritize HA rules, bulk actions, SDN fabrics |
New |
| M6 |
Broad exception catches |
PveCmdletBase.cs, VmService.cs, ContainerService.cs |
Filtered when clauses are better than bare catches but still catch broadly |
Consider more specific exception types |
Open |
🟢 Low / Nice-to-have (polish, discoverability, stretch goals)
| # |
What |
Where |
Why |
Fix |
Prior Status |
| L1 |
No IconUri in manifest |
PSProxmoxVE.psd1 |
Improves PSGallery listing appearance |
Create icon, host it, add URI |
Open |
| L2 |
System.Management.Automation pinned to 7.4.0 |
PSProxmoxVE.csproj |
Consider updating when targeting .NET 10 |
Update with TFM migration |
Open |
| L3 |
No config.yml for issue templates |
.github/ISSUE_TEMPLATE/ |
Controls blank issue creation |
Add simple config.yml |
Open |
| L4 |
No CODEOWNERS |
Repo root |
Documents ownership for PR auto-assignment |
Add CODEOWNERS with maintainer |
Open |
| L5 |
Disk management (0% coverage) |
Module |
18 endpoints — LVM, ZFS, SMART, wipe |
Implement as demand grows |
Open |
| L6 |
Notifications (0% coverage) |
Module |
32 endpoints — new in PVE 8.1+ |
Implement for monitoring automation |
Open |
| L7 |
ACME/Certificates (0% coverage) |
Module |
23 endpoints — TLS cert management |
Implement as demand grows |
Open |
| L8 |
Verify netstandard2.0 loads on PS 5.1 |
Publish workflow |
Manifest says Desktop compatible |
Add PS 5.1 smoke test to publish workflow |
Open |
Summary Statistics
| Metric |
This Scan |
Prior Scan |
Delta |
| Total cmdlets |
169 |
148 |
+21 |
| Cmdlets with ShouldProcess |
All mutating |
All mutating |
— |
| Cmdlets with OutputType |
169 (100%) |
~94 (~64%) |
+36% |
| Cmdlets sealed |
169 (100%) |
~60 (~40%) |
+60% |
| Cmdlets with HelpMessage |
169 (100%) |
148 (100%) |
— |
| xUnit test files |
15 |
15 |
— |
| Pester test files |
~48 |
~45 |
+3 |
| Integration test coverage |
~62% (105/169) |
~57% (85/148) |
+5% |
| PVE API areas with >0% coverage |
17 of 30 |
17 of 29 |
— |
| PVE API total coverage |
27.9% (180/646) |
27.9% (180/646) |
— |
| Critical issues |
1 |
2 |
-1 |
| High issues |
3 |
5 |
-2 |
| Medium issues |
7 |
10 |
-3 |
| Low issues |
7 |
11 |
-4 |
| Total issues |
18 |
28 |
-10 |
| Issues fixed from prior |
16 |
9 |
+7 |
| New issues found |
5 |
16 |
-11 |
| NuGet dependencies (runtime) |
3 |
3 |
— |
| Security vulnerabilities |
0 |
0 |
— |
| Community files present |
9/9 |
9/9 |
— |
* Integration test coverage improved both in absolute count (+20 cmdlets) and percentage (+5%).