mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-09-06 12:09:01 +00:00
18 KiB
18 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Conventional Commits.
[Unreleased]
Added
Get-PveFirewallRule,New-PveFirewallRule,Set-PveFirewallRuleandRemove-PveFirewallRuleaccept-Level Group -Group <name>to manage the rules of a firewall security group; theFirewallServicemethods for group rules existed with no cmdlet surface, so a group created withNew-PveFirewallGroupcould not be given rules from PowerShell. (#126)New-PveNetworkandSet-PveNetworkgained-BridgeVlanAware, so a VLAN-aware Linux bridge can be created and toggled from the module instead of only being read back. The model already surfacedbridge_vlan_awareasBridgeVlanAware, so this closed a write-path gap. OnSet-PveNetworkthe switch is only sent when explicitly bound, so an update that omits it leaves the flag alone. Clearing it goes through the endpoint'sdeletelist rather thanbridge_vlan_aware=0: PVE merges supplied keys onto the stored stanza and accepts the0without acting on it, so the obvious form is a silent no-op — confirmed against a live PVE 9 cluster, where the bridge stayed VLAN-aware.bridge_vidsis not covered; it is an independent parameter and PVE defaults to 2-4094. (#92)
Changed
- Every API call opened a fresh TLS connection:
PveHttpClientnow shares one pooled transport per host, port and certificate-check setting for the life of the process, andWait-PveTaskand every-Waitcmdlet poll over one connection, backing off from 1 s toward a 10 s cap instead of a new handshake every 2 s. An explicit-PollIntervalis still honoured as a fixed interval. (#151) - The 31 cmdlets that built their own HTTP request now send it through their
*Service, so the path and payload each emits is asserted by offline tests:New-/Remove-/Restore-PveSnapshot;Get-PveNodeandGet-PveNodeStatus;Get-PveUser,Get-PveRole,New-PveRoleandSet-PvePermission;New-PveContainerand its three snapshot cmdlets;Get-PveCloudInitConfigandGet-PveTemplate;Get/New/Set/Remove-PveNetwork,Invoke-PveNetworkApply,Get/New-PveSdnZone,Get/New-PveSdnVnet,Get/New-PveSdnSubnetandRemove-PveSdnSubnet;New-PveStorage,Invoke-PveStorageDownloadandSend-PveFile. Where a service and its cmdlet disagreed, the shipped cmdlet behaviour won: an unset switch is omitted rather than sent as0(New-PveSnapshot -IncludeVmState,Set-PvePermission -Propagate), and a task returned without-WaitreportsStatus = "running".New-PveSdnZone,New-PveSdnVnet,New-PveSdnSubnetandRemove-PveSdnSubnetnow validate theirVnet/Zoneidentifiers against the same pattern the other SDN cmdlets use. (#126) - Removed the eight duplicated task-response parsers in favour of one shared one, so every cmdlet that returns a task without
-WaitreportsStatus = "running"where several (New-PveVm, the VM lifecycle cmdlets,Copy-PveVm,Move-PveVm,Resize-PveVmDisk,Import-PveVmDisk,New-PveBackup,Start/Stop-PveNodeAll,New-PveTemplate, and the container lifecycle cmdlets) left it blank. Removed the unusedPveAuthenticationException, thePut/Deletesync wrappers onPveHttpClientand the duplicateClusterConfigService.GetClusterStatus; the firewall cmdlets validate-Level/-Node/-VmId/-Groupthrough one shared check instead of 18 copies, with messages and error categories unchanged; the three hand-rolled version warnings go throughPveCmdletBase.WarnIfBelowVersion; and the offline suite lost 126 tests that asserted a null-session guard onlynull!in a test could reach. (#154) - The offline Pester suite can now fail:
Skip-IfMissing, which skipped a test whenever the cmdlet it was about was missing, is gone; one manifest test diffsCmdletsToExportagainst the built module in both directions and checks the per-cmdlet conventions by reflection, replacing 894 tests that restated[Cmdlet]and[Parameter]attributes. The help was regenerated for the 25 cmdlets (the HA and Cluster families) that shipped without any. (#153) Newtonsoft.Jsonis now 13.0.4 in both shipped assemblies, with every package version managed centrally inDirectory.Packages.propsso the two can no longer drift; the SDK is pinned byglobal.json(10.0, latest feature band) and the net48 test build no longer emits theSystem.MemoryMSB3277 conflict. (#156)
Fixed
Send-PveFile -ContentType vztmpland-ContentType importuploaded asiso; the content type is now sent as given.Invoke-PveStorageDownload -TimeoutSecondskeeps applying to the download request. (#126)Get-PveTemplatewarns for each node skipped because it was unreachable instead of silently returning a shorter list, and an empty-Nodeagain means all nodes. (#126)- A connection dropped while the response body was being read escaped
PveHttpClientas a rawHttpRequestExceptioninstead of aPveApiException; the body read is now inside the same guard as the request. (#154) Copy-PveVmandCopy-PveContainernow allocate a valid guest ID throughcluster/nextidwhen-NewVmIdis omitted, instead of sendingnewid=0, which PVE rejects. Both cmdlets now forward-Storageto the clone request; it was declared and silently dropped, so a full clone always landed on the source storage.New-PveVmandImport-PveOvause the same service call for their ID allocation, so a response withoutdatais a clear error rather than aNullReferenceException. (#135)Import-PveOvano longer throws an unhandledInvalidOperationExceptionwhen the created VM is not yet listed on the node (the disk import still running without-Wait); it returns the basic VM record instead, as the cmdlet always intended. Its upload no longer runs under the session's 100-second timeout, so an OVA that takes longer to transfer completes;-TimeoutSecondswas added (default 30 minutes,0for none), mirroringSend-PveFile. (#139)Wait-PveTaskpolls throughTaskService.WaitForTasklike every other-Waitpath, so it clamps the poll interval to one second, checks the task before sleeping, and no longer overflows on intervals over 24 days. An omitted-Timeoutstill waits indefinitely. (#140)Get-PveVmandGet-PveContainerwarn for each node skipped because it was unreachable or returned a server error, instead of silently returning a partial or empty list, and a permission error on any node now surfaces instead of reading as "no guests". Lifecycle cmdlets with-Waitsurface an expired session, a permission error or a missing guest during the status poll immediately, instead of failing with a generic timeout after the full-Timeoutwindow. (#142)Remove-PveStorage,Remove-PveSdnVnetandRemove-PveSdnZonenow percent-encode the name before building the API path and reject names outsideA-Z a-z 0-9 . _ -, so a name containing../can no longer be turned into a request against a different endpoint. The three cmdlets now call the existing service methods instead of building their own request. (#145)Invoke-PveVmGuestExecnow recognises a booleanexitedfrom the guest agent, instead of polling until-Timeouton PVE builds that returntruerather than1. (#141)Disconnect-PveServerno longer issues aDELETEto/access/ticket, an endpoint PVE does not have; the call always failed and was hidden. It now discards the local session only and gained-Sessionso an explicitly created session can be disconnected. The warning for a session that is not the module-level one names the credential's real lifecycle: tickets expire on their own, API tokens do not and can be revoked withRemove-PveApiToken. (#144)Import-PveOvanow places disks on the bus the OVF descriptor names. The controller mapping had SCSI and SATA swapped for VMware-produced OVAs, and the computed bus was then ignored in favour ofscsifor every disk. (#138)Import-PveOvarejects an OVF descriptor whose disk file name contains anything outsideA-Z a-z 0-9 . _ -, and refuses descriptors with a DTD. A crafted archive could otherwise inject extra keys into the disk config line or exhaust memory through entity expansion. (#148)Get-PvePermissionnow returns the privileges granted on each path in aPrivilegesproperty; previously the map PVE returned was dropped and every result carried only the path. The key's presence is the grant; the value is whether it propagates to sub-paths. (#137)Remove-PveVm -Forcenow sendsskiplock=1(PVE honours it forroot@pamonly) andRemove-PveContainer -Forcesendsforce=1; both switches were accepted and ignored before. (#136)Restart-PveVmnow uses PVE's native reboot endpoint (POST {vmid}/status/reboot) instead of composing a shutdown followed by a start. The two-call form raced Proxmox's own post-stop cleanup: the start won the guest's config lock,qm cleanupthen held that lock for 30 seconds waiting on the newly started process, and the caller's next operation failed withcan't lock file '/var/lock/qemu-server/lock-<vmid>.conf' - got timeout. Reproduced in integration runs 183, 185 and 186 as a cascade of 4 failures.Restart-PveContaineris unchanged — LXC has no reboot endpoint. SeeDECISIONS.mdD016.- Guest operations that Proxmox rejects with
can't lock file '/var/lock/qemu-server/lock-<vmid>.conf' - got timeoutare now reissued for up to 45 seconds instead of surfacing as an error. That flock is taken byqm cleanupfor up to 30 seconds after a guest stops and is not exposed through the API in any form, so it can only be retried past, never waited on. Covers both the synchronous form (Set-PveVmConfig,Resize-PveVmDisk, and every other call through the HTTP client) and the asynchronous form, where the request succeeds and the PVE task then fails (Reset-PveVm,Copy-PveVm). Reproduced on a client ~40% slower than CI, which failed three VM tests on a commit CI passed. (#113) SeeDECISIONS.mdD020. - Lifecycle cmdlets with
-Wait(Start/Stop/Restart/Reset/Resumefor VMs and containers) also wait for the guest's config lock (thelock:property, e.g.backupormigrate) to clear before returning, and the post-timeout fallback tests the most recent poll rather than whether a match was ever seen. SeeDECISIONS.mdD015 — that guard covers the config lock only; the separate flock race is D020. New-PveCluster -Waitnow blocks until the cluster reports quorum, not merely until the creation task finishes. PVE's create task returns before corosync converges (~6s earlier in testing), so the naturalNew-PveCluster -Wait→Add-PveClusterMembersequence failed withcluster not ready - no quorum?. Adds-Timeout(seconds, default 60, range 1-3600) following the-Waittimeout convention used byStop-PveContainerandReset-PveVm. SeeDECISIONS.mdD014.
[0.2.0] - 2026-05-22
Added
New-PveVmdisk controller / IO options:-DiskBus(virtio/scsi/sata/ide),-ScsiHardware(scsihw),-DiskIoThread,-DiskAio,-DiskSsd,-DiskDiscard,-DiskCache. Invalid combinations (e.g.ssdon virtio,iothreadon sata/ide or scsi withoutvirtio-scsi-single) are rejected up front with a clear error. (#65)Get-PveVmConfignow surfacesscsihw,efidisk0, andtpmstate0as typed properties, plus anAdditionalPropertiesdictionary capturing any other config key (e.g.hostpci0) as native .NET values instead of silently dropping it. (#65)
Fixed
- Form values containing
;were split into bogus fields by PVE's parser, so a multi-device boot order set viaSet-PveVmConfig -AdditionalConfig @{ boot = 'order=scsi0;ide2' }failed withunable to parse drive options. Semicolons are now percent-encoded. (#64) Invoke-PveVmGuestExec -Argswere delivered to the guest as JSON on STDIN instead of as argv, so commands ran with no/garbage arguments. Arguments are now sent as the PVEcommandarray (repeated keys), reaching the process as real argv. (#68)
[0.1.3] - 2026-05-20
Added
Connect-PveServer -TimeoutSecondsto set the session-defaultHttpClienttimeout (default 100s;0= infinite). (#59)Send-PveFile -TimeoutSecondsandInvoke-PveStorageDownload -TimeoutSecondsfor per-call override with a 30-minute implicit default so large uploads/downloads no longer trip the 100s default. (#59)
Fixed
New-PveVm -DiskSizeandNew-PveContainer -RootFsSizenow normalize unit suffixes (32G,1T,32GB, etc.) to bare GiB before constructing the disk spec. Previously the suffix was passed verbatim, which LVM/LVM-thin storages rejected withunable to parse lvm volume name '32G'. Sub-GB units (M,MB,K,KB) are now rejected client-side with a clear error. (#58)PveHttpClient.SendAsyncsurfacesHttpClient.Timeoutfirings asPveApiException(RequestTimeout)with the resource path and configured timeout, instead of leaking a rawTaskCanceledException. Works acrossnet48,net10.0, andnetstandard2.0. (#59)- Disk-size validation runs before
ShouldProcessso typos like512Mare caught with-WhatIf, regardless of whether-DiskStorage/-RootFsStorageis also supplied. (#58)
[0.1.2] - 2026-03-27
Fixed
Get-PveApiToken:FullTokenIdis now computed fromUserId!TokenId(was always empty). (#44)Set-PvePermission: addedtokenACL type with auto-detection from!in-UgId, enabling permission assignment for API tokens. (#43)Connect-PveServer: always emits the session to the pipeline. Use-Quietto suppress;-PassThruis kept hidden for backwards compatibility. (#45)
[0.1.1] - 2026-03-26
Added
- Firewall management cmdlets (21): rules, security groups, aliases, IP sets, options at cluster/node/VM/container levels
- Backup/vzdump cmdlets (5): ad-hoc backup creation and scheduled backup job CRUD
- SDN IPAM cmdlets (3):
Get/New/Remove-PveSdnIpamfor IPAM plugin management - SDN DNS cmdlets (3):
Get/New/Remove-PveSdnDnsfor DNS plugin management - SDN Controller cmdlets (3):
Get/New/Remove-PveSdnControllerfor controller management - SDN Update cmdlets (7):
Set-PveSdnZone/Vnet/Subnet/Controller/Ipam/Dns+Invoke-PveSdnApply Set-PveRole,Set-PveStorage,Set-PveApiTokenfor missing update operationsGet-PveClusterResource: single-call cluster-wide inventory of all VMs, containers, nodes, storage- Task management:
Get-PveTaskList(list tasks on node),Stop-PveTask(cancel running tasks) - Pool management cmdlets (4):
Get/New/Set/Remove-PvePool Get-PveBackupInfo: find VMs/containers not covered by backup jobs- VM disk operations:
Move-PveVmDisk(storage migration),Remove-PveVmDisk(detach/delete) - Guest agent extensions (6):
Get-PveVmGuestOsInfo,Get-PveVmGuestFsInfo,Read/Write-PveVmGuestFile,Set-PveVmGuestPassword,Invoke-PveVmGuestFsTrim - Container gaps (6):
Suspend/Resume-PveContainer,Resize-PveContainerDisk,New-PveContainerTemplate,Move-PveContainerVolume,Get-PveContainerInterface - Storage content management (4):
Get-PveStorageStatus,Remove/Set-PveStorageContent,New-PveStorageDisk - Node operations (6):
Get/Set-PveNodeConfig,Get/Set-PveNodeDns,Start/Stop-PveNodeVms - Access management (9):
Get/New/Set/Remove-PveGroup,Get/New/Set/Remove-PveDomain,Set-PvePassword - Two-tier version gating: introduced vs default version with clear user messaging
- 70 xUnit tests validating every
ValidateSetagainst the PVE OpenAPI spec, withpve-api-enums.jsonfixture extracted from the full spec - Integration tests for firewall rules, aliases, IP sets, backup jobs, and OVA import
- PSGallery version badge in README
Changed
- All cmdlet classes sealed for design clarity and JIT optimization
[OutputType]attribute added to all 169 cmdlets for IntelliSense and pipeline support- Publishable projects retargeted to
netstandard2.0for PS 5.1 + PS 7.x compatibility System.Text.Jsonattributes removed — module usesNewtonsoft.Jsonexclusively- Inline task-polling loops replaced with
TaskService.WaitForTask(timeout + progress support) - Password parameters changed from
stringtoSecureStringwith secure memory handling ValidateRange(100, 999999999)added to allVmIdparametersUri.EscapeDataString()applied to all dynamic URL path segments- Hardcoded verb strings replaced with verb class constants (
VerbsCommon.Get, etc.) - Auth header magic strings extracted to named constants in
PveHttpClient - Bare
catchblocks replaced with specific or filtered exception handling - MAML help (dll-Help.xml) and 170 markdown cmdlet docs generated
- PSGallery publish workflow with PS 5.1 smoke testing
Fixed
ConfirmImpact.Highadded to all destructive cmdlets (Stop, Reset, Restart, Suspend, Remove, Restore, New-PveTemplate)- Storage
ValidateSet: removedglusterfs(dropped in PVE 9), addedbtrfsandesxi - Backup compression:
none→0(PVE expects the string"0", not"none") - Cluster resource filter: removed
lxc(PVE usesvmfor both QEMU and LXC) - Hardcoded test password moved from CI workflow to GitHub Actions secret
- Terraform variable default password removed (requires env var)
[0.1.0-preview] - 2026-03-19
Added
- Initial project structure and solution setup
- Ticket and API token authentication with session management
- HTTP client with manual multipart ISO upload (bugzilla 7389 workaround)
- Typed response models for PVE 8.x and 9.x API resources
- Service layer for all resource domains
- 66 PowerShell cmdlets for VMs, containers, storage, networking, SDN, users, roles, permissions, API tokens, templates, cloud-init, snapshots, and tasks
- QEMU guest agent cmdlets (Test-PveVmGuestAgent, Get-PveVmGuestNetwork, Invoke-PveVmGuestExec)
- xUnit unit tests for core library
- Pester 5 cmdlet tests across OS/PS version matrix (Windows PS 5.1, PS 7.5 on Windows/Linux/macOS)
- Integration tests against live PVE 8 and PVE 9 instances via Terraform-provisioned nested VMs
- GitHub Actions CI/CD workflows (build, unit tests, integration tests)
- Format definitions for default table output on all PS versions