I am working with a Powershell script that adds scheduled tasks to systems in our domain. When I run this script, it will prompt me for my password. I sometimes fat finger the password and the process starts, which locks out my account. Is there a way to verify my credentials to make sure that what I typed in will validate with the Domain?

I'd like to find a way to query the Domain controller. I've done some Google searches and I should be able to do a WMI query and trap for an error. I would like to avoid that style of validation if possible.

Any ideas? Thanks in advance.

up vote 25 down vote accepted

I have this in my library:

$cred = Get-Credential #Read credentials
 $username = $cred.username
 $password = $cred.GetNetworkCredential().password

 # Get current domain using logged-on user's credentials
 $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
 $domain = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$UserName,$Password)

if ($domain.name -eq $null)
{
 write-host "Authentication failed - please verify your username and password."
 exit #terminate the script.
}
else
{
 write-host "Successfully authenticated with domain $domain.name"
}
  • This is exactly what I am looking for. Thanks! – Doltknuckle Jun 3 '11 at 19:50
  • If I'm not mistaken, this would end up sending the password in plain text across the network, right? If it does, then am I right in assuming that AccountManagement.PrincipalContext.ValidateCredentials() does not (if you provide a securestring for the password)? – Code Jockey Jul 23 '15 at 19:00
  • Why aren't you using the ActiveDirectory module to do your LDAP query? – Kolob Canyon Mar 28 at 18:50
  • 6 years ago there was no active directory module – Jim B Mar 28 at 23:36
  • This script also helps for situations where you can't install the AD PowerShell modules for one reason or another. – Dodzi Dzakuma Jul 11 at 16:03

This is what I've used in the past; it's supposed to work for local machine accounts and 'application directory', but so far I've only used it successfully with AD credentials:

    function Test-Credential {
    <#
    .SYNOPSIS
        Takes a PSCredential object and validates it against the domain (or local machine, or ADAM instance).

    .PARAMETER cred
        A PScredential object with the username/password you wish to test. Typically this is generated using the Get-Credential cmdlet. Accepts pipeline input.

    .PARAMETER context
        An optional parameter specifying what type of credential this is. Possible values are 'Domain','Machine',and 'ApplicationDirectory.' The default is 'Domain.'

    .OUTPUTS
        A boolean, indicating whether the credentials were successfully validated.

    #>
    param(
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Management.Automation.PSCredential]$credential,
        [parameter()][validateset('Domain','Machine','ApplicationDirectory')]
        [string]$context = 'Domain'
    )
    begin {
        Add-Type -assemblyname system.DirectoryServices.accountmanagement
        $DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::$context) 
    }
    process {
        $DS.ValidateCredentials($credential.UserName, $credential.GetNetworkCredential().password)
    }
}
  • I'd love to hear if someone notices this - I believe that when I use ValidateCredentials() in this manner with an incorrect password, it seems to trigger two (2) bad password attempts - I can't control the number of attempts threshold on our domain, and it's low, so I'd prefer not to have two bad attempts when I'm making a single call... can anyone see this as well? – Code Jockey Jul 23 '15 at 18:53
  • Are you using domain\user or UPN (user@domain) format? I'm not in a position to replicate this, but the following URL describes a similar problem: social.msdn.microsoft.com/Forums/vstudio/en-US/… – jbsmith Jul 27 '15 at 21:36
  • You should be able to just pass $context as the argument to the constructor. PowerShell will automatically convert strings to an enum. Better yet, just make [System.DirectoryServices.AccountManagement.ContextType] the type of $context. Also, why are you using begin and process here? The pipeline seems like an odd way to use this function. – jpmc26 Mar 8 '17 at 22:53
  • @jpmc26: typing the $context parameter [System.DirectoryServices.AccountManagement.ContextType] is not an option, because the assembly containing isn't loaded until the function body is executed; using the pipeline is helpful if you want to validate multiple credentials. – mklement Mar 9 at 18:52
  • @mklement There's no reason the Add-Type call can't be moved outside the function, to before its definition is executed. I'm hesitant to have an Add-Type call unconditionally run repeatedly inside the function even if it's already loaded, anyway. Validating multiple credentials simultaneously seems like an odd situation in the first place. In the rare case that's what you want, you can easily wrap the call in ForEach-Object, so I don't see a reason to complication the function with it. – jpmc26 Mar 9 at 19:00

I've found this post useful however it didn't solve my problem as I was trying to run it from a script with the local admin account logged on. It does not seem to work as local admin (only when logged on as a domain user).

However I did finally manage to get a working solution and since it was so much trouble I thought I'd share it here so anyone else with this problem will have the answer right here. Both answers on the one page depending on your needs.

Note that higher up in the scipt (not included here as this is just the get-credentials section) powergui is installed and is a requirement for this code below (as well as the "Add-PSSnapin Quest.ActiveRoles.ADManagement" line). Not sure what powergui does that's different but no one else could tell me and it works.

Subsitute your own domain name in the "domain_name" sections.

#Get credentials
$credential_ok = 0
while ($credential_ok -ne 1)
{
    $credential = get-credential
    $result = connect-qadservice -service *domain_name* -credential $credential
    [string]$result_string = $result.domain
    if ($result_string -eq "*domain_name*")
    {
        $credential_ok = 1
        #authenticated
    }
    else
    {
        #failed
    }     
}
$username = $credential.username 
$password = $credential.GetNetworkCredential().password 

$date = get-date
Add-Content "c:\lbin\Install_log.txt" "Successfully authenticated XP script as $username $date"

(yet) Another version:

param([string]$preloadServiceAccountUserName = "")

function HarvestCredentials()
{

        [System.Management.Automation.PSCredential]$credentialsOfCurrentUser = Get-Credential -Message "Please enter your username & password" -UserName $preloadServiceAccountUserName

        if ( $credentialsOfCurrentUser )
        {
            $credentialsOfCurrentUser = $credentialsOfCurrentUser
        }
        else
        {
            throw [System.ArgumentOutOfRangeException] "Gui credentials not entered correctly"          
        }

    Try
    {


        # see https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.path(v=vs.110).aspx
        # validate the credentials are legitimate
        $validateCredentialsTest = (new-object System.DirectoryServices.DirectoryEntry ("WinNT://"+$credentialsOfCurrentUser.GetNetworkCredential().Domain), $credentialsOfCurrentUser.GetNetworkCredential().UserName, $credentialsOfCurrentUser.GetNetworkCredential().Password).psbase.name
        if ( $null -eq  $validateCredentialsTest)
        {
            throw [System.ArgumentOutOfRangeException] "Credentials are not valid.  ('" + $credentialsOfCurrentUser.GetNetworkCredential().Domain + '\' + $credentialsOfCurrentUser.GetNetworkCredential().UserName + "')"
        }
        else
        {
            $t = $host.ui.RawUI.ForegroundColor
            $host.ui.RawUI.ForegroundColor = "Magenta"
            Write-Output "GOOD CREDENTIALS"
            $host.ui.RawUI.ForegroundColor = $t
        }
    }
    Catch
    {

        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        $StackTrace = $_.Exception.StackTrace

        $t = $host.ui.RawUI.ForegroundColor
        $host.ui.RawUI.ForegroundColor = "Red"

        Write-Output "Exception - $ErrorMessage"
        Write-Output "Exception - $FailedItem"
        Write-Output "Exception - $StackTrace"

        $host.ui.RawUI.ForegroundColor = $t

        throw [System.ArgumentOutOfRangeException] "Attempt to create System.DirectoryServices.DirectoryEntry failed.  Most likely reason is that credentials are not valid."
    }

}


Try
{

    HarvestCredentials

}
Catch
{
    $ErrorMessage = $_.Exception.Message
    $FailedItem = $_.Exception.ItemName
    $StackTrace = $_.Exception.StackTrace

    $t = $host.ui.RawUI.ForegroundColor
    $host.ui.RawUI.ForegroundColor = "Red"

    Write-Output "Exception - " + $ErrorMessage
    Write-Output "Exception - " + $FailedItem
    Write-Output "Exception - " + $StackTrace

    $host.ui.RawUI.ForegroundColor = $t

    Break
}
Finally
{
    $Time=Get-Date
    Write-Output "Done - " + $Time
}

and

.\TestCredentials.ps1 -preloadServiceAccountUserName "mydomain\myusername"

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.