I'm using the below code to pull the IP Address of the User (supplied at beginning of code) that had a failed logon attempt. The code works, but when I use GetType() the variable $ipp, it comes back as a Name is Object[] Base Type is System.Array I need this variable to be a string (I'm looking for the IP in a text file and removing it if it's found).
$ipp = Get-WinEvent -FilterHashtable #{LogName='Security';Id=4625;StartTime=$hours} |
Where-Object {$_.Properties[5].Value -like "*$userName*"} |
Select-Object -First 1 {$_.Properties[19].value}
I'm using PowerShell 5
Thanks
Kevin
Pre-warning: This will probably be your best bet for a full array of each bit of information from the bad attempt/lockout event. You can assign each object to a variable easily, check out the last line for some of the property names I use when checking locked accounts.
I have been doing a lot of this sort of stuff at work lately and came across a nice Microsoft demo. I unashamedly stole their script, works like a charm.
I hoped you were connecting to a domain controller but it looks like that event ID is for a bad attempt on the clients machine, not the DC.
Changed it a bit so you can slot it in after you have defined your $userName and left the Microsoft comments. Just check out line 87/88 as you may need to complete that if you encounter errors with your DC.
# Set up the lockout report
$report = #()
# Pick the DCs to crawl
$DCs = Get-ADDomainController -Filter * |
Select-Object HostName, IPv4Address, Site, OperatingSystem, OperationMasterRoles |
Out-Gridview -Title "Select the DCs to query" -PassThru |
Select-Object -ExpandProperty HostName
# Find the lockout stats for that user on all selected DCs
ForEach ($DC in $DCs) {
$report += Get-ADUser $userName -Server $DC -ErrorAction Continue `
-Properties cn, LockedOut, pwdLastSet, badPwdCount, badPasswordTime, lastLogon, lastLogoff, lastLogonTimeStamp, whenCreated, whenChanged | `
Select-Object *, #{name='DC';expression={$DC}}
}
$DCs = $report |
Select-Object `
DC, `
cn, `
LockedOut, `
pwdLastSet, `
#{name='pwdLastSetConverted';expression={[datetime]::fromFileTime($_.pwdlastset)}}, `
badPwdCount,
badPasswordTime, `
#{name='badPasswordTimeConverted';expression={[datetime]::fromFileTime($_.badPasswordTime)}}, `
lastLogon, `
#{name='lastLogonConverted';expression={[datetime]::fromFileTime($_.lastLogon)}}, `
lastLogoff, `
#{name='lastLogoffConverted';expression={[datetime]::fromFileTime($_.lastLogoff)}}, `
lastLogonTimeStamp, `
#{name='lastLogonTimestampConverted';expression={[datetime]::fromFileTime($_.lastLogonTimestamp)}}, `
whenCreated, `
whenChanged |
Out-GridView -Title "Select the DC to query event logs for lockouts" -PassThru
# Filter generated using Event Viewer GUI Custom View
# Logon/Lockout events in the last 24 hours
[xml]$xmlFilter = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[(EventID=529 or EventID=644 or EventID=675 or EventID=676 or EventID=681 or EventID=4740 or EventID=4771) and TimeCreated[timediff(#SystemTime) <= 86400000]]]</Select>
</Query>
</QueryList>
"#
$Events = #()
ForEach ($DC in $DCs) {
"Getting events from $($DC.DC)"
# Must enable the firewall rule for remote EventLog management - CHECK WITH YOUR IT TEAM, THIS MAY BREACH YOUR COMPANY SECURITY POLICY
# Invoke-Command -ComputerName $DC.DC -ScriptBlock {Get-NetFirewallRule -Name *eventlog* | Where-Object {$_.Enabled -eq 'False'} | Enable-NetFirewallRule -Verbose}
### Filter for the userID in the event message properties
$Events += Get-WinEvent -ComputerName $DC.DC -FilterXML $xmlFilter
}
ForEach ($Event in $Events) {
# Convert the event to XML
$eventXML = [xml]$Event.ToXml()
# Iterate through each one of the XML message properties
For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++) {
# Append these as object properties
Add-Member -InputObject $Event -MemberType NoteProperty -Force `
-Name $eventXML.Event.EventData.Data[$i].name `
-Value $eventXML.Event.EventData.Data[$i].'#text'
}
}
# View the lockout details
$Events | Where-Object {$_.TargetUserName -eq $userName} | Select-Object TargetUserName, IPAddress, MachineName, TimeCreated | Out-GridView
Related
I have a script to check active directory for windows 7 computers, ping them and report back the ip address.
The export-csv function writes the correct fields and data, except the IP address. The IP address shows as "Microsoft.ActiveDirectory.Management.ADPropertyValueCollection"
Copy of Script
Function Get-Win7 {
$Win7list = get-adcomputer -filter {(operatingsystem -like "Windows 7 Professional") -and (enabled -eq "True")} -properties operatingsystem, lastlogondate
foreach ($pc in $Win7list){
$pingtest = test-connection $pc.name -erroraction silentlycontinue -errorvariable pingfail
if (get-variable -name pingfail -erroraction silentlycontinue) {
if ($pingfail.exception -match "failed"){
$IP3 = "No IP"
$pingfall = $null
}
}
$pc.IP = New-Object -TypeName PSCustomObject -Property #{IPAddress = $pingtest.IPV4Address.ToString | select-object -first 1}
$PC |select-object name,operatingsystem, lastlogondate, IP |sort-object lastlogondate | export-csv -path c:\users\{user}\desktop\Win7-GSN.csv -notypeinfo -append
}
}
Any help is appreciated.
You can use a calculated property in Select-Object, which allows you to add a custom property and give it a custom value. Here we can add a custom property IP and give it the IPV4Address.
$PC | Select-Object name,operatingsystem, lastlogondate, #{n='IP';e={$pingtest[0].IPV4Address}}
As a result, you can remove the $pc.IP = ... line entirely.
Would anybody have any suggestions? I need to generate a list of users and the computers they're logging into, from Active Directory. I'm hoping to get something like this:
Username Hostname
user.lastname ComputerA1
So far, I've gotten:
Enter-PSSession Import-Module ActiveDirectory Get-ADComputer
-Filter * -Properties Name Get-ADuser -filter * -Properties * | export-csv '\\\AD_UserLists.csv'
This works, kinda. I can generate a list of computers from AD and I can generate a list of ADUsers (albeit with ALL the users information). Unfortunately, I can't generate the data into a single CSV.
Suggestions/Advice????
Thanx,
David
Here is a way to get what you want. You will have to run this against AD-Computer objects when the machines are online, and catch the names of the computers you could not reach. Something like this...
#grab the DN of the OU where your computer objects are located...
$OU = ("OU=Computers,DC=domain,DC=com")
#put your filtered results in $computers (I filtered for Enabled objects)...
$computers = #()
ForEach ($O in $OU) {
$computers += Get-ADComputer -SearchBase $O -filter 'Enabled -eq "True"' -Properties CN,distinguishedname,lastLogonTimeStamp | Select-Object CN,distinguishedname,lastLogonTimeStamp
}
#instantiate some arrays to catch your results
#collected user info
$userInfo = #()
#computers you cannot ping
$offline = #()
#computers you can ping but cannot establish WinRM connection
$winRmIssue = #()
#iterate over $computers list to get user info on each...
ForEach ($computer in $computers) {
#filter out System account SIDs
$WQLFilter = "NOT SID = 'S-1-5-18' AND NOT SID = 'S-1-5-19' AND NOT SID = 'S-1-5-20'"
$WQLFilter = $WQLFilter + " AND NOT SID = `'$FilterSID`'"
#set number of login events to grab
$newest = 20
#attempt to ping computer once by name. return 'true' is success...
if (Test-Connection -ComputerName $computer.CN -Count 1 -ErrorAction Stop -Quiet) {
#if ping is true, try to get some info...
Try {
#currently logged in user...
$user = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computer.CN | select -ExpandProperty username
#the most commonly logged in user, based on the past 20 log-ins...
$UserProperty = #{n="User";e={((New-Object System.Security.Principal.SecurityIdentifier $_.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])).ToString()}}
$logs = Get-EventLog System -Source Microsoft-Windows-Winlogon -ComputerName $computer.CN -newest $newest | select $UserProperty
$freqent = $logs | Group User | Sort-Object Count | Select -First 1 | Select-Object -ExpandProperty Name
}
#catch any connection issues...
Catch {
$cantInvoke = [pscustomobject][ordered]#{
'Computer' = $computer.CN
'Message' = "Could not Invoke-Command. Probably a WinRM issue."
}
$winRMIssue += $cantInvoke
}
#custom psobject of gathered user info...
$userInfoObj = New-Object psobject -Property ([ordered]#{
'Computer' = $computer.CN
'LoggedInUser' = $user
'mostCommonUser' = $frequent
})
$userInfo += $userInfoObj
}
#if you could not ping the computer, gather that info here in a custom object...
else {
$noPing = [pscustomobject][ordered]#{
'Computer' = $computer.CN
'DN' = $computer.distinguishedname
'lastLogonDate' = [datetime]::FromFileTime($computer.lastLogonTimeStamp).toShortDateString()
}
$offline += $noPing
}
#then kick out the results to csv
$userInfo | Sort-Object Computer | export-csv -Path c:\path\file.csv -NoTypeInformation
$offline | Sort-Object lastLogonDate | export-csv -Path c:\path.file2csv -NoTypeInformation
$winRmIssue | Sort-Object Computer | export-csv -Path c:\path\file3.csv -NoTypeInformation
You could use the wmi function
Get-WmiObject -Class Win32_ComputerSystem -ComputerName "computersname" | Select-Object Name,Username
I need to generate a list of users and the computers they're logging into, from Active Directory.
This information is not stored in Active Directory. You may be able to retrieve this information with Active Directory auditing. Otherwise, you'll need to poll each individual workstation.
I am trying to move mailboxes to a new Exchange server on a different O365 tenant. This script is a portion of this move which attempts to list all Exchange Online users who have licenses, create a contact for each user pointing to their new email address, and forwards their email to their new address as well as their mailbox
#requires -Version 3 -Modules MSOnline
$mailboxlist = Get-Mailbox | Select-Object -Property userprincipalname |
Get-MsolUser | Where-Object -Property islicensed -EQ -Value $true |
Select-Object -Property firstname, lastname, userprincipalname |
Where-Object -Property firstname -NE -Value $null |
Format-list -AutoSize
#Begin foreach loop
foreach ($item in $mailboxlist)
{
#Create the forwarding address
$forwardingaddress = $item.firstname + '.' + $item.lastname + '#newdomain.com'
#Check for a contact, add if not present
If (!(Get-MailContact $forwardingaddress -ErrorAction silentlycontinue)){
New-MailContact $forwardingaddress -ExternalEmailAddress $forwardingaddress
}
#assign forwarding address
set-mailbox -ForwardingAddress $forwardingaddress -DeliverToMailboxAndForward $true
}
The result of the above is a $mailboxlist which is populated with first and last names and the users UPN which is also an email address. The result of $forwardingaddress is .#newdomain.com.
I don't think I am creating the initial data correctly for the foreach loop. I know that if I replace the $item.firstname with $_.firstname I get the same empty result. I would much appreciate if someone knowledgeable on the topic could assist.
Thanks!
Edit: Final config with Kiran's suggestion
#requires -Version 3 -Modules MSOnline
$mailboxlist = Get-Mailbox | Get-MsolUser | Where-Object { ($_.islicensed -eq $true) -and ($_.firstname -ne $null) }
#Begin foreach loop
foreach ($item in $mailboxlist)
{
#Create the forwarding address
$forwardingaddress = $item.firstname + '.' + $item.lastname + '#newdomain.com'
#Remove any spaces from the email address
$forwardingaddress = ($forwardingaddress -replace " ","").trim()
#Check for a contact, add if not present
If (!(Get-MailContact $forwardingaddress -ErrorAction silentlycontinue))
{
New-MailContact $forwardingaddress -ExternalEmailAddress $forwardingaddress
}
#assign forwarding address
Set-Mailbox -ForwardingAddress $forwardingaddress -DeliverToMailboxAndForward $true
}
try this:
$mailboxlist = Get-Mailbox | Get-MsolUser |
Where-Object { ($_.islicensed -eq $true) -and ($_.firstname -ne $null) }
the UserPrincipalName of get-Msoluser accepts pipeline input by propertyname so you should just pipe the output of get-mailbox to get-msoluser
select-object should be preferred over format-* commands because of the type of objects that are created.
Use format* when you want to show data on the console.
The where-object clause allows you to create complex conditions so try to combine them where you can. This should be the flow of commands:
cmdlet | where-object { some condition(s)} | select properties
List all active machineaccounts in the current domain
$ComputerScan = #(Get-QADComputer -sizelimit $sizelimit -IncludedProperties LastLogonTimeStamp -WarningAction SilentlyContinue -Inactive:$false -OSName $computerFilter | where {$_.AccountIsDisabled -eq $false} )
# Create list of computers
ForEach ($Computer in $ComputerScan){
$compObj = New-Object PsObject -Property #{
Computer = $computer
Credentials = $credentials
Domain = $domain
}
$computers += $compObj
}
I am doing a foreach on $computers after this but I would like to have a exclusionlist..
Preferably formatted like this
computer1
server4
computet4
But, how?
Greetings from Norway!
A few improvements to the computer query:
LastLogonTimeStamp is returned by default, no need to include it
-Inactive is $false by default, no need to specify it.
Instaed of using where-object, use ldap filters to get enabled computers
$computerScan = Get-QADComputer
-LdapFilter '(!(userAccountControl:1.2.840.113556.1.4.803:=2))'
-Sizelimit $sizelimit -WarningAction SilentlyContinue
-OSName $computerFilter |
Select-Object -ExpandProperty Name
$ComputerScan = #('blah', 'bluh', 'blih', 'bloh')
$ExclusionList = #('blih', 'blah')
$ComputerScan | where { $ExclusionList -notcontains $_ } | Write-Host
I'd like to have a report with all the local users and their relative groups (users, power users, administrators and so on.
I get the users in this way:
$adsi = [ADSI]"WinNT://."
$adsi.psbase.children | where {$_.psbase.schemaClassName -match "user"} | select #{n="Name";e={$_.name}}
but I don't know how to retrieve their groups. Thanks in advance.
For Googlers, another way to get a list of users is to use:
Get-WmiObject -Class Win32_UserAccount
From http://buckeyejeeps.com/blog/?p=764
$adsi = [ADSI]"WinNT://$env:COMPUTERNAME"
$adsi.Children | where {$_.SchemaClassName -eq 'user'} | Foreach-Object {
$groups = $_.Groups() | Foreach-Object {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
$_ | Select-Object #{n='UserName';e={$_.Name}},#{n='Groups';e={$groups -join ';'}}
}
Update as an alternative to the excellent answer from 2010:
You can now use the Get-LocalGroupMember, Get-LocalGroup, Get-LocalUser etc. from the Microsoft.PowerShell.LocalAccounts module to get and map users and groups, available in PowerShell 5.1 and above.
Example:
PS C:\WINDOWS\system32> Get-LocalGroupMember -name users
ObjectClass Name PrincipalSource
----------- ---- ---------------
User DESKTOP-R05QDNL\someUser1 Local
User DESKTOP-R05QDNL\someUser2 MicrosoftAccount
Group NT AUTHORITY\INTERACTIVE Unknown
You could combine that with Get-LocalUser. Alias glu can also be used instead. Aliases exists for the majority of the new cmdlets.
In case some are wondering (I know you didn't ask about this)
Adding users could be for example done like so:
$description = "Netshare user"
$userName = "Test User"
$user = "test.user"
$pwd = "pwd123"
New-LocalUser $user -Password (ConvertTo-SecureString $pwd -AsPlainText -Force) -FullName $userName -Description $description
Use this to get an array with the local users and the groups they are member of:
Get-LocalUser |
ForEach-Object {
$user = $_
return [PSCustomObject]#{
"User" = $user.Name
"Groups" = Get-LocalGroup | Where-Object { $user.SID -in ($_ | Get-LocalGroupMember | Select-Object -ExpandProperty "SID") } | Select-Object -ExpandProperty "Name"
}
}
To get an array with the local groups and their members:
Get-LocalGroup |
ForEach-Object {
$group = $_
return [PSCustomObject]#{
"Group" = $group.Name
"Members" = $group | Get-LocalGroupMember | Select-Object -ExpandProperty "Name"
}
}
Expanding on mjswensen's answer, the command without the filter could take minutes, but the filtered command is almost instant.
PowerShell - List local user accounts
Fast way
Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'" | select name, fullname
Slow way
Get-WmiObject -Class Win32_UserAccount |? {$_.localaccount -eq $true} | select name, fullname
try this one :),
Get-LocalGroup | %{ $groups = "$(Get-LocalGroupMember -Group $_.Name | %{ $_.Name } | Out-String)"; Write-Output "$($_.Name)>`r`n$($groups)`r`n" }