AzureDevOpsDscNative.psd1
|
@{ RootModule = 'AzureDevOpsDscNative.psm1' # Version number of this module. # # This value is a fallback for local and CI builds only. Released versions are # driven by the git tag: the publish workflow sets $env:ModuleVersion from the # tag, and the build stamps that value into the packaged manifest instead of this # one. Do not hand-edit this to cut a release - push a vX.Y.Z tag. moduleVersion = '1.2.0' # ID used to uniquely identify this module GUID = 'e7eb078e-5e97-42be-ae8f-decb140fc38e' # Author of this module Author = 'ZanattaMichael' # Company or vendor of this module CompanyName = 'ZanattaMichael' # Copyright statement for this module Copyright = 'Copyright the DSC Community contributors and ZanattaMichael. All rights reserved.' # Description of the functionality provided by this module Description = 'A fork of the DSC Community AzureDevOpsDsc module with native DSC v3 support: every resource is discoverable and invokable by dsc.exe via the Microsoft.Adapter/PowerShell adapter, using generated adapted resource manifests, without requiring a wrapper resource.' # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '7.0' # Minimum version of the common language runtime (CLR) required by this module CLRVersion = '4.0' # Functions to export from this module #FunctionsToExport = @() # Cmdlets to export from this module #CmdletsToExport = @() # Variables to export from this module VariablesToExport = @() # Aliases to export from this module AliasesToExport = @() # Import all the 'DSCClassResource', modules as part of this module NestedModules = @() DscResourcesToExport = @('AzDoGroupPermission','AzDoOrganizationGroup','AzDoProject','AzDoProjectServices','AzDoProjectGroup','AzDoGroupMember','AzDoGitRepository','AzDoGitPermission','AzDoAreaPermission','AzDoIterationPermission','AzDoWIPTags','AzDoAreaNodes','AzDoIterationNodes','AzDoBranchPolicy','AzDoVariableGroup','AzDoServiceConnection','AzDoPipelineEnvironment','AzDoAgentPool','AzDoAgentQueue','AzDoTeam','AzDoTeamMember','AzDoPipeline','AzDoPipelinePermission','AzDoEnvironmentApproval','AzDoVariableGroupPermission','AzDoServiceConnectionPermission','AzDoAgentPoolPermission','AzDoSecurityNamespacePermission','AzDoArtifactFeed','AzDoArtifactFeedPermission','AzDoDeploymentGroup','AzDoTaskGroup','AzDoOrganizationSettings','AzDoExtension','AzDoAuditStream','AzDoProjectPermission','AzDoEnvironmentPermission','AzDoWiki','AzDoNotificationSubscription','AzDoRepositorySettings','AzDoCheckConfiguration','AzDoTeamSettings','AzDoArtifactFeedSettings','AzDoArtifactFeedView','AzDoProcess','AzDoProcessPermission','AzDoUserEntitlement','AzDoServiceHook','AzDoPipelineSettings','AzDoQueryFolder','AzDoWorkItemQuery','AzDoQueryPermission','AzDoWIPTagHygiene','AzDoSecureFile','AzDoSecureFilePermission','AzDoPipelineFolder','AzDoPipelineFolderPermission','AzDoGroupEntitlement','AzDoServicePrincipalEntitlement','AzDoPicklist','AzDoProcessWorkItemType','AzDoProcessField','AzDoProcessState','AzDoProcessRule','AzDoProcessBehavior','AzDoPipelineAuthorization','AzDoEnvironmentKubernetesResource','AzDoEnvironmentVMResource','AzDoDeploymentGroupTarget','AzDoReleaseFolder','AzDoReleaseFolderPermission','AzDoReleaseDefinitionPermission','AzDoTestVariable','AzDoTestConfiguration','AzDoTestPlan','AzDoTestSuite','AzDoBuildRetentionSettings','AzDoWikiPage','AzDoTaggingPermission','AzDoAnalyticsPermission','AzDoAnalyticsViewsPermission') RequiredAssemblies = @() # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{ PSData = @{ # Set to a prerelease string value if the release should be a prerelease. Prerelease = '' # Tags applied to this module. These help with module discovery in online galleries. Tags = @('DesiredStateConfiguration', 'DSC', 'DSCResourceKit', 'DSCResource', 'DSCv3', 'AzureDevOps') # A URL to the license for this module. LicenseUri = 'https://github.com/ZanattaMichael/AzureDevOpsDsc/blob/main/LICENSE' # A URL to the main website for this project. ProjectUri = 'https://github.com/ZanattaMichael/AzureDevOpsDsc' # A URL to an icon representing this module. IconUri = 'https://dsccommunity.org/images/DSC_Logo_300p.png' # ReleaseNotes of this module. # Per-release notes are generated from the CHANGELOG's [Unreleased] section # at build time and attached to the GitHub Release. This link is the fallback # shown on the Gallery listing. ReleaseNotes = '## [1.2.0] - 2026-10-04 ### Changed - Build - `azure-pipelines.yml` brought in line with the GitHub workflows so it runs on current Microsoft-hosted agents: full-history checkout for GitVersion, GitVersion.Tool 5.12.0 run with `DOTNET_ROLL_FORWARD=Major` (hosted images no longer ship .NET 6/7), unit tests run under Pester 5.7.1 as in `unit-tests.yml` instead of the Pester 4 `build.ps1 -tasks test` path, HQRM reported but non-gating, and the retired Codecov bash uploader and `PublishCodeCoverageResults@1` removed. The Deploy stage no longer requires a `dsccommunity` organization; it runs only on a `v*` tag with the pipeline variable `PublishRelease` set to `true`. - The integration workflows now cope with more than one runner carrying the `AZDO-AGENT` label. The v2 and v3 live-organization jobs share one concurrency group, so they no longer run against the organization at the same time and delete each other''s test objects in their pre-run teardown. - The integration workflows no longer move module copies out of, and back into, the runner''s standard module folders around each run - a failed move there stranded copies in `RUNNER_TEMP`, which the runner empties between jobs. They load the module only from their workspace build and now fail, naming each one, if a copy is installed in a standard module folder. `tests/Integration/README.md` lists what an `AZDO-AGENT` machine needs. - `scripts/redeploy-module.ps1` no longer copies the build into `Documents\PowerShell\Modules`. It puts `output\builtModule` at the front of `PSModulePath` for the current session and warns about any copy in a standard module folder. - AzureDevOpsDscNative - `AzDoProject.ProcessTemplate` no longer restricts a project to the four system processes (`Agile`, `Scrum`, `CMMI`, `Basic`) via `ValidateSet` - any process name known to the organization, including an inherited process, is accepted and resolved against the `LiveProcesses` cache, falling back to a live lookup. `Set` can now change a project''s process: `Get-AzDoProject` compares the project''s current process against the desired one and, when they differ, resolves both to their system-process ancestor (`Get-AzDoProcessFamilyRootId`) to decide whether Azure DevOps will permit the migration. A compatible change (moving between a system process and one of its inherited children, or between two inherited children of the same parent) is applied via the new `projectprocessmigration` endpoint (`Move-DevOpsProjectProcess`); an incompatible one - crossing unrelated process families - is refused with a clear error in both `Get` and `Set`, since `Get`''s `Error` status still routes to `Set` and the refusal has to be repeated there to hold. Previously, `ProcessTemplate` was listed in `GetDscResourcePropertyNamesWithNoSetSupport()` and `Update-DevOpsProject` took a `ProcessTemplateId` parameter it never referenced, so a process change on an existing project was always a silent no-op ([issue #75](https://github.com/ZanattaMichael/AzureDevOpsDsc/issues/75)). - Performance - `Set()` now runs the resource''s `Get` function once instead of twice: `SetToDesiredState()` reads the current state and passes it to a new `GetDscRequiredAction([Hashtable])` overload rather than reading it again. - The fixed 2-second sleep after every `Set()` is gone. `GetPostSetWaitTimeMs()` now defaults to `0`; a resource whose API needs time before a write is readable overrides it. - Caches are loaded on first use. `Construct()` no longer initializes every cache type (with `-Debug` forced on) each time a resource is instantiated; `Get-CacheObject` already imports a cache when it is first read. A missing cache file is now reported as verbose output rather than a warning, since it is the normal state for a cache nothing has written yet. - Cache lookups no longer copy or scan the whole cache: - `Get-CacheObject` returns the live cache list instead of letting PowerShell unroll it into a copy on every read. An empty cache comes back as an empty list rather than `$null`, and a cache stored as an array is normalized to a `List[CacheItem]` once. - `Add-CacheItem` and `Get-CacheItem` find a key through a new case-insensitive key index (`Get-CacheKeyIndex`) instead of a `Where-Object` scan, so filling a cache is linear rather than quadratic. The index is rebuilt whenever the cache list is replaced or its count changes, and a cache holding a duplicate key falls back to scanning. - `Add-CacheItem` replaces an existing key in place instead of copying the cache through `Remove-CacheItem`. - `Find-Identity` filters the group, user and service-principal caches with `.Where()` instead of copying each one per ACE. - `CacheItem` stamps its creation time with `[datetime]::Now` rather than a `Get-Date` call. ### Fixed - Integration tests - `AzDoQueryPermission` and `AzDoWorkItemQuery` create their query folder through the new `Invoke-TestQueryFolderSet`. It retries the `TF401256: You do not have Write permissions for query Shared Queries` 403 that a project returns for a few seconds after it reaches `wellFormed`. `Invoke-AzDevOpsApiRestMethod` no longer retries a 403, and that retry used to hide the delay. - `AzDoReleaseDefinitionPermission` calls `Enable-TestClassicPipeline` before creating its classic release definition, and skips when an organization policy forbids classic pipelines, as `AzDoTaskGroup` and `AzDoDeploymentGroup` already do. - `AzDoPicklist` polls for up to 30 seconds for the removed picklist to drop out of the picklist list. The list could still return it for a moment after a successful DELETE. - `Get-MIToken` requests its token with `-NoAuthentication`, which `Invoke-APIRestMethod` now honours. It used to build an Authorization header from `$Global:DSCAZDO_AuthenticationToken`, so after a test whose token request failed had left that global null, the post-run teardown threw before cleaning up or reporting the test results. - AzureDevOpsDscNative - `Invoke-AzDevOpsApiRestMethod -AzureArcAuthentication` retries a 408, 429 or 5xx from the Azure Arc token endpoint like any other request. It used to hand every error straight back to `Get-AzManagedIdentityToken`, which only needs the 401 challenge unchanged, so a throttled token request failed the resource being constructed. It showed up as a 429 failing `[AzDoProject]::Export()` and `[AzDoGitRepository]::Export()`. - `Invoke-AzDevOpsApiRestMethod` no longer throws "Unable to find type [APIRateLimit]" on a 429 or a response carrying rate-limit headers. The class lives in the root module, which the nested `AzureDevOpsDsc.Common` module cannot resolve type names from; it now builds the object through the new `New-APIRateLimit` function, as the token classes already do. - The nested `AzureDevOpsDsc.Common` module now imports the `DscResource.Common` copy shipped beside it. It called `Get-LocalizedData` without importing it, so the command was found through auto-discovery as an export of `AzureDevOpsDscNative`, which was itself still loading. Every process that had not already imported `DscResource.Common` globally failed to load the module with "the module could not be loaded". That included each `dsc resource get/test/set` call through the DSC v3 PowerShell adapter. - The identity cache initializer (`AzDoAPI_7_IdentitySubjectDescriptors`) re-added every group, user and service principal with the whole cache item as its value, so `.value.ACLIdentity` read `$null` for all of them and every descriptor lookup in `Find-Identity` missed the cache and fell through to the API. The resolved identity is now stamped onto the cached item in place. - `Invoke-AzDevOpsApiRestMethod` retry and rate-limit handling: - A 429 without a `Retry-After` header stored the retry interval (milliseconds) in a field read as seconds, so the next attempt slept for 250 seconds. It now backs off exponentially in milliseconds. - `Retry-After` was read with a string indexer that PowerShell 7''s `HttpResponseHeaders` does not have, so it was never found. It is now read from any header shape, as seconds or an HTTP date. - Non-transient errors (400, 401, 403, 404, 409 and other 4xx except 408 and 429) are no longer retried; they throw on the first failure. Network errors, 408, 429 and 5xx are still retried, and there is no sleep after the final failed attempt. - `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` are now read from successful responses, so the "close to throttled" slow-down acts on what Azure DevOps reports; a `Retry-After` wait is honoured once instead of before every request until the next success. - `APIRateLimit.xRateLimitRemaining` defaults to `-1` (not reported) rather than `0`, which read as an exhausted budget and added an extra wait after every 429. - With `-NoAuthentication`, the caller''s own `Authorization` header was cleared after the first attempt, so every retry was sent unauthenticated. The header is now cleared only when the function added it. The authentication header check also tested a non-existent `Authentication` key; the module token header is now set explicitly before every request. - Fixed `Get-AzDoProject` throwing "Process template '''' not found" instead of naming the process that was actually missing - the "not found" error interpolated an unrelated, always-null variable rather tha' } # End of PSData hashtable } # End of PrivateData hashtable } |