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 { $ResultEvents = @() 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() # Building output based on advanced properties $ResultEvents += @{ LockedUserName = $eventXML.Event.EventData.Data[5].'#text' LogonType = $LogonInfo.PrivateData.LogonType."$($eventXML.Event.EventData.Data[10].'#text')" LogonProcessName = $eventXML.Event.EventData.Data[11].'#text' ProcessName = $eventXML.Event.EventData.Data[18].'#text' FailureReason = $LogonInfo.PrivateData.FailureReason."$($eventXML.Event.EventData.Data[8].'#text')" FailureStatus = $LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[7].'#text')" FailureSubStatus = $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 }) { #Building output based on advanced properties $ResultEvents += @{ LockedUserName = $eventXML.Event.EventData.Data[5].'#text' LogonType = $LogonInfo.PrivateData.LogonType.($eventXML.Event.EventData.Data[10].'#text') LogonProcessName = $eventXML.Event.EventData.Data[11].'#text' ProcessName = $eventXML.Event.EventData.Data[18].'#text' FailureReason = $LogonInfo.PrivateData.FailureReason."$($eventXML.Event.EventData.Data[8].'#text')" FailureStatus = $LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[7].'#text')" FailureSubStatus = $LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[9].'#text')" } } } } } } end { return $ResultEvents } } #EndRegion '.\Public\Get-UserLockoutReason.ps1' 153 |