ComputerManagementDsc icon indicating copy to clipboard operation
ComputerManagementDsc copied to clipboard

Computer: Remove deletion of AD computer object when using PasswordPass and UnsecuredJoin options or JoinReadOnly option

Open webalexeu opened this issue 9 months ago • 6 comments

Pull Request (PR) description

When using PasswordPass and UnsecuredJoin options or JoinReadOnly option means AD computer object has been pre-created within Active Directory prior to domain join and should not be deleted

This Pull Request (PR) fixes the following issues

  • Fixes #446

Task list

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

This change is Reviewable

webalexeu avatar May 16 '25 15:05 webalexeu

Walkthrough

The changes modify the DSC_Computer resource to conditionally preserve pre-created Active Directory computer objects when using specific options (PasswordPass and UnsecuredJoin or JoinReadOnly), preventing deletion during domain join operations that expect the object to already exist.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md
Added entry documenting that the computer object is no longer deleted when PasswordPass and UnsecuredJoin options or JoinReadOnly option are used (Issue #446).
Resource Logic
source/DSCResources/DSC_Computer/DSC_Computer.psm1
Introduces conditional logic to detect precreated computer object requirements via $requiresPrecreated based on JoinReadOnly or (PasswordPass and UnsecuredJoin) options. When precreation is required and object doesn't exist, raises ObjectNotFoundException. When precreation is not required and object exists, proceeds with deletion. Includes minor comment correction.
Localization
source/DSCResources/DSC_Computer/en-US/DSC_Computer.strings.psd1
Added new string resource ComputerObjectNotFound for localized error message when computer object is not found in domain.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as DSC Configuration
    participant Resource as DSC_Computer<br/>(Set-TargetResource)
    participant AD as Active Directory
    participant Error as Error Handler

    Caller->>Resource: Invoke Set-TargetResource
    
    Note over Resource: Detect precreated requirement<br/>($requiresPrecreated = JoinReadOnly OR<br/>(PasswordPass AND UnsecuredJoin))
    
    Resource->>AD: Query for existing computer object
    alt Object Exists
        alt Precreation NOT Required
            Resource->>AD: Delete computer object
            Resource->>Caller: ✓ Proceed with join
        else Precreation Required
            Resource->>Caller: ✓ Object exists, continue
        end
    else Object Does NOT Exist
        alt Precreation Required
            Resource->>Error: Raise ObjectNotFoundException
            Error->>Caller: ✗ Computer object not found error
        else Precreation NOT Required
            Resource->>Caller: ✓ Proceed (no deletion needed)
        end
    end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes introduce a new conditional control flow with multiple branches based on precreation detection and object existence, requiring careful verification that the option combinations and error conditions are correct. The logic is focused but depends on accurate interpretation of the PasswordPass, UnsecuredJoin, and JoinReadOnly options.

Pre-merge checks

✅ Passed checks (5 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly identifies the resource and concisely describes the primary change of preventing deletion of the AD computer object when using the specified options, directly reflecting the main focus of the changeset.
Linked Issues Check ✅ Passed The changes implement logic to detect and preserve pre-created AD computer objects when using PasswordPass, UnsecuredJoin, or JoinReadOnly options and add corresponding error handling and localization, fully satisfying the objectives of linked issue #446.
Out of Scope Changes Check ✅ Passed All modifications are confined to adjusting the computer resource behavior for pre-created objects and updating related localization and documentation, with no unrelated or extraneous changes introduced.
Description Check ✅ Passed The description succinctly explains the rationale behind the change, clarifies that pre-created AD computer objects should not be deleted when using the specified options, and references the related issue, making it clearly relevant to the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17e10f3b5c778db2c5cde0848888ca8fbe3af2a5 and 06fe4cbf82abfc3f3eddda461adf215750184a0b.

📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • source/DSCResources/DSC_Computer/DSC_Computer.psm1 (1 hunks)
  • source/DSCResources/DSC_Computer/en-US/DSC_Computer.strings.psd1 (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**

⚙️ CodeRabbit configuration file

**: # DSC Community Guidelines

Terminology

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

Build & Test Workflow Requirements

  • Run PowerShell script files from repository root
  • Setup build and test environment (once per pwsh session): ./build.ps1 -Tasks noop
  • Build project before running tests: ./build.ps1 -Tasks build
  • Always run tests in new pwsh 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 instructions over existing code patterns
  • Follow PowerShell style and test guideline instructions strictly
  • 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
  • DSC resources should always be created as class-based resources
  • Add unit tests for all commands/functions/resources
  • Add integration tests for all public commands and resources

Files:

  • source/DSCResources/DSC_Computer/en-US/DSC_Computer.strings.psd1
  • source/DSCResources/DSC_Computer/DSC_Computer.psm1
  • CHANGELOG.md
{**/*.ps1,**/*.psm1,**/*.psd1}

⚙️ CodeRabbit configuration file

{**/*.ps1,**/*.psm1,**/*.psd1}: # 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...

Files:

  • source/DSCResources/DSC_Computer/en-US/DSC_Computer.strings.psd1
  • source/DSCResources/DSC_Computer/DSC_Computer.psm1
source/DSCResources/**/*.psm1

⚙️ CodeRabbit configuration file

source/DSCResources/**/*.psm1: # MOF-based Desired State Configuration (DSC) Resources Guidelines

Required Functions

  • Every DSC resource must define: Get-TargetResource, Set-TargetResource, Test-TargetResource
  • Export using *-TargetResource pattern

Function Return Types

  • Get-TargetResource: Must return hashtable with all resource properties
  • Test-TargetResource: Must return boolean ($true/$false)
  • Set-TargetResource: Must not return anything (void)

Parameter Guidelines

  • Get-TargetResource: Only include parameters needed to retrieve actual current state values
  • Get-TargetResource: Remove non-mandatory parameters that are never used
  • Set-TargetResource and Test-TargetResource: Must have identical parameters
  • Set-TargetResource and Test-TargetResource: Unused mandatory parameters: Add "Not used in <function_name>" to help comment

Required Elements

  • Each function must include Write-Verbose at least once
    • Get-TargetResource: Use verbose message starting with "Getting the current state of..."
    • Set-TargetResource: Use verbose message starting with "Setting the desired state of..."
    • Test-TargetResource: Use verbose message starting with "Determining the current state of..."
  • Use localized strings for all messages (Write-Verbose, Write-Error, etc.)
  • Import localized strings using Get-LocalizedData at module top

Error Handling

Files:

  • source/DSCResources/DSC_Computer/DSC_Computer.psm1
**/*.md

⚙️ CodeRabbit configuration file

**/*.md: # Markdown Style Guidelines

  • Wrap lines at word boundaries when over 80 characters (except tables/code blocks)
  • Use 2 spaces for indentation
  • Use '1.' for all items in ordered lists (1/1/1 numbering style)
  • Disable MD013 rule by adding a comment for tables/code blocks exceeding 80 characters
  • Empty lines required before/after code blocks and headings (except before line 1)
  • Escape backslashes in file paths only (not in code blocks)
  • Code blocks must specify language identifiers

Text Formatting

  • Parameters: bold
  • Values/literals: inline code
  • Resource/module/product names: italic
  • Commands/files/paths: inline code

Files:

  • CHANGELOG.md
CHANGELOG.md

⚙️ CodeRabbit configuration file

CHANGELOG.md: # Changelog Guidelines

  • Always update the Unreleased section in CHANGELOG.md
  • Use Keep a Changelog format
  • Describe notable changes briefly, ≤2 items per change type
  • Reference issues using format issue #<issue_number>
  • No empty lines between list items in same section
  • Skip adding entry if same change already exists in Unreleased section
  • No duplicate sections or items in Unreleased section

Files:

  • CHANGELOG.md
⏰ 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). (1)
  • GitHub Check: dsccommunity.ComputerManagementDsc (Build Package Module)

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.

coderabbitai[bot] avatar Sep 03 '25 19:09 coderabbitai[bot]

Codecov Report

:x: Patch coverage is 71.42857% with 2 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 86%. Comparing base (17e10f3) to head (06fe4cb).

Files with missing lines Patch % Lines
source/DSCResources/DSC_Computer/DSC_Computer.psm1 71% 2 Missing :warning:
Additional details and impacted files

Impacted file tree graph

@@         Coverage Diff         @@
##           main   #447   +/-   ##
===================================
- Coverage    86%    86%   -1%     
===================================
  Files        21     21           
  Lines      2083   2088    +5     
===================================
+ Hits       1805   1808    +3     
- Misses      278    280    +2     
Files with missing lines Coverage Δ
source/DSCResources/DSC_Computer/DSC_Computer.psm1 89% <71%> (-1%) :arrow_down:
:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov[bot] avatar Sep 04 '25 11:09 codecov[bot]

[!NOTE] Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

coderabbitai[bot] avatar Sep 04 '25 17:09 coderabbitai[bot]

[!NOTE] Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

coderabbitai[bot] avatar Sep 04 '25 18:09 coderabbitai[bot]

[!CAUTION] CodeRabbit failed during planning: Script execution failed: Command failed with exit code 1: jk_chrootlaunch --jail /inmem/6553/21e489e2-4643-4d6d-bc9c-97f5bf37d490 --group jailuser --user jailuser --exec /usr/bin/env -- '/bin/bash --norc --noprofile -c "cd '''/home/jailuser/git''' && bash -x /.coderabbit_commands_65c9413d-5e6e-4cf9-9c9f-9d6d60f7e1e3.sh"'

  • set -euo pipefail
  • test_file=tests/Unit/DSC_Computer.Tests.ps1
  • sed -i '/^Describe '''DSC_Computer\Test-TargetResource''' {$/,/^}$/ { /^(}\s*)$/!b }' tests/Unit/DSC_Computer.Tests.ps1
  • sed -i '/^}\s*$/{ h }' tests/Unit/DSC_Computer.Tests.ps1
  • sed -i '/^Describe '''DSC_Computer\Get-TargetResource''' {/i
    \ Context '''When description parameter is empty but current description is empty''' {\n\ BeforeAll {\n\ Mock -CommandName Get-CimInstance -MockWith {\n\ [PSCustomObject] @{ Description = "" }\n\ }\n\ }\n\n\ BeforeDiscovery {\n\ $testCases = @(\n\ @{ Name = $env:COMPUTERNAME }\n\ @{ Name = '''localhost''' }\n\ )\n\ }\n\n\ It '''Should return $true when Name is <Name>''' -ForEach $testCases {\n\ InModuleScope -Parameters $_ -ScriptBlock {\n\ Set-StrictMode -Version 1.0\n\n\ $testTargetParams = @{ Name = $Name; Description = "" }\n\ Test-TargetResource @testTargetParams | Should -BeTrue\n\ }\n\ }\n\ }\n\n\ Context '''When Domain is specified with empty username credential''' {\n\ It '''Should throw correct error''' {\n\ InModuleScope -ScriptBlock {\n\ Set-StrictMode -Version 1.0\n\n\ $secure = New-Object -Type SecureString\n\ $emptyUserCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ,$secure\n\n\ $errorRecord = Get-InvalidArgumentRecord \n\ -Message ($LocalizedData.CredentialsNotSpecifiedError) \n\ -ArgumentName '''Credentials'''\n\n\ $testTargetParams = @{ Name = $env:COMPUTERNAME; DomainName = '''contoso.com'''; Credential = $emptyUserCred }\n\ { Test-TargetResource @testTargetParams } | Should -Throw -ExpectedMessage $errorRecord\n\ }\n\ }\n\ }\n' tests/Unit/DSC_Computer.Tests.ps1
  • sed -i '/^\sIt '''Should return a hashtable containing Name, DomainName, JoinOU, CurrentOU, Credential, UnjoinCredential, WorkGroupName and Description''' {/,/^\s}\s*$/ { /}\s*$/a
    \ It '''Should return expected types for core properties''' {\n\ InModuleScope -ScriptBlock {\n\ Set-StrictMode -Version 1.0\n\n\ $getTargetParams = @{ Name = $env:COMPUTERNAME }\n\ $result = Get-TargetResource @getTargetParams\n\ ($result.Name -is [string]) | Should -BeTrue\n\ $result.ContainsKey(Credential) | Should -BeTrue\n\ if ($null -ne $result.Credential) { ($result.Credential -is [System.Management.Automation.PSCredential]) | Should -BeTrue }\n\ $result.ContainsKey(UnjoinCredential) | Should -BeTrue\n\ if ($null -ne $result.UnjoinCredential) { ($result.UnjoinCredential -is [System.Management.Automation.PSCredential]) | Should -BeTrue }\n\ }\n\ }\n} ' tests/Unit/DSC_Computer.Tests.ps1 sed: -e expression #1, char 0: unmatched `{'

coderabbitai[bot] avatar Sep 04 '25 18:09 coderabbitai[bot]

[!CAUTION] CodeRabbit timed out while planning changes for Tests/CHANGELOG.Tests.ps1. Skipping this file.

coderabbitai[bot] avatar Sep 04 '25 18:09 coderabbitai[bot]