Проверьте правильность ввода пароля пользователя в скрипте Powershell

30

Я работаю со скриптом Powershell, который добавляет запланированные задачи к системам в нашем домене. Когда я запускаю этот скрипт, он запрашивает мой пароль. Я иногда толстым пальцем набираю пароль и начинается процесс, который блокирует мою учетную запись. Есть ли способ проверить мои учетные данные, чтобы убедиться, что то, что я ввел, будет проверяться с доменом?

Я хотел бы найти способ запросить контроллер домена. Я сделал несколько поисков в Google, и я должен быть в состоянии сделать запрос WMI и ловушку для ошибки. Я хотел бы избежать такого стиля проверки, если это возможно.

Любые идеи? Заранее спасибо.

Doltknuckle
источник

Ответы:

26

У меня есть это в моей библиотеке:

$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"
}
Джим Б
источник
1
Если я не ошибаюсь, это приведет к отправке пароля в виде простого текста по сети, верно? Если да, то правильно ли я предположить, что AccountManagement.PrincipalContext.ValidateCredentials()это не так (если вы предоставляете безопасную строку для пароля)?
Код жокея
Почему вы не используете ActiveDirectoryмодуль для выполнения LDAP-запроса?
Колоб Каньон
6 лет назад не было активного модуля каталогов
Джим Б
Этот сценарий также помогает в ситуациях, когда вы не можете установить модули AD PowerShell по тем или иным причинам.
Додзи Дзакума
16

Это то, что я использовал в прошлом; он должен работать для учетных записей локальных компьютеров и «каталога приложений», но до сих пор я успешно использовал его только с учетными данными 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
источник
Я хотел бы услышать, если кто-то заметит это - я полагаю, что когда я использую ValidateCredentials () таким образом с неверным паролем, он, кажется, вызывает две (2) попытки неверного пароля - я не могу контролировать порог количества попыток на нашем домене, и он низкий, поэтому я бы предпочел не делать двух неудачных попыток, когда я делаю один звонок ... может кто-нибудь тоже это увидит?
Код жокея
Используете ли вы формат домен \ пользователь или UPN (пользователь @ домен)? Я не в состоянии повторить это, но следующий URL-адрес описывает подобную проблему: social.msdn.microsoft.com/Forums/vstudio/en-US/…
jbsmith
Вы должны иметь возможность просто передать $contextв качестве аргумента конструктору. PowerShell автоматически преобразует строки в перечисление. Еще лучше, просто сделайте [System.DirectoryServices.AccountManagement.ContextType]тип $context. Кроме того, почему вы используете beginи processздесь? Конвейер кажется странным способом использования этой функции.
jpmc26
@ jpmc26: ввод $contextпараметра [System.DirectoryServices.AccountManagement.ContextType]не возможен , поскольку сборка, содержащая сборку, не загружается до тех пор, пока не будет выполнено тело функции ; Использование конвейера полезно, если вы хотите проверить несколько учетных данных.
Мклемент
@mklement Нет причин, по которым Add-Typeвызов не может быть перемещен за пределы функции до выполнения ее определения. Я сомневаюсь, чтобы Add-Typeвызов безоговорочно выполнялся повторно внутри функции, даже если она уже загружена. Проверка нескольких учетных данных одновременно кажется странной ситуацией. В редком случае это то, что вы хотите, вы можете легко обернуть вызов ForEach-Object, поэтому я не вижу причин усложнять функцию с ним.
jpmc26
1

Я нашел этот пост полезным, однако он не решил мою проблему, так как я пытался запустить его из скрипта с локальной учетной записью администратора. Кажется, он не работает как локальный администратор (только при входе в систему как пользователь домена).

Однако мне, наконец, удалось получить рабочее решение, и, так как это было так сложно, я решил поделиться им здесь, чтобы у кого-нибудь еще с этой проблемой был ответ прямо здесь. Оба ответа на одной странице в зависимости от ваших потребностей.

Обратите внимание, что выше в scipt (сюда не входит, так как это просто раздел get-credentials) установлен powergui, и он является обязательным требованием для этого кода ниже (а также строки «Add-PSSnapin Quest.ActiveRoles.ADManagement»). Не уверен, что Powergui делает это по-другому, но никто не мог сказать мне, и это работает.

Подставьте свое собственное доменное имя в разделы "имя_домена".

#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"
Майкл
источник
1

(пока) Другая версия:

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
}

а также

.\TestCredentials.ps1 -preloadServiceAccountUserName "mydomain\myusername"
granadaCoder
источник