ADUser search: Get-ADUser and DirectorySearcher - powershell

With PowerShell, I'm trying to get an ADUser account with Get-ADUser with LdapFilter using the employeeid attribute. I'm using a GC server of the domain as the sourcing server for faster results. However, I'm not getting the matching ADUser account(s). However, I'm able to retrieve results using a DirectorySearcher object. Please refer to the tried code snippets below,
###
#1 DirectorySearcher
$empid = "123456"
$ldapcn = "GC://dc=mydomain,dc=net"
$ldapfilter = "(&(ObjectCategory=Person)(objectclass=user)(employeeid=" + $empid + "))"
$objent = new-object System.DirectoryServices.DirectoryEntry($ldapcn)
$objsearch = new-object System.DirectoryServices.DirectorySearcher
$objsearch.SearchRoot = $objent
$objsearch.SearchScope = "subtree"
$objsearch.Filter = $ldapfilter
$objsearch.pagesize = 1000
$properties = "employeeid","givenname","sn","samaccountname"
$objsearch.propertiestoload.addrange($properties)
$results = $objsearch.Findall()
# Working
# $results contains matching user records
######################################################
#2 Get-ADUser
$empid = "123456"
$Server_AD_GC = (Get-ADDomainController -Server mydomain.net | select -exp hostname) + ":3268"
$ldapfilter = "(&(ObjectCategory=Person)(objectclass=user)(employeeid=" + $empid + "))"
$results = Get-ADUser -LdapFilter $ldapfilter -Properties employeeid, givenname, sn, samaccountname -Server $Server_AD_GC
# NOT WORKING!
# $results DOES NOT CONTAIN matching user records
What am I missing here?! Any help would be highly appreciated.
UPDATE 1
I just verified the Partial Attribute Set (PAS) with the code below and DO NOT SEE employeeid included in the list
$Domain = "mydomain.net"
# $schemaNamingContext = "cn=Schema,cn=Configuration,dc=mydomain,dc=net"
$schemaNamingContext = (Get-ADRootDSE -Server $Domain).SchemaNamingContext
Get-ADObject -SearchBase $schemaNamingContext -LDAPFilter "(isMemberOfPartialAttributeSet=TRUE)" -Properties ldapDisplayName | Select ldapDisplayName | sort ldapDisplayName
For more background, I'm running the 'DirectorySearcher' code block to search the source mydomain.net and running it from a W2012R2 server joined to a trusted domain, say mycaller.net, which is from a different forest. Importantly, the calling trusted domain mycaller.net's PAS CONTAINS employeeid. However, as already said Get-ADUser is unable to fetch the record(s).
Below is a screenshot of results observed with different environments,
Now, if not for a solution, I'd be glad if at least someone is able to reproduce this behavior.
Query:
In my example,
DirectorySearcher's $ldapcn = "GC://DC=mydomain,DC=net"
vs
Get-ADUser's $Server_AD_GC = (Get-ADDomainController -Server $Domain | select -exp hostname) + ":3268"
I expected both to work in a similar fashion. I see that I haven't specified a host for DirectorySearcher but have given one for Get-ADUser. Is this something to be looked into?

Related

Exporting last logon date for inactive users via PowerShell

I have a command that will export a list of users who have logged in for 12 months but I am struggling to export the last login date and time.
The command is as follows:
Search-ADAccount –AccountInActive -UsersOnly –TimeSpan 365:00:00:00 –ResultPageSize 2000 –ResultSetSize $null |?{$_.Enabled –eq $True} | Select-Object Name, SamAccountName, DistinguishedName, lastLogon| Export-CSV “C:\Users\Me\Desktop\InactiveUsers.CSV” –NoTypeInformation
But lastLogon is showing a blank in the CSV file.
I am new to PowerShell I understand the command can be made much smoother.
Any help on this is much appreciated.
Search-ADAccount doesn't have an option to pull other attributes from the AD Objects than the default ones, you can use Get-ADUser with an elaborate filter to query the users who haven't logged on for the past year. One option is to query the user's lastLogonTimeStamp attribute however by doing so you're risking not getting accurate results because this attribute is not replicated in real time. To get accurate one must query the user's lastLogon attribute but, since this attribute is not replicated across the Domain, one must query all Domain Controllers to get the latest logon from the user.
For more information on this topic, please check this excellent TechNet Article: Understanding the AD Account attributes - LastLogon, LastLogonTimeStamp and LastLogonDate.
$dateLimit = [datetime]::UtcNow.AddYears(-1).ToFileTimeUtc()
$AllDCs = Get-ADDomainController -Filter *
$logons = #{}
$params = #{
LDAPFilter = -join #(
"(&" # AND, all conditions must be met
"(!samAccountName=krbtgt)" # exclude krbtgt from this query
"(!samAccountName=Guest)" # exclude Guest from this query
"(userAccountControl:1.2.840.113556.1.4.803:=2)" # object is Disabled
"(lastLogon<=$dateLimit)" # lastLogon is below the limit
")" # close AND clause
)
Properties = 'lastLogon'
}
foreach($DC in $AllDCs) {
$params['Server'] = $DC
foreach($user in Get-ADUser #params) {
# this condition is always met on first loop iteration due to ldap filtering condition
if($logons[$user.samAccountName].LastLogon -lt $user.LastLogon) {
$logons[$user.samAccountName] = $user
}
}
}
$logons.Values | ForEach-Object {
[PSCustomObject]#{
Name = $_.Name
SamAccountName = $_.SamAccountName
DistinguishedName = $_.DistinguishedName
lastLogon = [datetime]::FromFileTimeUtc($_.lastLogon).ToString('u')
}
} | Export-CSV "C:\Users\Me\Desktop\InactiveUsers.CSV" -NoTypeInformation

The server has returned the following error: invalid enumeration context. Get-ADComputer

I have this portion of code that is throwing an invalid enumeration context error.
$ADComputers1 = (get-adcomputer -Filter {enabled -eq $true} -ResultPageSize 500 -ResultSetSize $null -Properties instanceType, IPv4Address, IPv6Address, isCriticalSystemObject, isDeleted, KerberosEncryptionType, LastBadPasswordAttempt, LastKnownParent, localPolicyFlags, Location, CannotChangePassword)
foreach ($computer in $ADComputers1){
$values += [PSCustomObject]#{
instanceType=$computer.instanceType #check
IPv4Address=$computer.IPv4Address #fail
IPv6Address=$computer.IPv6Address #fail
isCriticalSystemObject=$computer.isCriticalSystemObject
isDeleted=$computer.isDeleted
KerberosEncryptionType=$computer.KerberosEncryptionType
LastBadPasswordAttempt=$computer.LastBadPasswordAttempt
LastKnownParent=$computer.LastKnownParent #fail
localPolicyFlags=$computer.localPolicyFlags
Location=$computer.Location
CannotChangePassword=$computer.CannotChangePassword
}
}
I have looked online and found multiple errors similar to the one that is being thrown. In doing so, I have adjusted the -Filter, -ResultPageSize, and shortened the number of properties being accessed multiple times, yet this error is always thrown.
The rest of this code is checking about 70 properties fine, but this section, no matter how small or large I make it, is always throwing an error.
Any help would be appreciated.
This TechNet article provides information about this error, basically this happens when a single query has been running for more than 30 minutes. This answer also provide a few more details.
In this case, there doesn't seem to be a way to refine your LDAP query further because you're interested in gathering all Computer Objects, however something that may help is to query one Organizational Unit at a time. This would increment the number of queries but also reduce the time per query. In my personal experience, changing the values for -ResultPageSize and -ResultSetSize don't give me better results but I'll leave up to you for testing.
Get-ADOrganizationalUnit -Filter * | & {
begin {
$params = #{
Filter = "enabled -eq '$true'"
Properties = #(
'instanceType'
'IPv4Address'
'IPv6Address'
'isCriticalSystemObject'
'isDeleted'
'KerberosEncryptionType'
'LastBadPasswordAttempt'
'LastKnownParent'
'localPolicyFlags'
'Location'
'CannotChangePassword'
)
}
}
process {
$params['SearchBase'] = $_.DistinguishedName
Get-ADComputer #params | & {
process {
[PSCustomObject]#{
instanceType = $_.instanceType
IPv4Address = $_.IPv4Address
IPv6Address = $_.IPv6Address
isCriticalSystemObject = $_.isCriticalSystemObject
isDeleted = $_.isDeleted
KerberosEncryptionType = $_.KerberosEncryptionType
LastBadPasswordAttempt = $_.LastBadPasswordAttempt
LastKnownParent = $_.LastKnownParent
localPolicyFlags = $_.localPolicyFlags
Location = $_.Location
CannotChangePassword = $_.CannotChangePassword
}
}
}
}
} | Export-Csv path\to\export.csv -NoTypeInformation
If have Computers in Containers instead of Organizational Units, which would be pretty odd, you can change the initial query for:
Get-ADObject -LDAPFilter '(|(objectclass=container)(objectclass=organizationalUnit))' | & {

i am trying to get the following fields from AD using powershell

Import-Module activedirectory
$Name = "Larry Page"
$Searcher = [ADSISearcher]"(&(objectCategory=person)(objectClass=user)(cn=$Name))"
[void]$Searcher.PropertiesToLoad.Add("sAMAccountName")
$Results = $Searcher.FindAll()
ForEach ($User In $Results)
{
$NTName = $User.Properties.Item("sAMAccountName")
$CompanyName = $User.Properties.Item("company")
$NTName + " " + $CompanyName
[string]$userName = $NTName.properties.name
Get-ADUser "L2371732" -Properties company,PasswordExpired, PasswordLastSet, PasswordNeverExpires
}
This is my code so far. I am trying to substitute $userName for L2371732 in the following line but I am getting a different error so I hard coded the username in the Get-ADUser.
I only wan the fields I specified however I am getting everything (company, distinguishedname,enabled, etc)
Just trying to focus on the title portion of the question.
As per documentation -Properties does the following:
Specifies the properties of the output object to retrieve from the server. Use this parameter to retrieve properties that are not included in the default set.
So you would be seeing what you asked for in addition to the default set. If you don't want those properties you can drop the by piping to Select-Object and ask for only what you need.
$props = 'company', 'PasswordExpired', 'PasswordLastSet', 'PasswordNeverExpires'
Get-ADUser "L2371732" -Properties $props | Select-Object $props
If you wanted a default property returned as well e.g. samaccountname you can add that to the list with no issue.

Find users with AD property .whenCreated with less than 90 days

$daysOld = "-90"
$currentDate = get-date
$removeIfBefore = $currentDate.AddDays($daysOld)
$vpnuserstest = Get-ADGroupMember VPN_users -Recursive | select samaccountname | foreach ($_.samaccountname) {
Get-ADUser $_.samaccountname -Properties samaccountname, whenCreated |
Select-Object samaccountname,#{n='Days Since Created';e={($((Get-Date)) - $($_.WhenCreated)).Days}} |
Format-table -AutoSize}
Detailed Description:
I am taking the users in the group VPN_users and searching for their "samaccountname" and "whenCreated" properties. Then I would like to take today's date and go back 90 days. Anyone who's "whenCreated" date falls within that 90 day window, I want to add to a table so that I can export it later.
When I run the above code, I get everything listed as I would like, but it still includes everyone who's "whenCreated" property is above 90 days.
Sorry if the code looks "frankenstein'd" together....because it is. I took different aspects from different Google searches and threw them together.
Here's one way: Construct a timestamp-string and use with the -LDAPFilter parameter. Example:
$daysOld = 90
$timestampUTC = (Get-Date).AddDays(-$daysOld).ToUniversalTime()
$timestampString = "{0:yyyyMMddHHmmss.0Z}" -f $timestampUTC
Get-ADUser -Properties whenCreated -LDAPFilter "(whenCreated<=$timestampString)"
If you want to limit results to users that are a member of a particular group, you can update the LDAP query filter. Example:
$daysOld = 90
$timestampUTC = (Get-Date).AddDays(-$daysOld).ToUniversalTime()
$timestampString = "{0:yyyyMMddHHmmss.0Z}" -f $timestampUTC
Get-ADUser -Properties whenCreated -LDAPFilter "(&(whenCreated<=$timestampString)(memberOf=CN=Group Name,OU=Container,DC=fabrikam,DC=com))"

How to list AD group membership for AD users using input list?

I'm fairly new PS user... Looking for some assistance with a powershell script to obtain list of security groups user is member of.
To describe what I need:
I have input list (txt file) with many users (samaccountnames). Every name is on a new line.
I need the script to search these names in AD - whole forest, not just one single domain
output should look like "samaccountname" and list of groups this account is member of in one line, so I can sort it in excel
This is the script I have:
$users = Get-Content C:\users.txt
ForEach ($User in $users) {
$getmembership = Get-ADUser $User.Users -Properties MemberOf | Select -ExpandProperty memberof
$getmembership | Out-File -Append c:\membership.txt
}
but it throws me an error:
Get-ADUser : Cannot validate argument on parameter 'Identity'. The argument is null. Supply a non-null argument and try the command again.
At line:4 char:28
+ $getmembership = Get-ADUser <<<< $User.Users -Properties MemberOf | Select -ExpandProperty memberof
+ CategoryInfo : InvalidData: (:) [Get-ADUser], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Anyway, this script wouldn't search the whole forest.
Sample input list:
username1
username2
username3
username4... etc
Sample output list
username1;group1;group2;group3
username2;group1;group2;group3;group4... etc or something similar
Any help would be greatly appreciated.
First: As it currently stands, the $User variable does not have a .Users property. In your code, $User simply represents one line (the "current" line in the foreach loop) from the text file.
$getmembership = Get-ADUser $User -Properties MemberOf | Select -ExpandProperty memberof
Secondly, I do not believe you can query an entire forest with one command. You will have to break it down into smaller chunks:
Query forest for list of domains
Call Get-ADUser for each domain (you may have to specify alternate credentials via the -Credential parameter
Thirdly, to get a list of groups that a user is a member of:
$User = Get-ADUser -Identity trevor -Properties *;
$GroupMembership = ($user.memberof | % { (Get-ADGroup $_).Name; }) -join ';';
# Result:
Orchestrator Users Group;ConfigMgr Administrators;Service Manager Admins;Domain Admins;Schema Admins
Fourthly: To get the final, desired string format, simply add the $User.Name, a semicolon, and the $GroupMembership string together:
$User.SamAccountName + ';' + $GroupMembership;
Get-ADPrincipalGroupMembership username | select name
Got it from another answer but the script works magic. :)
Or add "sort name" to list alphabetically
Get-ADPrincipalGroupMembership username | select name | sort name
Everything in one line:
get-aduser -filter * -Properties memberof | select name, #{ l="GroupMembership"; e={$_.memberof -join ";" } } | export-csv membership.csv
The below code will return username group membership using the samaccountname. You can modify it to get input from a file or change the query to get accounts with non expiring passwords etc
$location = "c:\temp\Peace2.txt"
$users = (get-aduser -filter *).samaccountname
$le = $users.length
for($i = 0; $i -lt $le; $i++){
$output = (get-aduser $users[$i] | Get-ADPrincipalGroupMembership).name
$users[$i] + " " + $output
$z = $users[$i] + " " + $output
add-content $location $z
}
Sample Output:
Administrator Domain Users Administrators Schema Admins Enterprise Admins Domain Admins Group Policy Creator Owners
Guest Domain Guests Guests
krbtgt Domain Users Denied RODC Password Replication Group
Redacted Domain Users CompanyUsers Production
Redacted Domain Users CompanyUsers Production
Redacted Domain Users CompanyUsers Production