PSSYSAdm.psm1

#Region '.\Public\Disable-CompromisedUser.ps1' 0
function Disable-CompromisedUser
{
<#
    .SYNOPSIS
    Disable compromised user
 
    .DESCRIPTION
    In case of compromission from some users, you can rapidly disable this users.
    You can pass to parameter :
        - a nominative list of user
        - a file with a nominative list of users (one user by line)
        - an OU to disable all users
    Check example for more details (get-help Disable-CompromisedUser -Examples)
    A log file is create in your temp directory ($env:temp)
 
    .PARAMETER Identity
    One or more user(s) to disable
 
    .PARAMETER FileName
    File with a list of users to disable. txt with one name by line
 
    .PARAMETER OU
    One or more OU(s) in which we want to disable all users
 
    .PARAMETER Check
    Only check if the users passed in parameter, whatever the way (Identity, Filename or OU), are disable
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1"
 
    Disable the user account : User1
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1" -Check
 
    Check if user account User1 is disable
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1","User2","User3"
 
    Disable users account : User1, User2 and User3
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1","User2","User3" -Check
 
    Check if users account User1, User2 and User3 are disable
 
    .EXAMPLE
    Disable-CompromisedUser -FileName "c:\temp\CompromisedUser.txt"
 
    File template CompromisedUser.txt :
    User1
    User2
    User3
 
    Disable users account : User1, User2 and User3
 
    .EXAMPLE
    Disable-CompromisedUser -FileName "c:\temp\CompromisedUser.txt" -Check
 
    File template CompromisedUser.txt :
    User1
    User2
    User3
 
    Check if users account User1, User2 and User3 are disable
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com"
 
    Disable all users present in OU1
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com" -Check
 
    Check if all users present in OU1 are disable
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com","OU=OU2,DC=contoso,DC=com"
 
    Disable all users present in OU1 and OU2
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com","OU=OU2,DC=contoso,DC=com" -check
 
    Check if all users present in OU1 and OU2 are disable
 
    .NOTES
    General notes
#>

    [CmdletBinding(DefaultParameterSetName = "ByUser")]
    param (
        [Parameter(
            ParameterSetName = "ByUser",
            HelpMessage = 'One or more user(s) to disable'
        )]
        [System.String[]]$Identity,
        [Parameter(
            ParameterSetName = "ByFileName",
            HelpMessage = 'File with a list of users to disable. txt with one name by line'
        )]
        [System.String]$FileName,
        [Parameter(
            ParameterSetName = "ByOu",
            HelpMessage = 'One or more OU(s) in which we want to disable all users'
        )]
        [System.String[]]$OU,
        [Parameter(
            HelpMessage = 'Only check if the users passed in parameter, whatever the way (Identity, Filename or OU), are disable'
        )]
        [Switch]$Check
    )

    begin
    {

        $LogFile = "$env:temp\DisableCompromisedUser-$((get-date).ToString("yyyyMMddTHHmmss")).log"
        if (Test-Path -Path $LogFile)
        {
            Remove-Item -Path $LogFile -Force
        }
        Write-Verbose ('[{0:O}] Log File {1}' -f (get-date),$LogFile)
        Write-Verbose ('[{0:O}] Retrieve AD User Account ' -f (get-date))
        $Users = @()

        switch ($PSCmdlet.ParameterSetName)
        {
            ByUser
            {
                Add-content $Logfile -value ('[{0:O}] Retrieve AD User Account by user list ' -f (get-date))
                foreach ($User in $Identity)
                {
                    try
                    {
                        $Users += Get-ADUser -Identity $User -Properties SamAccountName,DisplayName,Enabled -ErrorAction Continue | Select-Object SamAccountName,DisplayName,Enabled
                        Write-Verbose ('[{0:O}] User {1} found ' -f (get-date),$User)
                        Add-content $Logfile -value ('[{0:O}] User {1} found ' -f (get-date),$User)
                    }
                    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
                    {
                        Write-Verbose ('[{0:O}] user {1} not found' -f (get-date), $User)
                        Add-content $Logfile -value (('[{0:O}] user {1} not found' -f (get-date), $User))
                    }
                }
            }
            ByFileName
            {
                Add-content $Logfile -value ('[{0:O}] [INFO] Retrieve AD User Account by filename ' -f (get-date))
                foreach ($User in (Get-Content -Path $FileName))
                {
                    try
                    {
                        $Users += Get-ADUser -Identity $User -Properties SamAccountName,DisplayName,Enabled -ErrorAction Continue | Select-Object SamAccountName,DisplayName,Enabled
                        Write-Verbose ('[{0:O}] [INFO] [FOUND] user {1} ' -f (get-date),$User)
                        Add-content $Logfile -value ('[{0:O}] [INFO] [FOUND] user {1} ' -f (get-date),$User)
                    }
                    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
                    {
                        Write-Verbose ('[{0:O}] [ERROR] [NOTFOUND] user {1} ' -f (get-date), $User)
                        Add-content $Logfile -value (('[{0:O}] [ERROR] [NOTFOUND] user {1}' -f (get-date), $User))
                    }
                }
            }
            ByOu
            {
                Add-content $Logfile -value ('[{0:O}] [INFO] Retrieve AD User Account by OU list ' -f (get-date))
                foreach ($Organ in $OU)
                {
                    Write-Verbose ('[{0:O}] [INFO] Retrieve all users from OU {1}' -f (get-date), $Organ)
                    Add-content $Logfile -value (('[{0:O}] [INFO] Retrieve all users from OU {1}' -f (get-date), $Organ))
                    $Users += Get-ADUser -Filter * -SearchBase $Organ -Properties SamAccountName,DisplayName,Enabled | Select-Object SamAccountName,DisplayName,Enabled
                }
            }
        }

        Write-Verbose ('[{0:O}] [INFO] {1} AD user account found ' -f (get-date), $Users.Count)
        Add-content $Logfile -value (('[{0:O}] [INFO] {1} AD user account found ' -f (get-date), $Users.Count))
    }

    process
    {

        foreach ($user in $Users)
        {
            if ($Check)
            {
                Write-Verbose (('[{0:O}] [INFO] Check state for user {1} ' -f (get-date), $User.SamAccountName))
                Add-content $Logfile -value (('[{0:O}] [INFO] Check state for user {1} [{2}]' -f (get-date), $User.SamAccountName,$user.DisplayName))
                if ($user.Enabled -eq "True")
                {
                    Write-Verbose (('[{0:O}] [INFO] [ENABLE] user {1} ' -f (get-date), $User.SamAccountName))
                    Add-content $Logfile -value (('[{0:O}] [ENABLE] user {1} [{2}] ' -f (get-date), $User.SamAccountName,$user.DisplayName))
                } else
                {
                    Write-Verbose (('[{0:O}] [INFO] [DISABLE] user {1}' -f (get-date), $User.SamAccountName))
                    Add-content $Logfile -value (('[{0:O}] [DISABLE] user {1} [{2}] ' -f (get-date), $User.SamAccountName,$User.DisplayName))
                }
            } else
            {
                Write-Verbose ('[{0:O}] [INFO] Disable AD Account {1} ' -f (get-date), $User.SamAccountName)
                Disable-ADAccount -Identity $user.SamAccountName -WhatIf -Confirm:$false
                Add-content $Logfile -value (('[{0:O}] [INFO] {1} [{2}] AD account disabled ' -f (get-date), $User.SamAccountName,$User.DisplayName))
            }
        }
    }

    end
    {

    }
}
#EndRegion '.\Public\Disable-CompromisedUser.ps1' 212
#Region '.\Public\Find-UserLockoutsInformation.ps1' 0
Function Find-UserLockoutsInformation
{
<#
    .SYNOPSIS
    Find information about locked user account
 
    .DESCRIPTION
    This fonction search for locked user on PDC Emulator and return the lock source
    return :
    User : User1
    DomainController : PDCEmulator
    EventId : 4740
    LockoutTimeStamp : 8/3/2023 6:18:12 AM
    Message : A user account was locked out.
    LockoutSource : SourceComputer
    To find the reason use : Get-UserLockoutReason -Computer SourceComputer -Identity User1
 
    .PARAMETER Identity
    User to check (by default all)
 
    .PARAMETER DC
    Domain controller on which you want to look up information (by default PDC Emulator)
 
    .PARAMETER Credential
    Administrator credential to connect to the DC
 
    .EXAMPLE
    Find-UserLockoutsInformation -Credential (Get-Credential MyAdminAccount)
    Search information for all locked users in PDC Emulator
 
    .EXAMPLE
    Find-UserLockoutsInformation -Identity User1 -Credential (Get-Credential MyAdminAccount)
    Search information for user User1 in PDC Emulator
 
    .EXAMPLE
    Find-UserLockoutsInformation -Identity User1 -DC MyDC1 -Credential (Get-Credential MyAdminAccount)
    Search information for user User1 in specific domain controler MyDC1
 
    .NOTES
    General notes
#>

    [CmdletBinding(
        DefaultParameterSetName = 'All'
    )]
    param (
        [Parameter(
            ValueFromPipeline = $true,
            ParameterSetName = 'ByUser'
        )]
        [System.String]$Identity,
        [System.String]$DC = (Get-ADDomain).PDCEmulator,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )
    Begin
    {
        Write-Verbose ('[{0:O}] Searching EventID : 4740 on Server : {1} ' -f (get-date), $DC)
        $WinEventArguments = @{
            ComputerName    = $DC
            FilterHashtable = @{LogName = 'Security'; Id = 4740 }
        }

        if ($PSBoundParameters.ContainsKey('Credential'))
        {
            $WinEventArguments['Credential'] = $Credential
        }
        try {
            $LockedOutEvents = Get-WinEvent @WinEventArguments -ErrorAction Stop | Sort-Object -Property TimeCreated -Descending
        }
        catch {
            if ($Error[-1].Exception.Message -like "*elevated user rights*") {
                throw ('[{0:O}] You need an admin account. Please provide with the -Credential parameter' -f (get-date))
            }
        }

        if ($LockedOutEvents) {
            Write-Verbose ('[{0:O}] {1} event found' -f (get-date), $LockedOutEvents.Count)
        } else {
            throw ('[{0:O}] No event found' -f (get-date))
        }
    }

    Process
    {
        switch ($PSCmdlet.ParameterSetName)
        {
            ByUser
            {
                Write-Verbose ('[{0:O}] Searching information for user : {1}' -f (get-date), $Identity)
                $UserInfo = Get-ADUser -Identity $Identity
                Foreach ($Event in $LockedOutEvents)
                {
                    If ($Event | Where-Object { $_.Properties[2].value -match $UserInfo.SID.Value })
                    {

                        $Event | Select-Object -Property @(
                            @{Label = 'User'; Expression = { $_.Properties[0].Value } }
                            @{Label = 'DomainController'; Expression = { $_.MachineName } }
                            @{Label = 'EventId'; Expression = { $_.Id } }
                            @{Label = 'LockoutTimeStamp'; Expression = { $_.TimeCreated } }
                            @{Label = 'Message'; Expression = { $_.Message -split "`r" | Select-Object -First 1 } }
                            @{Label = 'LockoutSource'; Expression = { $_.Properties[1].Value } }
                        )
                    }
                }
            }
            All
            {
                Write-Verbose ('[{0:O}] Searching information for all user(s) ' -f (get-date))
                Foreach ($Event in $LockedOutEvents)
                {

                    $Event | Select-Object -Property @(
                        @{Label = 'User'; Expression = { $_.Properties[0].Value } }
                        @{Label = 'DomainController'; Expression = { $_.MachineName } }
                        @{Label = 'EventId'; Expression = { $_.Id } }
                        @{Label = 'LockoutTimeStamp'; Expression = { $_.TimeCreated } }
                        @{Label = 'Message'; Expression = { $_.Message -split "`r" | Select-Object -First 1 } }
                        @{Label = 'LockoutSource'; Expression = { $_.Properties[1].Value } }
                    )
                }
            }
        }
    }
    End
    {
    }

}
#EndRegion '.\Public\Find-UserLockoutsInformation.ps1' 134
#Region '.\Public\Get-RemoteRDPSession.ps1' 0
function Get-RemoteRDPSession
{
<#
    .SYNOPSIS
    Retrieve RDP session
 
    .DESCRIPTION
    This function retrive all rdp session on a remote computer.
    Result il like :
    UserName : UserName
    SessionName : SessionName
    ID : SessionID
    State : SessionState
    IdleTime : SessionIdleTime
    LogonTime : SessionLogonType
 
    .PARAMETER ComputerName
    The remote computer on which you want RDP sessions
 
    .PARAMETER Credential
    An account with the necessary privileges to connect to the remote computer
 
    .EXAMPLE
    Get-RemoteRDPSessions -ComputerName Server1 -Credential MyAdmAccount
 
    .NOTES
    General notes
#>

    param (
        [Parameter()]
        [string]$ComputerName,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    $QueryArguments = @{
        ComputerName    = $ComputerName
    }

    if ($PSBoundParameters.ContainsKey('Credential'))
    {
        $QueryArguments['Credential'] = $Credential
    }

    $query = Invoke-Command @QueryArguments -ScriptBlock { quser }
    if ($query -match 'No User exists for ')
    {
        Write-Output "No active RDP sessions found on $ComputerName."
        return
    }

    $sessions = $query | Select-Object -Skip 1 | ForEach-Object {
        $parts = $_.Trim() -split '\s+'
        [PSCustomObject]@{
            UserName    = $parts[0]
            SessionName = $parts[1]
            ID          = $parts[2]
            State       = $parts[3]
            IdleTime    = if ($parts.Count -ge 6)
            {
                $parts[5]
            }
            else
            {
                'N/A'
            }
            LogonTime   = if ($parts.Count -ge 5)
            {
                "$($parts[4]) $([DateTime]::Now.ToShortDateString())"
            }
            else
            {
                'N/A'
            }
        }
    }

    return $sessions
}
#EndRegion '.\Public\Get-RemoteRDPSession.ps1' 84
#Region '.\Public\Get-UserLockoutReason.ps1' 0
function Get-UserLockoutReason
{
    <#
    .SYNOPSIS
    Search user lockout reason
 
    .DESCRIPTION
    You can search the reason of locked user on a specific computer
    To find the source you can use : Find-UserLockoutsInformation -Identity User1 -DC MyDC1 -Credential (Get-Credential MyAdminAccount)
 
    .PARAMETER Computer
    User lockout source computer
 
    .PARAMETER Identity
    Name of the user for whom we are looking for the source of the lock
 
    .PARAMETER Credential
    Administrator credential to connect to the computer
 
    .EXAMPLE
    Get-UserLockoutReason -Computer ComputerSource -Identity User1 -Credential (Get-Credential MyAdminAccount)
 
    .NOTES
    General notes
#>

    [CmdletBinding(
        DefaultParameterSetName = 'All'
    )]
    [OutputType([System.Object[]])]
    param (
        [System.String]$Computer,
        [Parameter(
            ValueFromPipeline = $true,
            ParameterSetName = 'ByUser'
        )]
        [System.String]$Identity,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    begin
    {
        $LogonInfo = Import-PSFPowerShellDataFile -Path $PSScriptRoot/PSSYSAdm.psd1
        Write-Verbose ('[{0:O}] Searching EventID : 4625 on Computer : {1} ' -f (get-date), $Computer)

        $WinEventArguments = @{
            ComputerName    = $Computer
            FilterHashtable = @{LogName = 'Security'; Id = 4625 }
        }

        if ($PSBoundParameters.ContainsKey('Credential'))
        {
            $WinEventArguments['Credential'] = $Credential
        }

        $lockoutEvents = $null
        Write-Verbose ('[{0:O}] Test if computer : {1} is alive ' -f (get-date), $Computer)
        if (Test-Connection -ComputerName $Computer -Quiet -Count 2)
        {
            try
            {
                $lockoutEvents = Get-WinEvent @WinEventArguments -ErrorAction Stop
            }
            catch
            {
                if ($_.Exception.Message -match "No events were found that match the specified selection criteria")
                {
                    Write-Verbose ('[{0:O}] No logs found' -f (get-date))
                }
                if ($Error[-1].Exception.Message -like "*elevated user rights*")
                {
                    throw ('[{0:O}] You need an admin account. Please provide with the -Credential parameter' -f (get-date))
                }
            }
        }
        else
        {
            throw ('[{0:O}] computer {1} is not alive' -f (get-date), $Computer)
        }

        if ($lockoutEvents)
        {
            Write-Verbose ('[{0:O}] {1} event found' -f (get-date), $lockoutEvents.Count)
        }
        else
        {
            throw ('[{0:O}] No event found' -f (get-date))
        }
    }

    process
    {
        switch ($PSCmdlet.ParameterSetName)
        {
            All
            {
                Write-Verbose ('[{0:O}] Searching information for all user(s) ' -f (get-date))
                Foreach ($Event in $lockoutEvents)
                {
                    $eventXML = [xml]$event.ToXml()
                    $Event | Select-Object -Property @(
                        @{label = 'LockedUserName' ; Expression = {$eventXML.Event.EventData.Data[5].'#text'}}
                        @{label = 'LogonType' ; Expression = {$LogonInfo.PrivateData.LogonType."$($eventXML.Event.EventData.Data[10].'#text')"}}
                        @{label = 'LogonProcessName' ; Expression = {$eventXML.Event.EventData.Data[11].'#text'}}
                        @{label = 'ProcessName' ; Expression = {$eventXML.Event.EventData.Data[18].'#text'}}
                        @{label = 'FailureReason' ; Expression = {$LogonInfo.PrivateData.FailureReason."$($eventXML.Event.EventData.Data[8].'#text')"}}
                        @{label = 'FailureStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[7].'#text')"}}
                        @{label = 'FailureSubStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[9].'#text')"}}
                    )
                }
            }
            ByUser
            {
                Write-Verbose ('[{0:O}] Searching information for user : {1}' -f (get-date), $Identity)
                Foreach ($Event in $lockoutEvents)
                {
                    $eventXML = [xml]$event.ToXml()
                    If ($Event | Where-Object { $eventXML.Event.EventData.Data[5].'#text' -match $Identity })
                    {
                        $Event | Select-Object -Property @(
                            @{label = 'LockedUserName' ; Expression = {$eventXML.Event.EventData.Data[5].'#text'}}
                            @{label = 'LogonType' ; Expression = {$LogonInfo.PrivateData.LogonType."$($eventXML.Event.EventData.Data[10].'#text')"}}
                            @{label = 'LogonProcessName' ; Expression = {$eventXML.Event.EventData.Data[11].'#text'}}
                            @{label = 'ProcessName' ; Expression = {$eventXML.Event.EventData.Data[18].'#text'}}
                            @{label = 'FailureReason' ; Expression = {$LogonInfo.PrivateData.FailureReason."$($eventXML.Event.EventData.Data[8].'#text')"}}
                            @{label = 'FailureStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[7].'#text')"}}
                            @{label = 'FailureSubStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[9].'#text')"}}
                        )
                    }

                }

            }
        }


    }

    end
    {
    }
}
#EndRegion '.\Public\Get-UserLockoutReason.ps1' 147