Skip to content

Conversation

@dan-hughes
Copy link
Contributor

@dan-hughes dan-hughes commented Jul 24, 2025

Pull Request (PR) description

Convert AdcsOnlineResponder to class-based resource

This Pull Request (PR) fixes the following issues

Task list

  • Added an entry under the Unreleased section of the change log in the CHANGELOG.md.
    Entry should say what was changed, and how that affects users (if applicable).
  • Resource documentation added/updated in README.md in resource folder.
  • Resource parameter descriptions added/updated in schema.mof
    and comment-based help.
  • Comment-based help added/updated.
  • Localization strings added/updated in all localization files as appropriate.
  • Examples appropriately added/updated.
  • Unit tests added/updated. See DSC Resource Testing Guidelines.
  • Integration tests added/updated (where possible). See DSC Resource Testing Guidelines.
  • New/changed code adheres to DSC Resource Style Guidelines and Best Practices.

This change is Reviewable

@coderabbitai
Copy link

coderabbitai bot commented Jul 24, 2025

Walkthrough

Migrates AdcsOnlineResponder from a MOF/module-based DSC resource to a class-based DSC resource: removes legacy MOF/module/strings/README and module-based tests, adds AdcsOnlineResponder class, new en-US strings and class-based Pester tests, adds an OCSP exception stub, fixes an unrelated test brace, and updates RequiredModules entry. (50 words)

Changes

Cohort / File(s) Change Summary
Changelog
CHANGELOG.md
Formatted component names with backticks and added a note that AdcsOnlineResponder was converted to a class-based resource.
New class resource
source/Classes/020.AdcsOnlineResponder.ps1
Added class-based DSC resource AdcsOnlineResponder with properties (IsSingleInstance, Credential, Ensure, Reasons), public methods (Get, Set, Test), and hidden helpers (GetCurrentState, Modify, AssertProperties) that call ADCSDeployment cmdlets and surface localized errors.
Removed legacy MOF/module/docs/strings
source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1, .../DSC_AdcsOnlineResponder.schema.mof, .../README.md, .../en-US/DSC_AdcsOnlineResponder.strings.psd1
Deleted legacy MOF/module implementation, schema, README, and localized strings for the previous resource.
New localization
source/en-US/AdcsOnlineResponder.strings.psd1
Added en-US string file exposing ErrorGetCurrentState for the class resource.
New tests (class-based)
tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1
Added Pester unit tests for the class-based resource covering construction, Get/Set/Test, hidden member behaviors, and property assertions using mocks/stubs.
Removed legacy tests
tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1
Removed previous MOF/module-based test suite.
Test fix
tests/Unit/Classes/AdcsAuthorityInformationAccess.Tests.ps1
Fixed a missing closing brace } in a BeforeAll block to correct block structure.
Test stubs
tests/Unit/Stubs/AdcsDeploymentStub.psm1
Added OnlineResponderSetupException class in Microsoft.CertificateServices.Deployment.Common.OCSP namespace for unit test simulation.
Required modules update
RequiredModules.psd1
Changed DscResource.Common entry from scalar 'latest' to @{ Version = 'latest'; Parameters = @{ AllowPrerelease = $true } } to allow prerelease resolution.
Module manifest export
source/ActiveDirectoryCSDsc.psd1
Changed CmdletsToExport from @() to '*' to export all cmdlets.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LCM as "DSC Engine (LCM)"
    participant Class as "AdcsOnlineResponder (Class)"
    participant ADCS as "ADCSDeployment Module"

    User->>LCM: Apply configuration (AdcsOnlineResponder)
    LCM->>Class: Invoke Get/Test/Set
    Class->>ADCS: Call Install-AdcsOnlineResponder / Uninstall-AdcsOnlineResponder / Install-AdcsOnlineResponder -WhatIf
    alt ADCS returns success
        ADCS-->>Class: Success
        Class-->>LCM: Return state / success
    else ADCS throws OnlineResponderSetupException
        ADCS-->>Class: OnlineResponderSetupException
        Class-->>LCM: Interpret as "Present" / return state
    else ADCS throws other error
        ADCS-->>Class: Error
        Class-->>LCM: Throw localized error (ErrorGetCurrentState)
    end
    LCM-->>User: Report status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective (issue#) Addressed Explanation
Convert AdcsOnlineResponder to class-based resource (#155)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
RequiredModules.psd1 — changed module entry to allow prerelease (RequiredModules.psd1) Dependency/prerelease configuration change not required by conversion objective.
CHANGELOG.md — component name formatting (CHANGELOG.md) Documentation formatting only; unrelated to conversion implementation.
Fixed missing brace in tests (tests/Unit/Classes/AdcsAuthorityInformationAccess.Tests.ps1) Test syntax fix unrelated to converting the resource; corrects existing test structure.
source/ActiveDirectoryCSDsc.psd1CmdletsToExport changed to '*' (source/ActiveDirectoryCSDsc.psd1) Module manifest export behavior change unrelated to the conversion objective.
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6dd161 and 553587e.

📒 Files selected for processing (9)
  • CHANGELOG.md (3 hunks)
  • source/Classes/020.AdcsOnlineResponder.ps1 (1 hunks)
  • source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1 (0 hunks)
  • source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.schema.mof (0 hunks)
  • source/DSCResources/DSC_AdcsOnlineResponder/README.md (0 hunks)
  • source/DSCResources/DSC_AdcsOnlineResponder/en-US/DSC_AdcsOnlineResponder.strings.psd1 (0 hunks)
  • source/en-US/AdcsOnlineResponder.strings.psd1 (1 hunks)
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (1 hunks)
  • tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1 (0 hunks)
💤 Files with no reviewable changes (5)
  • source/DSCResources/DSC_AdcsOnlineResponder/en-US/DSC_AdcsOnlineResponder.strings.psd1
  • source/DSCResources/DSC_AdcsOnlineResponder/README.md
  • source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.schema.mof
  • tests/Unit/DSC_AdcsOnlineResponder.Tests.ps1
  • source/DSCResources/DSC_AdcsOnlineResponder/DSC_AdcsOnlineResponder.psm1
🔇 Additional comments (1)
CHANGELOG.md (1)

10-10: LGTM! Changelog updates are properly formatted and documented.

The addition of backticks for code formatting and the new entry documenting the conversion to a class-based resource are appropriate and follow the established changelog format.

Also applies to: 25-25, 38-39

@codecov
Copy link

codecov bot commented Jul 24, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98%. Comparing base (60f9961) to head (b0ef088).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@         Coverage Diff         @@
##           main   #158   +/-   ##
===================================
- Coverage    98%    98%   -1%     
===================================
  Files         8     10    +2     
  Lines       514    477   -37     
===================================
- Hits        505    468   -37     
  Misses        9      9           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (2)

473-571: Remove skipped tests that reference non-existent properties.

These tests reference AiaUri and OcspUri properties that don't belong to the AdcsOnlineResponder class. They appear to be copied from AdcsAuthorityInformationAccess tests and are not applicable here.


573-854: Remove skipped tests that reference non-existent properties.

These Modify() tests also reference AiaUri and OcspUri properties and CA Authority Information Access commands that are not relevant to the AdcsOnlineResponder class.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 553587e and 51b7e02.

📒 Files selected for processing (2)
  • tests/Unit/Classes/AdcsAuthorityInformationAccess.Tests.ps1 (1 hunks)
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (1 hunks)
🔇 Additional comments (1)
tests/Unit/Classes/AdcsAuthorityInformationAccess.Tests.ps1 (1)

597-597: Good catch! Fixed missing closing brace.

This corrects the block structure by properly closing the BeforeAll block.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (4)

304-304: Add missing space before opening brace.

-Describe 'AdcsOnlineResponder\Set()' -Tag 'Set' {
+Describe 'AdcsOnlineResponder\Set()' -Tag 'Set' {

473-571: Remove skipped tests that reference non-existent properties.

These tests reference AiaUri and OcspUri properties that don't exist in the AdcsOnlineResponder class. They appear to be copied from another resource and should be removed entirely as they're not applicable to this resource.


573-854: Remove skipped Modify() tests that use incorrect properties.

Like the GetCurrentState() tests, these Modify() tests reference non-existent AiaUri and OcspUri properties and mock commands that aren't relevant to AdcsOnlineResponder. These tests should be removed or completely rewritten to test the actual functionality of the AdcsOnlineResponder resource.


888-888: Fix incorrect test description.

The test description says "Should throw an error" but the test expects it NOT to throw.

-        It 'Should throw an error' {
+        It 'Should not throw an error' {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51b7e02 and 5c28b65.

📒 Files selected for processing (1)
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (1 hunks)
🔇 Additional comments (3)
tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (3)

60-88: Well-structured class instantiation tests.

The tests correctly verify that the AdcsOnlineResponder class can be instantiated and has the expected type.


90-302: Comprehensive Get() method test coverage.

The tests properly cover all scenarios for the Get() method including desired/not desired states and installed/not installed conditions. Good use of mocking for internal methods.


393-471: Well-implemented Test() method tests.

The tests correctly verify the Test() method behavior for both desired and not desired states.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
source/en-US/AdcsOnlineResponder.strings.psd1 (1)

7-13: String resource added and correctly keyed.

ErrorGetCurrentState is now active and matches the tests’ expectation. Thanks for closing the loop.

tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (1)

574-854: Remove the skipped Modify() tests that reference non-existent AIA/OCSP properties.

They’re from another resource and add noise. Either replace with AdcsOnlineResponder-specific Modify() tests or delete.

Apply this diff to remove the irrelevant block:

-Describe 'AdcsOnlineResponder\Modify()' -Tag 'HiddenMember' -Skip:$true {
-    # ... AIA/OCSP tests ...
-}
🧹 Nitpick comments (5)
RequiredModules.psd1 (1)

41-46: Consider pinning to a known-good version to keep CI deterministic.

Using 'latest' + prerelease can introduce breaking changes unexpectedly. If stability is preferred, pin a specific version or minimum compatible range once validated.

tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (4)

62-68: Avoid “Should -Not -Throw” per test guidelines; this test is redundant.

Type/constructor existence is already covered below. Recommend removing this It block.

Apply this diff:

-        It 'Should not throw an exception' {
-            InModuleScope -ScriptBlock {
-                Set-StrictMode -Version 1.0
-
-                { [AdcsOnlineResponder]::new() } | Should -Not -Throw
-            }
-        }

516-519: Throw a typed exception instead of a string to accurately exercise catch logic.

Mocking with a string throws RuntimeException; if the resource catches OnlineResponderSetupException by type, this test may be misleading.

Apply this diff here:

-            Mock -CommandName Install-AdcsOnlineResponder -MockWith {
-                throw 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException'
-            }
+            Mock -CommandName Install-AdcsOnlineResponder -MockWith {
+                throw [Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException]::new('Already installed')
+            }

And define the mock exception type in AdcsDeploymentStub.psm1:

Add-Type -TypeDefinition @'
namespace Microsoft.CertificateServices.Deployment.Common.OCSP {
    public class OnlineResponderSetupException : System.Exception {
        public OnlineResponderSetupException() {}
        public OnlineResponderSetupException(string message) : base(message) {}
    }
}
'@

420-425: Return a value from mocked Get() for clarity.

Base Test() may read Get()’s output; returning an explicit state makes the tests more robust.

Apply this diff in both Get() mocks:

                     Add-Member -Force -MemberType 'ScriptMethod' -Name 'Get' -Value {
                         $script:getMethodCallCount += 1
+                        return @{
+                            IsSingleInstance = 'Yes'
+                            Ensure           = [Ensure]::Present
+                            Reasons          = @()
+                        }
                     }

Also applies to: 446-449


35-37: Remove commented-out code or implement the mock exception properly.

Keep tests clean: either define the exception in the stub (see suggestion above) or delete this commented line.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5c28b65 and 16761af.

📒 Files selected for processing (4)
  • RequiredModules.psd1 (1 hunks)
  • source/Classes/020.AdcsOnlineResponder.ps1 (1 hunks)
  • source/en-US/AdcsOnlineResponder.strings.psd1 (1 hunks)
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/Classes/020.AdcsOnlineResponder.ps1
🧰 Additional context used
📓 Path-based instructions (3)
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

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

Build & Test Workflow

  • Run in PowerShell, from repository root
  • Build before running tests: .\build.ps1 -Tasks build
  • Always run tests in new PowerShell session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow guidelines over existing code patterns
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • source/en-US/AdcsOnlineResponder.strings.psd1
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1
  • RequiredModules.psd1
**/*.ps?(m|d)1

⚙️ CodeRabbit configuration file

**/*.ps?(m|d)1: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type (one per line) with a 1‑line description.
  • OUTPUTS: Lis...

Files:

  • source/en-US/AdcsOnlineResponder.strings.psd1
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1
  • RequiredModules.psd1
**/*.[Tt]ests.ps1

⚙️ CodeRabbit configuration file

**/*.[Tt]ests.ps1: # Tests Guidelines

Core Requirements

  • All public commands, private functions and classes must have unit tests
  • All public commands and class-based resources must have integration tests
  • Use Pester v5 syntax only
  • Test code only inside Describe blocks
  • Assertions only in It blocks
  • Never test verbose messages, debug messages or parameter binding behavior
  • Pass all mandatory parameters to avoid prompts

Naming

  • One Describe block per file matching the tested entity name
  • Context descriptions start with 'When'
  • It descriptions start with 'Should', must not contain 'when'
  • Mock variables prefix: 'mock'

Structure & Scope

  • Public commands: Never use InModuleScope (unless retrieving localized strings)
  • Private functions/class resources: Always use InModuleScope
  • Each class method = separate Context block
  • Each scenario = separate Context block
  • Use nested Context blocks for complex scenarios
  • Mocking in BeforeAll (BeforeEach only when required)
  • Setup/teardown in BeforeAll,BeforeEach/AfterAll,AfterEach close to usage

Syntax Rules

  • PascalCase: Describe, Context, It, Should, BeforeAll, BeforeEach, AfterAll, AfterEach
  • Prefer -BeTrue/-BeFalse over -Be $true/-Be $false
  • Never use Assert-MockCalled, use Should -Invoke instead
  • No Should -Not -Throw - invoke commands directly
  • Never add an empty -MockWith block
  • Omit -MockWith when returning $null
  • Set $PSDefaultParameterValues for Mock:ModuleName, Should:ModuleName, InModuleScope:ModuleName
  • Omit -ModuleName parameter on Pester commands
  • Never use Mock inside InModuleScope-block

File Organization

  • Class resources: tests/Unit/Classes/{Name}.Tests.ps1
  • Public commands: tests/Unit/Public/{Name}.Tests.ps1
  • Private functions: tests/Unit/Private/{Name}.Tests.ps1

Data-Driven Tests

  • Define variables in separate BeforeDiscovery for -ForEach (close to usage)
  • -ForEach al...

Files:

  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1
🔇 Additional comments (1)
RequiredModules.psd1 (1)

41-46: Allowing prerelease for DscResource.Common looks correct for class-based resources.

This aligns with the class-based migration and matches how DscResource.Base is handled. LGTM.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
tests/Unit/Stubs/AdcsDeploymentStub.psm1 (1)

10-17: Guard Add-Type and add inner-exception ctor for fidelity.

Prevents redefinition errors across repeated imports and better mirrors real .NET exceptions.

-Add-Type -TypeDefinition @'
+if (-not ('Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException' -as [type]))
+{
+Add-Type -TypeDefinition @'
 namespace Microsoft.CertificateServices.Deployment.Common.OCSP {
     public class OnlineResponderSetupException : System.Exception {
-        public OnlineResponderSetupException() {}
-        public OnlineResponderSetupException(string message) : base(message) {}
+        public OnlineResponderSetupException() {}
+        public OnlineResponderSetupException(string message) : base(message) {}
+        public OnlineResponderSetupException(string message, System.Exception inner) : base(message, inner) {}
     }
 }
 '@
+}
source/Classes/020.AdcsOnlineResponder.ps1 (3)

6-11: Add Required “Requirements” and “Known issues” subsections in DESCRIPTION.

Needed by repo guidelines; include link to open issues.

 .DESCRIPTION
     This resource can be used to install an ADCS Online Responder after the feature
     has been installed on the server.
     Using this DSC Resource to configure an ADCS Certificate Authority assumes that
-    the ```ADCS-Online-Responder``` feature has already been installed.
+    the 'ADCS-Online-Responder' feature has already been installed.
+
+    ## Requirements
+        - Windows Server with ADCSDeployment module available.
+        - DscResource.Base and DscResource.Common modules.
+
+    ## Known issues
+        All issues are not listed here, see all open issues:
+        https://github.com/dsccommunity/ActiveDirectoryCSDsc/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+AdcsOnlineResponder

140-143: Validate IsSingleInstance value in AssertProperties.

Ensure only 'Yes' is accepted; fail fast with localized message.

 hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
 {
     Assert-Module -ModuleName 'ADCSDeployment'
+
+    if ($properties.ContainsKey('IsSingleInstance') -and $properties.IsSingleInstance -ne 'Yes')
+    {
+        # Example key: ErrorIsSingleInstance = "IsSingleInstance must be 'Yes'. Actual: {0} (AOR0003)"
+        New-InvalidDataException -Message ($this.localizedData.ErrorIsSingleInstance -f $properties.IsSingleInstance)
+    }
 }

28-35: Add EXAMPLE section(s) to comment-based help.

Required by repo guidelines; include at least Present and Absent examples.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 16761af and 58f1c2f.

📒 Files selected for processing (3)
  • source/Classes/020.AdcsOnlineResponder.ps1 (1 hunks)
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1 (1 hunks)
  • tests/Unit/Stubs/AdcsDeploymentStub.psm1 (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/Unit/Classes/AdcsOnlineResponder.Tests.ps1
🧰 Additional context used
📓 Path-based instructions (4)
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

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

Build & Test Workflow

  • Run in PowerShell, from repository root
  • Build before running tests: .\build.ps1 -Tasks build
  • Always run tests in new PowerShell session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow guidelines over existing code patterns
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • tests/Unit/Stubs/AdcsDeploymentStub.psm1
  • source/Classes/020.AdcsOnlineResponder.ps1
**/*.ps?(m|d)1

⚙️ CodeRabbit configuration file

**/*.ps?(m|d)1: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type (one per line) with a 1‑line description.
  • OUTPUTS: Lis...

Files:

  • tests/Unit/Stubs/AdcsDeploymentStub.psm1
  • source/Classes/020.AdcsOnlineResponder.ps1
source/**/*.ps1

⚙️ CodeRabbit configuration file

source/**/*.ps1: # Localization Guidelines

Requirements

  • Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages
  • Use localized string keys, not hardcoded strings
  • Assume $script:localizedData is available

String Files

  • Commands/functions: source/en-US/{MyModuleName}.strings.psd1
  • Class resources: source/en-US/{ResourceClassName}.strings.psd1

Key Naming Patterns

  • Format: Verb_FunctionName_Action (underscore separators), e.g. Get_Database_ConnectingToDatabase

String Format

ConvertFrom-StringData @'
    KeyName = Message with {0} placeholder. (PREFIX0001)
'@

String IDs

  • Format: (PREFIX####)
  • PREFIX: First letter of each word in class or function name (SqlSetup → SS, Get-SqlDscDatabase → GSDD)
  • Number: Sequential from 0001

Usage

Write-Verbose -Message ($script:localizedData.KeyName -f $value1)

Files:

  • source/Classes/020.AdcsOnlineResponder.ps1
source/[cC]lasses/**/*.ps1

⚙️ CodeRabbit configuration file

source/[cC]lasses/**/*.ps1: # DSC Class-Based Resource Guidelines

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

Requirements

  • File: source/Classes/020.{ResourceName}.ps1
  • Decoration: [DscResource(RunAsCredential = 'Optional')] (replace with 'Mandatory' if required)
  • Inheritance: Must inherit ResourceBase (part of module DscResource.Base)
  • $this.localizedData hashtable auto-populated by ResourceBase from localization file
  • value-type properties: Use [Nullable[{FullTypeName}]] (e.g., [Nullable[System.Int32]])

Required constructor

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

Required Method Pattern

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

    # If needed, post-processing on current state that can not 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 can not 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 can not 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 contain those that must change state
}

Optional Method Pattern

hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
{
    # Validate user-provided properties, $p...

Files:

  • source/Classes/020.AdcsOnlineResponder.ps1
🧠 Learnings (2)
📓 Common learnings
Learnt from: dan-hughes
PR: dsccommunity/ActiveDirectoryCSDsc#158
File: source/Classes/020.AdcsOnlineResponder.ps1:0-0
Timestamp: 2025-08-30T18:18:31.483Z
Learning: For ADCS resources in ActiveDirectoryCSDsc, when catching exceptions from Install-Adcs* commands to determine installation state, use string matching on the exception message (e.g., `$_.Exception.ToString() -match 'OnlineResponderSetupException$'`) instead of catching specific exception types. This avoids dependency on importing types that may not be available in all environments like CI systems or DSC authoring machines.
📚 Learning: 2025-08-30T18:18:31.483Z
Learnt from: dan-hughes
PR: dsccommunity/ActiveDirectoryCSDsc#158
File: source/Classes/020.AdcsOnlineResponder.ps1:0-0
Timestamp: 2025-08-30T18:18:31.483Z
Learning: For ADCS resources in ActiveDirectoryCSDsc, when catching exceptions from Install-Adcs* commands to determine installation state, use string matching on the exception message (e.g., `$_.Exception.ToString() -match 'OnlineResponderSetupException$'`) instead of catching specific exception types. This avoids dependency on importing types that may not be available in all environments like CI systems or DSC authoring machines.

Applied to files:

  • tests/Unit/Stubs/AdcsDeploymentStub.psm1
  • source/Classes/020.AdcsOnlineResponder.ps1
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: dsccommunity.ActiveDirectoryCSDsc (Test Unit)
  • GitHub Check: dsccommunity.ActiveDirectoryCSDsc (Test HQRM)
  • GitHub Check: dsccommunity.ActiveDirectoryCSDsc (Test Integration)
  • GitHub Check: dsccommunity.ActiveDirectoryCSDsc (Build Package Module)

Comment on lines 104 to 128
hidden [void] Modify([System.Collections.Hashtable] $properties)
{
if ($properties.ContainsKey('Ensure') -and $properties.Ensure -eq [Ensure]::Absent)
{
try
{
Uninstall-AdcsOnlineResponder -Force
}
catch
{
New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
}
}
else
{
try
{
Install-AdcsOnlineResponder -Credential $this.Credential -Force
}
catch
{
New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Localize error messages and promote non-terminating errors to terminating.

Use -ErrorAction Stop and localized strings with placeholders; avoid leaking raw exception text directly.

 hidden [void] Modify([System.Collections.Hashtable] $properties)
 {
     if ($properties.ContainsKey('Ensure') -and $properties.Ensure -eq [Ensure]::Absent)
     {
         try
         {
-            Uninstall-AdcsOnlineResponder -Force
+            Uninstall-AdcsOnlineResponder -Force -ErrorAction Stop
         }
         catch
         {
-            New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
+            # Example key: ErrorModifyUninstall = "Failed to uninstall Online Responder. Details: {0} (AOR0001)"
+            New-InvalidOperationException -Message ($this.localizedData.ErrorModifyUninstall -f $_.Exception.Message) -ErrorRecord $_
         }
     }
     else
     {
         try
         {
-            Install-AdcsOnlineResponder -Credential $this.Credential -Force
+            Install-AdcsOnlineResponder -Credential $this.Credential -Force -ErrorAction Stop
         }
         catch
         {
-            New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
+            # Example key: ErrorModifyInstall = "Failed to install Online Responder. Details: {0} (AOR0002)"
+            New-InvalidOperationException -Message ($this.localizedData.ErrorModifyInstall -f $_.Exception.Message) -ErrorRecord $_
         }
     }
 }

Add the suggested keys to source/en-US/AdcsOnlineResponder.strings.psd1. I can draft them if helpful.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
hidden [void] Modify([System.Collections.Hashtable] $properties)
{
if ($properties.ContainsKey('Ensure') -and $properties.Ensure -eq [Ensure]::Absent)
{
try
{
Uninstall-AdcsOnlineResponder -Force
}
catch
{
New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
}
}
else
{
try
{
Install-AdcsOnlineResponder -Credential $this.Credential -Force
}
catch
{
New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
}
}
}
hidden [void] Modify([System.Collections.Hashtable] $properties)
{
if ($properties.ContainsKey('Ensure') -and $properties.Ensure -eq [Ensure]::Absent)
{
try
{
Uninstall-AdcsOnlineResponder -Force -ErrorAction Stop
}
catch
{
# Example key in source/en-US/AdcsOnlineResponder.strings.psd1:
# ErrorModifyUninstall = "Failed to uninstall Online Responder. Details: {0} (AOR0001)"
New-InvalidOperationException -Message ($this.localizedData.ErrorModifyUninstall -f $_.Exception.Message) -ErrorRecord $_
}
}
else
{
try
{
Install-AdcsOnlineResponder -Credential $this.Credential -Force -ErrorAction Stop
}
catch
{
# Example key in source/en-US/AdcsOnlineResponder.strings.psd1:
# ErrorModifyInstall = "Failed to install Online Responder. Details: {0} (AOR0002)"
New-InvalidOperationException -Message ($this.localizedData.ErrorModifyInstall -f $_.Exception.Message) -ErrorRecord $_
}
}
}
🤖 Prompt for AI Agents
In source/Classes/020.AdcsOnlineResponder.ps1 around lines 104-128, the Modify
method currently calls Install-AdcsOnlineResponder/Uninstall-AdcsOnlineResponder
without forcing terminating errors and logs raw exception text; update both
cmdlet calls to include -ErrorAction Stop so non-terminating errors become
terminating, replace direct use of $_.Exception.Message with localized string
lookups containing placeholders (add corresponding keys to
source/en-US/AdcsOnlineResponder.strings.psd1), and in each catch construct and
throw a terminating error using New-InvalidOperationException with the formatted
localized message and the original ErrorRecord so callers receive a proper
terminating error and no raw exception text is leaked.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
source/Classes/020.AdcsOnlineResponder.ps1 (3)

28-29: Use RunAsCredential = 'Optional' to align with module guidelines.

Guidelines require 'Optional' (or 'Mandatory' if needed); 'NotSupported' deviates.

-[DscResource(RunAsCredential = 'NotSupported')]
+[DscResource(RunAsCredential = 'Optional')]
 class AdcsOnlineResponder : ResourceBase

95-119: Promote non-terminating errors to terminating and localize error messages in Modify().

  • Add -ErrorAction Stop for both cmdlets.
  • Use localized messages with placeholders; avoid leaking raw exception text.
     hidden [void] Modify([System.Collections.Hashtable] $properties)
     {
         if ($properties.ContainsKey('Ensure') -and $properties.Ensure -eq [Ensure]::Absent)
         {
             try
             {
-                $null = Uninstall-AdcsOnlineResponder -Force
+                $null = Uninstall-AdcsOnlineResponder -Force -ErrorAction Stop
             }
             catch
             {
-                New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
+                # Example key: ErrorModifyUninstall = "Failed to uninstall Online Responder. Details: {0} (ADCSOR0002)"
+                New-InvalidOperationException -Message ($this.localizedData.ErrorModifyUninstall -f $_.Exception.Message) -ErrorRecord $_
             }
         }
         else
         {
             try
             {
-                $null = Install-AdcsOnlineResponder -Credential $this.Credential -Force
+                $null = Install-AdcsOnlineResponder -Credential $this.Credential -Force -ErrorAction Stop
             }
             catch
             {
-                New-InvalidOperationException -Message $_.Exception.Message -ErrorRecord $_
+                # Example key: ErrorModifyInstall = "Failed to install Online Responder. Details: {0} (ADCSOR0003)"
+                New-InvalidOperationException -Message ($this.localizedData.ErrorModifyInstall -f $_.Exception.Message) -ErrorRecord $_
             }
         }
     }

If you want, I can draft the en-US string entries (ErrorModifyInstall/Uninstall) and update the unit tests accordingly.


63-82: Make GetCurrentState robust: force terminating errors, avoid type dependency, and do not return from New-InvalidOperationException.

  • Add -ErrorAction Stop so errors are catchable.
  • Match by message/type text (per learning) rather than CLR type.
  • New-* helper throws; don’t return its result.
     [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties)
     {
         try
         {
-            $null = Install-AdcsOnlineResponder -Credential $this.Credential -WhatIf
+            $null = Install-AdcsOnlineResponder -Credential $this.Credential -WhatIf -ErrorAction Stop
 
             return @{}
         }
         catch
         {
-            if ($_.Exception.GetType().FullName -eq 'Microsoft.CertificateServices.Deployment.Common.OCSP.OnlineResponderSetupException')
+            if ($_.Exception.ToString() -match 'OnlineResponderSetupException$')
             {
                 return @{
                     IsSingleInstance = $this.IsSingleInstance
                 }
             }
 
-            return New-InvalidOperationException -Message $this.localizedData.ErrorGetCurrentState -ErrorRecord $_
+            New-InvalidOperationException -Message $this.localizedData.ErrorGetCurrentState -ErrorRecord $_
         }
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8ad4cf0 and 1001230.

📒 Files selected for processing (1)
  • source/Classes/020.AdcsOnlineResponder.ps1 (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

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

Build & Test Workflow

  • Run in PowerShell, from repository root
  • Build before running tests: .\build.ps1 -Tasks build
  • Always run tests in new PowerShell session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow guidelines over existing code patterns
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • source/Classes/020.AdcsOnlineResponder.ps1
**/*.ps?(m|d)1

⚙️ CodeRabbit configuration file

**/*.ps?(m|d)1: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type (one per line) with a 1‑line description.
  • OUTPUTS: Lis...

Files:

  • source/Classes/020.AdcsOnlineResponder.ps1
source/**/*.ps1

⚙️ CodeRabbit configuration file

source/**/*.ps1: # Localization Guidelines

Requirements

  • Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages
  • Use localized string keys, not hardcoded strings
  • Assume $script:localizedData is available

String Files

  • Commands/functions: source/en-US/{MyModuleName}.strings.psd1
  • Class resources: source/en-US/{ResourceClassName}.strings.psd1

Key Naming Patterns

  • Format: Verb_FunctionName_Action (underscore separators), e.g. Get_Database_ConnectingToDatabase

String Format

ConvertFrom-StringData @'
    KeyName = Message with {0} placeholder. (PREFIX0001)
'@

String IDs

  • Format: (PREFIX####)
  • PREFIX: First letter of each word in class or function name (SqlSetup → SS, Get-SqlDscDatabase → GSDD)
  • Number: Sequential from 0001

Usage

Write-Verbose -Message ($script:localizedData.KeyName -f $value1)

Files:

  • source/Classes/020.AdcsOnlineResponder.ps1
source/[cC]lasses/**/*.ps1

⚙️ CodeRabbit configuration file

source/[cC]lasses/**/*.ps1: # DSC Class-Based Resource Guidelines

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

Requirements

  • File: source/Classes/020.{ResourceName}.ps1
  • Decoration: [DscResource(RunAsCredential = 'Optional')] (replace with 'Mandatory' if required)
  • Inheritance: Must inherit ResourceBase (part of module DscResource.Base)
  • $this.localizedData hashtable auto-populated by ResourceBase from localization file
  • value-type properties: Use [Nullable[{FullTypeName}]] (e.g., [Nullable[System.Int32]])

Required constructor

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

Required Method Pattern

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

    # If needed, post-processing on current state that can not 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 can not 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 can not 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 contain those that must change state
}

Optional Method Pattern

hidden [void] AssertProperties([System.Collections.Hashtable] $properties)
{
    # Validate user-provided properties, $p...

Files:

  • source/Classes/020.AdcsOnlineResponder.ps1
🧠 Learnings (2)
📓 Common learnings
Learnt from: dan-hughes
PR: dsccommunity/ActiveDirectoryCSDsc#158
File: source/Classes/020.AdcsOnlineResponder.ps1:0-0
Timestamp: 2025-08-30T18:18:31.483Z
Learning: For ADCS resources in ActiveDirectoryCSDsc, when catching exceptions from Install-Adcs* commands to determine installation state, use string matching on the exception message (e.g., `$_.Exception.ToString() -match 'OnlineResponderSetupException$'`) instead of catching specific exception types. This avoids dependency on importing types that may not be available in all environments like CI systems or DSC authoring machines.
📚 Learning: 2025-08-30T18:18:31.483Z
Learnt from: dan-hughes
PR: dsccommunity/ActiveDirectoryCSDsc#158
File: source/Classes/020.AdcsOnlineResponder.ps1:0-0
Timestamp: 2025-08-30T18:18:31.483Z
Learning: For ADCS resources in ActiveDirectoryCSDsc, when catching exceptions from Install-Adcs* commands to determine installation state, use string matching on the exception message (e.g., `$_.Exception.ToString() -match 'OnlineResponderSetupException$'`) instead of catching specific exception types. This avoids dependency on importing types that may not be available in all environments like CI systems or DSC authoring machines.

Applied to files:

  • source/Classes/020.AdcsOnlineResponder.ps1

Comment on lines +6 to +11
.DESCRIPTION
This resource can be used to install an ADCS Online Responder after the feature
has been installed on the server.
Using this DSC Resource to configure an ADCS Certificate Authority assumes that
the ```ADCS-Online-Responder``` feature has already been installed.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Fix inaccurate wording and add required “Requirements” and “Known issues” sections in .DESCRIPTION.

“Certificate Authority” is incorrect here; this resource configures the Online Responder. Also add the required sections per guidelines.

     .DESCRIPTION
-        This resource can be used to install an ADCS Online Responder after the feature
-        has been installed on the server.
-        Using this DSC Resource to configure an ADCS Certificate Authority assumes that
-        the ```ADCS-Online-Responder``` feature has already been installed.
+        This resource can be used to install and configure an ADCS Online Responder after
+        the Windows feature has been installed on the server.
+        Using this DSC resource to configure an ADCS Online Responder assumes that the
+        'ADCS-Online-Responder' Windows feature is already installed.
+
+        ## Requirements
+            - Windows Server with Active Directory Certificate Services available.
+            - ADCSDeployment PowerShell module present on the node.
+            - 'ADCS-Online-Responder' feature installed.
+
+        ## Known issues
+            All issues are not listed here, see all open issues:
+            https://github.com/dsccommunity/ActiveDirectoryCSDsc/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+AdcsOnlineResponder
🤖 Prompt for AI Agents
In source/Classes/020.AdcsOnlineResponder.ps1 around lines 6 to 11, the
.DESCRIPTION text incorrectly refers to a "Certificate Authority" and lacks
required "Requirements" and "Known issues" sections; update the description to
say this resource installs and configures an ADCS Online Responder after the
Windows feature is installed, change wording to reference the
'ADCS-Online-Responder' Windows feature (no triple-backticks), and append a
Requirements section listing: Windows Server with AD CS available;
ADCSDeployment PowerShell module present on the node; 'ADCS-Online-Responder'
feature installed, plus a Known issues section that points to the repository
issues URL for AdcsOnlineResponder.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 (2)

248-251: DRY this by moving AfterEach to the Describe scope.

Define a single AfterEach at the Describe 'DSC_AdcsAuthorityInformationAccess_Integration' level to cover both contexts, and remove the two duplicated blocks.

Apply within these lines:

-        AfterEach {
-            Wait-ForIdleLcm
-        }

Add once inside the Describe (outside the contexts), for example right after the config import:

AfterEach {
    Wait-ForIdleLcm
}

297-300: Same here — consolidate AfterEach at Describe level.

Remove this duplicate AfterEach if you adopt a single Describe-scoped hook.

Apply within these lines:

-        AfterEach {
-            Wait-ForIdleLcm
-        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1001230 and 43ad21f.

📒 Files selected for processing (1)
  • tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

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

Build & Test Workflow

  • Run in PowerShell, from repository root
  • Build before running tests: .\build.ps1 -Tasks build
  • Always run tests in new PowerShell session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow guidelines over existing code patterns
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1
**/*.ps?(m|d)1

⚙️ CodeRabbit configuration file

**/*.ps?(m|d)1: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type (one per line) with a 1‑line description.
  • OUTPUTS: Lis...

Files:

  • tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1
**/*.[Tt]ests.ps1

⚙️ CodeRabbit configuration file

**/*.[Tt]ests.ps1: # Tests Guidelines

Core Requirements

  • All public commands, private functions and classes must have unit tests
  • All public commands and class-based resources must have integration tests
  • Use Pester v5 syntax only
  • Test code only inside Describe blocks
  • Assertions only in It blocks
  • Never test verbose messages, debug messages or parameter binding behavior
  • Pass all mandatory parameters to avoid prompts

Naming

  • One Describe block per file matching the tested entity name
  • Context descriptions start with 'When'
  • It descriptions start with 'Should', must not contain 'when'
  • Mock variables prefix: 'mock'

Structure & Scope

  • Public commands: Never use InModuleScope (unless retrieving localized strings)
  • Private functions/class resources: Always use InModuleScope
  • Each class method = separate Context block
  • Each scenario = separate Context block
  • Use nested Context blocks for complex scenarios
  • Mocking in BeforeAll (BeforeEach only when required)
  • Setup/teardown in BeforeAll,BeforeEach/AfterAll,AfterEach close to usage

Syntax Rules

  • PascalCase: Describe, Context, It, Should, BeforeAll, BeforeEach, AfterAll, AfterEach
  • Prefer -BeTrue/-BeFalse over -Be $true/-Be $false
  • Never use Assert-MockCalled, use Should -Invoke instead
  • No Should -Not -Throw - invoke commands directly
  • Never add an empty -MockWith block
  • Omit -MockWith when returning $null
  • Set $PSDefaultParameterValues for Mock:ModuleName, Should:ModuleName, InModuleScope:ModuleName
  • Omit -ModuleName parameter on Pester commands
  • Never use Mock inside InModuleScope-block

File Organization

  • Class resources: tests/Unit/Classes/{Name}.Tests.ps1
  • Public commands: tests/Unit/Public/{Name}.Tests.ps1
  • Private functions: tests/Unit/Private/{Name}.Tests.ps1

Data-Driven Tests

  • Define variables in separate BeforeDiscovery for -ForEach (close to usage)
  • -ForEach al...

Files:

  • tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1
tests/[iI]ntegration/**/*.[iI]ntegration.[tT]ests.ps1

⚙️ CodeRabbit configuration file

tests/[iI]ntegration/**/*.[iI]ntegration.[tT]ests.ps1: # Integration Tests Guidelines

Requirements

  • Location Commands: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1
  • Location Resources: tests/Integration/Resources/{ResourceName}.Integration.Tests.ps1
  • No mocking - real environment only
  • Cover all scenarios and code paths
  • Use Get-ComputerName for computer names in CI
  • Avoid ExpectedMessage for Should -Throw assertions
  • Only run integration tests in CI unless explicitly instructed.
  • Call commands with -Force parameter where applicable (avoids prompting).
  • Use -ErrorAction Stop on commands so failures surface immediately

Required Setup Block

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
param ()

BeforeDiscovery {
    try
    {
        if (-not (Get-Module -Name 'DscResource.Test'))
        {
            # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
            if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
            {
                # Redirect all streams to $null, except the error stream (stream 2)
                & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
            }

            # If the dependencies have not been resolved, this will throw an error.
            Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
        }
    }
    catch [System.IO.FileNotFoundException]
    {
        throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
    }
}

BeforeAll {
    $script:moduleName = '{MyModuleName}'

    Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop'
}

Files:

  • tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1
🧠 Learnings (1)
📓 Common learnings
Learnt from: dan-hughes
PR: dsccommunity/ActiveDirectoryCSDsc#158
File: source/Classes/020.AdcsOnlineResponder.ps1:0-0
Timestamp: 2025-08-30T18:18:31.483Z
Learning: For ADCS resources in ActiveDirectoryCSDsc, when catching exceptions from Install-Adcs* commands to determine installation state, use string matching on the exception message (e.g., `$_.Exception.ToString() -match 'OnlineResponderSetupException$'`) instead of catching specific exception types. This avoids dependency on importing types that may not be available in all environments like CI systems or DSC authoring machines.
🔇 Additional comments (1)
tests/Integration/DSC_AdcsCertificationAuthority.Integration.Tests.ps1 (1)

248-251: Solid stability improvement: waiting for LCM between tests.

This reduces flakiness from overlapping LCM runs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
source/ActiveDirectoryCSDsc.psd1 (2)

30-30: Avoid wildcard export for CmdletsToExport; use empty array

No binary cmdlets are present; wildcard hurts manifest hygiene and (slightly) perf. Prefer explicit or empty export.

-    CmdletsToExport      = '*'
+    CmdletsToExport      = @()

38-40: Explicitly export class-based DSC resources

List the new AdcsOnlineResponder to aid discovery and keep manifest explicit. Verify the class name matches exactly.

-    DscResourcesToExport = @()
+    DscResourcesToExport = @(
+        'AdcsOnlineResponder'
+    )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4ba8b9a and b0ef088.

📒 Files selected for processing (2)
  • RequiredModules.psd1 (1 hunks)
  • source/ActiveDirectoryCSDsc.psd1 (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • RequiredModules.psd1
🧰 Additional context used
📓 Path-based instructions (2)
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

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

Build & Test Workflow

  • Run in PowerShell, from repository root
  • Build before running tests: .\build.ps1 -Tasks build
  • Always run tests in new PowerShell session: Invoke-Pester -Path @({test paths}) -Output Detailed

File Organization

  • Public commands: source/Public/{CommandName}.ps1
  • Private functions: source/Private/{FunctionName}.ps1
  • Unit tests: tests/Unit/{Classes|Public|Private}/{Name}.Tests.ps1
  • Integration tests: tests/Integration/Commands/{CommandName}.Integration.Tests.ps1

Requirements

  • Follow guidelines over existing code patterns
  • Always update CHANGELOG.md Unreleased section
  • Localize all strings using string keys; remove any orphaned string keys
  • Check DscResource.Common before creating private functions
  • Separate reusable logic into private functions
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • source/ActiveDirectoryCSDsc.psd1
**/*.ps?(m|d)1

⚙️ CodeRabbit configuration file

**/*.ps?(m|d)1: # PowerShell Guidelines

Naming

  • Use descriptive names (3+ characters, no abbreviations)
  • Functions: PascalCase with Verb-Noun format using approved verbs
  • Parameters: PascalCase
  • Variables: camelCase
  • Keywords: lower-case
  • Classes: PascalCase
  • Include scope for script/global/environment variables: $script:, $global:, $env:

File naming

  • Class files: ###.ClassName.ps1 format (e.g. 001.SqlReason.ps1, 004.StartupParameters.ps1)

Formatting

Indentation & Spacing

  • Use 4 spaces (no tabs)
  • One space around operators: $a = 1 + 2
  • One space between type and variable: [String] $name
  • One space between keyword and parenthesis: if ($condition)
  • No spaces on empty lines
  • Try to limit lines to 120 characters

Braces

  • Newline before opening brace (except variable assignments)
  • One newline after opening brace
  • Two newlines after closing brace (one if followed by another brace or continuation)

Quotes

  • Use single quotes unless variable expansion is needed: 'text' vs "text $variable"

Arrays

  • Single line: @('one', 'two', 'three')
  • Multi-line: each element on separate line with proper indentation
  • Do not use the unary comma operator (,) in return statements to force
    an array

Hashtables

  • Empty: @{}
  • Each property on separate line with proper indentation
  • Properties: Use PascalCase

Comments

  • Single line: # Comment (capitalized, on own line)
  • Multi-line: <# Comment #> format (opening and closing brackets on own line), and indent text
  • No commented-out code

Comment-based help

  • Always add comment-based help to all functions and scripts
  • Comment-based help: SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections before function/class
  • Comment-based help indentation: keywords 4 spaces, text 8 spaces
  • Include examples for all parameter sets and combinations
  • INPUTS: List each pipeline‑accepted type (one per line) with a 1‑line description.
  • OUTPUTS: Lis...

Files:

  • source/ActiveDirectoryCSDsc.psd1
🧠 Learnings (1)
📓 Common learnings
Learnt from: dan-hughes
PR: dsccommunity/ActiveDirectoryCSDsc#158
File: source/Classes/020.AdcsOnlineResponder.ps1:0-0
Timestamp: 2025-08-30T18:18:31.483Z
Learning: For ADCS resources in ActiveDirectoryCSDsc, when catching exceptions from Install-Adcs* commands to determine installation state, use string matching on the exception message (e.g., `$_.Exception.ToString() -match 'OnlineResponderSetupException$'`) instead of catching specific exception types. This avoids dependency on importing types that may not be available in all environments like CI systems or DSC authoring machines.

@johlju
Copy link
Member

johlju commented Oct 16, 2025

@dan-hughes is this ready to be reviewed?

@dan-hughes
Copy link
Contributor Author

dan-hughes commented Oct 16, 2025

No, I need to test on a real system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AdcsOnlineResponder: Convert to class-based resource

2 participants