Sorting properties with PowerShell splatting - powershell

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

Related

removing 'CN' from DistinguishedName in Powershell script

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

How to save output of split as columns with custom headers in Powershell

Using the suggestion mentioned here: split command I am able to split canonicalname.
Get-ADOrganizationalUnit -Properties DistinguishedName, WhenCreated, Name, CanonicalName -Filter * |Select DistinguishedName, WhenCreated, Name, CanonicalName| Select-Object -Property CanonicalName | ForEach-Object { ($_ -split '/') }
How can I display output with custom headers, split on CanonicalName, display original CanonicalName, and show the output in column format?
New Column Header would look like following:
DistinguishedName, WhenCreated, CanonicalName, Name, Servers,OSLevel1, OSLevel2,OSLevel3,Environment,Lane,OU,SubOU
For future clarity: Canonical name structure for me looks like:
dev.company.com/Band/Servers/Application/Development/Marketing/DevMarketing
dev.company.com/Rhel/Application/Development/Marketing/DevMarketing
Where OSLevel1 = Band
OSLevel2=Servers
OSLevel3=Application
For Rhel, I understand it will be in different columns.
It's unclear what data is supposed to go into which column. You mention splitting the CanonicalName, but where do you want the data to land? Is OSLevel really supposed to mean OULevel?
What we can talk about is the ability to add properties to objects. This can be done in different ways. Probably the most popular is to incorporate calculated properties (expressed as hash tables) in a Select-Object command(s).
Get-ADOrganizationalUnit -Filter * -Properties * |
Select-Object DistinguishedName,
#{ Name = 'CanonicalBaseName'; Expression = { $_.CanonicalName.Split('/')[-1] } }
Obviously this is just an example, adding only 1 property. You can add as many properties as you want. Just add a comma followed by another hash table.
If correct and you are looking to put Each OU level into a field. You may want to add an interim property by running Select-Object twice.
Get-ADOrganizationalUnit -Filter * -Properties * |
Select-Object DistinguishedName,
#{ Name = 'CanonicalLevels'; Expression = { $_.CanonicalName.Split('/') } } |
Select-Object DistinguishedName,
#{ Name = 'OULevel1'; Expression = { $_.CanonicalLevels[0] } },
#{ Name = 'OULevel2'; Expression = { $_.CanonicalLevels[1] } },
#{ Name = 'OULevel3'; Expression = { $_.CanonicalLevels[2] } }
In this example an array is added representing all the container levels in the CanonicalName. then passed to another Select-Object command that will add custom properties based on the previously added property's array indices. Notice the CanonicalLevels property isn't output because it's not included in the 2nd Select-Object command.
The expression can be almost anything! Regardless of the question's shortcomings, this should be enough to create almost any column to want. If you search Google for something like "PowerShell calculated property" you'll find tons of guidance and examples.

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.

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.

Multiple rows in a grid [duplicate]

This question already has answers here:
Export hashtable to CSV with the key as the column heading
(2 answers)
Closed 4 years ago.
I'm trying to list all ad group memberships of specific users. The input would be a string of logins split with a comma 'login1,login2'.
So I go over each user and list their memberships with the username as title. Somehow it only shows the first entry. Also it shows the user groups in one row and I don't know how to change that.
Code below:
$users = $logon -split ','
$q = #()
foreach ($user in $users) {
$usernm = Get-ADUser -Filter 'samAccountName -like $user' | select Name
$useraccess = Get-ADPrincipalGroupMembership $user | Select-Object Name
$userobj = New-Object PSObject
$userobj | Add-Member Noteproperty $usernm.Name $useraccess.Name
$q += $userobj
}
Expected output would be something like:
fullnameuser1 fullnameuser2 list of users goes on...
------------- ------------- ------------------------
adgroup1 adgroup3 ...
adgroup2 adgroup4
... ...
In principle this would also mean that if i typed $q.'fullnameuser1' output would be:
fullnameuser1
-------------
adgroup1
adgroup2
...
Whenever the code is ran, it will only ever add the first user's access, also returning all groups on one row. So somehow I need to go over all the group memberships and add a row for each one.
First and foremost, PowerShell does not expand variables in single-quoted strings. Because of that Get-ADUser will never find a match unless you have a user with the literal account name $user. Also, using the -like operator without wildcards produces the same results as the -eq operator. If you're looking for an exact match use the latter. You probably also need to add nested quotes.
Get-ADUser -Filter "samAccountName -eq '${user}'"
Correction: Get-ADUser seems to resolve variables in filter strings by itself. I verified and the statement
Get-ADUser -Filter 'samAccountName -eq $user'
does indeed return the user object for $user despite the string being in single quotes.
If you want a fuzzy match it's better to use ambiguous name resolution.
Get-ADUser -LDAPFilter "(anr=${user})"
You may also want to avoid appending to an array in a loop, and adding members to custom objects after creation. Both are slow operations. Collect the loop output in a variable, and specify the object properties directly upon object creation.
$q = foreach ($user in $users) {
...
New-Object -Type PSObject -Property {
$usernm.Name = $useraccess.Name
}
}
Lastly, I'd consider using the user's name as the property name bad design. That would be okay if you were building a hashtable (which is mapping unique keys to values), but for custom objects the property names should be identical for all objects of the same variety.
New-Object -Type PSObject -Property {
Name = $usernm.Name
Group = $useraccess.Name
}
Basily query all the users and store it in $users, example:
Get-ADUser -Filter * -SearchBase "dc=domain,dc=local"
And then you can export the results as csv or a table.
To Export as CSV :
Get-ADPrincipalGroupMembership <Username> | select name, groupcategory, groupscope | export-CSV C:\data\ADUserGroups.csv`
To Format the result as Table in the console itslef :
Get-ADPrincipalGroupMembership <Username> | select name, groupcategory, groupscope | Format-Table