Verifique se a entrada da senha do usuário é válida no script do Powershell

30

Estou trabalhando com um script do Powershell que adiciona tarefas agendadas aos sistemas em nosso domínio. Quando executo esse script, ele solicita minha senha. Às vezes, digito a senha e o processo é iniciado, o que bloqueia minha conta. Existe uma maneira de verificar minhas credenciais para garantir que o que eu digitei será validado com o domínio?

Eu gostaria de encontrar uma maneira de consultar o controlador de domínio. Fiz algumas pesquisas no Google e devo fazer uma consulta WMI e interceptar um erro. Eu gostaria de evitar esse estilo de validação, se possível.

Alguma ideia? Desde já, obrigado.

Doltknuckle
fonte

Respostas:

26

Eu tenho isso na minha biblioteca:

$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"
}
Jim B
fonte
11
Se não me engano, isso acabaria enviando a senha em texto sem formatação pela rede, certo? Em caso afirmativo, estou certo ao assumir que AccountManagement.PrincipalContext.ValidateCredentials()não (se você fornecer uma proteção para a senha)?
Code Jockey
Por que você não está usando o ActiveDirectorymódulo para fazer sua consulta LDAP?
Kolob Canyon 28/03
Há 6 anos não havia módulo do diretório ativo
Jim B
Esse script também ajuda em situações nas quais você não pode instalar os módulos do AD PowerShell por um motivo ou outro.
Dodzi Dzakuma
16

Isto é o que eu usei no passado; ele deve funcionar para contas de máquinas locais e 'diretório de aplicativos', mas até agora só o usei com sucesso com credenciais do AD:

    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)
    }
}
jbsmith
fonte
Gostaria de saber se alguém percebe isso - acredito que, quando uso ValidateCredentials () dessa maneira com uma senha incorreta, parece desencadear duas (2) tentativas incorretas de senha - não consigo controlar o número de tentativas no nosso domínio, e é baixo, então prefiro não ter duas tentativas ruins ao fazer uma única ligação ... alguém pode ver isso também?
Code Jockey
Você está usando o formato domínio \ usuário ou UPN (usuário @ domínio)? Eu não estou em uma posição para replicar isso, mas o seguinte URL descreve um problema semelhante: social.msdn.microsoft.com/Forums/vstudio/en-US/...
jbsmith
Você deve ser capaz de passar apenas $contextcomo argumento para o construtor. O PowerShell converterá automaticamente as seqüências de caracteres em uma enumeração. Melhor ainda, basta fazer [System.DirectoryServices.AccountManagement.ContextType]o tipo de $context. Além disso, por que você está usando begine processaqui? O pipeline parece uma maneira estranha de usar essa função.
Jpmc26
@ jpmc26: digitar o $contextparâmetro [System.DirectoryServices.AccountManagement.ContextType]não é uma opção, porque a montagem que contém não é carregada até que o corpo da função seja executado; o uso do pipeline é útil se você deseja validar várias credenciais.
precisa saber é
@mklement Não há motivo para a Add-Typechamada não ser movida para fora da função antes de sua definição ser executada. Eu hesito em ter uma Add-Typechamada incondicionalmente executada repetidamente dentro da função, mesmo que já esteja carregada. A validação de várias credenciais simultaneamente parece uma situação estranha em primeiro lugar. No caso raro, é isso que você deseja, você pode facilmente encerrar a ligação ForEach-Object, para que não veja uma razão para complicar a função.
Jpmc26 9/0318
1

Achei este post útil, mas ele não resolveu o meu problema, pois estava tentando executá-lo a partir de um script com a conta de administrador local conectada. Parece não funcionar como administrador local (somente quando conectado como um usuário de domínio).

No entanto, finalmente consegui obter uma solução funcional e, como havia muitos problemas, pensei em compartilhá-la aqui para que qualquer outra pessoa com esse problema tenha a resposta aqui. Ambas as respostas em uma página, dependendo de suas necessidades.

Observe que no nível superior (não incluído aqui, pois esta é apenas a seção obter credenciais), o powergui está instalado e é um requisito para este código abaixo (assim como a linha "Add-PSSnapin Quest.ActiveRoles.ADManagement"). Não sei o que o powergui faz, é diferente, mas ninguém mais poderia me dizer e funciona.

Substitua seu próprio nome de domínio nas seções "domain_name".

#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"
Michael
fonte
1

(ainda) Outra versão:

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
}

e

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