removing 'CN' from DistinguishedName in Powershell script - powershell

I have the below script that I use to periodically export the list of users in all of the OUs in AD, and it works pretty well, but 'DistinguishedName' isn't all that great to have as an output as it makes it hard to filter the output by OU. I've been looking, and it should be possible to remove the 'CN=' portion, leaving just the OUs, but scripting is my Achilles Heel and everything I've tried to add in from examples I've found has either returned strange results or blown up when run. How could the below script be modified to make the last column the Distinguished Name minus the 'CN=_______,'?
import-module ActiveDirectory
#Set the domain to search at the Server parameter. Run powershell as a user with privilieges in that domain to pass different credentials to the command.
#Searchbase is the OU you want to search. By default the command will also search all subOU's. To change this behaviour, change the searchscope parameter. Possible values: Base, onelevel, subtree
#Ignore the filter and properties parameters
$ADUserParams=#{
'Server' = 'DC01'
'Searchbase' = 'OU=Users,OU="OU2",OU=OU1,DC=Domain,DC=Local'
'Searchscope'= 'Subtree'
'Filter' = '*'
'Properties' = '*'
}
$maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
#This is where to change if different properties are required.
$DNList | ForEach-Object{($_ -split "," | Select-Object -Skip 1) -join ","}
$SelectParams=#{
'Property' = 'DisplayName', 'SAMAccountname', 'enabled', 'lastlogondate', 'logoncount', 'passwordlastset', 'created', 'DistinguishedName'
}
get-aduser #ADUserParams | select-object #SelectParams | #DNList | export-csv "c:\temp\userlist_test_$(get-date -f yyyy-MM-dd).csv"

First things first, 'Properties' = '*' is not a good idea, you would be querying for all user's Attributes when you only need those in $ADUserParams. You should always query for those attributes you actually need as, not only, your query will run faster but also it will have less impact on your Domain Controller(s) depending on the size of it and how many objects you have in your Domain.
As for getting the Organizational Unit from the user's DistinguishedName, I personally would use any of the nice regexes shown in this question, for this particular example I'm using the one shown in mjolinor's answer which would suffice in almost any case.
The code would look like this:
$ADUserParams = #{
Server = 'DC01'
Searchbase = 'OU=Users,OU="OU2",OU=OU1,DC=Domain,DC=Local'
Searchscope = 'Subtree'
Filter = '*'
Properties = #(
'DisplayName'
'SAMAccountname'
'enabled'
'lastlogondate'
'logoncount'
'passwordlastset'
'created'
'DistinguishedName'
)
}
Get-ADUser #ADUserParams | Select-Object #($ADUserParams.Properties + #{
Name = 'OU'
Expression = { $_.DistinguishedName -replace '^CN=.+?(?<!\\),' }
}) | Export-Csv path\to\export.csv -NoTypeInformation

you can accomplish that retrieving also name attribute, then you can create a calculated property
#{l='OU';e={$_.distinguishedname -replace "CN=$($_.name),"}}
where you replace name data with in distinguishedname string.
$SelectParams=#{ 'Property' = 'DisplayName', 'SAMAccountname', 'enabled', 'lastlogondate', 'logoncount', 'passwordlastset', 'created', 'DistinguishedName','name' ,#{l='OU';e={$_.distinguishedname -replace "CN=$($_.name),"}}}
get-aduser #ADUserParams | select-object #SelectParams

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

How to handle hyphenated names in powershell when getting active directory info

I'm trying to get the password expiration date in active directory using powershell for users with hyphenated names (IE firstname.last-name) and on the hyphenated names it gives an invalid cmdlet error. How do I query the hyphenated names?
The current command I have is
net user $username /DOMAIN | find "Password expires"
Maybe use the ActiveDirectory module instead of the net commands:
$MaxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
Get-ADUser -Filter { Name -like "*-*" } -Properties 'PasswordLastSet', 'DisplayName' |
Select-Object Name,DisplayName,
#{ Name = 'PasswordExpires'; Expression = { $_.PasswordLastSet.AddDays( $MaxPwdAge ) } }
If needed You can change the filter to look at DisplayName instead -Filter { DisplayName -like "*-*" }
You may need to adjust the properties you're retrieving depending on what you want to include in the output. This is just an example but it works, and can be used to plot a path forward. It does seem like you have to calculate the expiration date. But I can work on that and see if there's a better way.
If you want to Query for a specific user:
Get-ADUser Name-Name -Properties 'PasswordLastSet',DisplayName |
Select-Object Name,DisplayName,
#{ Name = 'PasswordExpires'; Expression = { $_.PasswordLastSet.AddDays( $MaxPwdAge ) } }
This assumes the Hyphenated name is a samAccountName. If you need to search by DisplayName you'll have to resort back to filter, even if you are looking for only the one user.
Get-ADUser -Filter { DisplayName -eq "Name-Name" } -Properties 'PasswordLastSet',DisplayName |
Select-Object Name,DisplayName,
#{ Name = 'PasswordExpires'; Expression = { $_.PasswordLastSet.AddDays( $MaxPwdAge ) } }
Note: That you have to change the "Name-Name". Also in the last example I changed to using the -eq operator instead of -like. Obviously this assumes you know exactly what you're looking for. Though you can use -Like with DisplayName or even the surName attribute if you like.

Sorting properties with PowerShell splatting

I am using Active Directory module for Windows PowerShell to export certain values from Active Directory. How can I display the results in the same order as the properties are listed? When I run this command I get all of the properties available listed in alphabetical order. But what I want and expect is to get only the properties I have listed in the hashtable in the same order as the hash table.
$GetADUserOptions = #{
properties = #(
"employeeID",
"employeeNumber",
"whencreated",
"wWWHomePage",
"c",
"CO"
)
}
Get-ADUser #GetADUserOptions
What am I missing?
You can't control the order the properties are returned to you by Active Directory or the module.
But if what you're doing with the resulting data is exporting to something like CSV (or even just the console) and you care about the order of the columns, just use Select-Object with your desired order before doing the export.
You can just pass the array from the splat as #AdminOfThings suggested like this
Get-ADUser #GetADUserOptions | Select-Object $GetADUserOptions.properties
Or you can do it explicitly which also allows for some post-processing of attributes that aren't very human-readable by default like lastLogonTimestamp or pwdLastSet.
# assuming lastLogonTimestamp was added to your list of properties
Get-ADUser #GetADUserOptions | Select-Object sAMAccountName,#{
Label='LastLogonTS'
Expression={
[DateTime]::FromFiletime($_.lastLogonTimestamp)
}
}
Using the [ORDERED] syntax will force the array to return the order of the results.
$GetADUserPropertiesEAD = [ORDERED]#{
'Properties' = 'Name',
'GivenName',
'Surname',
'Description',
'Enabled',
'LastLogonDate',
'ObjectClass',
'ObjectGUID',
'SamAccountName',
'SID',
'UserPrincipalName',
'DistinguishedName',
'extensionattribute5'
} #end $GetADUserProperties
get-aduser -Filter {enabled -eq $False} #GetADUserPropertiesEAD | select $GetADUserPropertiesEAD.Properties

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.

CSV export is missing data in one of the columns

I have a csv file that this script works fine on.
$CCure = Import-csv C:\Scripts\file1.csv
ForEach ($user in $CCure) {
[string]$1Name = $User.FirstName
[string]$2Name = $User.LastName
[string]$GivenName = $1Name.Split(" ")[0]
[string]$SN = $2Name.Split(",")[0]
[string]$ID = $User.ObjectID
[string]$EmpID = $User.Int5 |
Select #{Name="First Name";Expression={$GivenName}}, #{Name="Last Name";Expression={$SN}}, #{Name="CCure ObjectID";Expression={$ID}}, #{Name="CCure Int5 Row";Expression={$EmpID}} |
Export-csv C:\Scripts\CCure\CCure-Names-Test.csv -Append -notypeinformation
}
However, when I try a similar script going out to AD and want to use RegEx, things don't work. It seems to hang or when it does run, the SurName is missing. Why doesn't the second one work? I must be missing something simple?
$Users = Get-ADUser -LDAPFilter "(&(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))" -properties samaccountname,givenname,sn
ForEach ($User in $Users) {
[string]$1Name = $User.GivenName
[string]$2Name = $User.SN
[string]$GivenName = $1Name.Split(" ")[0]
[string]$SN = $2Name.Split(",")[0] |
Select #{Name="First Name";Expression={$GivenName}}, #{Name="Last Name";Expression={$SN}},#{Name="SID";Expression={$User.samaccountname}}| Export-Csv C:\scripts\ccure\AD-Active-Names3.csv -NoTypeInformation -append
}
In your second example $sn would be null. This is because of the trailing pipe character that you have. This issue is also present in your first code block for $EmpID. The last command Export-CSV returns nothing to the output stream so the variable in both cases would be $null.
You are taking the result of $2Name.Split(",")[0] and sending that into the pipeline which is then left unused for Select-Object.
So the simple answer is remove the pipeline character and those two lines will now work separately.
[string]$SN = $2Name.Split(",")[0]
Select #{Name="First Name";Expression={$GivenName}}, #{Name="Last Name";Expression={$SN}},#{Name="SID";Expression={$User.samaccountname}}| Export-Csv C:\scripts\ccure\AD-Active-Names3.csv -NoTypeInformation -append
Also consider making your own object if you are changing property names and values that much. This should accomplish the same thing, be easier to read and take advantage of the pipeline.
$Users = Get-ADUser -LDAPFilter "(&(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))"
$Users | ForEach-Object {
$props = #{
"First Name" = ($_.GivenName).Split(" ")[0]
"Last Name" = ($_.SurName).Split(",")[0]
"SID" = $_.samaccountname
}
New-Object -TypeName psobject -Property $props
} | Select-Object "First Name","Last Name",SID | Export-Csv C:\scripts\ccure\AD-Active-Names3.csv -NoTypeInformation
You will note that I used $_.SurName as the property names used since PowerShell AD Objects do not directly match their LDAP attribute names. If you tried to access $_.SN you would get a null value. GivenName,Surname and SID are part of the value set returned by default so you don't need to request them.
Looking at about_ActiveDirectory_ObjectModel you will see under AdUser:
Surname - A property of type System.String, derived from the directory attribute: sn
You will still get errors with this if Surname or GivenName are not populated. Accounting for that would be a simple if statement if that is going to be an issue.