Conversation
michaeltlombardi
left a comment
There was a problem hiding this comment.
Quick review pass on the manifests, looking at resource implementation next.
michaeltlombardi
left a comment
There was a problem hiding this comment.
A few more comments on the schema and implementation.
|
Is the plan to add a discover extension in DSC to be able to find these resource manifests? If so, is there an issue/pr for that? |
| "type": "Microsoft.PowerShell.PSResourceGet/PSResources", | ||
| "version": "0.0.1", | ||
| "get": { | ||
| "executable": "pwsh", |
There was a problem hiding this comment.
How is Windows PowerShell handled? PSResourceGet supports both. For PSScript DSC v3 resource there are actually two different resources to account for different versions of PowerShell.
| "type": "Microsoft.PowerShell.PSResourceGet/Repository", | ||
| "version": "0.0.1", | ||
| "get": { | ||
| "executable": "pwsh", |
There was a problem hiding this comment.
How is Windows PowerShell handled? PSResourceGet supports both. For PSScript DSC v3 resource there are actually two different resources to account for different versions of PowerShell.
There was a problem hiding this comment.
If there's a need, we could have a Microsoft.WindowsPowerShell.PSResourceGet type
@ThomasNieto yup! PowerShell/DSC#913 proposes a discovery extension for finding resource and extension manifests through the |
|
I logged PowerShell/DSC#1024 issue. PSResourceGet will also have the same issue since it uses NuGet version range syntax containing square brackets. |
|
@adityapatwardhan - I think you've followed the news, but you should be able to define a single resource manifest now e.g.,: // psresourceget.dsc.manifests.json
{
"resources": [
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"description": "Manage PowerShell resources using PSResourceGet.",
"tags": [
"linux",
"windows",
"macos",
"powershell",
"nuget"
],
"type": "Microsoft.PowerShell.PSResourceGet/PSResourceList",
"version": "0.0.1",
"get": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'psresourcelist' -operation 'get'"
],
"input": "stdin"
},
"set": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'psresourcelist' -operation set"
],
"input": "stdin",
"return": "stateAndDiff"
},
"export": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"./psresourceget.ps1 -resourcetype 'psresourcelist' -operation export"
],
"input": "stdin"
},
"test": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'psresourcelist' -operation test"
],
"input": "stdin",
"return": "stateAndDiff"
},
"schema": {
"embedded": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "PSResourceList",
"type": "object",
"additionalProperties": false,
"required": [
"repositoryName"
],
"properties": {
"repositoryName": {
"title": "Repository Name",
"description": "The name of the repository from where the resources are acquired.",
"type": "string"
},
"resources": {
"title": "Resources",
"description": "The list of resources to manage.",
"type": "array",
"items": {
"$ref": "#/$defs/PSResource"
},
"minItems": 0
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json"
},
"_inDesiredState": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json"
}
},
"$defs": {
"Scope": {
"type": "string",
"title": "Scope",
"description": "Scope of the resource installation.",
"enum": [
"CurrentUser",
"AllUsers"
]
},
"PSResource": {
"type": "object",
"additionalProperties": false,
"required": [
"name"
],
"properties": {
"name": {
"title": "Name",
"description": "The name of the resource.",
"type": "string"
},
"version": {
"title": "Version",
"description": "The version range of the resource.",
"type": "string",
"pattern": "^(\\[|\\()\\s*\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?\\s*(,\\s*(\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?)?\\s*(\\]|\\)))?$"
},
"scope": {
"title": "Scope",
"description": "The scope of the resource. Can be 'CurrentUser' or 'AllUsers'.",
"$ref": "#/$defs/Scope"
},
"repositoryName": {
"title": "Repository Name",
"description": "The name of the repository from where the resource is acquired.",
"type": "string"
},
"preRelease": {
"title": "Pre-Release version",
"description": "Indicates whether to include pre-release versions of the resource.",
"type": "boolean",
"default": false
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json"
},
"_inDesiredState": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json"
}
}
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json",
"title": "Instance should exist",
"description": "Indicates whether the DSC resource instance should exist.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json",
"title": "Instance is in desired state",
"description": "Indicates whether the DSC resource instance is in the desired state.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
}
}
}
}
},
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"description": "Manage PowerShell repositories using PSResourceGet.",
"tags": [
"linux",
"windows",
"macos",
"powershell",
"nuget"
],
"type": "Microsoft.PowerShell.PSResourceGet/Repository",
"version": "0.0.1",
"get": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'repository' -operation 'get'"
],
"input": "stdin"
},
"set": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'repository' -operation set"
],
"input": "stdin"
},
"delete": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'repository' -operation delete"
],
"input": "stdin"
},
"export": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"./psresourceget.ps1 -resourcetype 'repository' -operation export"
],
"input": "stdin"
},
"schema": {
"embedded": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Repository",
"description": "A PowerShell Resource repository from where to acquire the resources.",
"type": "object",
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": {
"_exist": {
"const": false
}
}
},
"then": {
"required": [
"name"
]
},
"else": {
"required": [
"name",
"uri"
]
}
}
],
"properties": {
"name": {
"title": "Name",
"description": "The name of the repository.",
"type": "string"
},
"uri": {
"title": "URI",
"description": "The URI of the repository.",
"type": "string",
"format": "uri"
},
"trusted": {
"title": "Trusted",
"description": "Indicates whether the repository is trusted.",
"type": "boolean"
},
"priority": {
"title": "Priority",
"description": "The priority of the repository. Lower numbers indicate higher priority.",
"type": "integer",
"minimum": 0,
"maximum": 100
},
"repositoryType": {
"title": "Repository Type",
"description": "The type of the repository.",
"$ref": "#/$defs/RepositoryType"
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json"
}
},
"$defs": {
"RepositoryType": {
"type": "string",
"title": "Repository Type",
"description": "The type of the repository. Can be 'Unknown', 'V2', 'V3', 'Local', 'NugetServer', or 'ContainerRegistry'.",
"enum": [
"Unknown",
"V2",
"V3",
"Local",
"NugetServer",
"ContainerRegistry"
]
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json",
"title": "Instance should exist",
"description": "Indicates whether the DSC resource instance should exist.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
}
}
}
}
}
]
} |
|
I think the pattern for version should also slightly change to: "pattern": "^((\\[|\\()[ \\t]*(>=|>|<=|<)?[ \\t]*\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?[ \\t]*(,[ \\t]*(>=|>|<=|<)?[ \\t]*(\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?)?[ \\t]*)?(\\]|\\))|\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?)$" |
feafc53 to
6df0729
Compare
|
@Gijsreyn - thanks for your comments. I would still maybe want to keep it separate files for two resources. Easier to understand. What do others think? Also, I removed the pattern validation for the NuGet version ranges. It can get really unwieldy and difficult to maintain. |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Close / Re-Open to re-kick off pipelines. |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
| _cmdletPassedIn); | ||
| } | ||
|
|
||
| _cmdletPassedIn.WriteVerbose("Exiting ContainerRegistryServerAPICalls::GetHttpResponseJObjectUsingDefaultHeaders() with NULL"); |
There was a problem hiding this comment.
Do you want to keep this? If so, I would suggest changing to a debug message?
There was a problem hiding this comment.
Seems like a rebasing issue. This should not part of this PR.
| [string] ToJson() { | ||
| $resourceJson = if ($this.resources) { ($this.resources | ForEach-Object { $_.ToJson() }) -join ',' } else { '' } | ||
| $resourceJson = "[$resourceJson]" | ||
| $jsonString = "{'repositoryName': '$($this.repositoryName)','resources': $resourceJson}" | ||
| $jsonString = $jsonString -replace "'", '"' | ||
| return $jsonString | ConvertFrom-Json | ConvertTo-Json -Compress | ||
| } |
There was a problem hiding this comment.
Wouldn't it be better to have everything kept as a PSObject or HashTable and just use ConvertTo-Json -Compress once?
There was a problem hiding this comment.
It makes in much easier in the implementation of other operation if it is a strongly type object.
| "type": "Microsoft.PowerShell.PSResourceGet/Repository", | ||
| "version": "0.0.1", | ||
| "get": { | ||
| "executable": "pwsh", |
There was a problem hiding this comment.
If there's a need, we could have a Microsoft.WindowsPowerShell.PSResourceGet type
There was a problem hiding this comment.
Pull request overview
This PR adds an initial DSC v3 integration for PSResourceGet by introducing two DSC resources (Repository and PSResourceList), along with test configurations and Pester coverage to exercise schema and basic end-to-end scenarios.
Changes:
- Added DSC v3 resource manifests for
Microsoft.PowerShell.PSResourceGet/RepositoryandMicrosoft.PowerShell.PSResourceGet/PSResourceList. - Added the PowerShell implementation script (
src/dsc/psresourceget.ps1) backing the DSC resource operations. - Added Pester tests and DSC YAML configs for schema validation, E2E behavior, and error-code scenarios; updated build packaging to include the DSC assets.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| test/DscResource/configs/repository.unregister.dsc.yaml | Adds DSC config to ensure a repository is absent. |
| test/DscResource/configs/repository.register.dsc.yaml | Adds DSC config to register a repository with expected properties. |
| test/DscResource/configs/repository.get.dsc.yaml | Adds DSC config to assert repository settings. |
| test/DscResource/configs/repository.export.dsc.yaml | Adds DSC config used for repository export assertions. |
| test/DscResource/configs/psresourcegetlist.uninstall.dsc.yaml | Adds DSC config to uninstall a PSResource via PSResourceList. |
| test/DscResource/configs/psresourcegetlist.prerelease.install.dsc.yaml | Adds DSC config to install stable + prerelease variants. |
| test/DscResource/configs/psresourcegetlist.oneexisting.install.dsc.yaml | Adds DSC config for mixed “already installed + missing” scenario. |
| test/DscResource/configs/psresourcegetlist.moddeps.install.dsc.yaml | Adds DSC config for installing a module with dependencies. |
| test/DscResource/configs/psresourcegetlist.install.dsc.yaml | Adds DSC config to install a single resource. |
| test/DscResource/configs/psresourcegetlist.export.dsc.yaml | Adds DSC config used for PSResourceList export assertions. |
| test/DscResource/configs/psresourcegetlist.error.noresource.dsc.yaml | Adds DSC config used to validate “resource not found” errors. |
| test/DscResource/configs/psresourcegetlist.error.norepo.dsc.yaml | Adds DSC config used to validate “repo not found” errors. |
| test/DscResource/configs/psresourcegetlist.error.install.untrustedrepo.dsc.yaml | Adds DSC config used to validate “repo not trusted” errors. |
| test/DscResource/PSResourceGetDSCResource.Tests.ps1 | Adds schema, unit-style, and E2E Pester tests for the new resources. |
| src/dsc/repository.dsc.resource.json | Adds the Repository DSC v3 resource manifest and embedded schema. |
| src/dsc/psresourcelist.dsc.resource.json | Adds the PSResourceList DSC v3 resource manifest, schema, and exit code mapping. |
| src/dsc/psresourceget.ps1 | Implements operations (get/set/test/export/delete) for the DSC resources. |
| src/code/ContainerRegistryServerAPICalls.cs | Adds a verbose line before returning null from a helper method. |
| doBuild.ps1 | Updates build packaging to copy DSC scripts/manifests into the build output. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $ret = if ($err.FullyQualifiedErrorId -eq 'ErrorGettingSpecifiedRepo,Microsoft.PowerShell.PSResourceGet.Cmdlets.GetPSResourceRepository') { | ||
| Write-Trace -message "Repository not found: $($inputRepository.Name). Returning _exist = false" | ||
| [Repository]::new( | ||
| $InputRepository.Name, | ||
| $false | ||
| ) | ||
| } | ||
| else { | ||
| [Repository]::new( | ||
| $rep.Name, | ||
| $rep.Uri, | ||
| $rep.Trusted, | ||
| $rep.Priority, | ||
| $rep.ApiVersion | ||
| ) | ||
|
|
||
| Write-Trace -message "Returning repository object for: $($ret.Name)" | ||
| } | ||
|
|
||
| return ( $ret.ToJson() ) |
There was a problem hiding this comment.
In the Repository get path, the else branch of the $ret = if (...) { ... } else { ... } expression doesn't output the newly created Repository object as the branch value (the last statement is Write-Trace). This makes $ret end up $null, and return ($ret.ToJson()) will fail. Assign the new object to $ret (or make it the last expression) before calling Write-Trace.
| $currentState = GetPSResourceList -inputObj $inputObj | ||
|
|
||
| $inputObj.resources | ForEach-Object { | ||
| $resourceDesiredState = ConvertInputToPSResource -inputObj $_ -repositoryName $repositoryName | ||
| $name = $resourceDesiredState.name | ||
| $version = $resourceDesiredState.version | ||
| $scope = if ($resourceDesiredState.scope) { $resourceDesiredState.scope } else { "CurrentUser" } | ||
|
|
||
| # Resource should not exist - uninstall if it does | ||
| $currentState.resources | ForEach-Object { | ||
|
|
||
| $isInDesiredState = $_.IsInDesiredState($resourceDesiredState) | ||
|
|
||
| # Uninstall if resource should not exist but does | ||
| if (-not $resourceDesiredState._exist -and $_._exist) { | ||
| Write-Trace -message "Resource $($resourceDesiredState.name) exists but _exist is false. Adding to uninstall list." -level info | ||
| $resourcesToUninstall += $_ | ||
| } | ||
| # Install if resource should exist but doesn't, or exists but not in desired state | ||
| elseif ($resourceDesiredState._exist -and (-not $_._exist -or -not $isInDesiredState)) { | ||
| Write-Trace -message "Resource $($resourceDesiredState.name) needs to be installed." -level info | ||
| $versionStr = if ($version) { $resourceDesiredState.version } else { 'latest' } | ||
| $key = $name.ToLowerInvariant() + '-' + $versionStr.ToLowerInvariant() | ||
| if (-not $resourcesToInstall.ContainsKey($key)) { | ||
| $resourcesToInstall[$key] = $resourceDesiredState | ||
| } | ||
| } | ||
| # Otherwise resource is in desired state, no action needed | ||
| else { | ||
| Write-Trace -message "Resource $($resourceDesiredState.name) is in desired state." -level info | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
SetPSResourceList only iterates over $currentState.resources when deciding what to install. But GetPSResourceList returns only the resources that exist when at least one match is found (it omits placeholders for missing desired resources). In that situation, a desired resource with a different name that isn't currently installed will never be added to $resourcesToInstall because there is no corresponding entry in $currentState.resources to compare against. Consider building a lookup by name and explicitly handling the 'not found in current state' case as needing install.
| version: '[[0.0.93,)' | ||
| _exist: true | ||
| preRelease: false | ||
| - name: testmodule99 | ||
| version: '[[100.0.99,)' |
There was a problem hiding this comment.
The version range strings here start with [[ (e.g. [[0.0.93,)), which is not valid NuGet version-range syntax and will fail parsing (VersionRange.Parse expects forms like [0.0.93,)). Update these version ranges to valid NuGet range notation so the 'one existing, one missing' scenario behaves as intended.
| version: '[[0.0.93,)' | |
| _exist: true | |
| preRelease: false | |
| - name: testmodule99 | |
| version: '[[100.0.99,)' | |
| version: '[0.0.93,)' | |
| _exist: true | |
| preRelease: false | |
| - name: testmodule99 | |
| version: '[100.0.99,)' |
| @@ -0,0 +1,7 @@ | |||
| $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json | |||
| resources: | |||
| - name: register PSGallery | |||
There was a problem hiding this comment.
This config is intended to unregister the repository (_exist: false), but the resource instance name is "register PSGallery". Renaming it to reflect the action (e.g., "unregister …") will make test output/logs easier to interpret.
| - name: register PSGallery | |
| - name: unregister PSGallery |
| if ($null -eq $rep) { | ||
| Register-PSResourceRepository @splatt | ||
| } | ||
| else { | ||
| if ($inputObj._exist -eq $false) { | ||
| Write-Trace -message "Repository $($inputObj.Name) exists and _exist is false. Deleting it." -level info | ||
| Unregister-PSResourceRepository -Name $inputObj.Name | ||
| } |
There was a problem hiding this comment.
Repository SetOperation registers the repository whenever $rep is $null, even if the desired state is _exist = false. For an 'ensure absent' request, this should be a no-op (or at most verify it's absent), not an attempted register (which will also fail if uri isn't provided, as in the unregister config). Add a branch that skips registration when _exist is explicitly false.
| if (-not $repositoryState) { | ||
| Write-Trace -message "Repository not found: $($inputObj.repositoryName). Returning PSResourceList with _inDesiredState = false." -level info | ||
| $retValue = [PSResourceList]::new($inputObj.repositoryName, $inputResources, $false) | ||
| $retValue._inDesiredState = $false | ||
| $retValue.ToJsonForTest() | ||
| '["repositoryName", "resources"]' | ||
| } | ||
|
|
||
| $inputPSResourceList = [PSResourceList]::new($inputObj.repositoryName, $inputResources, $repositoryState.Trusted) | ||
|
|
There was a problem hiding this comment.
TestPSResourceList doesn't return after handling the 'repository not found' case. After emitting output, it continues and then dereferences $repositoryState.Trusted even though $repositoryState is $null, which will throw. Add an explicit return (or exit) after writing the state/diff for this branch.
| $inputObj.resources | ForEach-Object { | ||
| $resourceDesiredState = ConvertInputToPSResource -inputObj $_ -repositoryName $repositoryName | ||
| $name = $resourceDesiredState.name | ||
| $version = $resourceDesiredState.version | ||
| $scope = if ($resourceDesiredState.scope) { $resourceDesiredState.scope } else { "CurrentUser" } | ||
|
|
||
| # Resource should not exist - uninstall if it does | ||
| $currentState.resources | ForEach-Object { | ||
|
|
||
| $isInDesiredState = $_.IsInDesiredState($resourceDesiredState) | ||
|
|
||
| # Uninstall if resource should not exist but does | ||
| if (-not $resourceDesiredState._exist -and $_._exist) { | ||
| Write-Trace -message "Resource $($resourceDesiredState.name) exists but _exist is false. Adding to uninstall list." -level info | ||
| $resourcesToUninstall += $_ | ||
| } | ||
| # Install if resource should exist but doesn't, or exists but not in desired state | ||
| elseif ($resourceDesiredState._exist -and (-not $_._exist -or -not $isInDesiredState)) { | ||
| Write-Trace -message "Resource $($resourceDesiredState.name) needs to be installed." -level info | ||
| $versionStr = if ($version) { $resourceDesiredState.version } else { 'latest' } | ||
| $key = $name.ToLowerInvariant() + '-' + $versionStr.ToLowerInvariant() | ||
| if (-not $resourcesToInstall.ContainsKey($key)) { | ||
| $resourcesToInstall[$key] = $resourceDesiredState | ||
| } | ||
| } | ||
| # Otherwise resource is in desired state, no action needed | ||
| else { | ||
| Write-Trace -message "Resource $($resourceDesiredState.name) is in desired state." -level info | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if ($resourcesToUninstall.Count -gt 0) { | ||
| Write-Trace -message "Uninstalling resources: $($resourcesToUninstall | ForEach-Object { "$($_.Name) - $($_.Version)" })" | ||
| $resourcesToUninstall | ForEach-Object { | ||
| Uninstall-PSResource -Name $_.Name -Scope $scope -ErrorAction Stop | ||
| } |
There was a problem hiding this comment.
SetPSResourceList computes $scope per desired resource, but later uses that single (last-assigned) $scope for all uninstall and install operations. This can uninstall/install into the wrong scope when the input contains mixed scopes. Use the scope from the specific resource being installed/uninstalled (e.g., store it on the queued item and pass it through).
| $resources += $resourcesExist | ForEach-Object { | ||
| [PSResource]::new( | ||
| $_.Name, | ||
| $_.Version.PreRelease ? $_.Version.ToString() + "-" + $_.PreRelease : $_.Version.ToString(), | ||
| $_.Scope, | ||
| $_.RepositoryName, | ||
| $_.PreRelease ? $true : $false | ||
| ) |
There was a problem hiding this comment.
PopulatePSResourceListObjectByRepository treats $_ .Version as if it has a .PreRelease property ($_.Version.PreRelease), but in this code path Version is a string (see PSResource definition and how $allPSResources is populated). This will throw at runtime. Build the version string without accessing .PreRelease on it, or store version/prerelease as separate fields.
| version: '[[0.0.93,)' | ||
| _exist: true | ||
| preRelease: false | ||
| - name: testmodule99 | ||
| version: '[[100.0.99,)' |
There was a problem hiding this comment.
The version range strings here start with [[ (e.g. [[0.0.93,)), which is not valid NuGet version-range syntax and will fail parsing (VersionRange.Parse expects forms like [0.0.93,)). Update these version ranges to valid NuGet range notation so prerelease/stable selection works.
| version: '[[0.0.93,)' | |
| _exist: true | |
| preRelease: false | |
| - name: testmodule99 | |
| version: '[[100.0.99,)' | |
| version: '[0.0.93,)' | |
| _exist: true | |
| preRelease: false | |
| - name: testmodule99 | |
| version: '[100.0.99,)' |
There was a problem hiding this comment.
Need to escape the [
|
|
||
| if ($found) { | ||
| Write-Trace -message "Resource match found for: $($otherResource.name)" -level trace | ||
| break |
There was a problem hiding this comment.
PSResourceList.IsInDesiredState breaks out of the outer loop on the first matching resource, so it can return true even when later desired resources do not match. Replace the break in the $found branch with continue (or remove it) so every desired resource is validated.
| break | |
| continue |
PR Summary
The initial implementation of DSC v3 resource for PSResourceGet. It include two resources, Repository and PSResources.
PR Context
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.