Skip to content

Commit

Permalink
BREAKING CHANGE: PSResourceRepository: Resource to manage PowerShell …
Browse files Browse the repository at this point in the history
…Package Repositories (#395)
  • Loading branch information
nickgw authored Dec 11, 2022
1 parent 6c3f2fd commit e312353
Show file tree
Hide file tree
Showing 27 changed files with 2,618 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- PSResourceRepository
- New class-based resource to manage PowerShell Resource Repositories - Fixes [Issue #393](https://github.com/dsccommunity/ComputerManagementDsc/issues/393)
- Computer
- Support Options Parameter for domain join - Fixes [Issue #234](https://github.com/dsccommunity/ComputerManagementDsc/issues/234).
- 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).

### Changed

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

## [8.5.0] - 2021-09-13

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

For a full list of resources in ComputerManagementDsc and examples on their use,
check out the [ComputerManagementDsc wiki](https://github.com/dsccommunity/ComputerManagementDsc/wiki).

## Requirements
### Windows Management Framework 5.0

Required because this module now implements class-based resources.
Class-based resources can only work on computers with Windows
Management Framework 5.0 or above.

### PSResourceRepository

The resource `PSResourceRepository` requires that the PowerShell modules `PowerShellGet` and `PackageManagement` are already present on the target computer.
69 changes: 69 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# HOW TO DEBUG: See start of each build run's output how to connect with RDP to the build server for debugging.
# See section on_finish last in this file on how to pause build and to keep RDP open.
# Look for each "DEBUG:" comment below how to change

version: 1.0.{build}

# Do not build on full releases.
skip_tags: true

# See https://www.appveyor.com/docs/windows-images-software
# DEBUG: for debug purpose, comment and un-comment images as needed.
image:
- Visual Studio 2019 # Windows Server 2019
#- Visual Studio 2017 # Windows Server 2016
#- Visual Studio 2013 # Windows Server 2012 R2

environment:
Dummy: AnyValue
# DEBUG: Un-comment this to get the same password for the RDP session for each build
#APPVEYOR_RDP_PASSWORD: D5c1234!

# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
init:
- ps: |
# Only run for pull requests
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
install:
- ps: |
# Only run for pull requests
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
winrm quickconfig -quiet
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
build_script:
- pwsh: |
# Only run for pull requests
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
# Build the module
./build.ps1 -ResolveDependency -tasks build
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
test_script:
- ps: |
# Only run for pull requests
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
./build.ps1 -Tasks test -PesterScript 'tests/Integration' -CodeCoverageThreshold 0
deploy: off

# DEBUG: Un-comment the line "$blockRdp = $true" so that build worker is kept up all of the 60 minutes.
# DEBUG: If running on own AppVeyor project, comment the if-block below to run on all branches.
on_finish:
- ps: |
# Only run for pull requests
if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -ForegroundColor 'Yellow' -Object 'Not a pull request, skipping.'; return }
<#
These two lines can also be added in one or more places somewhere in the integration tests to pause the test run. Continue
running the tests by deleting the file on the desktop that was created by "enable-rdp.ps1" when $blockRdp is $true.
#>
#$blockRdp = $true
#iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ stages:
- job: Package_Module
displayName: 'Package Module'
pool:
vmImage: 'ubuntu-latest'
vmImage: 'windows-latest'
steps:
- pwsh: |
dotnet tool install --global GitVersion.Tool
Expand Down
1 change: 1 addition & 0 deletions build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CopyPaths:
- en-US
- DSCResources
- Modules
Prefix: prefix.ps1
Encoding: UTF8
VersionedOutputDirectory: true

Expand Down
260 changes: 260 additions & 0 deletions source/Classes/010.ResourceBase.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
<#
.SYNOPSIS
A class with methods that are equal for all class-based resources.
.DESCRIPTION
A class with methods that are equal for all class-based resources.
.NOTES
This class should be able to be inherited by all DSC resources. This class
shall not contain any DSC properties, neither shall it contain anything
specific to only a single resource.
#>

class ResourceBase
{
# Property for holding localization strings
hidden [System.Collections.Hashtable] $localizedData = @{}

# Property for derived class to set properties that should not be enforced.
hidden [System.String[]] $ExcludeDscProperties = @()

# Default constructor
ResourceBase()
{
<#
TODO: When this fails, for example when the localized string file is missing
the LCM returns the error 'Failed to create an object of PowerShell
class SqlDatabasePermission' instead of the actual error that occurred.
#>
$this.localizedData = Get-LocalizedDataRecursive -ClassName ($this | Get-ClassName -Recurse)
}

[ResourceBase] Get()
{
$this.Assert()

# Get all key properties.
$keyProperty = $this | Get-DscProperty -Type 'Key'

Write-Verbose -Message ($this.localizedData.GetCurrentState -f $this.GetType().Name, ($keyProperty | ConvertTo-Json -Compress))

$getCurrentStateResult = $this.GetCurrentState($keyProperty)

$dscResourceObject = [System.Activator]::CreateInstance($this.GetType())

# Set values returned from the derived class' GetCurrentState().
foreach ($propertyName in $this.PSObject.Properties.Name)
{
if ($propertyName -in @($getCurrentStateResult.Keys))
{
$dscResourceObject.$propertyName = $getCurrentStateResult.$propertyName
}
}

$keyPropertyAddedToCurrentState = $false

# Set key property values unless it was returned from the derived class' GetCurrentState().
foreach ($propertyName in $keyProperty.Keys)
{
if ($propertyName -notin @($getCurrentStateResult.Keys))
{
# Add the key value to the instance to be returned.
$dscResourceObject.$propertyName = $this.$propertyName

$keyPropertyAddedToCurrentState = $true
}
}

if (($this | Test-ResourceHasDscProperty -Name 'Ensure') -and -not $getCurrentStateResult.ContainsKey('Ensure'))
{
# Evaluate if we should set Ensure property.
if ($keyPropertyAddedToCurrentState)
{
<#
A key property was added to the current state, assume its because
the object did not exist in the current state. Set Ensure to Absent.
#>
$dscResourceObject.Ensure = [Ensure]::Absent
$getCurrentStateResult.Ensure = [Ensure]::Absent
}
else
{
$dscResourceObject.Ensure = [Ensure]::Present
$getCurrentStateResult.Ensure = [Ensure]::Present
}
}

<#
Returns all enforced properties not in desires state, or $null if
all enforced properties are in desired state.
#>
$propertiesNotInDesiredState = $this.Compare($getCurrentStateResult, @())

<#
Return the correct values for Reasons property if the derived DSC resource
has such property and it hasn't been already set by GetCurrentState().
#>
if (($this | Test-ResourceHasDscProperty -Name 'Reasons') -and -not $getCurrentStateResult.ContainsKey('Reasons'))
{
# Always return an empty array if all properties are in desired state.
$dscResourceObject.Reasons = $propertiesNotInDesiredState |
ConvertTo-Reason -ResourceName $this.GetType().Name
}

# Return properties.
return $dscResourceObject
}

[void] Set()
{
# Get all key properties.
$keyProperty = $this | Get-DscProperty -Type 'Key'

Write-Verbose -Message ($this.localizedData.SetDesiredState -f $this.GetType().Name, ($keyProperty | ConvertTo-Json -Compress))

$this.Assert()

<#
Returns all enforced properties not in desires state, or $null if
all enforced properties are in desired state.
#>
$propertiesNotInDesiredState = $this.Compare()

if ($propertiesNotInDesiredState)
{
$propertiesToModify = $propertiesNotInDesiredState | ConvertFrom-CompareResult

$propertiesToModify.Keys |
ForEach-Object -Process {
Write-Verbose -Message ($this.localizedData.SetProperty -f $_, $propertiesToModify.$_)
}

<#
Call the Modify() method with the properties that should be enforced
and was not in desired state.
#>
$this.Modify($propertiesToModify)
}
else
{
Write-Verbose -Message $this.localizedData.NoPropertiesToSet
}
}

[System.Boolean] Test()
{
# Get all key properties.
$keyProperty = $this | Get-DscProperty -Type 'Key'

Write-Verbose -Message ($this.localizedData.TestDesiredState -f $this.GetType().Name, ($keyProperty | ConvertTo-Json -Compress))

$this.Assert()

$isInDesiredState = $true

<#
Returns all enforced properties not in desires state, or $null if
all enforced properties are in desired state.
#>
$propertiesNotInDesiredState = $this.Compare()

if ($propertiesNotInDesiredState)
{
$isInDesiredState = $false
}

if ($isInDesiredState)
{
Write-Verbose $this.localizedData.InDesiredState
}
else
{
Write-Verbose $this.localizedData.NotInDesiredState
}

return $isInDesiredState
}

<#
Returns a hashtable containing all properties that should be enforced and
are not in desired state, or $null if all enforced properties are in
desired state.
This method should normally not be overridden.
#>
hidden [System.Collections.Hashtable[]] Compare()
{
# Get the current state, all properties except Read properties .
$currentState = $this.Get() | Get-DscProperty -Type @('Key', 'Mandatory', 'Optional')

return $this.Compare($currentState, @())
}

<#
Returns a hashtable containing all properties that should be enforced and
are not in desired state, or $null if all enforced properties are in
desired state.
This method should normally not be overridden.
#>
hidden [System.Collections.Hashtable[]] Compare([System.Collections.Hashtable] $currentState, [System.String[]] $excludeProperties)
{
# Get the desired state, all assigned properties that has an non-null value.
$desiredState = $this | Get-DscProperty -Type @('Key', 'Mandatory', 'Optional') -HasValue

$CompareDscParameterState = @{
CurrentValues = $currentState
DesiredValues = $desiredState
Properties = $desiredState.Keys
ExcludeProperties = ($excludeProperties + $this.ExcludeDscProperties) | Select-Object -Unique
IncludeValue = $true
# This is needed to sort complex types.
SortArrayValues = $true
}

<#
Returns all enforced properties not in desires state, or $null if
all enforced properties are in desired state.
#>
return (Compare-DscParameterState @CompareDscParameterState)
}

# This method should normally not be overridden.
hidden [void] Assert()
{
# Get the properties that has a non-null value and is not of type Read.
$desiredState = $this | Get-DscProperty -Type @('Key', 'Mandatory', 'Optional') -HasValue

$this.AssertProperties($desiredState)
}

<#
This method can be overridden if resource specific property asserts are
needed. The parameter properties will contain the properties that was
assigned a value.
#>
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('AvoidEmptyNamedBlocks', '')]
hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
{
}

<#
This method must be overridden by a resource. The parameter properties will
contain the properties that should be enforced and that are not in desired
state.
#>
hidden [void] Modify([System.Collections.Hashtable] $properties)
{
throw $this.localizedData.ModifyMethodNotImplemented
}

<#
This method must be overridden by a resource. The parameter properties will
contain the key properties.
#>
hidden [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties)
{
throw $this.localizedData.GetCurrentStateMethodNotImplemented
}
}
Loading

0 comments on commit e312353

Please sign in to comment.