ตรวจสอบว่าการป้อนรหัสผ่านผู้ใช้ถูกต้องในสคริปต์ Powershell


30

ฉันกำลังทำงานกับสคริปต์ Powershell ที่เพิ่มงานที่กำหนดเวลาไว้ในระบบในโดเมนของเรา เมื่อฉันเรียกใช้สคริปต์นี้มันจะพร้อมท์ให้ฉันใส่รหัสผ่าน บางครั้งฉันลืมรหัสผ่านและกระบวนการเริ่มต้นซึ่งล็อคบัญชีของฉัน มีวิธีการยืนยันข้อมูลรับรองของฉันเพื่อให้แน่ใจว่าสิ่งที่ฉันพิมพ์จะตรวจสอบกับโดเมนหรือไม่

ฉันต้องการค้นหาวิธีสอบถามตัวควบคุมโดเมน ฉันทำการค้นหาโดย Google แล้วและฉันควรจะสามารถสืบค้นและดักจับ WMI เพื่อหาข้อผิดพลาดได้ ฉันต้องการหลีกเลี่ยงการตรวจสอบรูปแบบนั้นถ้าเป็นไปได้

ความคิดใด ๆ ขอบคุณล่วงหน้า.

คำตอบ:


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()ไม่ใช่ (ถ้าคุณให้รหัสลับเพื่อความปลอดภัย)
รหัส Jockey

ทำไมคุณไม่ใช้ActiveDirectoryโมดูลเพื่อทำแบบสอบถาม LDAP ของคุณ?
Kolob Canyon

6 ปีที่แล้วไม่มีโมดูลไดเรกทอรีที่ใช้งานอยู่
Jim B

สคริปต์นี้ยังช่วยในสถานการณ์ที่คุณไม่สามารถติดตั้งโมดูล AD PowerShell ด้วยเหตุผลใดก็ตาม
Dodzi Dzakuma

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)
    }
}

ฉันชอบที่จะได้ยินว่ามีคนสังเกตเห็นสิ่งนี้ - ฉันเชื่อว่าเมื่อฉันใช้ ValidateCredentials () ในลักษณะนี้ด้วยรหัสผ่านที่ไม่ถูกต้องดูเหมือนว่าจะเรียกรหัสผ่านไม่ถูกต้องสองครั้ง (2) ครั้ง - ฉันไม่สามารถควบคุมจำนวน ในโดเมนของเราและอยู่ในระดับต่ำดังนั้นฉันไม่ต้องการมีความพยายามที่ไม่ดีสองครั้งเมื่อฉันโทรเพียงครั้งเดียว ... ทุกคนสามารถเห็นสิ่งนี้ได้เช่นกัน?
รหัส Jockey

คุณใช้โดเมน \ user หรือรูปแบบ UPN (user @ domain) หรือไม่ ฉันไม่ได้อยู่ในฐานะที่จะทำซ้ำสิ่งนี้ แต่ URL ต่อไปนี้อธิบายถึงปัญหาที่คล้ายกัน: social.msdn.microsoft.com/Forums/vstudio/en-US/…
jbsmith

คุณควรจะสามารถส่งผ่าน$contextเป็นอาร์กิวเมนต์ไปยังตัวสร้าง PowerShell จะแปลงสตริงเป็น enum โดยอัตโนมัติ ยังดีกว่าเพียงแค่ทำให้ประเภทของ[System.DirectoryServices.AccountManagement.ContextType] $contextนอกจากนี้คุณใช้ทำไมbeginและprocessที่นี่ ไพพ์ไลน์ดูเหมือนเป็นวิธีแปลกในการใช้ฟังก์ชั่นนี้
jpmc26

@ jpmc26: พิมพ์$contextพารามิเตอร์[System.DirectoryServices.AccountManagement.ContextType]ไม่ได้ตัวเลือกเพราะการชุมนุมที่มีไม่โหลดจนกว่าการทำงานของร่างกายจะถูกดำเนินการ; การใช้ไปป์ไลน์มีประโยชน์หากคุณต้องการตรวจสอบความถูกต้องของข้อมูลรับรองหลายตัว
mklement

@mklement ไม่มีเหตุผลที่Add-Typeไม่สามารถย้ายสายนอกฟังก์ชั่นไปก่อนที่จะดำเนินการตามคำนิยาม ฉันลังเลที่จะรับAdd-Typeสายโดยไม่มีเงื่อนไขทำงานซ้ำ ๆ ภายในฟังก์ชั่นแม้ว่าจะโหลดแล้วก็ตาม การตรวจสอบข้อมูลรับรองหลายอย่างพร้อมกันดูเหมือนว่าเป็นสถานการณ์ที่แปลกตั้งแต่แรก ในกรณีที่หายากซึ่งเป็นสิ่งที่คุณต้องการคุณสามารถปิดการโทรได้อย่างง่ายดายForEach-Objectดังนั้นฉันจึงไม่เห็นเหตุผลที่จะทำให้ฟังก์ชั่นซับซ้อนด้วย
jpmc26

1

ฉันพบว่าโพสต์นี้มีประโยชน์ แต่ก็ไม่ได้แก้ปัญหาของฉันเพราะฉันพยายามที่จะเรียกใช้จากสคริปต์ที่มีบัญชีผู้ดูแลระบบท้องถิ่นเข้าสู่ระบบ ดูเหมือนว่าจะไม่ทำงานในฐานะผู้ดูแลท้องถิ่น (เฉพาะเมื่อเข้าสู่ระบบในฐานะผู้ใช้โดเมน)

อย่างไรก็ตามในที่สุดฉันก็จัดการเพื่อหาทางออกในการทำงานและเนื่องจากมันเป็นปัญหามากฉันคิดว่าฉันจะแบ่งปันที่นี่เพื่อให้คนอื่นที่มีปัญหานี้จะได้รับคำตอบที่นี่ คำตอบทั้งสองในหน้าเดียวขึ้นอยู่กับความต้องการของคุณ

โปรดทราบว่าสูงขึ้นใน scipt (ไม่รวมที่นี่เพราะนี่เป็นเพียงแค่ส่วนรับข้อมูลประจำตัว) ติดตั้ง powergui และเป็นข้อกำหนดสำหรับรหัสนี้ด้านล่าง (เช่นเดียวกับสาย "Add-PSSnapin Quest.ActiveRoles.ADManagement") ไม่แน่ใจว่า powergui ทำในสิ่งที่แตกต่าง แต่ไม่มีใครสามารถบอกฉันได้และใช้งานได้

สมัครสมาชิกชื่อโดเมนของคุณเองในส่วน "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"

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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.