Public/Get-MDSADLockoutSource.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
Function Get-MDSADLockoutSource {
    <#
    .SYNOPSIS
    Query Active Directory for the lockout source for the most recently lockout event

    .DESCRIPTION
    Query Active Directory for the lockout source for the most recently lockout event. If a server is listed the query will be for the last lockout event on that specific server.

    .EXAMPLE
    Get-MDSADLockoutSource -SamAccountName $SamAccountName

    Query a single user's lockout source
    .EXAMPLE
    Get-MDSADLockoutSource -SamAccountName SamAccountName1,SamAccountName2

    Query multiple users at a time. Also accepts SamAccountNames via the pipeline
    .EXAMPLE
    Get-MDSADLockoutSource -SamAccountName $SamAccountName -Server Server.domain.com

    Accepts a specific server to query assuming the metadata time is the event time for that server
    .NOTES
    Written by Rick A., December 2017

    #>

    [CmdletBinding(DefaultParameterSetName='None')]
    [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingPlainTextForPassword','')]
    [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUsePSCredentialType','')]

    param(
        [Parameter(
            Mandatory                       = $true,
            Position                        = 0,
            ValueFromPipeline               = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [Parameter(ParameterSetName="MDSCredential")]
        [Parameter(ParameterSetName="Credential")]
        [Parameter(ParameterSetName="None")]
        [ValidateNotNullOrEmpty()]
        [string[]]$SamAccountName,

        [Parameter(Position=1,ParameterSetName="MDSCredential")]
        [Parameter(Position=1,ParameterSetName="Credential")]
        [Parameter(Position=1,ParameterSetName="None")]
        [string]$Server,

        [parameter(Position=2,ParameterSetName="MDSCredential")]
        [ValidateNotNullOrEmpty()]
        [String]$MDSCredential,

        [parameter(Position=2,ParameterSetName="Credential")]
        [ValidateNotNullOrEmpty()]
        [System.Management.Automation.CredentialAttribute()]
        $Credential
    )
    #requires -Module ActiveDirectory
    begin {}
    process    {
        Try {
            # MDSCredential
            If ($PSBoundParameters.MDSCredential) {
                $Credential = Get-MDSCredential -Name $MDSCredential -ErrorAction Stop
            }

            If ($null -eq $PSBoundParameters.Server) {
                $Server = Get-ADDomain -ErrorAction Stop | Select-Object -Expand PDCEmulator
                $VerboseString = 'No server specified. Using the PDCEmulator {0}.' -f $Server
                Write-Verbose $VerboseString
            }
        }
        Catch {
            $PsCmdlet.ThrowTerminatingError($PSItem)
        }

        ForEach ($Name in $SamAccountName) {
            Try {
                $Events = $ADUser = $null

                $VerboseString = 'Performing AD query for {0}.' -f $Name
                Write-Verbose $VerboseString
                $getADUserSplat = @{
                    Filter      = {SamAccountName -eq $Name}
                    Properties  = 'AccountLockoutTime'
                    Server      = $Server
                    ErrorAction = 'Stop'
                }
                $ADUser = Get-ADUser @getADUserSplat

                If ($null -eq $ADUser) {
                    $ErrorString = 'Cannot find object with samaccountname: {0}' -f $SamAccountName
                    Write-Error $ErrorString
                    Continue
                }

                # Lockout: 'Microsoft-Windows-Security-Auditing', ID 4740
                # Failure Event: 'Microsoft-Windows-Security-Auditing',ID 4771
                $FilterHashtable = @{
                    LogName         = 'Security'
                    ID              = 4740
                    ProviderName    = 'Microsoft-Windows-Security-Auditing'
                    Data            = $Name
                }
                $getWinEventSplat = @{
                    ComputerName    = $Server
                    FilterHashtable = $FilterHashtable
                    ErrorAction     = 'Stop'
                    Verbose         = $False
                }
                If ($Credential) {
                    [void]$getWinEventSplat.Add('Credential',$Credential)
                }
                Try {
                    [array]$Events = Get-WinEvent @getWinEventSplat
                }
                Catch {
                    Write-Error $PSItem
                    Continue
                }

                If ($null -eq $Events) {continue}

                Write-Verbose 'Parsing returned events'
                ForEach ($Event in $Events) {
                    If($Event | Where-Object {$_.Properties[2].Value -match $ADUser.SID.Value}) {
                        [PSCustomObject] @{
                            AccountName     = $Name
                            EventComputer   = $Event.Properties[4].Value
                            LockoutTime     = $Event.TimeCreated
                            LockoutSource   = $Event.Properties[1].Value
                        }
                    }
                }
            }
            Catch {
                Write-Error $PSItem
            }
        }
    }
    end {}
}