Skip to content

AADSyncRuleCount: Add report-only rule-count DSC resource#32

Open
raandree wants to merge 1 commit into
dsccommunity:mainfrom
raandree:feature/AadsyncrulecountResource
Open

AADSyncRuleCount: Add report-only rule-count DSC resource#32
raandree wants to merge 1 commit into
dsccommunity:mainfrom
raandree:feature/AadsyncrulecountResource

Conversation

@raandree
Copy link
Copy Markdown
Collaborator

@raandree raandree commented May 18, 2026

Pull Request (PR) description

Adds a new class-based DSC resource, AADSyncRuleCount, that verifies the number of Azure AD Connect synchronization rules against an expected value and reports drift.

Key behavior:

  • Scope: per-connector via ConnectorName, or across all connectors when ConnectorName is empty or *.
  • Report-only: Set() deliberately throws a descriptive error on drift. The resource never attempts to remediate a count difference, because automatically adding or deleting sync rules to match a number is not meaningful — drift must be investigated and resolved by an operator.
  • LCM integration: throwing in Set() causes the LCM to mark the configuration as failed, surfacing the drift in standard DSC reporting.

Changes in this PR:

  • New resource class AADSyncRuleCount.ps1.
  • Registered the resource in AADConnectDsc.psd1.
  • Added a basic example 1-AADSyncRuleCount_Basic.ps1.
  • Updated CHANGELOG.md under [Unreleased].

This Pull Request (PR) fixes the following issues

None.

Task list

  • Added an entry to the change log under the Unreleased section of the file CHANGELOG.md.
  • Resource documentation added/updated in README.md.
  • Resource parameter descriptions added/updated in README.md, 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 Community Testing Guidelines.
  • Integration tests added/updated (where possible). See DSC Community Testing Guidelines.
  • New/changed code adheres to DSC Community Style Guidelines.

This change is Reviewable

New class-based DSC resource that compares the expected number of
AAD Connect sync rules against the current state and reports drift.
Scoped per connector via ConnectorName, or across all connectors when
ConnectorName is empty or '*'. Set() throws on drift; the resource
never attempts to remediate count differences because that is not
meaningful.

Also registers the resource in the manifest, adds a basic example,
and updates CHANGELOG and the memory bank.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Review Change Stack

Walkthrough

This PR ships a new DSC resource AADSyncRuleCount to the AADConnectDsc module. The resource validates Azure AD Connect synchronization rule counts against expected values in report-only mode, supporting per-connector or global scoping via ConnectorName. It includes module export, implementation with event logging, example usage, and documentation updates.

Changes

AADSyncRuleCount DSC Resource

Layer / File(s) Summary
Module export and resource contract
source/AADConnectDsc.psd1, source/Classes/AADSyncRuleCount.ps1
Extends module manifest to export AADSyncRuleCount; introduces resource class with key ConnectorName, desired property RuleCount (uint32), and read-only CurrentRuleCount.
State verification and drift detection
source/Classes/AADSyncRuleCount.ps1
Get() retrieves current rule count via Get-ADSyncRule with optional connector filtering and null-coercion to zero; Test() compares expected vs. current with verbose output and information-level event logging.
Drift handling and event logging
source/Classes/AADSyncRuleCount.ps1
Set() implements non-remediating report-only behavior: writes error event and throws when drift detected so LCM marks configuration failed; adds helpers GetScopeDescription() and TryWriteEventLog() for safe event logging.
Usage example and release documentation
CHANGELOG.md, source/Examples/Resources/AADSyncRuleCount/1-AADSyncRuleCount_Basic.ps1, .memory-bank/activeContext.md, .memory-bank/progress.md
Adds example DSC configuration validating per-connector and global rule counts; documents resource in changelog; updates memory bank to reflect shipment on ai/aadsyncrulecount-resource branch, version bump to 0.6.0, and notes remaining unit test work.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'AADSyncRuleCount: Add report-only rule-count DSC resource' accurately and specifically summarizes the main change—adding a new DSC resource with clear description of its report-only nature.
Description check ✅ Passed The description thoroughly explains the resource's purpose, scope, behavior, and key design decision (report-only), and lists all changes included in the PR, making it directly relevant to the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
source/Examples/Resources/AADSyncRuleCount/1-AADSyncRuleCount_Basic.ps1 (1)

1-8: ⚡ Quick win

Add required script help sections before the example.

The header currently includes only .EXAMPLE. Please add at least .SYNOPSIS and .DESCRIPTION so the script-level help meets repository standards.

♻️ Suggested update
 <#
+    .SYNOPSIS
+        Demonstrates report-only validation of sync rule counts.
+
+    .DESCRIPTION
+        Shows how to validate connector-specific and global Azure AD Connect
+        synchronization rule counts using the AADSyncRuleCount DSC resource.
+
 .EXAMPLE 1
 
 Verifies that the 'contoso.com' connector has exactly 42 sync rules.
 If the actual count differs, the resource throws an error during Set
 and the LCM marks the configuration as failed. The resource never
 attempts to add or remove rules to reach the expected count.
 #>

As per coding guidelines, "Always add comment-based help to all functions and scripts" and include "SYNOPSIS, DESCRIPTION (40+ chars), PARAMETER, EXAMPLE sections".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/Examples/Resources/AADSyncRuleCount/1-AADSyncRuleCount_Basic.ps1`
around lines 1 - 8, The script example file 1-AADSyncRuleCount_Basic.ps1 only
contains a .EXAMPLE help block; add full comment-based help by inserting at the
top a .SYNOPSIS (one-line summary) and a .DESCRIPTION (40+ characters) above or
adjacent to the existing .EXAMPLE, and also include PARAMETER stubs if the
script accepts parameters so the help meets repository standards; ensure the new
help uses the PowerShell comment-based help keywords (.SYNOPSIS, .DESCRIPTION,
.PARAMETER, .EXAMPLE) and describes the purpose (e.g., verifying contoso.com has
42 sync rules) without changing the example logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.memory-bank/progress.md:
- Around line 25-27: Change the three numbered list items so they all use the
1/1/1 ordered-list numbering style: replace the leading "1.", "2.", "3." before
"Unit tests for AADSyncRuleCount (mock Get-ADSyncRule)", "Markdown lint sweep
across docs/ — minor formatting drift", and "Link validation for
internal/external links in README.md and" so each line begins with "1." to
satisfy MD029 and the project's Markdown guideline.

In `@source/Classes/AADSyncRuleCount.ps1`:
- Around line 38-44: Replace hardcoded user-facing and diagnostic strings in the
AADSyncRuleCount class (the Write-Verbose calls and TryWriteEventLog invocations
that produce the information/warning messages) with localized string keys and
lookup calls; e.g., introduce/consume a localization helper (Get-LocalizedString
or $this.Localize) and pass the RuleCount, scope, and CurrentRuleCount as format
arguments to that helper instead of embedding values in literal strings, and
update the other occurrences noted (the messages at the other
Write-Verbose/TryWriteEventLog sites referenced in the comment) to use the same
localization keys and helper so all
Write-Debug/Write-Verbose/Write-Error/Write-Warning and event log messages are
sourced from localized resources.
- Around line 1-105: Add unit and integration tests for the new DSC resource
AADSyncRuleCount: write unit tests that exercise AADSyncRuleCount::Test, ::Get,
::Set, ::GetScopeDescription and ::TryWriteEventLog using mocked Get-ADSyncRule
and Write-AADConnectEventLog to cover scenarios (all connectors vs specific
ConnectorName, zero rules, non-zero rules, and exception path when writing event
log), and add integration tests that deploy the resource to a test LCM/AD
Connect environment to validate behavior end-to-end (expected count, drift error
thrown by Set, and event log entries with EventId 1100–1102).
- Around line 1-3: Update the AADSyncRuleCount DSC resource to follow the DSC
class pattern: change the class attribute to [DscResource(RunAsCredential =
'Optional')], inherit from ResourceBase (class AADSyncRuleCount : ResourceBase)
and implement the required constructor that calls the base ctor; refactor the
Test(), Get(), and Set() methods to call the corresponding base class
implementations (e.g., base.Test(), base.Get(), base.Set()) as part of their
workflows; replace hardcoded Write-Verbose and error strings in methods (lines
referenced in the review) with localized messages (use the existing localization
mechanism used in other resources); and replace the raw throw $message on
failure in Set() with the appropriate New-*Exception cmdlet (e.g.,
New-ItemStateChangeException or the project-standard New-*-Exception helper)
while including the localized message.
- Around line 80-82: Replace the raw "throw $message" with a typed exception
created by New-InvalidOperationException to comply with class DSC resource
rules: after calling $this.TryWriteEventLog('Error', 1102, $message) change the
termination to "throw (New-InvalidOperationException -Message $message)" (or
equivalent New-*Exception helper) so the resource (AADSyncRuleCount class/method
using $this.TryWriteEventLog and throw $message) raises a proper
InvalidOperationException rather than a raw throw.

---

Nitpick comments:
In `@source/Examples/Resources/AADSyncRuleCount/1-AADSyncRuleCount_Basic.ps1`:
- Around line 1-8: The script example file 1-AADSyncRuleCount_Basic.ps1 only
contains a .EXAMPLE help block; add full comment-based help by inserting at the
top a .SYNOPSIS (one-line summary) and a .DESCRIPTION (40+ characters) above or
adjacent to the existing .EXAMPLE, and also include PARAMETER stubs if the
script accepts parameters so the help meets repository standards; ensure the new
help uses the PowerShell comment-based help keywords (.SYNOPSIS, .DESCRIPTION,
.PARAMETER, .EXAMPLE) and describes the purpose (e.g., verifying contoso.com has
42 sync rules) without changing the example logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69d767b1-23c9-4f7b-9201-64d772b5738c

📥 Commits

Reviewing files that changed from the base of the PR and between 91d5a6a and 35d00a2.

📒 Files selected for processing (6)
  • .memory-bank/activeContext.md
  • .memory-bank/progress.md
  • CHANGELOG.md
  • source/AADConnectDsc.psd1
  • source/Classes/AADSyncRuleCount.ps1
  • source/Examples/Resources/AADSyncRuleCount/1-AADSyncRuleCount_Basic.ps1

Comment thread .memory-bank/progress.md
Comment on lines +25 to +27
1. **Unit tests** for ``AADSyncRuleCount`` (mock ``Get-ADSyncRule``).
2. **Markdown lint sweep** across ``docs/`` — minor formatting drift.
3. **Link validation** for internal/external links in ``README.md`` and
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use 1/1/1 ordered-list numbering to satisfy markdown rules.

This section currently uses 1., 2., 3. and triggers MD029 warnings.

✅ Minimal fix
-1. **Unit tests** for ``AADSyncRuleCount`` (mock ``Get-ADSyncRule``).
-2. **Markdown lint sweep** across ``docs/`` — minor formatting drift.
-3. **Link validation** for internal/external links in ``README.md`` and
+1. **Unit tests** for ``AADSyncRuleCount`` (mock ``Get-ADSyncRule``).
+1. **Markdown lint sweep** across ``docs/`` — minor formatting drift.
+1. **Link validation** for internal/external links in ``README.md`` and

As per coding guidelines, Markdown requires "Use '1.' for all items in ordered lists (1/1/1 numbering style)".

📝 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
1. **Unit tests** for ``AADSyncRuleCount`` (mock ``Get-ADSyncRule``).
2. **Markdown lint sweep** across ``docs/`` — minor formatting drift.
3. **Link validation** for internal/external links in ``README.md`` and
1. **Unit tests** for ``AADSyncRuleCount`` (mock ``Get-ADSyncRule``).
1. **Markdown lint sweep** across ``docs/`` — minor formatting drift.
1. **Link validation** for internal/external links in ``README.md`` and
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 26-26: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1

(MD029, ol-prefix)


[warning] 27-27: Ordered list item prefix
Expected: 1; Actual: 3; Style: 1/1/1

(MD029, ol-prefix)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.memory-bank/progress.md around lines 25 - 27, Change the three numbered
list items so they all use the 1/1/1 ordered-list numbering style: replace the
leading "1.", "2.", "3." before "Unit tests for AADSyncRuleCount (mock
Get-ADSyncRule)", "Markdown lint sweep across docs/ — minor formatting drift",
and "Link validation for internal/external links in README.md and" so each line
begins with "1." to satisfy MD029 and the project's Markdown guideline.

Comment on lines +1 to +105
[DscResource()]
class AADSyncRuleCount
{
<#
.SYNOPSIS
Verifies the number of Azure AD Connect synchronization rules.

.DESCRIPTION
Read-only / report-only DSC resource that compares the expected
number of AAD Connect sync rules against the current state and
reports a drift if they differ. The resource never attempts to
remediate drift because creating or removing rules to match a
count is not a meaningful operation; the user must investigate
and reconcile manually.

Use `ConnectorName` to scope the count to a specific connector.
Leave `ConnectorName` empty (or set it to `*`) to count every
sync rule across all connectors.
#>

# `ConnectorName` is the key. Empty string or '*' means "all connectors".
[DscProperty(Key = $true)]
[string]$ConnectorName

[DscProperty(Mandatory = $true)]
[uint32]$RuleCount

[DscProperty(NotConfigurable)]
[uint32]$CurrentRuleCount

[bool]Test()
{
$currentState = $this.Get()
$scope = $this.GetScopeDescription()

if ($currentState.CurrentRuleCount -eq $this.RuleCount)
{
Write-Verbose -Message "AADSyncRuleCount: $scope has the expected $($this.RuleCount) sync rule(s)."
$this.TryWriteEventLog('Information', 1100, "AADSyncRuleCount in desired state for $scope (count=$($this.RuleCount)).")
return $true
}

Write-Verbose -Message "AADSyncRuleCount: $scope has $($currentState.CurrentRuleCount) sync rule(s) but expected $($this.RuleCount)."
$this.TryWriteEventLog('Warning', 1101, "AADSyncRuleCount drift for $scope. Expected=$($this.RuleCount); Current=$($currentState.CurrentRuleCount).")
return $false
}

[AADSyncRuleCount]Get()
{
$currentState = [AADSyncRuleCount]::new()
$currentState.ConnectorName = $this.ConnectorName
$currentState.RuleCount = $this.RuleCount

$rules = if ([string]::IsNullOrEmpty($this.ConnectorName) -or $this.ConnectorName -eq '*')
{
Get-ADSyncRule
}
else
{
Get-ADSyncRule -ConnectorName $this.ConnectorName
}

# Get-ADSyncRule may return $null when no rules match; coerce to 0.
$currentState.CurrentRuleCount = if ($null -eq $rules) { 0 } else { @($rules).Count }

return $currentState
}

[void]Set()
{
# This resource is report-only. Adjusting the rule count automatically
# is not safe and not meaningful — the operator must investigate which
# rules are missing or extra. Throw a clear error so the LCM marks the
# configuration as failed.

$currentState = $this.Get()
$scope = $this.GetScopeDescription()
$message = "AADSyncRuleCount drift detected for $scope. Expected $($this.RuleCount) sync rule(s) but found $($currentState.CurrentRuleCount). This resource does not remediate count drift; investigate the AAD Connect configuration manually."

$this.TryWriteEventLog('Error', 1102, $message)
throw $message
}

hidden [string]GetScopeDescription()
{
if ([string]::IsNullOrEmpty($this.ConnectorName) -or $this.ConnectorName -eq '*')
{
return "all connectors"
}

return "connector '$($this.ConnectorName)'"
}

hidden [void]TryWriteEventLog([string]$EventType, [int]$EventId, [string]$Message)
{
try
{
Write-AADConnectEventLog -EventType $EventType -EventId $EventId -Message $Message -ConnectorName $this.ConnectorName
}
catch
{
Write-Verbose -Message "Failed to write event log entry: $($_.Exception.Message)"
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Add unit and integration tests for the new resource before merge.

This PR adds a new DSC resource, but no corresponding resource tests are included in the reviewed changes.

As per coding guidelines, Add unit tests for all commands/functions/resources and Add integration tests for all public commands and resources.

🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)

[warning] Missing BOM encoding for non-ASCII encoded file 'AADSyncRuleCount.ps1'

(PSUseBOMForUnicodeEncodedFile)


[info] 1-105: No examples found for resource 'AADSyncRuleCount'

(PSDSCDscExamplesPresent)


[info] 1-105: No tests found for resource 'AADSyncRuleCount'

(PSDSCDscTestsPresent)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/Classes/AADSyncRuleCount.ps1` around lines 1 - 105, Add unit and
integration tests for the new DSC resource AADSyncRuleCount: write unit tests
that exercise AADSyncRuleCount::Test, ::Get, ::Set, ::GetScopeDescription and
::TryWriteEventLog using mocked Get-ADSyncRule and Write-AADConnectEventLog to
cover scenarios (all connectors vs specific ConnectorName, zero rules, non-zero
rules, and exception path when writing event log), and add integration tests
that deploy the resource to a test LCM/AD Connect environment to validate
behavior end-to-end (expected count, drift error thrown by Set, and event log
entries with EventId 1100–1102).

Comment on lines +1 to +3
[DscResource()]
class AADSyncRuleCount
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file being reviewed
cat -n source/Classes/AADSyncRuleCount.ps1

Repository: dsccommunity/AADConnectDsc

Length of output: 4633


🏁 Script executed:

# Check if ResourceBase exists in the module
fd -type f "ResourceBase" source/

Repository: dsccommunity/AADConnectDsc

Length of output: 241


🏁 Script executed:

# Check for existing DSC resources in the module to understand the pattern
find source/Classes -name "*.ps1" -type f | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && head -15 {}'

Repository: dsccommunity/AADConnectDsc

Length of output: 1810


Restructure resource to follow the required DSC class pattern.

The resource deviates from mandatory guidelines: missing RunAsCredential decoration, ResourceBase inheritance, required constructor, and base method calls. Additionally, hardcoded strings violate localization requirements, and line 81 uses throw instead of New-*Exception for error handling.

Per coding guidelines:

  • Line 1: Change [DscResource()] to [DscResource(RunAsCredential = 'Optional')]
  • Line 2: Add : ResourceBase inheritance and implement required constructor
  • Lines 31-67, 69-82: Restructure Test(), Get(), Set() to call base class implementations
  • Lines 38, 43, 78, 81, 102: Localize hardcoded Write-Verbose and error messages
  • Line 81: Replace throw $message with appropriate New-*Exception command
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)

[warning] Missing BOM encoding for non-ASCII encoded file 'AADSyncRuleCount.ps1'

(PSUseBOMForUnicodeEncodedFile)


[info] 1-105: No examples found for resource 'AADSyncRuleCount'

(PSDSCDscExamplesPresent)


[info] 1-105: No tests found for resource 'AADSyncRuleCount'

(PSDSCDscTestsPresent)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/Classes/AADSyncRuleCount.ps1` around lines 1 - 3, Update the
AADSyncRuleCount DSC resource to follow the DSC class pattern: change the class
attribute to [DscResource(RunAsCredential = 'Optional')], inherit from
ResourceBase (class AADSyncRuleCount : ResourceBase) and implement the required
constructor that calls the base ctor; refactor the Test(), Get(), and Set()
methods to call the corresponding base class implementations (e.g., base.Test(),
base.Get(), base.Set()) as part of their workflows; replace hardcoded
Write-Verbose and error strings in methods (lines referenced in the review) with
localized messages (use the existing localization mechanism used in other
resources); and replace the raw throw $message on failure in Set() with the
appropriate New-*Exception cmdlet (e.g., New-ItemStateChangeException or the
project-standard New-*-Exception helper) while including the localized message.

Comment on lines +38 to +44
Write-Verbose -Message "AADSyncRuleCount: $scope has the expected $($this.RuleCount) sync rule(s)."
$this.TryWriteEventLog('Information', 1100, "AADSyncRuleCount in desired state for $scope (count=$($this.RuleCount)).")
return $true
}

Write-Verbose -Message "AADSyncRuleCount: $scope has $($currentState.CurrentRuleCount) sync rule(s) but expected $($this.RuleCount)."
$this.TryWriteEventLog('Warning', 1101, "AADSyncRuleCount drift for $scope. Expected=$($this.RuleCount); Current=$($currentState.CurrentRuleCount).")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Localize all user-facing and diagnostic messages.

Hardcoded strings are used in Write-Verbose and drift/event messages (Line 38, Line 43, Line 78, Line 102). These should come from localized string keys.

As per coding guidelines, Localize all Write-Debug, Write-Verbose, Write-Error, Write-Warning and $PSCmdlet.ThrowTerminatingError() messages and Use localized string keys, not hardcoded strings.

Also applies to: 78-78, 102-102

🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)

[warning] Missing BOM encoding for non-ASCII encoded file 'AADSyncRuleCount.ps1'

(PSUseBOMForUnicodeEncodedFile)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/Classes/AADSyncRuleCount.ps1` around lines 38 - 44, Replace hardcoded
user-facing and diagnostic strings in the AADSyncRuleCount class (the
Write-Verbose calls and TryWriteEventLog invocations that produce the
information/warning messages) with localized string keys and lookup calls; e.g.,
introduce/consume a localization helper (Get-LocalizedString or $this.Localize)
and pass the RuleCount, scope, and CurrentRuleCount as format arguments to that
helper instead of embedding values in literal strings, and update the other
occurrences noted (the messages at the other Write-Verbose/TryWriteEventLog
sites referenced in the comment) to use the same localization keys and helper so
all Write-Debug/Write-Verbose/Write-Error/Write-Warning and event log messages
are sourced from localized resources.

Comment on lines +80 to +82
$this.TryWriteEventLog('Error', 1102, $message)
throw $message
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

head -100 source/Classes/AADSyncRuleCount.ps1 | cat -n

Repository: dsccommunity/AADConnectDsc

Length of output: 4476


🏁 Script executed:

wc -l source/Classes/AADSyncRuleCount.ps1

Repository: dsccommunity/AADConnectDsc

Length of output: 110


🏁 Script executed:

sed -n '70,90p' source/Classes/AADSyncRuleCount.ps1 | cat -n

Repository: dsccommunity/AADConnectDsc

Length of output: 1107


🏁 Script executed:

grep -n "throw " source/Classes/AADSyncRuleCount.ps1

Repository: dsccommunity/AADConnectDsc

Length of output: 96


🏁 Script executed:

# Check if New-InvalidOperationException is available/used in this codebase
find source -name "*.ps1" -type f -exec grep -l "New-InvalidOperationException" {} \;

Repository: dsccommunity/AADConnectDsc

Length of output: 52


🏁 Script executed:

# Check what DscResource.Common functions are imported or referenced
grep -r "New-.*Exception" source --include="*.ps1" | head -20

Repository: dsccommunity/AADConnectDsc

Length of output: 52


🏁 Script executed:

# Check the module manifest for DscResource.Common dependencies
cat source/*.psd1 | grep -A 20 "RequiredModules"

Repository: dsccommunity/AADConnectDsc

Length of output: 947


🏁 Script executed:

# Check if there are any imports at the top of the file
head -20 source/Classes/AADSyncRuleCount.ps1

Repository: dsccommunity/AADConnectDsc

Length of output: 848


🏁 Script executed:

# Check if this module has any base classes or parent references
grep -n "inherit" source/Classes/AADSyncRuleCount.ps1

Repository: dsccommunity/AADConnectDsc

Length of output: 52


🏁 Script executed:

# Check the psm1 file to see what's imported
head -50 source/AADConnectDsc.psm1 | grep -i "function\|require\|import\|module"

Repository: dsccommunity/AADConnectDsc

Length of output: 152


🏁 Script executed:

# Check if there are other class-based resources in the source/Classes directory
find source/Classes -name "*.ps1" -type f

Repository: dsccommunity/AADConnectDsc

Length of output: 378


🏁 Script executed:

# Check if the module uses DscResource.Base or DscResource.Common in any way
grep -r "DscResource\|ResourceBase" source --include="*.ps1"

Repository: dsccommunity/AADConnectDsc

Length of output: 1172


🏁 Script executed:

# Check if this is actually an issue by looking at similar projects
# First, let's see what other classes exist
ls -la source/Classes/

Repository: dsccommunity/AADConnectDsc

Length of output: 772


🏁 Script executed:

# Check the Prefix.ps1 file to see DscResource.Common loading
cat source/Prefix.ps1 | head -30

Repository: dsccommunity/AADConnectDsc

Length of output: 234


🏁 Script executed:

# Check if the DscResource.Common module exists in the Modules directory
ls -la source/Modules/

Repository: dsccommunity/AADConnectDsc

Length of output: 133


🏁 Script executed:

# Check what exception helpers are available in DscResource.Common
find source/Modules/DscResource.Common -name "*.ps1" -type f | grep -i exception

Repository: dsccommunity/AADConnectDsc

Length of output: 139


🏁 Script executed:

# Let's verify the coding guideline applies to this class specifically
# Check if the class has [DscResource(...)] decoration
grep -A 2 "^class AADSyncRuleCount" source/Classes/AADSyncRuleCount.ps1

Repository: dsccommunity/AADConnectDsc

Length of output: 102


🏁 Script executed:

# Check the context around line 81 to understand the error scenario
sed -n '69,82p' source/Classes/AADSyncRuleCount.ps1 | cat -n

Repository: dsccommunity/AADConnectDsc

Length of output: 879


🏁 Script executed:

# Search for how other DSC resources in this repo handle errors
grep -r "New-InvalidOperationException\|New-InvalidDataException\|throw" source/Classes/*.ps1 | head -20

Repository: dsccommunity/AADConnectDsc

Length of output: 129


Replace raw throw with New-InvalidOperationException.

Line 81 uses throw $message in a class resource with [DscResource()] decoration. Per the coding guidelines, class resources must use New-InvalidOperationException (or another appropriate New-*Exception helper) instead of raw throw for terminating errors.

Since this resource is report-only and cannot remediate drift, New-InvalidOperationException is the appropriate exception type for this scenario.

🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)

[warning] Missing BOM encoding for non-ASCII encoded file 'AADSyncRuleCount.ps1'

(PSUseBOMForUnicodeEncodedFile)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/Classes/AADSyncRuleCount.ps1` around lines 80 - 82, Replace the raw
"throw $message" with a typed exception created by New-InvalidOperationException
to comply with class DSC resource rules: after calling
$this.TryWriteEventLog('Error', 1102, $message) change the termination to "throw
(New-InvalidOperationException -Message $message)" (or equivalent New-*Exception
helper) so the resource (AADSyncRuleCount class/method using
$this.TryWriteEventLog and throw $message) raises a proper
InvalidOperationException rather than a raw throw.

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.

1 participant