I'm currently asking myself if it is possible to determine the last logon time of any user of a computer object which is connected to an active directory?
I need to find out when any user was logged onto a specific computer which is still online, communicating with the domain but was not in use in the last X days by any user.
I've already tried the following queries:
get-adcomputer $computername -Properties lastlogon | select
#{Name="lastLogon";Expression={[datetime]::FromFileTime($_.'lastLogon')}}
AND
get-adcomputer za31testvmrobin -Properties lastlogondate
I'm expecting the timestamp of the last logondate of a user on a computer object.
Hope you can help me.
I somehow figured it out with help from #boxdog . Thanks for that.
Here is the Powershell Code in one line:
Get-EventLog -LogName Security -InstanceId 4624 -ComputerName $computer |
`where {$_.Message -match "Kontoname: USERNAME" -and
`$_.Message -match "Anmeldetyp: 2" } | select -First 1)
Kontoname = Accountname
Anmeldetyp = Logontype (2 means interactive from console with keyboard & mouse)
The tabulator is needed. You can also use wildcards like an asterisk.
I could not find an easier way to get it working. Therefor I had to use the comparison operator "match" to find a string with which I could search within the Message property of the Eventlog.
Unfortunately searching takes some time. Via remote it takes up to 5 minutes each computer which is quiet unsatisfying.
Maybe someone has another solution which is faster or knows a way to work parallel, actually I don't really know how to do that, because I'm getting content with
get-content c:\data\input.txt
Thanks in advance
Related
Something I do not unterstand. See the following two code examples.
$LDAPResult1 = Get-ADUser -LDAPFilter "(&(objectCategory=user)(sAMAccountName=*))" -Properties #("distinguishedName","sAMAccountName","extensionAttribute13") -SearchBase "ou=test,dc=test,dc=ch"
$LDAPElements1=#{}
$LDAPResult1 |% {$LDAPElements1.Add($_.SAMAccountName, $_.extensionattribute13)}
compared with (adding a specific server to ask "-Server 'dc.test.test.ch'"):
$LDAPResult1 = Get-ADUser -LDAPFilter "(&(objectCategory=user)(sAMAccountName=*))" -Properties #("distinguishedName","sAMAccountName","extensionAttribute13") -SearchBase "ou=test,dc=test,dc=ch" -Server 'dc.test.test.ch'
$LDAPElements1=#{}
$LDAPResult1 |% {$LDAPElements1.Add($_.SAMAccountName, $_.extensionattribute13)}
The first code takes 30 seconds, the second about 5 minutes. The problem ist not the AD query. This takes around 30 seconds in both cases. But filling the result into the hash table is what is differnet. It seems as if in the second case while filling the hash sill some data is requested from the DC.
What is also interesting. When I wait for five minutes after doing the AD query in case two and then execute the filling into the hash table, then the command takes a second.
I rather would likt to define to what server the command connects in order to execute the folloing commands on the same DC, but this does not make sense if it takes that long.
Can anyone enlighten me …
Addition: We are Talking about 26'000 accounts.
I was able to replicate this. The behaviour does change when you specify the -Server parameter vs. when you don't.
I used Process Monitor to watch network activity and it definitely is talking to the DC when looping through the results returned from using the -Server parameter.
I can't explain why, but it seems like the ADUser objects returned are not populated with the properties from the search. So when they are accessed, it loads the properties from the DC. I could see this when accessing one particular element in the array:
$LDAPResults1[1000]
It displayed the properties, but I also saw network activity in Process Monitor. Whereas I do not see network activity when accessing one element from the results returned when not using the -Server parameter.
So that kind of explains what is happening, but not why. And I really don't know why.
However, I have learned that if you want performance when talking to AD, you have to scrap all the "easy" ways and do things yourself. For example, use the .NET DirectoryEntry and DirectorySearcher classes directly, which can be done in PowerShell using the "type accelerators" [adsi] and [adsisearcher]. For example, this will do the same and will perform consistently:
$dc = "dc.test.test.ch"
$searchBase = "ou=test,dc=test,dc=ch"
$searcher = [adsisearcher]::new([adsi]"LDAP://$dc/$searchBase", "(objectCategory=user)")
$searcher.PropertiesToLoad.Add("sAMAccountName") > $null
$searcher.PropertiesToLoad.Add("extensionAttribute13") > $null
$searcher.PageSize = 1000
$LDAPElements1=#{}
foreach ($result in $searcher.FindAll()) {
$LDAPElements1.Add($result.Properties["sAMAccountName"][0], $result.Properties["extensionAttribute13"][0])
}
I found the following code to be extremely slow.
$user = Get-ADUser -LDAPFilter $filter -Server "xyc" -Properties "sAMAccountName"
I was able to rewrite it as:
$directorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$directorySearcher.SearchRoot = [ADSI]'LDAP://xyz'
[void]$directorySearcher.PropertiesToLoad.Add('cn')
[void]$directorySearcher.PropertiesToLoad.Add('sAMAccountName')
$directorySearcher.Filter = "(cn=abcd efg)"
$results = $directorySearcher.FindOne()
Write-Host $results.Properties["samaccountname"] -as [String]
and it was a lot faster (by an order of magnitude) than using GetAd-User (but still slow).
Export Get-ADUser results into a temporary CSV file and import it back to some objects.
Get-ADUser -LDAPFilter (....) | Export-Csv -Path "TempCSV.csv" -Encoding UTF8 -Delimiter ","
$ADUsers = Import-Csv -Path "TempCSV.csv" -Encoding UTF8 -Delimiter ","
Now you can loop the users object.
foreach ($ADUser in $ADUsers) { (....) }
I am writing some C# program that executes PowerShell script.
I have the following line
Get-Mailbox -ResultSize:unlimited |
Get-MailboxPermission |
Where {($_.IsInherited -eq $false) -and !($_.user -like "S-1*") -and !($_.user -like "NT A*") } |
select identity,user,#{n="objectid";e={(get-recipient -identity $_.user).ExternalDirectoryObjectId}}
basically it finds all mailbox permissions and retrieves corresponding ExternalDirectoryObjectId (which is same as Azure ObjectID)
The issue here is that the result returned is different from different machines. I would get all identity, user values, but for expression values that are in bold above, will only start to show up half way through the execution.
for example on computer x
Identity|User|objectid
user1 |userA|
user2 |userA|
user2 |userB|
... |... |
user10|userC|
user11|userC|<objectID1>
user11|userD|<objectID2>
I noticed that on fast computer the objectIDs start showing up late, on slower computers it starts showing up early, however execution times are different.
How do I modify this so that objectGuid is retrieved for all entries? Why is pipelining not waiting until the calculated property objectID is properly retrieved?
If I write a short PowerShell script and use for loops for each mboxpermissions and retrieve them one by one, all of those objectGuids are retrievable. But it's slow.
Thanks for help and Please give me any suggestions!
So the task I'm facing seems harsh to me, I barely started using PowerShell too.
I need to create a detailed List of all users by their display name, which means it begins with " x- "
I need their details, including user creation date, enabled/disabled, last login date, and company
can you help a fellow beginner out?
You should try googling and providing more information. It appears you have not completed any searching.
A simple "Get all users powershell" into google would bring you to Get-ADUser
Get-ADUser -Filter * -Properties * | Export-Csv "$env:USERPROFILE\Desktop\UserData.csv" -NoTypeInformation
# This gets all users in AD and all properties
Get-ADUser -Filter * -Properties *
# This will send those results to a CSV file on your desktop
| Export-Csv "$env:USERPROFILE\Desktop\UserData.csv" -NoTypeInformation
So, I have a Powershell script that I use to see if usernames in an array are Smartcard Enabled. A lot of the scripts that are used to automate my company use VBS. Unfortunately my VBS is VERY rusty and I need to convert this powershell into VBS so my lead programmer can use it in a larger script. The script is below. I am leaving out the ADUC Hierarchy for my company's safety. It will be written in the code as "OU=,DC=" Thanks for the assist.
$Array="C:\UserNames.csv"
ForEach($Name in $Array)
{
Get-ADUser -SearchBase "OU=,DC=" -Filter * -Properties * | Where {$_.CN -like "*$Name*"} | Where {$_.SmartcardLogonRequired -eg %False} | Select SamAccountName,GivenName,Surname,SmartcardLogonRequired
}
Turns out he didn't actually want this translated. He needed the UserAccountControl Code for SMARTCARD_REQUIRED (262144). Well, I can scrap the last 3 days of work. Thanks for the comments.
thank you for visiting my first question on this website.
The purpose of this PowerShell script is to query the user for a partial name of a pre-existing computer on the domain. After the query is complete it retrieves the full computer name from a specific OU in active directory, and copies this full computer's name it to the user's clipboard. This is to help save time to the people I work with at the help desk(including myself) who have to perform this action manually every day.
Note:I'm pretty sure the problem isn't with the two 'Get-ADComputer' lines because if I manually enter the full computer name in the script it works exactly as intended. The issue seems to be either with how I'm defining the user input, or how it's being passed along to the variable($PCName) inside of the 'Get-ADComputer' cmdlet.
Here is the script in its entirety, the only thing I omitted is the specific active directory OU - I know it's looking in the right OU, because the lines taken individually and with a manually PC Name entered work great.
$global:PCName=(Read-Host "Enter partial PC name")
write-host "You entered the partial PC Name: $PCName"
return $PCName
#PCName Information Table Display.
Get-ADComputer -SearchBase 'OU=(Disregard)' -Filter 'Name -like "*$PCName*"' -Properties IPv4Address | Format-Table Name,DNSHostName,IPv4Address -A
#Progress indicator advisory message.
Write-Output "Converting $PCname to full computer name and copying result to your clipboard."
#Clip Line - Retrieves full PC name and copies resolved PC name to clipboard.
Get-ADComputer -SearchBase 'OU=(Disregard)' -Filter 'Name -like "*$PCName*"' | Select Name -ExpandProperty Name | Clip
#End of script advisory message.
Write-Output "Full PC Name:$PCName - Resolved and copied to clipboard."
If there's any other fault to be pointed out, I would appreciate it. I have been using PowerShell for less than a week and am a new programmer overall. I've performed no less than 40 google queries and spent at least 3 hours trying to get this to work.
Thank you!
do {
$computerName = read-host "Enter partial computer name [blank=quit]"
if ( -not $computerName ) {
break
}
$sb = [ScriptBlock]::Create("name -like '*$computerName*'")
$computer = get-adcomputer -filter $sb
if ( $computer ) {
$computer
$computer | select-object -expandproperty Name | clip
"Copied name to clipboard"
}
else {
"Not found"
}
""
}
while ( $true )
In PowerShell, single and double quotes each have a different meaning and significance. Variables will only be expanded in double quotes.
Your query does not work because you use single quotes for the parameter:
-Filter 'Name -like "*$PCName*"'
In this string, $PCName will not be replaced by its value. The double quotes are not significant here, because inside a single quoted string, they are just characters.
You can build the parameter like this:
-Filter ('Name -like "*' + $PCName + '*"')
Additionally, you should remove the return statement and in your example there is no need to create a global variable $global:PCName, you can use $PCName instead
Your main issue is how you were quoting your -Filter. Variables do not expand inside single quotes. Your query was looking for a computer matching the string literal $pcname as supposed to the variable contents.
Also you make the same call twice which is inefficient. You should also know that it is possible to have more than one match with this so you need to be aware of/ account for that possibility.
$PCName=(Read-Host "Enter partial PC name")
write-host "You entered the partial PC Name: $PCName"
#PCName Information Table Display.
$results = Get-ADComputer -SearchBase 'OU=(Disregard)' -Filter "Name -like '*$pcname*'" -Properties IPv4Address
$results | Format-Table Name,DNSHostName,IPv4Address -A
#Progress indicator advisory message.
Write-host "Converting $PCname to full computer name and copying result to your clipboard."
#Clip Line - Retrieves full PC name and copies resolved PC name to clipboard.
$results| Select -ExpandProperty Name | Clip
#End of script advisory message.
Write-host "Full PC Name:$PCName - Resolved and copied to clipboard."
I don't see a need for a global variable here so I removed it. Changed all the Write-Output to Write-Host as that is how you were treating them. If nothing else you have them mixed together so picking one would be more my point.
I had a similar issue with filter (building into an ASP application) and solved it by using curly brackets.
$searchterm = "*$($PCName)*"
-Filter {Name -like $searchterm}
The extra $() is most likely unnecessary in this particular instance as we aren't doing anything with the variable, but it's a habit of mine now.