Search code examples
powershellactive-directoryldapcredentialsldap-query

How can I, a non-administrator, change my active directory password using PowerShell, when my computer is not a member of the domain?


I'm logged on to a laptop as a non-domain user.

I'm connected to a remote network using Open VPN, and can access domain resources through that VPN, such as an CIFS share, by entering my domain credentials when prompted.

I want to use PowerShell to change my password on the remote domain.

I have my current credentials stored as $credentials, a System.Management.Automation.PSCredential object.

I have my new password stored as $newPassword, a secure string,

How can I, a non-administrator, change my active directory password using PowerShell, when my computer is not a member of the domain?

The FQDN of the domain, d0-ad.domain.com, resolves to a domain controller IP address. I have added the netbios name, NP-DOMAIN, to the hosts file, so it also resolves to a domain controller.

This is the section of the script I'm having trouble with:

Write-Verbose "Setting up DirectoryEntry object"
$DomainEntry = New-Object -TypeName System.DirectoryServices.DirectoryEntry "LDAP://$($netBiosName)" ,$credentials.UserName,$($credentials.GetNetworkCredential().password)

Write-Verbose "Setting up DirectorySearcher object"
$Searcher = New-Object -TypeName System.DirectoryServices.DirectorySearcher

$Searcher.SearchRoot = $DomainEntry

$userName = $($credentials.UserName).Replace("$($netBiosName)\","")
Write-Verbose "Username set as $($userName)"
$Searcher.Filter = "(samaccountname=$($userName))"

$user = $Searcher.FindOne()

$userObject = [ADSI]$user.Path

if ($userObject) {
    Write-Verbose "Changing password for user: $($user.Path)"
    $userObject.ChangePassword($credentials.GetNetworkCredential().password, [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($NewPassword)))
} else {
    Write-Verbose "User $($username) not found"
    throw "User $($username) not found"
}

The problem occurs at

$userObject = [ADSI]$user.Path

If I try to access $userObject I receive the error:

format-default : The following exception occurred while retrieving member "distinguishedName": "A local error has occurred. " + CategoryInfo : NotSpecified: (:) [format-default], ExtendedTypeSystemException + FullyQualifiedErrorId : CatchFromBaseGetMember,Microsoft.PowerShell.Commands.FormatDefaultCommand

I know the credentials are correct and the connection to the directory works because the $Searcher.FindOne() method correctly searches for, finds, and returns the correct user.

So why am I getting "A local error has occurred."?


Solution

  • The error does seem odd, but I think it's probably because you're not giving it proper credentials. The [ADSI] type accelerator is just a shorthand for creating a DirectoryEntry object. So [ADSI]$user.Path is the equivalent of creating a DirectoryEntry like you did at the top of your code, except with no username and password.

    So you can:

    1. Create it like you did at the top of your file:
    $userObject = New-Object -TypeName System.DirectoryServices.DirectoryEntry $user.Path, $credentials.UserName, $($credentials.GetNetworkCredential().password)
    

    or,

    1. Call GetDirectoryEntry() on the SearchResult. The DirectoryEntry object it returns will have the same credentials set on it as what was set on the SearchRoot:
    $userObject = $user.GetDirectoryEntry()