From e1e40d958da6eaba670db77f58ee21a04b6518ee Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sat, 22 May 2021 21:45:35 -0400 Subject: [PATCH 1/5] Add NewName property to xUser. --- CHANGELOG.md | 1 + README.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed838106..5d0f68ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated build to use `Sampler.GitHubTasks` - Fixes [Issue #711](https://github.com/dsccommunity/xPSDesiredStateConfiguration/issues/711). - Added support for publishing code coverage to `CodeCov.io` and Azure Pipelines - Fixes [Issue #711](https://github.com/dsccommunity/xPSDesiredStateConfiguration/issues/711). +- Added NewName property to xUser. ## [9.1.0] - 2020-02-19 diff --git a/README.md b/README.md index 6a9f90e6..59d74294 100644 --- a/README.md +++ b/README.md @@ -886,6 +886,8 @@ None * Default Value: Present * **[String] FullName** _(Write)_: Represents a string with the full name you want to use for the user account. +* **[String] NewName** _(Write)_: Represents a string with the new name you + want to use for the user account. When setting this property, the UserName property must be set appropriately to uniquely identify the user both before and after setting the SamAccountName, e.g. by SID. * **[PSCredential] Password** _(Write)_: Indicates the password you want to use for this account. * **[Boolean] PasswordChangeNotAllowed** _(Write)_: Indicates if the user can From cf2fe169647664210c15dfc80949409dc80b6495 Mon Sep 17 00:00:00 2001 From: John D Pell <52194+gaelicWizard@users.noreply.github.com> Date: Sun, 16 May 2021 21:04:36 -0400 Subject: [PATCH 2/5] xUser: Add NewName property Add NewName property to allow setting the name of the user; this requires that the UserName property be specified with something other than the SamAccountName (e.g., the SID). --- .../DSC_xUserResource/DSC_xUserResource.psm1 | 95 +++++++++++++++++++ .../DSC_xUserResource.schema.mof | 1 + 2 files changed, 96 insertions(+) diff --git a/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 b/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 index efd8962e..2c54e335 100644 --- a/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 +++ b/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 @@ -67,6 +67,9 @@ function Get-TargetResource The (optional) full name or display name of the user. If not provided this value will remain blank. + .PARAMETER NewName + Specifies the new name of the user. + .PARAMETER Description Optional description for the user. @@ -113,6 +116,10 @@ function Set-TargetResource [System.String] $FullName, + [Parameter()] + [System.String] + $NewName, + [Parameter()] [System.String] $Description, @@ -165,6 +172,9 @@ function Set-TargetResource The full name/display name that the user should have. If not provided, this value will not be tested. + .PARAMETER NewName + Specifies the new name of the user. + .PARAMETER Description The description that the user should have. If not provided, this value will not be tested. @@ -204,6 +214,10 @@ function Test-TargetResource [System.String] $FullName, + [Parameter()] + [System.String] + $NewName, + [Parameter()] [System.String] $Description, @@ -328,6 +342,9 @@ function Get-TargetResourceOnFullSKU The (optional) full name or display name of the user. If not provided this value will remain blank. + .PARAMETER NewName + Specifies the new name of the user. + .PARAMETER Description Optional description for the user. @@ -372,6 +389,10 @@ function Set-TargetResourceOnFullSKU [System.String] $FullName, + [Parameter()] + [System.String] + $NewName, + [Parameter()] [System.String] $Description, @@ -404,6 +425,10 @@ function Set-TargetResourceOnFullSKU Write-Verbose -Message ($script:localizedData.ConfigurationStarted -f $UserName) Assert-UserNameValid -UserName $UserName + if ($newName) + { + Assert-UserNameValid -UserName $NewName + } # Try to find a user by name. $principalContext = New-Object ` @@ -426,6 +451,7 @@ function Set-TargetResourceOnFullSKU $whatIfShouldProcess = $true $userExists = $false $saveChanges = $false + $needsRename = $false if ($null -eq $user) { @@ -474,6 +500,13 @@ function Set-TargetResourceOnFullSKU $saveChanges = $true } + if ($PSBoundParameters.ContainsKey('NewName') -and (($userExists) -and ($NewName -ne $user.SamAccountName))) + { + $user.SamAccountName = $NewName + $saveChanges = $true + $needsRename = $true + } + # Set the password regardless of the state of the user if ($PSBoundParameters.ContainsKey('Password')) { @@ -514,6 +547,13 @@ function Set-TargetResourceOnFullSKU { $user.Save() + if ($needsRename) + { + $dirEntry = [System.DirectoryServices.DirectoryEntry]($user.GetUnderlyingObject()) + $dirEntry.Rename($newName); + $dirEntry.CommitChanges(); + } + # Send an operation success verbose message if ($userExists) { @@ -582,6 +622,9 @@ function Set-TargetResourceOnFullSKU The full name/display name that the user should have. If not provided, this value will not be tested. + .PARAMETER NewName + Specifies the new name of the user. + .PARAMETER Description The description that the user should have. If not provided, this value will not be tested. @@ -621,6 +664,10 @@ function Test-TargetResourceOnFullSKU [System.String] $FullName, + [Parameter()] + [System.String] + $NewName, + [Parameter()] [System.String] $Description, @@ -651,6 +698,10 @@ function Test-TargetResourceOnFullSKU Set-StrictMode -Version Latest Assert-UserNameValid -UserName $UserName + if ($newName) + { + Assert-UserNameValid -UserName $NewName + } # Try to find a user by a name $principalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext ` @@ -699,6 +750,13 @@ function Test-TargetResourceOnFullSKU return $false } + if ($PSBoundParameters.ContainsKey('NewName') -and $NewName -ne $user.SamAccountName) + { + # The Name property does not match + Write-Verbose -Message ($script:localizedData.PropertyMismatch -f 'NewName', $NewName, $user.SamAccountName) + return $false + } + # Password if ($PSBoundParameters.ContainsKey('Password')) { @@ -833,6 +891,9 @@ function Get-TargetResourceOnNanoServer The (optional) full name or display name of the user. If not provided this value will remain blank. + .PARAMETER NewName + Specifies the new name of the user. + .PARAMETER Description Optional description for the user. @@ -876,6 +937,10 @@ function Set-TargetResourceOnNanoServer [System.String] $FullName, + [Parameter()] + [System.String] + $NewName, + [Parameter()] [System.String] $Description, @@ -908,6 +973,10 @@ function Set-TargetResourceOnNanoServer Write-Verbose -Message ($script:localizedData.ConfigurationStarted -f $UserName) Assert-UserNameValid -UserName $UserName + if ($newName) + { + Assert-UserNameValid -UserName $NewName + } # Try to find a user by a name. $userExists = $false @@ -977,6 +1046,14 @@ function Set-TargetResourceOnNanoServer } } + if ($PSBoundParameters.ContainsKey('NewName') -and ((-not $userExists) -or ($NewName -ne $user.SamAccountName))) + { + if ($null -ne $NewName) + { + Rename-LocalUser -Sid $UserName -NewName $NewName + } + } + # Set the password regardless of the state of the user if ($PSBoundParameters.ContainsKey('Password')) { @@ -1054,6 +1131,9 @@ function Set-TargetResourceOnNanoServer The full name/display name that the user should have. If not provided, this value will not be tested. + .PARAMETER NewName + Specifies the new name of the user. + .PARAMETER Description The description that the user should have. If not provided, this value will not be tested. @@ -1093,6 +1173,10 @@ function Test-TargetResourceOnNanoServer [System.String] $FullName, + [Parameter()] + [System.String] + $NewName, + [Parameter()] [System.String] $Description, @@ -1123,6 +1207,10 @@ function Test-TargetResourceOnNanoServer Set-StrictMode -Version Latest Assert-UserNameValid -UserName $UserName + if ($newName) + { + Assert-UserNameValid -UserName $NewName + } # Try to find a user by a name try @@ -1171,6 +1259,13 @@ function Test-TargetResourceOnNanoServer return $false } + if ($PSBoundParameters.ContainsKey('NewName') -and $NewName -ne $user.SamAccountName) + { + # The Name property does not match + Write-Verbose -Message ($script:localizedData.PropertyMismatch -f 'NewName', $NewName, $user.SamAccountName) + return $false + } + if ($PSBoundParameters.ContainsKey('Password')) { if (-not (Test-CredentialsValidOnNanoServer -UserName $UserName -Password $Password.Password)) diff --git a/source/DSCResources/DSC_xUserResource/DSC_xUserResource.schema.mof b/source/DSCResources/DSC_xUserResource/DSC_xUserResource.schema.mof index 5bb01911..51d492e5 100644 --- a/source/DSCResources/DSC_xUserResource/DSC_xUserResource.schema.mof +++ b/source/DSCResources/DSC_xUserResource/DSC_xUserResource.schema.mof @@ -4,6 +4,7 @@ class DSC_xUserResource : OMI_BaseResource [Key,Description("The name of the User to Create/Modify/Delete")] String UserName; [Write,Description("An enumerated value that describes if the user is expected to exist on the machine"),ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] String Ensure; [Write,Description("The display name of the user")] String FullName; + [Write,Description("Specifies the new name of the user")] String NewName; [Write,Description("A description for the user")] String Description; [Write,Description("The password for the user"),EmbeddedInstance("MSFT_Credential")] String Password; [Write,Description("Value used to disable/enable a user account")] Boolean Disabled; From c88fc17b57d48330bd62c764749292edc5a59222 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Thu, 20 May 2021 13:25:50 -0400 Subject: [PATCH 3/5] xUser: Test NewName parameter --- tests/Unit/DSC_xUserResource.Tests.ps1 | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Unit/DSC_xUserResource.Tests.ps1 b/tests/Unit/DSC_xUserResource.Tests.ps1 index 4c4eeebd..57cd2809 100644 --- a/tests/Unit/DSC_xUserResource.Tests.ps1 +++ b/tests/Unit/DSC_xUserResource.Tests.ps1 @@ -134,6 +134,20 @@ try Test-User -UserName $script:newUserName2 | Should -BeTrue } + It 'Should rename the user' { + Test-User -UserName $script:newUserName1 | Should -BeFalse + Set-TargetResource -UserName $script:newUserName2 ` + -NewName $script:newUserName1 + Test-User -UserName $script:newUserName1 | Should -BeTrue + } + + It 'Should rename the user again' { + Test-User -UserName $script:newUserName2 | Should -BeFalse + Set-TargetResource -UserName $script:newUserName1 ` + -NewName $script:newUserName2 + Test-User -UserName $script:newUserName2 | Should -BeTrue + } + It 'Should update the user' { $disabled = $false $passwordNeverExpires = $true @@ -212,6 +226,20 @@ try Test-User -UserName $script:newUserName2 | Should -BeTrue } + It 'Should rename the user' -Skip:$script:skipMe { + Test-User -UserName $script:newUserName1 | Should -BeFalse + Set-TargetResource -UserName $script:newUserName2 ` + -NewName $script:newUserName1 + Test-User -UserName $script:newUserName1 | Should -BeTrue + } + + It 'Should rename the user again' -Skip:$script:skipMe { + Test-User -UserName $script:newUserName2 | Should -BeFalse + Set-TargetResource -UserName $script:newUserName1 ` + -NewName $script:newUserName2 + Test-User -UserName $script:newUserName2 | Should -BeTrue + } + It 'Should update the user' -Skip:$script:skipMe { $disabled = $false $passwordNeverExpires = $true From 5f5667d6ad54a64b28318b30d045ca450496e0ab Mon Sep 17 00:00:00 2001 From: John D Pell Date: Thu, 20 May 2021 18:29:50 -0400 Subject: [PATCH 4/5] xUser: Prohibit NewName for not-existing user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don’t allow the NewName parameter to set SamAccountName when creating an entirely new user. --- .../DSC_xUserResource/DSC_xUserResource.psm1 | 9 +++++++++ .../en-US/DSC_xUserResource.strings.psd1 | 1 + 2 files changed, 10 insertions(+) diff --git a/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 b/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 index 2c54e335..1552c928 100644 --- a/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 +++ b/source/DSCResources/DSC_xUserResource/DSC_xUserResource.psm1 @@ -472,6 +472,15 @@ function Set-TargetResourceOnFullSKU if (-not $userExists) { # The user with the provided name does not exist so add a new user + foreach ($incompatibleParameterName in @( 'NewName' )) + { + if ($PSBoundParameters.ContainsKey($incompatibleParameterName)) + { + New-InvalidArgumentException -ArgumentName $incompatibleParameterName ` + -Message ($script:localizedData.NewUserNewNameConflict -f 'NewName', $incompatibleParameterName) + } + } + $user = New-Object ` -TypeName System.DirectoryServices.AccountManagement.UserPrincipal ` -ArgumentList $principalContext diff --git a/source/DSCResources/DSC_xUserResource/en-US/DSC_xUserResource.strings.psd1 b/source/DSCResources/DSC_xUserResource/en-US/DSC_xUserResource.strings.psd1 index ee860bb7..092faf73 100644 --- a/source/DSCResources/DSC_xUserResource/en-US/DSC_xUserResource.strings.psd1 +++ b/source/DSCResources/DSC_xUserResource/en-US/DSC_xUserResource.strings.psd1 @@ -12,6 +12,7 @@ ConvertFrom-StringData @' UserRemoved = User {0} removed successfully. NoConfigurationRequired = User {0} exists on this node with the desired properties. No action required. NoConfigurationRequiredUserDoesNotExist = User {0} does not exist on this node. No action required. + NewUserNewNameConflict = The {0} parameter cannot be used when creating a new user. InvalidUserName = The name {0} cannot be used. Names may not consist entirely of periods and/or spaces, or contain these characters: {1} UserExists = A user with the name {0} exists. UserDoesNotExist = A user with the name {0} does not exist. From 50d41596ead9818b5dbe0f77bd3d95beed2280ee Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sun, 23 May 2021 00:52:54 -0400 Subject: [PATCH 5/5] =?UTF-8?q?xUser:=20unit=20tests=20appear=20not=20to?= =?UTF-8?q?=20=E2=80=98unit=E2=80=99=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Unit/DSC_xUserResource.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/DSC_xUserResource.Tests.ps1 b/tests/Unit/DSC_xUserResource.Tests.ps1 index 57cd2809..e2b0233c 100644 --- a/tests/Unit/DSC_xUserResource.Tests.ps1 +++ b/tests/Unit/DSC_xUserResource.Tests.ps1 @@ -120,6 +120,7 @@ try } Mock -CommandName Test-IsNanoServer -MockWith { return $false } + #Mock -CommandName New-Object New-User -Credential $script:newCredential1 -Description $script:newUserDescription1