Is there a AD lockout script showing actual machine - powershell

Does anyone know or have a script which tells you the actual device locking out an AD account. I have a working script which lists all users locked out in the last 3 days which tells me the DC its locked out. Rather than having to connect to this or via event log and locate the event id, i wanted to know if there was a PS script out there which would output where. Then we can go to said device and fix.
Google has brought up a few suggestions but not the clearest and some just do what i can already get via the current script.
Thanks

This returns an array of PsObjects, where:
property TargetUserName holds the user SamAccountName that is locked out
property TargetDomainName contains the computer name where the lockout originated from
property EventDate will show the time and date the lockout occurred
Code:
# get the domain controller that has the PDC Emulator Role
$pdc = (Get-ADDomain).PDCEmulator
$splat = #{
FilterHashtable = #{LogName="Security";Id=4740}
MaxEvents = 100
ComputerName = $pdc
Credential = Get-Credential -Message "Please enter credentials for '$pdc'"
}
$lockedOut = Get-WinEvent #splat | ForEach-Object {
# convert the event to XML and grab the Event node
$eventXml = ([xml]$_.ToXml()).Event
# create an ordered hashtable object to collect all data
# add some information from the xml 'System' node first
$evt = [ordered]#{
EventDate = [DateTime]$eventXml.System.TimeCreated.SystemTime
Level = [System.Diagnostics.Tracing.EventLevel]$eventXml.System.Level
}
# next see if there are childnodes under 'EventData'
if ($eventXml.EventData.HasChildNodes) {
$eventXml.EventData.ChildNodes | ForEach-Object {
$name = if ($_.HasAttribute("Name")) { $_.Name } else { $_.LocalName }
$value = $_.'#text'
if ($evt[$name]) {
# if an item with that name already exists, make it an array and append
$evt[$name] = #($evt[$name]) + $value
}
else { $evt[$name] = $value }
}
}
# output as PsCustomObject. This ensures the $result array can be written to CSV easily
[PsCustomObject]$evt
}
# output on screen
$lockedOut | fl *
# output to csv file
$lockedOut | Export-Csv -Path 'D:\lockedout.csv' -NoTypeInformation
If you want to search for a specific user (SamAccountName) for instance, just do
$lockedOut | Where-Object { $_.TargetUserName -eq 'UserSamAccountName' }
Hope that helps

Related

Extract Username From Log Text using Powershell

I'm trying to extract all usernames that has failed login atempts from Event Viewer log and then list only the usernames. However the data for each entry is text so I have a hard time extracting only the names (Intruder123 in this case). It would be a couple of hundred account names stored in an array.
$String = Get-WinEvent #{LogName='Security';ProviderName='Microsoft-Windows-Security-Auditing';ID=4625 } -ComputerName SECRETSERVER |
Select-Object -ExpandProperty Message
$string -match "Account Name: (?<content>.*)"
$matches['content']
The data looks like this (multiple times):
Account For Which Logon Failed:
Security ID: S-1-0-0
Account Name: Intruder123
Account Domain: SECRET.LOCAL
I think you could collect some more information like the time the failed logon happened and on which computer. For that, create a resulting array of objects.
Also, trying to parse the Message property can be cumbersome and I think it is much better to get the info from the Event as XML:
$filter = #{LogName='Security';ProviderName='Microsoft-Windows-Security-Auditing';ID=4625 }
$result = Get-WinEvent -FilterHashtable $filter -ComputerName SECRETSERVER | ForEach-Object {
# convert the event to XML and grab the Event node
$eventXml = ([xml]$_.ToXml()).Event
$userName = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
$computer = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'WorkstationName' }).'#text'
# output the properties you need
[PSCustomObject]#{
Time = [DateTime]$eventXml.System.TimeCreated.SystemTime
UserName = $userName
Computer = $computer
}
}
# output on screen
$result
# output to CSV file
$result | Export-Csv -Path 'X:\FailedLogons.csv' -NoTypeInformation

Report that compares AD users by department attribute and their ResourceName in SCCM

I am trying to develop a report for me and my team. The report looks at Active Directory and filters users based on department. I got that to work just fine. I then want those users to be cross referenced in SCCM to find their Resource Name devices. After they find the Resource Name devices I want their name and primary devices outputted and emailed to me in a report fashion. Note In the script below the $UserList is the list of AD users I already pulled based on the department FN(Finance). How can tell SCCM to take those users and find their primary device? Then how do I output both sets of data?
"$UserList = '\L007478\c$\temp\SCCM people.txt' ForEach ($User in $UserList) { $output = Get-CMUserDeviceAffinity -UserName $User
if ($output -eq $null) { $output -eq $null Write-Host "No Data was Found" } else { Write-Host $output }
}"
When you run Get-CMUserDeviceAffinity it will give you this data. All I really need is the ResourceName
SmsProviderObjectPath : SMS_UserMachineRelationship.RelationshipResourceID=25172891
CreationTime : 6/3/2020 10:11:33 AM
IsActive : True
RelationshipResourceID : 25172891
ResourceClientType : 1
ResourceID : 16780388
ResourceName : L007478
Sources : {4}
Types : {}
UniqueUserName : redgold\jknotts
You can do the following:
$UserList = Get-Content '\\L007478\c$\temp\SCCM people.txt'
$output = ForEach ($User in $UserList) {
$affinity = Get-CMUserDeviceAffinity -UserName $User
$obj = "" | Select User,ResourceName # Create custom object with properties User and ResourceName
$obj.User = $User # Set User property to $User
if (!$affinity) {
$obj.ResourceName = 'No data was found' # Set ResourceName property
}
else {
$obj.ResourceName = $affinity.ResourceName # Set ResourceName property
}
$obj # Output the custom object and store in collection $output
}
# output results
$output
# Output results to CSV
$output | Export-Csv output.csv -NoType
Since the Get-CMUserDeviceAffinity results contained a property called ResourceName that you want to retrieve, you can simply use the . member access operator. The syntax is $variable.Property or (command).Property.
Creating a custom object allows for custom properties.

How to save .csv paths in a object?

I have a foreach loop that works like that:
I load an object from XML, so an object composed from city and email of the ICT Head, then I set the future export path using the email. I also set $CurrentCity to get the city we are cycling on.
Then I make a query and check in a full report if there is that city taken from the object we are cycling in, and if there is, I make an export with the corresponding path (as I said before including corresponding email address).
The problem is that I'm gonna send those mail next but I need to collect path of the attachment and email of the recipient in an object.
How can I do that? I thought I could make a simple object AttachmentPath and Email and then make a foreach into that to get every time the values and send the mail who will be with single-attachment.
$LCL_Setting.Local_Config.LF_param.IctHead.city | foreach {
$tempfile = $myDir + $dir_out + $fileOut + $LogDate +'_'+$_.ICT_mail +'.csv'
$CurrentCity = $_.Branch
if ($result | where {$_.City -eq "$($CurrentCity)"}) {
$result |
where {$_.City -eq "$($CurrentCity)"} |
Export-Csv $tempfile -NoTypeInformation -Append
}
}
You can build custom objects with the e-mail address and output file path like this:
$temp_files = $LCL_Setting.Local_Config.LF_param.IctHead.city | foreach {
...
if ($result | where {$_.City -eq "$($CurrentCity)"}) {
...
New-Object -Type PSObject -Property #{
'Mail' = $_.ICT_mail
'File' = $tempfile
}
}
}
However, using a hashtable instead of a list of custom objects might be a better approach, because it allows you to look up the file path by e-mail address.
$temp_files = #{}
$LCL_Setting.Local_Config.LF_param.IctHead.city | foreach {
...
if ($result | where {$_.City -eq "$($CurrentCity)"}) {
...
$temp_files[$_.ICT_mail] = $tempfile
}
}

Powershell test-path against variable contents

I have imported a list of computer names from csv into a variable.
Now I'd like to test whether a path exists on each computer name from the list
desired output:
Computer Status
-------- ------
computer1 Online
computer2 Offline
Below will register the answer as false. That's one answer against 3 machines however. When i test the $userscomputer variable, it does contain the list of computernames and some of them are online.
Looks like I'll need to run against each machine in the variable but I've had no success so far. Thanks for reading.
$name = "vader"
$usersComputer = import-csv .....etc.
$path = "\\$userscomputer\c$\users\$name"
$componline = test-path $path
$componline
The csv file has 2 columns
"Host Name " "Logged User" computer names under host name and ad names under Logged user
computer1 bicard
computer2 bicard
computer3 vader
Ideally id like to show which computer is online my thought is below
$usersComputer | ForEach-Object {
$cn = $_."Host Name"
$path = "\\$cn\c$\users\$name"
$state = Test-Path $path
write-host $cn, $state
}
It outputs below, computer 3 however should report as true ans the $cn variable is not shown.
failed
failed
failed
I have rejigged your solution this about and it works wonderfully now. The importing of the CSV file was already done so the variable had the computer names. There after below worked.
$usersComputer | ForEach-Object {
$cn = $_
$comp = Test-Path \\$cn\c$\users\$username
[PSCustomObject]#{
Computer = $cn
Status = if ($componline) { 'Online' } else { 'Offline' }
}
}
$usersComputer will contain a collection of objects, and each object will have properties whose names match the columns in the CSV. You haven't provided a sample of what the CSV looks like. So if it has a single column called ComputerName, you might do something like this:
$usersComputer | ForEach-Object {
$cn = $_.ComputerName
$path = "\\$cn\c$\users\$name"
$componline = Test-Path $path
[PSCustomObject]#{
Computer = $cn
Status = if ($componline) { 'Online' } else { 'Offline' }
}
}

Match the User Name against the Security EventLog

I want to take a domain user and for it want to check the Security Event Logs for say Logon and then Print the events which match but it returns me null value:
Get-EventLog -Log Security -Computer PC1 -InstanceID 4624 -After(Get-Date).AddDays(-2) | ? {
$_.Message -match "Account Name:\s+qasimali\s" -and
$_.Message -match 'Logon Type:\s+(2|10)\s"
}
but it generates no data for output
Read-Host : name cannot be Null or Empty.
Whereas command runs and gives no error. I just want to check whether this command is running fine or not.
The way I have done this in the past is as follows ( Thoroughly Commented for clarity) :
## Set Username Input
$UserInput = "DOMAINUSER"
## Set date in past to retrieve events up to
$StartTime = ((Get-Date).AddMinutes(-2))
##Set Domain Controller to search on
$ComputerName = "DC1"
## Retrieve Event 4624 from DC Eveng Logs
$Logons = Get-WinEvent -ComputerName $ComputerName -FilterHashTable #{LogName="Security"; ID="4624"; StartTime=$StartTime;EndTime=(Get-Date)}
## Initialize variable to store outputs in
$EventOutput = #()
## Enumerate Events to retrieve usernames to compare against User Input
foreach ($Logon in $Logons) {
## Convert Event to XML
$LogonXML = [XML]$Logon.ToXML()
## Retrieve Username from XML Object
$LogonUser = (($LogonXML.Event.EventData.Data | Select "#text")[5])."#text"
## Retrieve Logon Type from XML Object
$LogonType = (($LogonXML.Event.EventData.Data | Select "#text")[8])."#text"
## Check Event Username matches User Input
if ($LogonUser -match $UserInput) {
## Check LogonType is correct
if ($LogonType -eq 2 -or $LogonType -eq 10) {
## Append Event Object to Event Output
$EventOutput += $Logon
}
}
}
## Output Resulting Event Output Object
$EventOutput
The Resulting Output can be manipulated to retrieve whatever details you wish. I find converting each Object to XML to parse further values useful.
NOTE : I've just thrown this together quickly from memory, this can be quickly restructured to enable other queries if required. Start and End Times will need to be changed to extract information from the correct timespan.