DSCResources/MSFT_xADUser/MSFT_xADUser.psm1
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUserNameAndPassWordParams', '')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "PasswordAuthentication")] param() $script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent $script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules' $script:localizationModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'xActiveDirectory.Common' Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath 'xActiveDirectory.Common.psm1') $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_xADUser' # Create a property map that maps the DSC resource parameters to the # Active Directory user attributes. $adPropertyMap = @( @{ Parameter = 'CommonName' ADProperty = 'cn' } @{ Parameter = 'UserPrincipalName' } @{ Parameter = 'DisplayName' } @{ Parameter = 'Path' ADProperty = 'distinguishedName' } @{ Parameter = 'GivenName' } @{ Parameter = 'Initials' } @{ Parameter = 'Surname' ADProperty = 'sn' } @{ Parameter = 'Description' } @{ Parameter = 'StreetAddress' } @{ Parameter = 'POBox' } @{ Parameter = 'City' ADProperty = 'l' } @{ Parameter = 'State' ADProperty = 'st' } @{ Parameter = 'PostalCode' } @{ Parameter = 'Country' ADProperty = 'c' } @{ Parameter = 'Department' } @{ Parameter = 'Division' } @{ Parameter = 'Company' } @{ Parameter = 'Office' ADProperty = 'physicalDeliveryOfficeName' } @{ Parameter = 'JobTitle' ADProperty = 'title' } @{ Parameter = 'EmailAddress' ADProperty = 'mail' } @{ Parameter = 'EmployeeID' } @{ Parameter = 'EmployeeNumber' } @{ Parameter = 'HomeDirectory' } @{ Parameter = 'HomeDrive' } @{ Parameter = 'HomePage' ADProperty = 'wWWHomePage' } @{ Parameter = 'ProfilePath' } @{ Parameter = 'LogonScript' ADProperty = 'scriptPath' } @{ Parameter = 'Notes' ADProperty = 'info' } @{ Parameter = 'OfficePhone' ADProperty = 'telephoneNumber' } @{ Parameter = 'MobilePhone' ADProperty = 'mobile' } @{ Parameter = 'Fax' ADProperty = 'facsimileTelephoneNumber' } @{ Parameter = 'Pager' } @{ Parameter = 'IPPhone' } @{ Parameter = 'HomePhone' } @{ Parameter = 'Enabled' } @{ Parameter = 'Manager' } @{ Parameter = 'Organization' } @{ Parameter = 'OtherName' } @{ Parameter = 'PasswordNeverExpires' UseCmdletParameter = $true } @{ Parameter = 'CannotChangePassword' UseCmdletParameter = $true } @{ Parameter = 'ChangePasswordAtLogon' UseCmdletParameter = $true ADProperty = 'pwdLastSet' } @{ Parameter = 'TrustedForDelegation' UseCmdletParameter = $true } @{ Parameter = 'AccountNotDelegated' UseCmdletParameter = $true } @{ Parameter = 'AllowReversiblePasswordEncryption' UseCmdletParameter = $true } @{ Parameter = 'CompoundIdentitySupported' UseCmdletParameter = $true } @{ Parameter = 'PasswordNotRequired' UseCmdletParameter = $true } @{ Parameter = 'SmartcardLogonRequired' UseCmdletParameter = $true } @{ Parameter = 'ServicePrincipalNames' ADProperty = 'ServicePrincipalName' Type = 'Array' } @{ Parameter = 'ProxyAddresses' Type = 'Array' } ) function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( # Name of the domain where the user account is located (only used if password is managed) [Parameter(Mandatory = $true)] [System.String] $DomainName, # Specifies the Security Account Manager (SAM) account name of the user (ldapDisplayName 'sAMAccountName') [Parameter(Mandatory = $true)] [System.String] $UserName, # Specifies a new password value for an account [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $Password, # Specifies whether the user account is created or deleted [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', # Specifies the common name assigned to the user account (ldapDisplayName 'cn') [Parameter()] [ValidateNotNull()] [System.String] $CommonName = $UserName, # Specifies the UPN assigned to the user account (ldapDisplayName 'userPrincipalName') [Parameter()] [ValidateNotNull()] [System.String] $UserPrincipalName, # Specifies the display name of the object (ldapDisplayName 'displayName') [Parameter()] [ValidateNotNull()] [System.String] $DisplayName, # Specifies the X.500 path of the Organizational Unit (OU) or container where the new object is created [Parameter()] [ValidateNotNull()] [System.String] $Path, # Specifies the user's given name (ldapDisplayName 'givenName') [Parameter()] [ValidateNotNull()] [System.String] $GivenName, # Specifies the initials that represent part of a user's name (ldapDisplayName 'initials') [Parameter()] [ValidateNotNull()] [System.String] $Initials, # Specifies the user's last name or surname (ldapDisplayName 'sn') [Parameter()] [ValidateNotNull()] [System.String] $Surname, # Specifies a description of the object (ldapDisplayName 'description') [Parameter()] [ValidateNotNull()] [System.String] $Description, # Specifies the user's street address (ldapDisplayName 'streetAddress') [Parameter()] [ValidateNotNull()] [System.String] $StreetAddress, # Specifies the user's post office box number (ldapDisplayName 'postOfficeBox') [Parameter()] [ValidateNotNull()] [System.String] $POBox, # Specifies the user's town or city (ldapDisplayName 'l') [Parameter()] [ValidateNotNull()] [System.String] $City, # Specifies the user's or Organizational Unit's state or province (ldapDisplayName 'st') [Parameter()] [ValidateNotNull()] [System.String] $State, # Specifies the user's postal code or zip code (ldapDisplayName 'postalCode') [Parameter()] [ValidateNotNull()] [System.String] $PostalCode, # Specifies the country or region code for the user's language of choice (ldapDisplayName 'c') [Parameter()] [ValidateNotNull()] [System.String] $Country, # Specifies the user's department (ldapDisplayName 'department') [Parameter()] [ValidateNotNull()] [System.String] $Department, # Specifies the user's division (ldapDisplayName 'division') [Parameter()] [ValidateNotNull()] [System.String] $Division, # Specifies the user's company (ldapDisplayName 'company') [Parameter()] [ValidateNotNull()] [System.String] $Company, # Specifies the location of the user's office or place of business (ldapDisplayName 'physicalDeliveryOfficeName') [Parameter()] [ValidateNotNull()] [System.String] $Office, # Specifies the user's title (ldapDisplayName 'title') [Parameter()] [ValidateNotNull()] [System.String] $JobTitle, # Specifies the user's e-mail address (ldapDisplayName 'mail') [Parameter()] [ValidateNotNull()] [System.String] $EmailAddress, # Specifies the user's employee ID (ldapDisplayName 'employeeID') [Parameter()] [ValidateNotNull()] [System.String] $EmployeeID, # Specifies the user's employee number (ldapDisplayName 'employeeNumber') [Parameter()] [ValidateNotNull()] [System.String] $EmployeeNumber, # Specifies a user's home directory path (ldapDisplayName 'homeDirectory') [Parameter()] [ValidateNotNull()] [System.String] $HomeDirectory, # Specifies a drive that is associated with the UNC path defined by the HomeDirectory property (ldapDisplayName 'homeDrive') [Parameter()] [ValidateNotNull()] [System.String] $HomeDrive, # Specifies the URL of the home page of the object (ldapDisplayName 'wWWHomePage') [Parameter()] [ValidateNotNull()] [System.String] $HomePage, # Specifies a path to the user's profile (ldapDisplayName 'profilePath') [Parameter()] [ValidateNotNull()] [System.String] $ProfilePath, # Specifies a path to the user's log on script (ldapDisplayName 'scriptPath') [Parameter()] [ValidateNotNull()] [System.String] $LogonScript, # Specifies the notes attached to the user's account (ldapDisplayName 'info') [Parameter()] [ValidateNotNull()] [System.String] $Notes, # Specifies the user's office telephone number (ldapDisplayName 'telephoneNumber') [Parameter()] [ValidateNotNull()] [System.String] $OfficePhone, # Specifies the user's mobile phone number (ldapDisplayName 'mobile') [Parameter()] [ValidateNotNull()] [System.String] $MobilePhone, # Specifies the user's fax phone number (ldapDisplayName 'facsimileTelephoneNumber') [Parameter()] [ValidateNotNull()] [System.String] $Fax, # Specifies the user's home telephone number (ldapDisplayName 'homePhone') [Parameter()] [ValidateNotNull()] [System.String] $HomePhone, # Specifies the user's pager number (ldapDisplayName 'pager') [Parameter()] [ValidateNotNull()] [System.String] $Pager, # Specifies the user's IP telephony phone number (ldapDisplayName 'ipPhone') [Parameter()] [ValidateNotNull()] [System.String] $IPPhone, # Specifies the user's manager specified as a Distinguished Name (ldapDisplayName 'manager') [Parameter()] [ValidateNotNull()] [System.String] $Manager, # Specifies the computers that the user can access. (ldapDisplayName 'userWorkStations') [Parameter()] [ValidateNotNull()] [System.String] $LogonWorkstations, # Specifies the user's organization (ldapDisplayName 'o') [Parameter()] [ValidateNotNull()] [System.String] $Organization, # Specifies a name in addition to a user's given name and surname (ldaDisplayName 'middleName') [Parameter()] [ValidateNotNull()] [System.String] $OtherName, # Specifies if the account is enabled (default True) [Parameter()] [ValidateNotNull()] [System.Boolean] $Enabled = $true, # Specifies whether the account password can be changed [Parameter()] [ValidateNotNull()] [System.Boolean] $CannotChangePassword, # Specifies whether the account password must be changed during the next logon attempt [Parameter()] [ValidateNotNull()] [System.Boolean] $ChangePasswordAtLogon, # Specifies whether the password of an account can expire [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverExpires, # Specifies whether an account is trusted for Kerberos delegation [Parameter()] [ValidateNotNull()] [System.Boolean] $TrustedForDelegation, # Indicates whether the security context of the user is delegated to a service. [Parameter()] [ValidateNotNull()] [System.Boolean] $AccountNotDelegated, # Indicates whether reversible password encryption is allowed for the account. [Parameter()] [ValidateNotNull()] [System.Boolean] $AllowReversiblePasswordEncryption, # Specifies whether an account supports Kerberos service tickets which includes the authorization data for the user's device. [Parameter()] [ValidateNotNull()] [System.Boolean] $CompoundIdentitySupported, # Specifies whether the account requires a password. A password is not required for a new account. [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNotRequired, # Specifies whether a smart card is required to logon. [Parameter()] [ValidateNotNull()] [System.Boolean] $SmartcardLogonRequired, # Specifies the Active Directory Domain Services instance to use to perform the task. [Parameter()] [ValidateNotNull()] [System.String] $DomainController, # Specifies the user account credentials to use to perform this task. Ideally this should just be called 'Credential' but is here for backwards compatibility [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $DomainAdministratorCredential, # Specifies the authentication context type when testing user passwords #61 [Parameter()] [ValidateSet('Default', 'Negotiate')] [System.String] $PasswordAuthentication = 'Default', # Specifies whether an existing user's password should be reset (default $false). [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverResets = $false, # Try to restore the organizational unit from the recycle bin before creating a new one. [Parameter()] [ValidateNotNull()] [System.Boolean] $RestoreFromRecycleBin, # Specifies the service principal names registered on the user account [Parameter()] [ValidateNotNull()] [System.String[]] $ServicePrincipalNames, # Specifies the Proxy Addresses registered on the user account [Parameter()] [ValidateNotNull()] [System.String[]] $ProxyAddresses ) Assert-Module -ModuleName 'ActiveDirectory' try { $adCommonParameters = Get-ADCommonParameters @PSBoundParameters $adProperties = @() # Create an array of the AD propertie names to retrieve from the property map foreach ($property in $adPropertyMap) { if ($property.ADProperty) { $adProperties += $property.ADProperty } else { $adProperties += $property.Parameter } } Write-Verbose -Message ($script:localizedData.RetrievingADUser -f $UserName, $DomainName) $adUser = Get-ADUser @adCommonParameters -Properties $adProperties Write-Verbose -Message ($script:localizedData.ADUserIsPresent -f $UserName, $DomainName) $Ensure = 'Present' } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { Write-Verbose -Message ($script:localizedData.ADUserNotPresent -f $UserName, $DomainName) $Ensure = 'Absent' } catch { $errorMessage = $script:localizedData.RetrievingADUserError -f $UserName, $DomainName New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } $targetResource = @{ DomainName = $DomainName Password = $Password UserName = $UserName DistinguishedName = $adUser.DistinguishedName; # Read-only property Ensure = $Ensure DomainController = $DomainController } # Retrieve each property from the ADPropertyMap and add to the hashtable foreach ($property in $adPropertyMap) { $parameter = $property.Parameter if ($parameter -eq 'Path') { # The path returned is not the parent container if (-not [System.String]::IsNullOrEmpty($adUser.DistinguishedName)) { $targetResource['Path'] = Get-ADObjectParentDN -DN $adUser.DistinguishedName } } elseif (($parameter) -eq 'ChangePasswordAtLogon') { if ($adUser.pwdlastset -eq 0) { $targetResource['ChangePasswordAtLogon'] = $true } else { $targetResource['ChangePasswordAtLogon'] = $false } } elseif ($property.ADProperty) { # The AD property name is different to the function parameter to use this $aDProperty = $property.ADProperty if ($property.Type -eq 'Array') { $targetResource[$parameter] = [System.String[]] $adUser.$aDProperty } else { $targetResource[$parameter] = $adUser.$aDProperty } } else { # The AD property name matches the function parameter if ($property.Type -eq 'Array') { $targetResource[$Parameter] = [System.String[]] $adUser.$parameter } else { $targetResource[$Parameter] = $adUser.$parameter } } } return $targetResource } #end function Get-TargetResource function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( # Name of the domain where the user account is located (only used if password is managed) [Parameter(Mandatory = $true)] [System.String] $DomainName, # Specifies the Security Account Manager (SAM) account name of the user (ldapDisplayName 'sAMAccountName') [Parameter(Mandatory = $true)] [System.String] $UserName, # Specifies a new password value for an account [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $Password, # Specifies whether the user account is created or deleted [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', # Specifies the common name assigned to the user account (ldapDisplayName 'cn') [Parameter()] [ValidateNotNull()] [System.String] $CommonName = $UserName, # Specifies the UPN assigned to the user account (ldapDisplayName 'userPrincipalName') [Parameter()] [ValidateNotNull()] [System.String] $UserPrincipalName, # Specifies the display name of the object (ldapDisplayName 'displayName') [Parameter()] [ValidateNotNull()] [System.String] $DisplayName, # Specifies the X.500 path of the Organizational Unit (OU) or container where the new object is created [Parameter()] [ValidateNotNull()] [System.String] $Path, # Specifies the user's given name (ldapDisplayName 'givenName') [Parameter()] [ValidateNotNull()] [System.String] $GivenName, # Specifies the initials that represent part of a user's name (ldapDisplayName 'initials') [Parameter()] [ValidateNotNull()] [System.String] $Initials, # Specifies the user's last name or surname (ldapDisplayName 'sn') [Parameter()] [ValidateNotNull()] [System.String] $Surname, # Specifies a description of the object (ldapDisplayName 'description') [Parameter()] [ValidateNotNull()] [System.String] $Description, # Specifies the user's street address (ldapDisplayName 'streetAddress') [Parameter()] [ValidateNotNull()] [System.String] $StreetAddress, # Specifies the user's post office box number (ldapDisplayName 'postOfficeBox') [Parameter()] [ValidateNotNull()] [System.String] $POBox, # Specifies the user's town or city (ldapDisplayName 'l') [Parameter()] [ValidateNotNull()] [System.String] $City, # Specifies the user's or Organizational Unit's state or province (ldapDisplayName 'st') [Parameter()] [ValidateNotNull()] [System.String] $State, # Specifies the user's postal code or zip code (ldapDisplayName 'postalCode') [Parameter()] [ValidateNotNull()] [System.String] $PostalCode, # Specifies the country or region code for the user's language of choice (ldapDisplayName 'c') [Parameter()] [ValidateNotNull()] [System.String] $Country, # Specifies the user's department (ldapDisplayName 'department') [Parameter()] [ValidateNotNull()] [System.String] $Department, # Specifies the user's division (ldapDisplayName 'division') [Parameter()] [ValidateNotNull()] [System.String] $Division, # Specifies the user's company (ldapDisplayName 'company') [Parameter()] [ValidateNotNull()] [System.String] $Company, # Specifies the location of the user's office or place of business (ldapDisplayName 'physicalDeliveryOfficeName') [Parameter()] [ValidateNotNull()] [System.String] $Office, # Specifies the user's title (ldapDisplayName 'title') [Parameter()] [ValidateNotNull()] [System.String] $JobTitle, # Specifies the user's e-mail address (ldapDisplayName 'mail') [Parameter()] [ValidateNotNull()] [System.String] $EmailAddress, # Specifies the user's employee ID (ldapDisplayName 'employeeID') [Parameter()] [ValidateNotNull()] [System.String] $EmployeeID, # Specifies the user's employee number (ldapDisplayName 'employeeNumber') [Parameter()] [ValidateNotNull()] [System.String] $EmployeeNumber, # Specifies a user's home directory path (ldapDisplayName 'homeDirectory') [Parameter()] [ValidateNotNull()] [System.String] $HomeDirectory, # Specifies a drive that is associated with the UNC path defined by the HomeDirectory property (ldapDisplayName 'homeDrive') [Parameter()] [ValidateNotNull()] [System.String] $HomeDrive, # Specifies the URL of the home page of the object (ldapDisplayName 'wWWHomePage') [Parameter()] [ValidateNotNull()] [System.String] $HomePage, # Specifies a path to the user's profile (ldapDisplayName 'profilePath') [Parameter()] [ValidateNotNull()] [System.String] $ProfilePath, # Specifies a path to the user's log on script (ldapDisplayName 'scriptPath') [Parameter()] [ValidateNotNull()] [System.String] $LogonScript, # Specifies the notes attached to the user's account (ldapDisplayName 'info') [Parameter()] [ValidateNotNull()] [System.String] $Notes, # Specifies the user's office telephone number (ldapDisplayName 'telephoneNumber') [Parameter()] [ValidateNotNull()] [System.String] $OfficePhone, # Specifies the user's mobile phone number (ldapDisplayName 'mobile') [Parameter()] [ValidateNotNull()] [System.String] $MobilePhone, # Specifies the user's fax phone number (ldapDisplayName 'facsimileTelephoneNumber') [Parameter()] [ValidateNotNull()] [System.String] $Fax, # Specifies the user's home telephone number (ldapDisplayName 'homePhone') [Parameter()] [ValidateNotNull()] [System.String] $HomePhone, # Specifies the user's pager number (ldapDisplayName 'pager') [Parameter()] [ValidateNotNull()] [System.String] $Pager, # Specifies the user's IP telephony phone number (ldapDisplayName 'ipPhone') [Parameter()] [ValidateNotNull()] [System.String] $IPPhone, # Specifies the user's manager specified as a Distinguished Name (ldapDisplayName 'manager') [Parameter()] [ValidateNotNull()] [System.String] $Manager, # Specifies the computers that the user can access. (ldapDisplayName 'userWorkStations') [Parameter()] [ValidateNotNull()] [System.String] $LogonWorkstations, # Specifies the user's organization (ldapDisplayName 'o') [Parameter()] [ValidateNotNull()] [System.String] $Organization, # Specifies a name in addition to a user's given name and surname (ldaDisplayName 'middleName') [Parameter()] [ValidateNotNull()] [System.String] $OtherName, # Specifies if the account is enabled (default True) [Parameter()] [ValidateNotNull()] [System.Boolean] $Enabled = $true, # Specifies whether the account password can be changed [Parameter()] [ValidateNotNull()] [System.Boolean] $CannotChangePassword, # Specifies whether the account password must be changed during the next logon attempt [Parameter()] [ValidateNotNull()] [System.Boolean] $ChangePasswordAtLogon, # Specifies whether the password of an account can expire [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverExpires, # Specifies whether an account is trusted for Kerberos delegation [Parameter()] [ValidateNotNull()] [System.Boolean] $TrustedForDelegation, # Indicates whether the security context of the user is delegated to a service. [Parameter()] [ValidateNotNull()] [System.Boolean] $AccountNotDelegated, # Indicates whether reversible password encryption is allowed for the account. [Parameter()] [ValidateNotNull()] [System.Boolean] $AllowReversiblePasswordEncryption, # Specifies whether an account supports Kerberos service tickets which includes the authorization data for the user's device. [Parameter()] [ValidateNotNull()] [System.Boolean] $CompoundIdentitySupported, # Specifies whether the account requires a password. A password is not required for a new account. [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNotRequired, # Specifies whether a smart card is required to logon. [Parameter()] [ValidateNotNull()] [System.Boolean] $SmartcardLogonRequired, # Specifies the Active Directory Domain Services instance to use to perform the task. [Parameter()] [ValidateNotNull()] [System.String] $DomainController, # Specifies the user account credentials to use to perform this task. Ideally this should just be called 'Credential' but is here for backwards compatibility [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $DomainAdministratorCredential, # Specifies the authentication context type when testing user passwords #61 [Parameter()] [ValidateSet('Default', 'Negotiate')] [System.String] $PasswordAuthentication = 'Default', # Specifies whether an existing user's password should be reset (default $false). [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverResets = $false, # Try to restore the organizational unit from the recycle bin before creating a new one. [Parameter()] [ValidateNotNull()] [System.Boolean] $RestoreFromRecycleBin, # Specifies the service principal names registered on the user account [Parameter()] [ValidateNotNull()] [System.String[]] $ServicePrincipalNames, # Specifies the Proxy Addresses registered on the user account [Parameter()] [ValidateNotNull()] [System.String[]] $ProxyAddresses ) Assert-Parameters @PSBoundParameters $targetResource = Get-TargetResource @PSBoundParameters $isCompliant = $true if ($Ensure -eq 'Absent') { if ($targetResource.Ensure -eq 'Present') { Write-Verbose -Message ($script:localizedData.ADUserNotDesiredPropertyState -f 'Ensure', $PSBoundParameters.Ensure, $targetResource.Ensure) $isCompliant = $false } } else { # Add common name, ensure and enabled as they may not be explicitly passed and we want to enumerate them $PSBoundParameters['Ensure'] = $Ensure $PSBoundParameters['Enabled'] = $Enabled foreach ($parameter in $PSBoundParameters.Keys) { if ($parameter -eq 'Password' -and $PasswordNeverResets -eq $false) { $testPasswordParams = @{ Username = $UserName Password = $Password DomainName = $DomainName PasswordAuthentication = $PasswordAuthentication } if ($DomainAdministratorCredential) { $testPasswordParams['DomainAdministratorCredential'] = $DomainAdministratorCredential } if (-not (Test-Password @testPasswordParams)) { Write-Verbose -Message ($script:localizedData.ADUserNotDesiredPropertyState -f 'Password', '<Password>', '<Password>') $isCompliant = $false } } # Only check properties that are returned by Get-TargetResource elseif ($targetResource.ContainsKey($parameter)) { # This check is required to be able to explicitly remove values with an empty string, if required if (([System.String]::IsNullOrEmpty($PSBoundParameters.$parameter)) -and ([System.String]::IsNullOrEmpty($targetResource.$parameter))) { # Both values are null/empty and therefore we are compliant } elseif (($null -ne $PSBoundParameters.$parameter -and $null -eq $targetResource.$parameter) -or ($null -eq $PSBoundParameters.$parameter -and $null -ne $targetResource.$parameter) -or (Compare-Object -ReferenceObject $PSBoundParameters.$parameter -DifferenceObject $targetResource.$parameter)) { Write-Verbose -Message ($script:localizedData.ADUserNotDesiredPropertyState -f $parameter, ($PSBoundParameters.$parameter -join '; '), ($targetResource.$parameter -join '; ')) $isCompliant = $false } } } #end foreach PSBoundParameter } return $isCompliant } #end function Test-TargetResource function Set-TargetResource { [CmdletBinding()] param ( # Name of the domain where the user account is located (only used if password is managed) [Parameter(Mandatory = $true)] [System.String] $DomainName, # Specifies the Security Account Manager (SAM) account name of the user (ldapDisplayName 'sAMAccountName') [Parameter(Mandatory = $true)] [System.String] $UserName, # Specifies a new password value for an account [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $Password, # Specifies whether the user account is created or deleted [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', # Specifies the common name assigned to the user account (ldapDisplayName 'cn') [Parameter()] [ValidateNotNull()] [System.String] $CommonName = $UserName, # Specifies the UPN assigned to the user account (ldapDisplayName 'userPrincipalName') [Parameter()] [ValidateNotNull()] [System.String] $UserPrincipalName, # Specifies the display name of the object (ldapDisplayName 'displayName') [Parameter()] [ValidateNotNull()] [System.String] $DisplayName, # Specifies the X.500 path of the Organizational Unit (OU) or container where the new object is created [Parameter()] [ValidateNotNull()] [System.String] $Path, # Specifies the user's given name (ldapDisplayName 'givenName') [Parameter()] [ValidateNotNull()] [System.String] $GivenName, # Specifies the initials that represent part of a user's name (ldapDisplayName 'initials') [Parameter()] [ValidateNotNull()] [System.String] $Initials, # Specifies the user's last name or surname (ldapDisplayName 'sn') [Parameter()] [ValidateNotNull()] [System.String] $Surname, # Specifies a description of the object (ldapDisplayName 'description') [Parameter()] [ValidateNotNull()] [System.String] $Description, # Specifies the user's street address (ldapDisplayName 'streetAddress') [Parameter()] [ValidateNotNull()] [System.String] $StreetAddress, # Specifies the user's post office box number (ldapDisplayName 'postOfficeBox') [Parameter()] [ValidateNotNull()] [System.String] $POBox, # Specifies the user's town or city (ldapDisplayName 'l') [Parameter()] [ValidateNotNull()] [System.String] $City, # Specifies the user's or Organizational Unit's state or province (ldapDisplayName 'st') [Parameter()] [ValidateNotNull()] [System.String] $State, # Specifies the user's postal code or zip code (ldapDisplayName 'postalCode') [Parameter()] [ValidateNotNull()] [System.String] $PostalCode, # Specifies the country or region code for the user's language of choice (ldapDisplayName 'c') [Parameter()] [ValidateNotNull()] [System.String] $Country, # Specifies the user's department (ldapDisplayName 'department') [Parameter()] [ValidateNotNull()] [System.String] $Department, # Specifies the user's division (ldapDisplayName 'division') [Parameter()] [ValidateNotNull()] [System.String] $Division, # Specifies the user's company (ldapDisplayName 'company') [Parameter()] [ValidateNotNull()] [System.String] $Company, # Specifies the location of the user's office or place of business (ldapDisplayName 'physicalDeliveryOfficeName') [Parameter()] [ValidateNotNull()] [System.String] $Office, # Specifies the user's title (ldapDisplayName 'title') [Parameter()] [ValidateNotNull()] [System.String] $JobTitle, # Specifies the user's e-mail address (ldapDisplayName 'mail') [Parameter()] [ValidateNotNull()] [System.String] $EmailAddress, # Specifies the user's employee ID (ldapDisplayName 'employeeID') [Parameter()] [ValidateNotNull()] [System.String] $EmployeeID, # Specifies the user's employee number (ldapDisplayName 'employeeNumber') [Parameter()] [ValidateNotNull()] [System.String] $EmployeeNumber, # Specifies a user's home directory path (ldapDisplayName 'homeDirectory') [Parameter()] [ValidateNotNull()] [System.String] $HomeDirectory, # Specifies a drive that is associated with the UNC path defined by the HomeDirectory property (ldapDisplayName 'homeDrive') [Parameter()] [ValidateNotNull()] [System.String] $HomeDrive, # Specifies the URL of the home page of the object (ldapDisplayName 'wWWHomePage') [Parameter()] [ValidateNotNull()] [System.String] $HomePage, # Specifies a path to the user's profile (ldapDisplayName 'profilePath') [Parameter()] [ValidateNotNull()] [System.String] $ProfilePath, # Specifies a path to the user's log on script (ldapDisplayName 'scriptPath') [Parameter()] [ValidateNotNull()] [System.String] $LogonScript, # Specifies the notes attached to the user's account (ldapDisplayName 'info') [Parameter()] [ValidateNotNull()] [System.String] $Notes, # Specifies the user's office telephone number (ldapDisplayName 'telephoneNumber') [Parameter()] [ValidateNotNull()] [System.String] $OfficePhone, # Specifies the user's mobile phone number (ldapDisplayName 'mobile') [Parameter()] [ValidateNotNull()] [System.String] $MobilePhone, # Specifies the user's fax phone number (ldapDisplayName 'facsimileTelephoneNumber') [Parameter()] [ValidateNotNull()] [System.String] $Fax, # Specifies the user's home telephone number (ldapDisplayName 'homePhone') [Parameter()] [ValidateNotNull()] [System.String] $HomePhone, # Specifies the user's pager number (ldapDisplayName 'pager') [Parameter()] [ValidateNotNull()] [System.String] $Pager, # Specifies the user's IP telephony phone number (ldapDisplayName 'ipPhone') [Parameter()] [ValidateNotNull()] [System.String] $IPPhone, # Specifies the user's manager specified as a Distinguished Name (ldapDisplayName 'manager') [Parameter()] [ValidateNotNull()] [System.String] $Manager, # Specifies the computers that the user can access. (ldapDisplayName 'userWorkStations') [Parameter()] [ValidateNotNull()] [System.String] $LogonWorkstations, # Specifies the user's organization (ldapDisplayName 'o') [Parameter()] [ValidateNotNull()] [System.String] $Organization, # Specifies a name in addition to a user's given name and surname (ldaDisplayName 'middleName') [Parameter()] [ValidateNotNull()] [System.String] $OtherName, # Specifies if the account is enabled (default True) [Parameter()] [ValidateNotNull()] [System.Boolean] $Enabled = $true, # Specifies whether the account password can be changed [Parameter()] [ValidateNotNull()] [System.Boolean] $CannotChangePassword, # Specifies whether the account password must be changed during the next logon attempt [Parameter()] [ValidateNotNull()] [System.Boolean] $ChangePasswordAtLogon, # Specifies whether the password of an account can expire [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverExpires, # Specifies whether an account is trusted for Kerberos delegation [Parameter()] [ValidateNotNull()] [System.Boolean] $TrustedForDelegation, # Indicates whether the security context of the user is delegated to a service. [Parameter()] [ValidateNotNull()] [System.Boolean] $AccountNotDelegated, # Indicates whether reversible password encryption is allowed for the account. [Parameter()] [ValidateNotNull()] [System.Boolean] $AllowReversiblePasswordEncryption, # Specifies whether an account supports Kerberos service tickets which includes the authorization data for the user's device. [Parameter()] [ValidateNotNull()] [System.Boolean] $CompoundIdentitySupported, # Specifies whether the account requires a password. A password is not required for a new account. [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNotRequired, # Specifies whether a smart card is required to logon. [Parameter()] [ValidateNotNull()] [System.Boolean] $SmartcardLogonRequired, # Specifies the Active Directory Domain Services instance to use to perform the task. [Parameter()] [ValidateNotNull()] [System.String] $DomainController, # Specifies the user account credentials to use to perform this task. Ideally this should just be called 'Credential' but is here for backwards compatibility [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $DomainAdministratorCredential, # Specifies the authentication context type when testing user passwords #61 [Parameter()] [ValidateSet('Default', 'Negotiate')] [System.String] $PasswordAuthentication = 'Default', # Specifies whether an existing user's password should be reset (default $false). [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverResets = $false, # Try to restore the organizational unit from the recycle bin before creating a new one. [Parameter()] [ValidateNotNull()] [System.Boolean] $RestoreFromRecycleBin, # Specifies the service principal names registered on the user account [Parameter()] [ValidateNotNull()] [System.String[]] $ServicePrincipalNames, # Specifies the Proxy Addresses registered on the user account [Parameter()] [ValidateNotNull()] [System.String[]] $ProxyAddresses ) Assert-Parameters @PSBoundParameters $targetResource = Get-TargetResource @PSBoundParameters # Add common name, ensure and enabled as they may not be explicitly passed $PSBoundParameters['Ensure'] = $Ensure $PSBoundParameters['Enabled'] = $Enabled if ($Ensure -eq 'Present') { if ($targetResource.Ensure -eq 'Absent') { # Try to restore account if it exists if ($RestoreFromRecycleBin) { Write-Verbose -Message ($script:localizedData.RestoringUser -f $UserName) $restoreParams = Get-ADCommonParameters @PSBoundParameters $restorationSuccessful = Restore-ADCommonObject @restoreParams -ObjectClass User -ErrorAction Stop } if (-not $RestoreFromRecycleBin -or ($RestoreFromRecycleBin -and -not $restorationSuccessful)) { # User does not exist and needs creating $newADUserParams = Get-ADCommonParameters @PSBoundParameters -UseNameParameter if ($PSBoundParameters.ContainsKey('Path')) { $newADUserParams['Path'] = $Path } # Populate the AccountPassword parameter of New-ADUser if password declared if ($PSBoundParameters.ContainsKey('Password')) { $newADUserParams['AccountPassword'] = $Password.Password } Write-Verbose -Message ($script:localizedData.AddingADUser -f $UserName) New-ADUser @newADUserParams -SamAccountName $UserName # Now retrieve the newly created user $targetResource = Get-TargetResource @PSBoundParameters } } $setADUserParams = Get-ADCommonParameters @PSBoundParameters $replaceUserProperties = @{ } $clearUserProperties = @() foreach ($parameter in $PSBoundParameters.Keys) { # Only check/action properties specified/declared parameters that match one of the function's # parameters. This will ignore common parameters such as -Verbose etc. if ($targetResource.ContainsKey($parameter)) { $adProperty = $adPropertyMap | Where-Object -FilterScript { $_.Parameter -eq $parameter } if ($parameter -eq 'Path' -and ($PSBoundParameters.Path -ne $targetResource.Path)) { # Cannot move users by updating the DistinguishedName property $adCommonParameters = Get-ADCommonParameters @PSBoundParameters # Using the SamAccountName for identity with Move-ADObject does not work, use the DN instead $adCommonParameters['Identity'] = $targetResource.DistinguishedName Write-Verbose -Message ($script:localizedData.MovingADUser -f $targetResource.Path, $PSBoundParameters.Path) Move-ADObject @adCommonParameters -TargetPath $PSBoundParameters.Path } elseif ($parameter -eq 'CommonName' -and ($PSBoundParameters.CommonName -ne $targetResource.CommonName)) { # Cannot rename users by updating the CN property directly $adCommonParameters = Get-ADCommonParameters @PSBoundParameters # Using the SamAccountName for identity with Rename-ADObject does not work, use the DN instead $adCommonParameters['Identity'] = $targetResource.DistinguishedName Write-Verbose -Message ($script:localizedData.RenamingADUser -f $targetResource.CommonName, $PSBoundParameters.CommonName) Rename-ADObject @adCommonParameters -NewName $PSBoundParameters.CommonName } elseif ($parameter -eq 'Password' -and $PasswordNeverResets -eq $false) { $adCommonParameters = Get-ADCommonParameters @PSBoundParameters $testPasswordParams = @{ Username = $UserName Password = $Password DomainName = $DomainName PasswordAuthentication = $PasswordAuthentication } if ($DomainAdministratorCredential) { $testPasswordParams['DomainAdministratorCredential'] = $DomainAdministratorCredential } if (-not (Test-Password @testPasswordParams)) { Write-Verbose -Message ($script:localizedData.SettingADUserPassword -f $UserName) Set-ADAccountPassword @adCommonParameters -Reset -NewPassword $Password.Password } } elseif ($parameter -eq 'Enabled' -and ($PSBoundParameters.$parameter -ne $targetResource.$parameter)) { <# We cannot enable/disable an account with -Add or -Replace parameters, but inform that we will change this as it is out of compliance (it always gets set anyway). #> Write-Verbose -Message ($script:localizedData.UpdatingADUserProperty -f $parameter, $PSBoundParameters.$parameter) } # Use Compare-Object to allow comparison of string and array parameters elseif (($null -ne $PSBoundParameters.$parameter -and $null -eq $targetResource.$parameter) -or ($null -eq $PSBoundParameters.$parameter -and $null -ne $targetResource.$parameter) -or (Compare-Object -ReferenceObject $PSBoundParameters.$parameter -DifferenceObject $targetResource.$parameter)) { # Find the associated AD property $adProperty = $adPropertyMap | Where-Object -FilterScript { $_.Parameter -eq $parameter } if ([System.String]::IsNullOrEmpty($adProperty)) { # We can't do anything is an empty AD property! } else { if ([System.String]::IsNullOrEmpty($PSBoundParameters.$parameter) -and (-not ([System.String]::IsNullOrEmpty($targetResource.$parameter)))) { # We are clearing the existing value Write-Verbose -Message ($script:localizedData.ClearingADUserProperty -f $parameter) if ($adProperty.UseCmdletParameter -eq $true) { # We need to pass the parameter explicitly to Set-ADUser, not via -Clear $setADUserParams[$adProperty.Parameter] = $PSBoundParameters.$parameter } elseif ([System.String]::IsNullOrEmpty($adProperty.ADProperty)) { $clearUserProperties += $adProperty.Parameter } else { $clearUserProperties += $adProperty.ADProperty } } #end if clear existing value else { # We are replacing the existing value Write-Verbose -Message ($script:localizedData.UpdatingADUserProperty -f $parameter, ($PSBoundParameters.$parameter -join ',')) if ($adProperty.UseCmdletParameter -eq $true) { # We need to pass the parameter explicitly to Set-ADUser, not via -Replace $setADUserParams[$adProperty.Parameter] = $PSBoundParameters.$parameter } elseif ([System.String]::IsNullOrEmpty($adProperty.ADProperty)) { $replaceUserProperties[$adProperty.Parameter] = $PSBoundParameters.$parameter } else { $replaceUserProperties[$adProperty.ADProperty] = $PSBoundParameters.$parameter } } } #end if replace existing value } } #end if TargetResource parameter } #end foreach PSBoundParameter # Only pass -Clear and/or -Replace if we have something to set/change if ($replaceUserProperties.Count -gt 0) { $setADUserParams['Replace'] = $replaceUserProperties } if ($clearUserProperties.Count -gt 0) { $setADUserParams['Clear'] = $clearUserProperties; } Write-Verbose -Message ($script:localizedData.UpdatingADUser -f $UserName) [ref] $null = Set-ADUser @setADUserParams -Enabled $Enabled } elseif (($Ensure -eq 'Absent') -and ($targetResource.Ensure -eq 'Present')) { # User exists and needs removing Write-Verbose ($script:localizedData.RemovingADUser -f $UserName) $adCommonParameters = Get-ADCommonParameters @PSBoundParameters [ref] $null = Remove-ADUser @adCommonParameters -Confirm:$false } } #end function Set-TargetResource # Internal function to validate unsupported options/configurations function Assert-Parameters { [CmdletBinding()] param ( [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] $Password, [Parameter()] [ValidateNotNull()] [System.Boolean] $Enabled = $true, [Parameter()] [ValidateNotNull()] [System.Boolean] $ChangePasswordAtLogon, [Parameter()] [ValidateNotNull()] [System.Boolean] $PasswordNeverExpires, [Parameter(ValueFromRemainingArguments)] $IgnoredArguments ) # We cannot test/set passwords on disabled AD accounts if (($PSBoundParameters.ContainsKey('Password')) -and ($Enabled -eq $false)) { $throwInvalidArgumentErrorParams = @{ ErrorId = 'xADUser_DisabledAccountPasswordConflict' ErrorMessage = $script:localizedData.PasswordParameterConflictError -f 'Enabled', $false, 'Password' } ThrowInvalidArgumentError @throwInvalidArgumentErrorParams } # ChangePasswordAtLogon cannot be set for an account that also has PasswordNeverExpires set if ($PSBoundParameters.ContainsKey('ChangePasswordAtLogon') -and $PSBoundParameters['ChangePasswordAtLogon'] -eq $true -and $PSBoundParameters.ContainsKey('PasswordNeverExpires') -and $PSBoundParameters['PasswordNeverExpires'] -eq $true) { $throwInvalidArgumentErrorParams = @{ ErrorId = 'xADUser_ChangePasswordParameterConflict' ErrorMessage = $script:localizedData.ChangePasswordParameterConflictError } ThrowInvalidArgumentError @throwInvalidArgumentErrorParams } } #end function Assert-Parameters # Internal function to test the validity of a user's password. function Test-Password { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $DomainName, [Parameter(Mandatory = $true)] [System.String] $UserName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $Password, [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.CredentialAttribute()] $DomainAdministratorCredential, # Specifies the authentication context type when testing user passwords #61 [Parameter(Mandatory = $true)] [ValidateSet('Default', 'Negotiate')] [System.String] $PasswordAuthentication ) Write-Verbose -Message ($script:localizedData.CreatingADDomainConnection -f $DomainName) Add-Type -AssemblyName 'System.DirectoryServices.AccountManagement' if ($DomainAdministratorCredential) { $principalContext = New-Object -TypeName 'System.DirectoryServices.AccountManagement.PrincipalContext' -ArgumentList @( [System.DirectoryServices.AccountManagement.ContextType]::Domain, $DomainName, $DomainAdministratorCredential.UserName, $DomainAdministratorCredential.GetNetworkCredential().Password ) } else { $principalContext = New-Object -TypeName 'System.DirectoryServices.AccountManagement.PrincipalContext' -ArgumentList @( [System.DirectoryServices.AccountManagement.ContextType]::Domain, $DomainName, $null, $null ) } Write-Verbose -Message ($script:localizedData.CheckingADUserPassword -f $UserName) if ($PasswordAuthentication -eq 'Negotiate') { return $principalContext.ValidateCredentials( $UserName, $Password.GetNetworkCredential().Password, [System.DirectoryServices.AccountManagement.ContextOptions]::Negotiate -bor [System.DirectoryServices.AccountManagement.ContextOptions]::Signing -bor [System.DirectoryServices.AccountManagement.ContextOptions]::Sealing ) } else { # Use default authentication context return $principalContext.ValidateCredentials( $UserName, $Password.GetNetworkCredential().Password ) } } #end function Test-Password Export-ModuleMember -Function *-TargetResource |