Commit Graph

29 Commits

Author SHA1 Message Date
Clint Branham 6a03be4af2 refactor: replace manual TAR parser with SharpCompress for OVA reading
System.Formats.Tar is not available as a standalone NuGet backport for
netstandard2.0/net48. Use SharpCompress 0.38.0 on all targets for a
single, well-tested code path that handles GNU long filenames, PAX
extended headers, and other TAR variants correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 13:16:08 -05:00
Clint Branham ca0cd945a0 feat: add Import-PveOva cmdlet for OVA appliance import
Parses OVF metadata client-side from the OVA TAR archive to extract
VM name, CPU, memory, disks, and network adapters. Then uploads the
OVA with content=import, creates the VM, and imports each disk.

- OvfMetadata parser with multi-target TAR support (System.Formats.Tar
  on net9.0, manual 512-byte header parsing on netstandard2.0/net48)
- VmService.UploadOva() for content=import uploads
- Import-PveOva cmdlet with -Name/-Memory/-Cores overrides and -Wait
- Pester unit tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 13:08:31 -05:00
Clint Branham 088221a5f1 feat: add Import-PveVmDisk cmdlet for disk image import
Imports disk images (qcow2, raw, vmdk) and OVA archives into VMs
via the PVE API using POST config with import-from syntax.

- VmService.ImportDisk() method using POST /nodes/{node}/qemu/{vmid}/config
- Import-PveVmDisk cmdlet with -Source, -Disk, -TargetStorage, -Format, -Wait
- Pester unit tests
- prepare-test-vm.sh updated to use Import-PveVmDisk instead of SSH qm importdisk
- Set-PveNetwork: add required Type parameter (fixes PVE API 400 error)
- Integration test fix: pass -Type bridge to Set-PveNetwork

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:55:36 -05:00
Clint Branham 4f04391e73 docs: add platyPS help generation and MAML XML
- generate-help.ps1 script to build markdown stubs and MAML XML
- 81 cmdlet markdown help files in docs/cmdlets/
- PSProxmoxVE.dll-Help.xml (898 KB) for Get-Help support
- PVE_API_COVERAGE.md documenting implemented and missing API areas
- .csproj updated to include help XML in build output
- HelpInfoUri added to module manifest

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:32:03 -05:00
Clint Branham dec8f2d4d7 feat: add cmdlet aliases for common operations
Aliases: cpve (Connect), dpve (Disconnect), gpvm (Get-PveVm),
gpct (Get-PveContainer), gpn (Get-PveNode), gpvs (Get-PveStorage),
gpt (Get-PveTask). AliasesToExport added to manifest.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:31:55 -05:00
Clint Branham de400e159c feat: add Move-PveContainer cmdlet for LXC migration
- New Move-PveContainer cmdlet with -Online and -Wait support
- Uses existing ContainerService.MigrateContainer
- Pester unit tests added to ContainerLifecycle.Tests.ps1
- README cmdlet reference updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:31:46 -05:00
Clint Branham fb4a21a4f9 fix: use cryptographic RNG for multipart boundary generation
Replace `new Random()` with `RandomNumberGenerator` in
PveHttpClient.GenerateBoundary(). Uses the static Fill() method on
.NET Core and the disposable Create() pattern on net48/netstandard2.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:31:40 -05:00
Clint Branham 14cbff9877 docs: add XML doc comments to Core public API and remove CS1591 suppression
- Add missing XML doc comments to all public types and members in
  PSProxmoxVE.Core (Authentication, Exceptions, Models, Client)
- Remove CS1591 suppression from PSProxmoxVE.Core.csproj
- Build succeeds with 0 warnings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:21:54 -05:00
Clint Branham ffec75b461 feat: add container snapshot and SDN subnet cmdlets
Container snapshots (4 cmdlets):
- Get-PveContainerSnapshot, New-PveContainerSnapshot
- Remove-PveContainerSnapshot, Restore-PveContainerSnapshot
- Service methods in ContainerService
- Pester unit tests

SDN subnet management (3 cmdlets):
- Get-PveSdnSubnet, New-PveSdnSubnet, Remove-PveSdnSubnet
- PveSdnSubnet model and NetworkService methods
- Pester unit tests

Also updates manifest (73 cmdlets), README cmdlet reference, and CHANGELOG.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:21:40 -05:00
Clint Branham 0bf275ea9f refactor: improve cmdlet quality across all 66 cmdlets
- Add HelpMessage to every [Parameter] attribute
- Add [ValidateRange(100, 999999999)] to all VmId parameters
- Add ConfirmImpact.High to Stop-PveVm and Reset-PveVm
- Add ShouldProcess to Invoke-PveVmGuestExec
- Add WriteVerbose before every API call
- Add WriteWarning on -SkipCertificateCheck usage in Connect-PveServer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:21:27 -05:00
Clint Branham b12ffc485d feat: add AdditionalConfig parameter and guest agent cmdlets (closes #2, #3)
Issue #3 — Set-PveVmConfig / Set-PveContainerConfig:
- Add -AdditionalConfig [Hashtable] for arbitrary PVE config keys
  (scsi0, boot, agent, net0, ide2, cicustom, etc.)
- Add -Delete [string] for removing config keys
- Unit tests for both new parameters

Issue #2 — QEMU Guest Agent cmdlets:
- Test-PveVmGuestAgent: pings guest agent, returns bool
- Get-PveVmGuestNetwork: returns guest network interfaces with IPs
- Invoke-PveVmGuestExec: executes command in guest, returns output
- New models: PveGuestNetworkInterface, PveGuestIpAddress
- Service methods in VmService for all agent operations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:06:55 -05:00
Clint Branham b8af36a7fc fix(build): add netstandard2.0 target to eliminate System.Runtime version mismatch
The net9.0 DLL references System.Runtime 9.0.0.0 which is unavailable
on GitHub runners where pwsh ships with .NET 8.x. Adding netstandard2.0
as a target produces a DLL compatible with any .NET version (PS 5.1 on
.NET Framework through PS 7.x on .NET 8/9).

- Add netstandard2.0 to TargetFrameworks in Core and module csproj
- Update #if NET48 conditionals to include NETSTANDARD2_0
- Switch CI workflows from net9.0 to netstandard2.0 for Pester tests
- Update _TestHelper.ps1 framework search order

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:34:40 -05:00
Clint Branham d187b0de52 fix: resolve net48-only nullable warnings (CS8601, CS8602, CS8604)
- CS8601: Add null-forgiving operator on guarded dictionary assignments
  in cmdlets where IsNullOrEmpty check precedes the assignment
- CS8602: Add Assert.NotNull after JObject["data"] in xUnit model tests
  (JToken indexer returns nullable on net48)
- CS8604: Add null-forgiving on guarded arguments in NodeService,
  WaitPveTaskCmdlet, GetPveTemplateCmdlet, and auth test parameters

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 08:32:57 -05:00
Clint Branham 0c70e11fe8 fix: resolve all C# compiler warnings (CS8604, CS8618, CS8603, CS1573, xUnit1012)
- CS8604: Use cmdlet's own Node property instead of nullable task.Node
  in WaitForTask calls across all VM cmdlets
- CS8618: Make PveSession.ServerVersion nullable (PveVersion?) since it
  is set post-construction by PveAuthenticator
- CS8603: Add null-forgiving operator where IsNullOrWhiteSpace guards
  guarantee non-null in PveHttpClient
- CS1573: Add XML param documentation to all public service methods
- xUnit1012: Make test parameters nullable (string?) for null test cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 18:11:49 -05:00
Clint Branham 8ea983c0fc fix: resolve all integration test failures against live PVE
- BaseUrl trailing slash and resource path cleanup: PveSession.BaseUrl now
  ends with '/', all cmdlet resource strings stripped of leading slashes and
  /api2/json/ prefixes so URLs compose correctly
- PveNodeStatus: rename Name -> Node to match JSON field and test expectations
- NewPveVmCmdlet: auto-allocate vmid via GET cluster/nextid when -VmId omitted
- UploadFileAsync (BZ 7389 workarounds):
  * Unquoted multipart boundary in Content-Type header
  * Quoted name= values in Content-Disposition (embedded double-quotes)
  * Content-Disposition set before Content-Type on file part — PVE's parser
    closes the connection if Content-Type appears first
- SendPveIsoCmdlet: run upload in Task.Run, track progress atomically with
  Interlocked, poll and call WriteProgress only from pipeline thread to avoid
  InvalidOperationException from PSCmdlet thread-affinity requirements
- Add debug/Capture-UploadDiff.ps1: mitmproxy capture script used to isolate
  the header-ordering bug by diffing raw multipart bytes from PS vs C# module

Integration test result: 11 passed, 0 failed, 4 skipped (expected — no
template/stopped VMs on bare nested PVE test node).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:57:21 -05:00
Clint Branham 94b0fcdad2 feat(users): add API token CRUD cmdlets (closes #1)
Implement Get-PveApiToken, New-PveApiToken, and Remove-PveApiToken to
enable automated token management without manual Proxmox VE UI interaction.
Adds PveApiToken model, UserService methods for the token endpoints, and
31 Pester unit tests covering parameters, ShouldProcess, and no-session behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 08:25:51 -05:00
Clint Branham 5b0c81a1a8 fix(auth): use TryAddWithoutValidation for Authorization header
.NET's HttpHeaders.Add() validates the Authorization header value
against the HTTP spec, rejecting PVE's custom PVEAPIToken scheme
that contains @, !, and = in the token string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 19:14:03 -05:00
Clint Branham dc9b253195 fix(tests): resolve all 400 unit test failures to reach green
Cmdlet fixes:
- GetPveSnapshotCmdlet: add -Name filter; fix s.SnapName → s.Name
- GetPveStorageCmdlet: add -Storage name filter
- GetPveNetworkCmdlet: add -Iface optional filter
- NewPveNetworkCmdlet: rename Interface → Iface (consistency with Set/Remove)
- SetPveNetworkCmdlet, RemovePveNetworkCmdlet: rename Interface → Iface
- RemovePveNetworkCmdlet, RemovePveSdnZoneCmdlet, RemovePveSdnVnetCmdlet,
  RemovePveUserCmdlet: add ConfirmImpact = ConfirmImpact.High
- SetPveCloudInitConfigCmdlet: rename User → CiUser; move GetSession() first;
  remove duplicate session variable
- SendPveIsoCmdlet: add sha512 to ChecksumAlgorithm ValidateSet
- GetPveUserCmdlet: add -Enabled switch; refactor into MatchesFilters(); fix
  int? comparison (Enabled != 1)
- GetPvePermissionCmdlet: rename UgId → UserId
- SetPvePermissionCmdlet: rename RoleId → Role
- NewPveTemplateCmdlet: add ConfirmImpact.High; move GetSession() before
  ShouldProcess so -WhatIf-less calls throw session error first
- NewPveVmFromTemplateCmdlet: rename Node → TemplateNode with [Alias("Node")]
- RemovePveSnapshotCmdlet, RestorePveSnapshotCmdlet: move GetSession() before
  ShouldProcess so session check precedes confirm prompt

Test fixes:
- All 18 Pester test files: update DLL candidates to net9.0
- Fix foreach+It closure capture using -TestCases pattern
- Remove-PveVm, Remove-PveContainer no-session tests: add -Confirm:$false to
  bypass ConfirmImpact.High prompt before GetSession() check
- Get-PveStorageContent test: add mandatory -Node/-Storage params
- Send-PveIso test: create temp file to satisfy FileExistsValidation
- New-PveVmFromTemplate test: add NewVmId to parameter splat

Tooling:
- Invoke-Tests.ps1: add -FromTerraform, explicit lab params, fix TFM
  auto-detection via Select-Xml, fix Pester import, fix variable scoping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 18:27:12 -05:00
Clint Branham c5d6cde6eb feat(format): add ps1xml format definitions and module manifest
Define default Format-Table views for PveVm, PveNode, PveStorage,
PveTask, PveSnapshot, PveContainer, and PveUser. Add module manifest
with all 60+ cmdlets explicitly listed, PowerShell 5.1+ compatibility,
and prerelease tag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:47:52 -05:00
Clint Branham 76c2ad4946 feat(cmdlets): implement snapshot, network, SDN, user, template, cloud-init cmdlets
Add cmdlets for snapshots (Get/New/Remove/Restore-PveSnapshot), network
(Get/New/Set/Remove-PveNetwork, Invoke-PveNetworkApply), SDN zones and
VNets (PVE 8.0+ version guard), users/roles/permissions, templates
(Get/New/Remove-PveTemplate, New-PveVmFromTemplate), cloud-init config,
and task management (Get-PveTask, Wait-PveTask).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:46:38 -05:00
Clint Branham 0c11bc4b1b feat(cmdlets): implement storage and ISO upload cmdlets
Add Get-PveStorage, Get-PveStorageContent, Send-PveIso (with manual
multipart upload and Write-Progress), Invoke-PveStorageDownload,
New-PveStorage, and Remove-PveStorage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:46:27 -05:00
Clint Branham 6bf5d195af feat(cmdlets): implement container cmdlets
Add Get-PveContainer, New-PveContainer, Remove-PveContainer,
Start/Stop/Restart-PveContainer, Copy-PveContainer,
Get-PveContainerConfig, and Set-PveContainerConfig. Mirrors VM
cmdlet patterns with LXC-appropriate parameters.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:46:07 -05:00
Clint Branham cc4d08070d feat(cmdlets): implement VM lifecycle cmdlets
Add Get-PveVm, New-PveVm, Remove-PveVm, Start/Stop/Suspend/Resume/
Reset/Restart-PveVm, Copy-PveVm, Move-PveVm, Get-PveVmConfig,
Set-PveVmConfig, and Resize-PveVmDisk. All support pipeline input,
-WhatIf/-Confirm on state changes, and -Wait for async tasks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:45:57 -05:00
Clint Branham 9b24eaf0f0 feat(cmdlets): implement connection and node cmdlets
Add ModuleState, PveCmdletBase with -Session parameter and session
validation. Implement Connect-PveServer, Disconnect-PveServer,
Test-PveConnection, Get-PveNode, and Get-PveNodeStatus with pipeline
support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:45:32 -05:00
Clint Branham 52f1978de4 feat(services): implement service layer for all domains
Add service classes for nodes, VMs, containers, storage, snapshots,
network/SDN, users/roles/permissions, templates, cloud-init, tasks,
and cluster. SDN services enforce PVE 8.0+ version guard. Task service
supports polling with configurable timeout and progress callbacks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:45:23 -05:00
Clint Branham 4ac38f7714 feat(models): implement typed response models for PVE 8.x and 9.x
Add C# model classes for all PVE API resources: nodes, VMs, VM config,
containers, storage, network interfaces, SDN zones/vnets, users, roles,
permissions, snapshots, tasks, and cluster status. All models use dual
JSON attributes (System.Text.Json + Newtonsoft.Json), nullable optional
fields, and human-readable ToString() overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:45:06 -05:00
Clint Branham 2c7e90d185 feat(client): implement HTTP client with manual multipart ISO upload (bugzilla 7389 workaround)
PveHttpClient handles auth headers, error parsing, and both sync/async
request methods. ISO upload constructs raw multipart body manually to
avoid .NET MultipartFormDataContent sub-headers that Proxmox pveproxy
mishandles. Streams files in 4MB chunks with progress callback support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:44:12 -05:00
Clint Branham d802b117ba feat(auth): implement ticket and API token authentication with session model
Add PveSession, PveAuthenticator, PveVersion, and PveAuthMode. Support
ticket-based auth (username/password with 2hr expiry) and API token auth
(USER@REALM!TOKENID=UUID format). Version detection on connect via
GET /api2/json/version. Custom exception types for API errors, expired
sessions, missing connections, version mismatches, and task failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:44:00 -05:00
Clint Branham 14d823af28 feat: initialize repository structure and solution
Set up the PSProxmoxVE repository with solution file, project files for
Core library (net10.0+net48), PowerShell module, and xUnit test project.
Includes .gitignore, .editorconfig, LICENSE (MIT), CHANGELOG, and README
with supported version matrix and full cmdlet reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:43:50 -05:00