Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Requirements

- ComputerManagementDsc-specific guidelines and requirements override general project
guidelines and requirements.

## Module Identity

**ComputerManagementDsc** is a DSC Community PowerShell module providing Desired State
Configuration resources for Windows computer and OS settings.

## Terminology

- **Command**: Public command
- **Function**: Private function
- **Resource**: DSC class-based resource

## Core Requirements

- Instructions take precedence over existing code patterns.
- Always update the `Unreleased` section of `CHANGELOG.md` for every code change.
- Localize all user-visible strings using `$script:localizedData` keys; never use
hardcoded string literals in `Write-Verbose`, `Write-Error`, or exception messages.
- Check [`DscResource.Common`](https://github.com/dsccommunity/DscResource.Common/wiki)
before creating private helper functions.
- Use `New-InvalidOperationException`, `New-ArgumentException`, and similar helpers from
`DscResource.Common` instead of `throw`.
- Separate reusable logic into private functions.
- Add unit tests for all commands, functions, and resources.
- Add integration tests for all public commands and resources.

## Resource Types

This repository contains two types of DSC resources:

- **MOF-based resources** (`source/DSCResources/DSC_<ResourceName>/`) — implement
`Get-TargetResource`, `Test-TargetResource`, and `Set-TargetResource`
- **Class-based resources** (`source/Classes/<N>.<ClassName>.ps1`) — inherit `ResourceBase`
from `DscResource.Base`; implement `GetCurrentState()` and `Modify()`
- Prefer class-based resources; use MOF-based only when required
(e.g. WMF 4.0 support).

## File Organization

- Class-based resources: `source/Classes/<DependencyGroupNumber>.<ClassName>.ps1`
- MOF-based resources: `source/DSCResources/DSC_<ResourceName>/DSC_<ResourceName>.psm1`
- Resource enums: `source/Enum/<DependencyGroupNumber>.<EnumName>.ps1`
- Unit tests (MOF): `tests/Unit/DSC_<ResourceName>.Tests.ps1`
- Unit tests (class): `tests/Unit/Classes/<ClassName>.Tests.ps1`
- Integration tests: `tests/Integration/*.Tests.ps1` (class resources in `tests/Integration/Classes/`)
## Naming Conventions

- MOF-based resources: `DSC_<ResourceName>` prefix on all files and all exported
functions (e.g. `DSC_TimeZone.psm1`; `Get-TargetResource` is exported via
`*-TargetResource`).
- Class-based resources: PascalCase class name; file prefix
`<DependencyGroupNumber>.<ClassName>.ps1` where the number is the dependency
group (e.g. `020.PSResourceRepository.ps1`).

## Build & Test Workflow

- Never use VS Code tasks; always use PowerShell scripts via terminal from the
repository root.
- Setup build and test environment (once per `pwsh` session):
`./build.ps1 -Tasks noop`
- Build project before running tests: `./build.ps1 -Tasks build`
- Run all unit tests: `Invoke-Pester -Path 'tests/Unit' -Output Detailed`
- Run a specific MOF resource unit test:
`Invoke-Pester -Path 'tests/Unit/DSC_<ResourceName>.Tests.ps1' -Output Detailed`
- Run a specific class resource unit test:
`Invoke-Pester -Path 'tests/Unit/Classes/<ClassName>.Tests.ps1' -Output Detailed`
- Never run integration tests locally.
- Run unit tests in a new `pwsh` session after changing class-based resources.

## Instruction Files

Read the following instruction files before working on the corresponding areas:

- `.github/instructions/dsc-community-powershell.instructions.md` — PowerShell style
- `.github/instructions/dsc-community-pester.instructions.md` — Pester test style
- `.github/instructions/dsc-community-unit-tests.instructions.md` — unit test setup and patterns
- `.github/instructions/dsc-community-integration-tests.instructions.md` — integration test patterns
- `.github/instructions/dsc-community-mof-resource.instructions.md` — MOF resource implementation
- `.github/instructions/dsc-community-class-resource.instructions.md` — class-based resource implementation
- `.github/instructions/dsc-community-localization.instructions.md` — localized string conventions
- `.github/instructions/dsc-community-changelog.instructions.md` — changelog format
- `.github/instructions/dsc-community-markdown.instructions.md` — markdown style

## Key External References

- [DSC Community Guidelines](https://dsccommunity.org/guidelines/)
- [DSC Community Blog](https://dsccommunity.org/blog/)
- [DscResource.Common](https://github.com/dsccommunity/DscResource.Common)
- [DscResource.Base](https://github.com/dsccommunity/DscResource.Base)
- [DscResource.Test](https://github.com/dsccommunity/DscResource.Test)
26 changes: 26 additions & 0 deletions .github/instructions/dsc-community-changelog.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
description: Guidelines for a consistent changelog.
applyTo: "CHANGELOG.md"
version: 1.0.0
---

# Changelog Guidelines

- Always update the `## [Unreleased]` section in `CHANGELOG.md`
- One section per change type (`Added`, `Changed`, `Fixed`) under `## [Unreleased]`
- Use Keep a Changelog format
- Describe changes briefly; ≤2 items per change type
- Reference issues using format
` - Fixes [Issue #<issue_number>](https://github.com/dsccommunity/ComputerManagementDsc/issues/<issue_number>)`
- capital `I` in `Issue`; `Fixes` prefix; full stop after closing parenthesis
- No empty lines between list items in same section
- No duplicate sections or items in `## [Unreleased]`; skip if entry already exists
- Mark breaking changes with `BREAKING CHANGE:` prefix on the entry in `### Changed`
or `### Fixed`
- Group multiple changes for the same resource using two-level indentation:

```markdown
- ResourceName
- First change description for this resource - Fixes [Issue #<issue_number>](https://github.com/dsccommunity/ComputerManagementDsc/issues/<issue_number>)
- Second change description for this resource - Fixes [Issue #<issue_number>](https://github.com/dsccommunity/ComputerManagementDsc/issues/<issue_number>)
```
168 changes: 168 additions & 0 deletions .github/instructions/dsc-community-class-resource.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
description: Guidelines for implementing Desired State Configuration (DSC) class-based resources.
applyTo: "source/[cC]lasses/**/*.ps1"
version: 1.0.0
---

# DSC Class-Based Resource Guidelines

**Applies to:** Classes with `[DscResource(...)]` decoration only.

## Requirements

- File: `source/Classes/<N>.<ClassName>.ps1`
- Decoration: `[DscResource(RunAsCredential = 'Optional')]` (use `'Mandatory'` if required)
- Inherit `ResourceBase` (DscResource.Base)
- `$this.localizedData` auto-populated by `ResourceBase` from localization file
- Value-type properties: use `[Nullable[{FullTypeName}]]` (e.g. `[Nullable[System.Int32]]`)

## Required Constructor

```powershell
MyResourceName () : base ($PSScriptRoot)
{
# Property names where state cannot be enforced, e.g. IsSingleInstance, Force
$this.ExcludeDscProperties = @()
}
```

## Required Method Pattern

```powershell
[MyResourceName] Get()
{
# Call base implementation to get current state
$currentState = ([ResourceBase] $this).Get()

# If needed, post-processing on current state that cannot be handled by GetCurrentState()

return $currentState
}

[System.Boolean] Test()
{
# Call base implementation to test current state
$inDesiredState = ([ResourceBase] $this).Test()

# If needed, post-processing on test result that cannot be handled by base Test()

return $inDesiredState
}

[void] Set()
{
# Call base implementation to set desired state
([ResourceBase] $this).Set()

# If needed, additional state changes that cannot be handled by Modify()
}

hidden [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties)
{
# Always return current state as hashtable; $properties contains key properties
}

hidden [void] Modify([System.Collections.Hashtable] $properties)
{
# Always set desired state; $properties contains those that must change state
}
```

## Optional Method Pattern

```powershell
hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
{
# Validate user-provided properties; $properties contains user-assigned values
}

hidden [void] NormalizeProperties([System.Collections.Hashtable] $properties)
{
# Normalize user-provided properties; $properties contains user-assigned values
}
```

## Required Comment-based Help

Add to `.DESCRIPTION` section:

- `## Requirements`: List minimum requirements
- `## Known issues`: Critical issues + pattern:
`All issues are not listed here, see [all open issues](https://github.com/dsccommunity/ComputerManagementDsc/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+{ResourceName}).`

## Error Handling for Classes

- Use `try/catch` blocks to handle exceptions
- Do not use `throw` for terminating errors; use `New-*Exception` commands:
- [`New-InvalidDataException`](https://github.com/dsccommunity/DscResource.Common/wiki/New%E2%80%91InvalidDataException)
- [`New-ArgumentException`](https://github.com/dsccommunity/DscResource.Common/wiki/New%E2%80%91ArgumentException)
- [`New-InvalidOperationException`](https://github.com/dsccommunity/DscResource.Common/wiki/New%E2%80%91InvalidOperationException)
- [`New-ObjectNotFoundException`](https://github.com/dsccommunity/DscResource.Common/wiki/New%E2%80%91ObjectNotFoundException)
- [`New-InvalidResultException`](https://github.com/dsccommunity/DscResource.Common/wiki/New%E2%80%91InvalidResultException)
- [`New-NotImplementedException`](https://github.com/dsccommunity/DscResource.Common/wiki/New%E2%80%91NotImplementedException)

## Property Attributes

- `[DscProperty(Key)]` — key (identity) properties; always mark at least one per resource
- `[DscProperty(Mandatory)]` — required (non-key) properties
- `[DscProperty()]` — optional properties
- `[DscProperty(NotConfigurable)]` — read-only / computed properties not configurable by the
user (e.g. `Reasons`)
- `[ValidateSet('Value1', 'Value2')]` — restrict allowed values on string properties
- For Enum-typed properties, set a default value:

```powershell
[DscProperty()]
[Ensure]
$Ensure = [Ensure]::Present
```

## Machine Configuration Compliance (`Reasons`)

Resources that support Azure Policy / Machine Configuration compliance auditing must include
a `Reasons` property using the `CMReason` helper class:

```powershell
[DscProperty(NotConfigurable)]
[CMReason[]]
$Reasons
```

## Class-Level Comment-Based Help

Place a comment block **above** the `[DscResource()]` decoration with:

- `.SYNOPSIS` — one-line description of the resource
- `.PARAMETER` — one entry per DSC property (name + description)
- `.EXAMPLE` — at least one `Invoke-DscResource` usage example

```powershell
<#
.SYNOPSIS
A resource to manage...

.PARAMETER Ensure
Specifies whether the resource should be Present or Absent.

.PARAMETER Name
Specifies the name.

.EXAMPLE
Invoke-DscResource -Name 'MyResource' -ModuleName 'MyModule' -Method 'Get' -Property @{
Name = 'Value'
Ensure = 'Present'
}
#>
[DscResource()]
class MyResource : ResourceBase
```

## Localized Data in Class Resources

- Strings are loaded automatically by `ResourceBase` when passing `$PSScriptRoot` to the
base constructor: `MyResource () : base ($PSScriptRoot)`
- Access localized strings via `$this.localizedData.KeyName` (not `$script:localizedData`)

```powershell
Write-Verbose -Message ($this.localizedData.GetTargetResourceMessage -f $this.Name)
```
Loading