PowerShell Output Related to ADObject Properties - powershell

I'm trying to retain the Microsoft.ActiveDirectory.Management.ADAccount object when searching and specifying return outputs; however, when selecting the outputs, additional fields are populating. Questions:
Why is this is happening?
Is there a method, command, or filter to return only the specified parameters? (not the extra fields listed in the example below)
Is there a way to remove properties from the ADAccount Object? ($a in this example)
For the select method, is there a way to retain the original object formatting ? (I do not want a table and still need to reference the object later)
Running the following command:
$a = Get-ADUser $targetPerson -Properties Department, EmailAddress, Office, OfficePhone
returns:
Department : ****
DistinguishedName : CN=1111,OU=2222,OU=3333,OU=4444,DC=5555,DC=6666
EmailAddress : ****#mail.com
Enabled : ****
GivenName : ****
Name : ****
ObjectClass : user
ObjectGUID : ****
Office : ****
OfficePhone : ****
SamAccountName : ****
SID : ****
Surname : ****
UserPrincipalName : ****

Get-ADUser has a default set of properties it always returns, including for instance the distinguished name, the SID, and the account name. The parameter -Properties is for specifying which additional properties the cmdlet should return, because the default property set is just a small subset of all available properties.
To limit the output of Get-ADUser to a specific set of properties you need to pipe the output through Select-Object:
$props = 'Department', 'EmailAddress', 'Office', 'OfficePhone'
$a = Get-ADUser $targetPerson -Properties $props |
Select-Object $props
Of course that will turn the ADAccount object into a custom object (PSCustomObject), but I don't think there's a way around that.

The object Microsoft.ActiveDirectory.Management.ADAccount inherits members from the class it is created from. Here are some of the inherited members -
Name, ObjectClass, ObjectGUID, SID, and SamAccountName.
More about AD Object
I don't think you can create a Microsoft.ActiveDirectory.Management.ADAccount object with out those inherited members.
But if your project can accept a PSCustomObject then pipe $a to Select-object.
$a | Select-Object -Property Department, EmailAddress, Office, OfficePhone

Related

Powershell get only properties matching string pattern from Get-ADUser

I was trying to get all properties containing the string "home" from an AD User (HomeDirectory, HomeDrive etc.). I can make that work by doing the following based off of this post:
Get-ADUser -Identity MyUser -Properties * | Select-Object -Property "*home*"
However, this will bog down the system if I'm doing it in a for-loop since it will fetch all properties first, and then after that filter out the ones that match the string "home" anywhere in the property name.
Is there a way to do this filtering already in the Get-ADUser call to reduce the amount of information being sent? I guess the more generic question would be: is there a way in Powershell to fetch only properties of an object that matches a specific string pattern?
You can create this pattern yourself by calling get-aduser -id myuser -properties * | % { $_.propertynames -match "home" } - doing this ONCE you can store the outcome into an array then supply this to further get-aduser calls.
$proplist=get-aduser -id myuser -properties * | % { $_.propertynames -match "home" }
get-aduser -properties $proplist
Another approach could be to first get an array of all LDAP attribute names from the AD Schema:
function Get-ADUserAttributeNames {
# First, get all AD user attributes defined in the Active Directory schema
$searchBase = (Get-ADRootDSE).SchemaNamingContext
$schemaAttribs = (Get-ADObject -SearchBase $searchBase -Filter "name -like 'user'" -Properties MayContain,SystemMayContain |
Select-Object #{Name = 'Attribs'; Expression = {$_.maycontain + $_.systemmaycontain}}).Attribs
# Next, get all created user attributes. These are not defined in the schema, but calculated when asked for
$flagsAttribs = (Get-ADObject -SearchBase $searchBase -LDAPFilter '(systemFlags:1.2.840.113556.1.4.803:=4)' -Properties systemFlags).Name
return ($schemaAttribs + $flagsAttribs) | Sort-Object
}
$userAttribs = Get-ADUserAttributeNames
In subsequent calls, use the returned $userAttribs array like this:
$homeAttribs = $userAttribs | Where-Object { $_ -like '*home*' }
Get-ADUser -Filter * -Properties $homeAttribs
Some explanation
This approach retrieves the list of LDAP user attribute names from the AD Schema itself, so there is no need to probe a known user. The returned attribs apply to any user object in your AD environment.
With Vesper's good answer you do need a user that you know exists, but that's no problem of course since you can simply use your own SamAccountName.
The reason I've emphasized LDAP is that Ldap attribute names are not always as self-descriptive as you would like, sometimes just one character and on other occasions ridiculously long..
That is why PowerShell maps most common atribute names to more friendly (and also case-insensitive) names.
Some examples:
LDAP PowerShell
---- ----------
l City
o Organization
cn Name
physicalDeliveryOfficeName Office
facsimileTelephoneNumber Fax
wWWHomePage HomePage
nTSecurityDescriptor CannotChangePassword
PowerShell in some cases also changes the format of an attribute to an easier to use format like with Enabled which returns a Boolean value from computing the LDAP userAccountControl (bit mask not 2) or PasswordLastSet which returns a DateTime object from ldap's pwdLastSet attribute.
The AD Schema can be extended with more attributes. Sometimes software does that (like Exchange that extends the schema with lots of msExch* atributes) but you (as administrator) can add new properties too.
The list you get with above function is therefore quite, but not completely static and can change over time.

How to export a multi line CSV that every item is in one cell?

I'm kinda new into the PowerShell world related to building gui's but I've managed to create a gui that in a few words, searches users in an AD and if the looked up information is correct it will store it on a CSV with the Out-File command.
An example looks like this.
Enabled : False
Locked : False
DisplayName : John Doe_test
GivenName : John
SurName : doe_test
SamAccountName : johndoe
Mail : ftestaddress#somemail.com
OfficePhone : 9999
Last Logon : 31/12/1600 21:00:00
Date Created : 7/6/2020 18:02:56
passwordlastset : 7/6/2020 18:02:56
And the code that outputs that is this one (this is the part that searches the user, displays it on a read only textbox and if the end user is right with the click of another button it will store the data. (The Write Host value is only to test the data, otherwise I'll have to enter to the csv file every time I store it.
$Formselected.controls.addrange(#($datousr,$save_btn))
$datousr.Text= Get-ADUser -filter {DisplayName -eq $username} -Properties * |Select-Object Enabled, #{Expression={$_.LockedOut};Label='Locked';}, DisplayName, GivenName, SurName, SamAccountName, Mail, OfficePhone, #{ Expression ={[DateTime]::FromFileTime($_.LastLogon)}; Label='Last Logon';}, #{Expression={$_.Created};Label='Date Created';}, passwordlastset | Out-String
$data_usr=$datousr.text
$save_btn.Add_Click{
Write-Host "$data_usr"
$data_usr |Out-File "C:\scripts\data load.csv" -Encoding UTF8 -Append -Force
}
I want to know, because it's driving me nuts how to assing "enable" on A1 and the result, which is "False" on A2 and so on because every item is in a line.
I've tried exporting to csv, but, because it comes from a variable it only stores the length of the output, not the value.
I'd like to be stored in this way:
Enabled Locked Username
False False JohnDoe
Export-CSV has a switch called -NoTypeInformation. With that appended to the cmdlet it saves the data only. However, you need to keep the data as Object for this, not converted to string as you have it now.
To do this, change the code block where the user information is gathered from AD into this:
# properties DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname, UserPrincipalName are returned by default.
$props = 'LockedOut','DisplayName','EmailAddress','OfficePhone','LastLogonDate','Created','PasswordLastSet'
# use the `script:` scope on the variable, so the button click has access to it
$script:data_usr = Get-ADUser -Filter "DisplayName -eq '$username'" -Properties $props -ErrorAction SilentlyContinue |
Select-Object Enabled,
#{Name = 'Locked'; Expression = {$_.LockedOut}},
DisplayName, GivenName, SurName, SamAccountName,
#{Name = 'Mail'; Expression = {$_.EmailAddress}},
OfficePhone,
#{Name = 'Last Logon'; Expression = {$_.LastLogonDate}},
#{Name = 'Date Created'; Expression = {$_.Created}},
PasswordLastSet
# display the data in the text box by formatting it as list and converting it to a string
$datousr.Text = ($data_usr | Format-List | Out-String)
Then in the code where you save the data to CSV, do:
$save_btn.Add_Click({
Write-Host $data_usr # display in the console
# save as proper CSV file (append to if the file already exists)
$script:data_usr | Export-Csv -Path "C:\scripts\data_load.csv" -Encoding UTF8 -Append -NoTypeInformation
})
Please note that it is better to name the properties you need from Get-ADUser then to use -Properties *. You don't need to add the properties returned by default (see the first code comment)
Also, I would recommend searching for the user on a user attribute other then the users DisplayName, because this tends the users of your GUI to enter variations like Bloggs, Joe vs. Joe Bloggs. EmailAddress could be more precise.

How to find *where* in ActiveDirectory an attribute is stored?

I want to use Power Query to extract a list of employee names including attributes such as username, telephone number, office number, etc.
I found an article that shows how to do just that:
http://datapigtechnologies.com/blog/index.php/pull-your-global-address-book-into-excel/
However, my question is: if I wanted to return an attribute that I know that exists, but I haven't a clue where in the Active Directory object/table model it resides, how might one perform a search to find the specific table & attribute that must be queried?
EDIT - Additional Information
"Is this more of a PowerQuery question that a PowerShell question" - I think the answer is both yes and no.
This command:
Get-ADUser <someValidUserName> - Property *
...does indeed output all the attributes for the specified user. However, as far as I can tell there is no indication in the output as to where in the AD object hierarchy each attribute resides.
From the Power Query article linked above, we see several "tables" noted in the Power Query interface to Active Directory. One such table is organizationalPerson which contains an attribute named physicalDeliveryOfficeName. It would seem that the notion of an organizationalPerson "object" isn't exclusive to Power Query, as it seems to correspond to the Ldap-Display-Name as documented here:
https://msdn.microsoft.com/en-us/library/ms683883(v=vs.85).aspx
So what I was hoping for was a means to wildcard search the AD attribute names themselves for the existence of the word "office" anywhere within any attribute name in the AD user hierarchy, and for the search results to return physicalDeliveryOfficeName as a result, including the fact that it resides within organizationalPerson
(Hopefully that makes the question a bit more clear?)
For posterity: Here is a PowerShell script (See Get Class Attributes) that will list all Active Directory classes + class attributes for a specified SamAccountName. From the list of attributes, you can then run something like the following to get the attribute values
#make a list of desired class attributes
$Properties = #('DisplayName', 'SamAccountName', 'mail', 'otherMailbox')
Get-ADUser -Filter * -SearchBase "dc=myDomain,dc=gov" -Properties $Properties | select $Properties
Credit to: http://virot.eu/getting-all-possible-classes-attributes-for-a-ad-object/
Get Class Attributes
#Run on Win 7 machine with PS 4.0 against A.D. running on a Win 2008 R2 domain controller
cls
$attributeList = New-Object System.Collections.ArrayList
$attributeListItem = [ordered]#{}
Import-Module ActiveDirectory
#Get an AD User and request objectClass
$aDObj = Get-ADUser "MyAccountName" -Properties objectClass
#get all class names
$nextClass = $aDObj.ObjectClass
$allClasses = Do
{
$currentClass = $nextClass
$nextClass = Get-ADObject -SearchBase "$((Get-ADRootDSE).SchemaNamingContext)" -Filter {lDAPDisplayName -eq $nextClass} -properties subClassOf | Select-Object -ExpandProperty subClassOf
$currentClass
}
While($currentClass -ne $nextClass)
#Get all attributes
$mandatoryAndOptionalAttributes = 'MayContain','MustContain','systemMayContain','systemMustContain'
ForEach ($class in $allClasses)
{
$classInfo = Get-ADObject -SearchBase "$((Get-ADRootDSE).SchemaNamingContext)" -Filter {lDAPDisplayName -eq $class} -properties $mandatoryAndOptionalAttributes
ForEach ($mandatoryAndOptionalAttribute in $mandatoryAndOptionalAttributes)
{
foreach ($classAttribute in $classInfo.$mandatoryAndOptionalAttribute)
{
$attributeListItem."Mandatory/Optional Attribute" = $mandatoryAndOptionalAttribute
$attributeListItem."Class" = $classInfo.Name
$attributeListItem."Class Attribute" = $classAttribute
$attributeList.add((New-Object PSObject -Property $attributeListItem)) | out-null
}
}
}
$attributeList | out-gridview -title ("All Class Attributes: " + $attributeList.count)

How to display all items in a member from Powershell without "..."

Run the following command:
Get-ADUser <username> -properties MemberOf | select MemberOf | Format-List *
results in something like
MemberOf : {CN=XXX,OU=xxx,OU=xxx,DC=xxx,DC=com, CN=XXX,OU=xxx,OU=xxx,DC=xxx,DC=com,CN=XXX,OU=xxx,OU=xxx,DC=xxx,DC=com,...}
I do not want to see "..." I actually want to see all the items.
Use Select-Object's -ExpandProperty switch:
Get-ADUser <username> -Properties MemberOf | select -ExpandProperty MemberOf
When you use Select-Object to filter for certain properties, it returns a PSCustomObject containing the specified properties of the object selected (or an array of PSCustomObjects, if multiple objects are selected). With -ExpandProperty, which may be used with only a single property, for each object selected it returns the object contained in the specified property.
So, with | select MemberOf, what's being returned is a PSCustomObject whose sole property is the MemberOf property of the ADUser object returned by Get-ADUser, displayed in list format (in the same style as it would display the results if you were listing multiple properties of the object).
With | select -ExpandProperty MemberOf, what's being returned is the ADPropertyCollection object which is contained in the MemberOf property (a collection of strings representing the DNs of the members), and that's the object that's displayed in list format.
BTW, I removed the | Format-List * because it's superfluous in this case.
Adi Inbar is correct. Let me expand on this by saying if you're having issues, often get-member is very useful for figuring out what is going on.
PS C:\> ipmo ActiveDirectory
PS C:\> Get-ADUser testuser42 | select memberof | gm
TypeName: Selected.Microsoft.ActiveDirectory.Management.ADUser
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
memberof NoteProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection memberof=Microsoft.ActiveDir...

Select AD member properties + extra column

I'm getting AD members for a group and list certain properties from that group. I can't seem to get the group name using the following code:
Import-Module ActiveDirectory
$strIdentity = "TestGroup"
$GroupMembers = Get-ADGroupMember -Identity $strIdentity -Recursive
$GroupMembers | select $strIdentity, Name, ObjectClass | sort name | Format-Table
When I get the output, I get a {} instead of TestGroup.
Select-Object is for selecting properties of an object so selecting $strIdentity doesn't make any sense here. Omit that part from your Select statement.
But what I think you are trying to do is add a property to reflect the parent group name.
$groupmembers | select #{Name="Group";Expression={$strIdentity}}, Name, ObjectClass
Remember it is all about the objects not text.
Enclose $strIdentity in double quotes:
$GroupMembers | select "$strIdentity",Name, ObjectClass ...
If the above doesn't work, try using a calculated property:
$GroupMembers | select #{Name='GroupName';Expression={$strIdentity}},Name, ObjectClass ...