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."?
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:
$userObject = New-Object -TypeName System.DirectoryServices.DirectoryEntry $user.Path, $credentials.UserName, $($credentials.GetNetworkCredential().password)
or,
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()