Skip to content

Commit e312353

Browse files
authored
BREAKING CHANGE: PSResourceRepository: Resource to manage PowerShell Package Repositories (#395)
1 parent 6c3f2fd commit e312353

27 files changed

Lines changed: 2618 additions & 2 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
### Added
1414

15+
- PSResourceRepository
16+
- New class-based resource to manage PowerShell Resource Repositories - Fixes [Issue #393](https://github.com/dsccommunity/ComputerManagementDsc/issues/393)
1517
- Computer
1618
- Support Options Parameter for domain join - Fixes [Issue #234](https://github.com/dsccommunity/ComputerManagementDsc/issues/234).
1719
- When joining a computer to a domain, existing AD computer objects will be deleted - Fixes [Issue #55](https://github.com/dsccommunity/ComputerManagementDsc/issues/55), [Issue #58](https://github.com/dsccommunity/ComputerManagementDsc/issues/58).
1820

1921
### Changed
2022

23+
- BREAKING CHANGE: Windows Management Framework 5.0 is required.
2124
- ComputerManagementDsc
2225
- The resource names were removed from the property `DscResourcesToExport`
2326
in the module manifest in the source folder as the built module is
2427
automatically updated with this information by the pipeline - Fixes [Issue #396](https://github.com/dsccommunity/ComputerManagementDsc/issues/396).
28+
- Moved the build step of the pipeline to a Windows build worker when running in Azure DevOps.
2529

2630
## [8.5.0] - 2021-09-13
2731

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ The **ComputerManagementDsc** module contains the following resources:
4343
predictably handle the condition.
4444
- **PowerPlan**: This resource allows specifying a power plan to activate.
4545
- **PowerShellExecutionPolicy**: Specifies the desired PowerShell execution policy.
46+
- **PSResourceRepository**: This resource manages PowerShellGet repositories.
4647
- **RemoteDesktopAdmin**: This resource will manage the remote desktop administration
4748
settings on a computer.
4849
- **ScheduledTask**: This resource is used to define basic run once or recurring
@@ -74,3 +75,14 @@ This project has adopted [this code of conduct](CODE_OF_CONDUCT.md).
7475

7576
For a full list of resources in ComputerManagementDsc and examples on their use,
7677
check out the [ComputerManagementDsc wiki](https://github.com/dsccommunity/ComputerManagementDsc/wiki).
78+
79+
## Requirements
80+
### Windows Management Framework 5.0
81+
82+
Required because this module now implements class-based resources.
83+
Class-based resources can only work on computers with Windows
84+
Management Framework 5.0 or above.
85+
86+
### PSResourceRepository
87+
88+
The resource `PSResourceRepository` requires that the PowerShell modules `PowerShellGet` and `PackageManagement` are already present on the target computer.

appveyor.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# HOW TO DEBUG: See start of each build run's output how to connect with RDP to the build server for debugging.
2+
# See section on_finish last in this file on how to pause build and to keep RDP open.
3+
# Look for each "DEBUG:" comment below how to change
4+
5+
version: 1.0.{build}
6+
7+
# Do not build on full releases.
8+
skip_tags: true
9+
10+
# See https://www.appveyor.com/docs/windows-images-software
11+
# DEBUG: for debug purpose, comment and un-comment images as needed.
12+
image:
13+
- Visual Studio 2019 # Windows Server 2019
14+
#- Visual Studio 2017 # Windows Server 2016
15+
#- Visual Studio 2013 # Windows Server 2012 R2
16+
17+
environment:
18+
Dummy: AnyValue
19+
# DEBUG: Un-comment this to get the same password for the RDP session for each build
20+
#APPVEYOR_RDP_PASSWORD: D5c1234!
21+
22+
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
23+
init:
24+
- ps: |
25+
# Only run for pull requests
26+
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
27+
28+
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
29+
30+
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
31+
install:
32+
- ps: |
33+
# Only run for pull requests
34+
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
35+
36+
winrm quickconfig -quiet
37+
38+
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
39+
build_script:
40+
- pwsh: |
41+
# Only run for pull requests
42+
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
43+
44+
# Build the module
45+
./build.ps1 -ResolveDependency -tasks build
46+
47+
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
48+
test_script:
49+
- ps: |
50+
# Only run for pull requests
51+
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
52+
53+
./build.ps1 -Tasks test -PesterScript 'tests/Integration' -CodeCoverageThreshold 0
54+
55+
deploy: off
56+
57+
# DEBUG: Un-comment the line "$blockRdp = $true" so that build worker is kept up all of the 60 minutes.
58+
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
59+
on_finish:
60+
- ps: |
61+
# Only run for pull requests
62+
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
63+
64+
<#
65+
These two lines can also be added in one or more places somewhere in the integration tests to pause the test run. Continue
66+
running the tests by deleting the file on the desktop that was created by "enable-rdp.ps1" when $blockRdp is $true.
67+
#>
68+
#$blockRdp = $true
69+
#iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ stages:
2424
- job: Package_Module
2525
displayName: 'Package Module'
2626
pool:
27-
vmImage: 'ubuntu-latest'
27+
vmImage: 'windows-latest'
2828
steps:
2929
- pwsh: |
3030
dotnet tool install --global GitVersion.Tool

build.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CopyPaths:
66
- en-US
77
- DSCResources
88
- Modules
9+
Prefix: prefix.ps1
910
Encoding: UTF8
1011
VersionedOutputDirectory: true
1112

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
<#
2+
.SYNOPSIS
3+
A class with methods that are equal for all class-based resources.
4+
5+
.DESCRIPTION
6+
A class with methods that are equal for all class-based resources.
7+
8+
.NOTES
9+
This class should be able to be inherited by all DSC resources. This class
10+
shall not contain any DSC properties, neither shall it contain anything
11+
specific to only a single resource.
12+
#>
13+
14+
class ResourceBase
15+
{
16+
# Property for holding localization strings
17+
hidden [System.Collections.Hashtable] $localizedData = @{}
18+
19+
# Property for derived class to set properties that should not be enforced.
20+
hidden [System.String[]] $ExcludeDscProperties = @()
21+
22+
# Default constructor
23+
ResourceBase()
24+
{
25+
<#
26+
TODO: When this fails, for example when the localized string file is missing
27+
the LCM returns the error 'Failed to create an object of PowerShell
28+
class SqlDatabasePermission' instead of the actual error that occurred.
29+
#>
30+
$this.localizedData = Get-LocalizedDataRecursive -ClassName ($this | Get-ClassName -Recurse)
31+
}
32+
33+
[ResourceBase] Get()
34+
{
35+
$this.Assert()
36+
37+
# Get all key properties.
38+
$keyProperty = $this | Get-DscProperty -Type 'Key'
39+
40+
Write-Verbose -Message ($this.localizedData.GetCurrentState -f $this.GetType().Name, ($keyProperty | ConvertTo-Json -Compress))
41+
42+
$getCurrentStateResult = $this.GetCurrentState($keyProperty)
43+
44+
$dscResourceObject = [System.Activator]::CreateInstance($this.GetType())
45+
46+
# Set values returned from the derived class' GetCurrentState().
47+
foreach ($propertyName in $this.PSObject.Properties.Name)
48+
{
49+
if ($propertyName -in @($getCurrentStateResult.Keys))
50+
{
51+
$dscResourceObject.$propertyName = $getCurrentStateResult.$propertyName
52+
}
53+
}
54+
55+
$keyPropertyAddedToCurrentState = $false
56+
57+
# Set key property values unless it was returned from the derived class' GetCurrentState().
58+
foreach ($propertyName in $keyProperty.Keys)
59+
{
60+
if ($propertyName -notin @($getCurrentStateResult.Keys))
61+
{
62+
# Add the key value to the instance to be returned.
63+
$dscResourceObject.$propertyName = $this.$propertyName
64+
65+
$keyPropertyAddedToCurrentState = $true
66+
}
67+
}
68+
69+
if (($this | Test-ResourceHasDscProperty -Name 'Ensure') -and -not $getCurrentStateResult.ContainsKey('Ensure'))
70+
{
71+
# Evaluate if we should set Ensure property.
72+
if ($keyPropertyAddedToCurrentState)
73+
{
74+
<#
75+
A key property was added to the current state, assume its because
76+
the object did not exist in the current state. Set Ensure to Absent.
77+
#>
78+
$dscResourceObject.Ensure = [Ensure]::Absent
79+
$getCurrentStateResult.Ensure = [Ensure]::Absent
80+
}
81+
else
82+
{
83+
$dscResourceObject.Ensure = [Ensure]::Present
84+
$getCurrentStateResult.Ensure = [Ensure]::Present
85+
}
86+
}
87+
88+
<#
89+
Returns all enforced properties not in desires state, or $null if
90+
all enforced properties are in desired state.
91+
#>
92+
$propertiesNotInDesiredState = $this.Compare($getCurrentStateResult, @())
93+
94+
<#
95+
Return the correct values for Reasons property if the derived DSC resource
96+
has such property and it hasn't been already set by GetCurrentState().
97+
#>
98+
if (($this | Test-ResourceHasDscProperty -Name 'Reasons') -and -not $getCurrentStateResult.ContainsKey('Reasons'))
99+
{
100+
# Always return an empty array if all properties are in desired state.
101+
$dscResourceObject.Reasons = $propertiesNotInDesiredState |
102+
ConvertTo-Reason -ResourceName $this.GetType().Name
103+
}
104+
105+
# Return properties.
106+
return $dscResourceObject
107+
}
108+
109+
[void] Set()
110+
{
111+
# Get all key properties.
112+
$keyProperty = $this | Get-DscProperty -Type 'Key'
113+
114+
Write-Verbose -Message ($this.localizedData.SetDesiredState -f $this.GetType().Name, ($keyProperty | ConvertTo-Json -Compress))
115+
116+
$this.Assert()
117+
118+
<#
119+
Returns all enforced properties not in desires state, or $null if
120+
all enforced properties are in desired state.
121+
#>
122+
$propertiesNotInDesiredState = $this.Compare()
123+
124+
if ($propertiesNotInDesiredState)
125+
{
126+
$propertiesToModify = $propertiesNotInDesiredState | ConvertFrom-CompareResult
127+
128+
$propertiesToModify.Keys |
129+
ForEach-Object -Process {
130+
Write-Verbose -Message ($this.localizedData.SetProperty -f $_, $propertiesToModify.$_)
131+
}
132+
133+
<#
134+
Call the Modify() method with the properties that should be enforced
135+
and was not in desired state.
136+
#>
137+
$this.Modify($propertiesToModify)
138+
}
139+
else
140+
{
141+
Write-Verbose -Message $this.localizedData.NoPropertiesToSet
142+
}
143+
}
144+
145+
[System.Boolean] Test()
146+
{
147+
# Get all key properties.
148+
$keyProperty = $this | Get-DscProperty -Type 'Key'
149+
150+
Write-Verbose -Message ($this.localizedData.TestDesiredState -f $this.GetType().Name, ($keyProperty | ConvertTo-Json -Compress))
151+
152+
$this.Assert()
153+
154+
$isInDesiredState = $true
155+
156+
<#
157+
Returns all enforced properties not in desires state, or $null if
158+
all enforced properties are in desired state.
159+
#>
160+
$propertiesNotInDesiredState = $this.Compare()
161+
162+
if ($propertiesNotInDesiredState)
163+
{
164+
$isInDesiredState = $false
165+
}
166+
167+
if ($isInDesiredState)
168+
{
169+
Write-Verbose $this.localizedData.InDesiredState
170+
}
171+
else
172+
{
173+
Write-Verbose $this.localizedData.NotInDesiredState
174+
}
175+
176+
return $isInDesiredState
177+
}
178+
179+
<#
180+
Returns a hashtable containing all properties that should be enforced and
181+
are not in desired state, or $null if all enforced properties are in
182+
desired state.
183+
184+
This method should normally not be overridden.
185+
#>
186+
hidden [System.Collections.Hashtable[]] Compare()
187+
{
188+
# Get the current state, all properties except Read properties .
189+
$currentState = $this.Get() | Get-DscProperty -Type @('Key', 'Mandatory', 'Optional')
190+
191+
return $this.Compare($currentState, @())
192+
}
193+
194+
<#
195+
Returns a hashtable containing all properties that should be enforced and
196+
are not in desired state, or $null if all enforced properties are in
197+
desired state.
198+
199+
This method should normally not be overridden.
200+
#>
201+
hidden [System.Collections.Hashtable[]] Compare([System.Collections.Hashtable] $currentState, [System.String[]] $excludeProperties)
202+
{
203+
# Get the desired state, all assigned properties that has an non-null value.
204+
$desiredState = $this | Get-DscProperty -Type @('Key', 'Mandatory', 'Optional') -HasValue
205+
206+
$CompareDscParameterState = @{
207+
CurrentValues = $currentState
208+
DesiredValues = $desiredState
209+
Properties = $desiredState.Keys
210+
ExcludeProperties = ($excludeProperties + $this.ExcludeDscProperties) | Select-Object -Unique
211+
IncludeValue = $true
212+
# This is needed to sort complex types.
213+
SortArrayValues = $true
214+
}
215+
216+
<#
217+
Returns all enforced properties not in desires state, or $null if
218+
all enforced properties are in desired state.
219+
#>
220+
return (Compare-DscParameterState @CompareDscParameterState)
221+
}
222+
223+
# This method should normally not be overridden.
224+
hidden [void] Assert()
225+
{
226+
# Get the properties that has a non-null value and is not of type Read.
227+
$desiredState = $this | Get-DscProperty -Type @('Key', 'Mandatory', 'Optional') -HasValue
228+
229+
$this.AssertProperties($desiredState)
230+
}
231+
232+
<#
233+
This method can be overridden if resource specific property asserts are
234+
needed. The parameter properties will contain the properties that was
235+
assigned a value.
236+
#>
237+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('AvoidEmptyNamedBlocks', '')]
238+
hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
239+
{
240+
}
241+
242+
<#
243+
This method must be overridden by a resource. The parameter properties will
244+
contain the properties that should be enforced and that are not in desired
245+
state.
246+
#>
247+
hidden [void] Modify([System.Collections.Hashtable] $properties)
248+
{
249+
throw $this.localizedData.ModifyMethodNotImplemented
250+
}
251+
252+
<#
253+
This method must be overridden by a resource. The parameter properties will
254+
contain the key properties.
255+
#>
256+
hidden [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties)
257+
{
258+
throw $this.localizedData.GetCurrentStateMethodNotImplemented
259+
}
260+
}

0 commit comments

Comments
 (0)