Periksa apakah input kata sandi pengguna valid dalam skrip Powershell

30

Saya bekerja dengan skrip Powershell yang menambahkan tugas terjadwal ke sistem di domain kami. Ketika saya menjalankan skrip ini, saya akan diminta kata sandi. Saya terkadang lupa kata sandi dan proses dimulai, yang mengunci akun saya. Apakah ada cara untuk memverifikasi kredensial saya untuk memastikan bahwa apa yang saya ketikkan akan divalidasi dengan Domain?

Saya ingin mencari cara untuk menanyakan pengontrol Domain. Saya telah melakukan beberapa pencarian Google dan saya harus dapat melakukan query dan trap WMI untuk kesalahan. Saya ingin menghindari gaya validasi itu jika memungkinkan.

Ada ide? Terima kasih sebelumnya.

Doltknuckle
sumber

Jawaban:

26

Saya punya ini di perpustakaan saya:

$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
sumber
1
Jika saya tidak salah, ini akan berakhir mengirimkan kata sandi dalam teks biasa di seluruh jaringan, kan? Jika ya, maka apakah saya benar dengan asumsi itu AccountManagement.PrincipalContext.ValidateCredentials()tidak (jika Anda memberikan kata sandi untuk keamanan)?
Code Jockey
Mengapa Anda tidak menggunakan ActiveDirectorymodul untuk melakukan permintaan LDAP Anda?
Kolob Canyon
6 tahun yang lalu tidak ada modul direktori aktif
Jim B
Skrip ini juga membantu untuk situasi di mana Anda tidak dapat menginstal modul AD PowerShell karena satu dan lain alasan.
Dodzi Dzakuma
16

Inilah yang saya gunakan di masa lalu; seharusnya berfungsi untuk akun mesin lokal dan 'direktori aplikasi', tetapi sejauh ini saya hanya menggunakannya dengan kredensial 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
sumber
Saya ingin mendengar jika seseorang memperhatikan ini - Saya percaya bahwa ketika saya menggunakan ValidateCredentials () dengan cara ini dengan kata sandi yang salah, tampaknya memicu dua (2) upaya kata sandi yang buruk - Saya tidak dapat mengontrol jumlah upaya ambang di domain kami, dan rendah, jadi saya lebih suka tidak melakukan dua upaya buruk ketika saya melakukan satu panggilan ... adakah yang bisa melihat ini juga?
Code Jockey
Apakah Anda menggunakan format domain \ user atau UPN (user @ domain)? Saya tidak dalam posisi untuk mereplikasi ini, tetapi URL berikut ini menjelaskan masalah yang serupa: social.msdn.microsoft.com/Forums/vstudio/en-US/…
jbsmith
Anda harus dapat menyampaikan $contextsebagai argumen kepada konstruktor. PowerShell akan secara otomatis mengonversi string menjadi enum. Lebih baik lagi, buat saja [System.DirectoryServices.AccountManagement.ContextType]jenisnya $context. Juga, mengapa Anda menggunakan begindan di processsini? Pipa sepertinya cara aneh untuk menggunakan fungsi ini.
jpmc26
@ jpmc26: mengetikkan $contextparameter [System.DirectoryServices.AccountManagement.ContextType]bukanlah suatu pilihan, karena rakitan yang berisi tidak dimuat sampai badan fungsi dijalankan; menggunakan pipa sangat membantu jika Anda ingin memvalidasi banyak kredensial.
mklement
@mklement Tidak ada alasan Add-Typepanggilan tidak dapat dipindahkan di luar fungsi, sebelum definisi dijalankan. Saya ragu untuk memiliki Add-Typepanggilan tanpa syarat berjalan berulang kali di dalam fungsi meskipun sudah dimuat, sih. Memvalidasi banyak kredensial secara bersamaan tampaknya merupakan situasi aneh di tempat pertama. Dalam kasus langka itu yang Anda inginkan, Anda dapat dengan mudah membungkus panggilan ForEach-Object, jadi saya tidak melihat alasan untuk menyulitkan fungsi dengannya.
jpmc26
1

Saya menemukan posting ini bermanfaat namun tidak menyelesaikan masalah saya karena saya mencoba menjalankannya dari skrip dengan akun admin lokal yang masuk. Tampaknya tidak berfungsi sebagai admin lokal (hanya ketika masuk sebagai pengguna domain).

Namun akhirnya saya berhasil mendapatkan solusi yang berhasil dan karena begitu banyak masalah, saya pikir saya akan membagikannya di sini sehingga orang lain yang memiliki masalah ini akan memiliki jawabannya di sini. Keduanya menjawab pada satu halaman tergantung pada kebutuhan Anda.

Perhatikan bahwa lebih tinggi di scipt (tidak termasuk di sini karena ini hanya bagian get-kredensial) powergui diinstal dan merupakan persyaratan untuk kode ini di bawah ini (serta baris "Tambahkan-PSSnapin Quest.ActiveRoles.ADManagement"). Tidak yakin apa yang dilakukan powergui itu berbeda tetapi tidak ada orang lain yang bisa memberi tahu saya dan itu berfungsi.

Ganti nama domain Anda sendiri di bagian "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
sumber
1

(belum) Versi lain:

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
}

dan

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