How to merge 2 properties into single output of AD Objects? - powershell

I need to merge two properties into one column, name of user is in DisplayName while Name of group is stored in Name how ever both types of objects has DisplayName, Name properties so I need to show them in one column.
Suppose Group is 'Test Group'
CN : …
ObjectGUID : 123-456-XXXX
ObjectClass: group
DisplayName:
Name: 'Test Group'
And 'Test User' Properties are
CN: …
ObjectGUID : 789-456-XXXX
ObjectClass: user
DisplayName: 'Test User'
Name:
I have tried using a for each looping but can't figure out the use of select statement.
Get-ADGroupMember -Identity $GroupGUID |
ForEach-Object{
if($_.ObjectClass -eq 'User'){
# process user object
$_ | Get-ADUser -Properties DisplayName
}elseif ($_.ObjectClass -eq 'User'){
# process group
$_ | Get-ADGroup -Properties Name
}
}
The expected output need to be
MemberName ObjectGUID
---------------- ------------------
Test Group 123-456-XXXX
Test User 789-456-XXXX

I'd use a switch statement to process each item depending on if it is a user or group, and then replace the MemberName property depending on what it is:
$Results = Switch(Get-ADGroupMember -Identity $GroupGUID){
{$_.ObjectClass -eq 'User'} {$_ | Get-ADUser -Prop DisplayName | Select *,#{l='MemberName';e={$_.DisplayName}} -ExcludeProperty MemberName}
{$_.ObjectClass -eq 'Group'} {$_ | Get-ADGroup | Select *,#{l='MemberName';e={$_.Name}} -ExcludeProperty MemberName}
}
$Results|Select MemberName,ObjectGUID
Or if you really want it all done in the pipeline you could do this:
Get-ADGroupMember -Identity $GroupGUID -PipelineVariable 'Member' | ForEach{If($Member.ObjectClass -eq 'User'){$_ | Get-ADUser -Properties DisplayName}Else{$_ | Get-ADGroup}} | Select #{l='MemberName';e={If($Member.ObjectClass -eq 'User'){$_.DisplayName}Else{$_.Name}}},ObjectGUID

i think you are wanting to merge the sources into one output object.
the usual way to add values from multiple sources into one object is to use a [PSCustomObject] to build a ... custom object. [grin] i don't have any AD access, so this is done with local user & group info. you can do some fairly complex structuring by calculating what you want to work with and stuffing it all into one neatly structured object.
here's a demo of the idea using local accounts ...
$GroupName = 'Homonymic_Tuu'
$MemberList = Get-LocalGroupMember -Group $GroupName |
Where-Object {$_.ObjectClass -eq 'User'}
$GroupInfo = Get-LocalGroup -Name $GroupName
foreach ($ML_Item in $MemberList)
{
$UserInfo = Get-LocalUser -Name $ML_Item.Name.Split('\')[-1]
if ([string]::IsNullOrEmpty($UserInfo.LastLogon))
{
$LastLogon = '_Never_'
}
else
{
$LastLogon = $UserInfo.LastLogon
}
[PSCustomObject]#{
Group_Name = $GroupInfo.Name
Group_Description = $GroupInfo.Description
User_Name = $UserInfo.Name
User_Description = $UserInfo.Description
User_Enabled = $UserInfo.Enabled
User_LastLogon = $LastLogon
}
}
truncated output ...
Group_Name : Homonymic_Tuu
Group_Description : Homonym - sounds like Tuu
User_Name : 22
User_Description : The Digit 2 Twice
User_Enabled : True
User_LastLogon : 2018-11-27 9:19:10 PM
[*...snip...*]
Group_Name : Homonymic_Tuu
Group_Description : Homonym - sounds like Tuu
User_Name : TwoTwo
User_Description : Repeating the name of the number after One.
User_Enabled : True
User_LastLogon : _Never_
the data will also export to a CSV file quite easily. [grin]

Related

Powershell - Update field in AD from 2 txt files

I'm using Powershell to update the manager attribute in AD using data from 2 txt files.
One txt file has employee IDs in one column their manager's ID in the other like this:
1111 2222
4444 3333
The other txt file has all employee info listed by IDs like this:
1111 POTTER HARRY HPOTTER 200 3108675309
2222 GRANGER HERMIONE HGRANGER 201 3107942312
HPOTTER and HGRANGER are the samaccountnames. I want to use the IDs to grab all the samaccountnames to update the manager attribute for each employee.
There are several employeeIDs listed in the first txt file that are not listed in the second txt file (they are no longer employed). I thought that wouldn't really matter, but what I wrote so far hasn't been updating every employee correctly. I rewrote it and am stuck on how to loop through $employees to get both the employee samaccountname and the manager samaccountname.
$employees = Get-Content -Path 'Staff.txt'
$supervisors = Get-Content -Path 'Supervisors.txt'
foreach($supervisor in $supervisors){
$employeeID = $supervisor.substring(0,7)
$managerID = $supervisor.substring(8,7)
foreach($employee in $employees){
if ($employee.contains($employeeID)){
$empsamName = $employee.split("`t")[3]
#some code to get the manSamName
$ADUser = Get-ADUser -Filter "samaccountname -like '$empSamName'"
$manager = Get-ADUser -Filter "samaccountname -like '$manSamName'"
if($ADUser -and $manager){
$ADUser | Set-ADUser -manager $manager
}
}
}
}
Thanks for the help!
Instead of running a loop through each line to check if it matches the employee/manager ID, uou would want to use Where-Object to find a match.
Example
$employees | Where-Object {$_ -like "*1111*"}
I've provided a full solution below that's a little more thorough, allowing you to reference each employee as a separate object, and their attributes using dot-notation
Result
Line 1
EmployeeID
EmployeeSamAccountName
ManagerID
Manager
1111
HPOTTER
2222
HGRANGER
Line 2
Employee ID 4444 no longer employed
EmployeeID
EmployeeSamAccountName
ManagerID
Manager
4444
3333
Code
$employees = Get-Content -Path 'Staff.txt'
$supervisors = Get-Content -Path 'Supervisors.txt'
$employeeTable = foreach ($employee in $employees) {
# From the staff file, split each column into an array
$employeeSplit = $employee.Split(" ")
# Create a table from all the split columns, and add this employee object into another array (the $employeeTable)
[PSCustomObject] #{
EmployeeID = $employeeSplit[0]
EmployeeFirstName = $employeeSplit[1]
EmployeeSurname = $employeeSplit[2]
EmployeeSamAccountName = $employeeSplit[3]
Manager = "" # Leave this blank #
Column5 = $employeeSplit[4]
Column6 = $employeeSplit[5]
}
}
foreach ($supervisor in $supervisors) {
# From the supervisor file, split the 2 columns into separate variables
$employeeID, $managerID = $supervisor.Split(" ")
# From the employee table, get the employee that matches the ID from column 1 of the supervisors file
$employee = ($employeeTable | Where-Object { $_.EmployeeId -eq $employeeId } )
# Continue if the employee is still employed
if ($employee -ne $null) {
# Update the employee table to add the manager's name
$employee.Manager = ($employeeTable | Where-Object { $_.EmployeeId -eq $managerID } ).EmployeeSamAccountName
# Do your stuff
$ADUser = Get-ADUser -Filter "samAccountName -eq '$($employeeTable.EmployeeSamAccountName)'"
$manager = Get-ADUser -Filter "samAccountName -eq '$($employeeTable.Manager)'"
}
# Build a new table for the supervisor file
$outputTable = [PSCustomObject] #{
EmployeeID = $employeeID
EmployeeSamAccountName = $($employee.EmployeeSamAccountName)
ManagerID = $managerId
Manager = $($employee.Manager)
}
# Sample output
Write-Host "Line $($supervisors.IndexOf($supervisor))" -BackgroundColor DarkCyan
if ($employee.EmployeeSamAccountName -eq $null) {
Write-Host "Employee ID $($employeeID) no longer employed" -ForegroundColor Red
}
Write-Host ($outputTable | ft | Out-String)
}

Get Distribution List muliple Owners in exchange

i need a power shell cmd or script which will give me the list of all the Distributions list along with the OWNERS of that like managed by.
But , if there are multiple users inside managedby attribute then I am getting System.Object[].
My question are :
1- how can we get multiple users for managedby attribute ?
2- how can we add employeeid and samaccountname for managedby users ?
3 - if there is no managed by user then it display "NO MANAGED BY USER"
4- I want to get mail groups not hidden.
script :
$DGroups=Get-DistributionGroup -resultsize unlimited
$mastertable=#()
ForEach($Group in $DGroups){
$table=[pscustomobject][ordered]#{
Name = $group.name
"Managed By" = $group.managedby.name
"DistinguishedName" = $group.DistinguishedName
}
$Mastertable += $table
}
$Mastertable | export-csv C:\tmp\managedby.csv -NoTypeInformation
My output :
"Name","Managed By","DistinguishedName"
"IT research","System.Object[]","CN=IT research,OU=TEST,DC=contoso,DC=com"
"Test Mail Group 1","User01","CN=\Test Mail Group 1,OU=Test,OU=COMPANY,DC=contoso,DC=com"
"Test Mail Group 2",,"CN=\Test Mail Group 2,OU=Test,OU=COMPANY,DC=contoso,DC=com"
My desired output :
"Name","Managed By","DistinguishedName","OWNERSAMACCOUNTNAME","OWNEREMPLOYEEID"
"IT research","User01;User02","CN=IT research,OU=TEST,DC=contoso,DC=com","tst124;tst125","242333;344232"
"Test Mail Group 1","User01","CN=\Test Mail Group 1,OU=Test,OU=COMPANY,DC=contoso,DC=com","tst124","242333"
"Test Mail Group 2","NO MANAGED BY USER","CN=\Test Mail Group 2,OU=Test,OU=COMPANY,DC=contoso,DC=com"
LAST UPDATE :
[PS] C:\Windows\system32>$group.ManagedBy
OrgHierarchyToIgnore :
IsDeleted : False
Rdn : CN=John T
Parent : contoso.com/COMPANY/IT
Depth : 5
DistinguishedName : CN=John T,OU=IT,DC=contoso,DC=com
IsRelativeDn : False
DomainId : contoso.com
PartitionGuid : 59ce2f71-eaa2-4ddf-a4fa-f25069d0b324
PartitionFQDN : contoso.com
ObjectGuid : 62d578e8-b69c-45bc-967a-e530d72792e1
Name : John T
[PS] C:\Windows\system32>$group.ManagedBy | ForEach-Object { $_ | Get-ADUser -Properties EmployeeId }
Get-ADUser : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties
do not match any of the parameters that take pipeline input.
At line:1 char:42
+ $group.ManagedBy | ForEach-Object { $_ | Get-ADUser -Properties EmployeeId }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (contoso.com/COMPANY/IT/John T:PSObject) [Get-ADUser], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Microsoft.ActiveDirectory.Management.Commands.GetADUser
It is my understanding the ManagedBy attribute stores the DistinguishedName(s) of one or more users (or none at all).
I haven't tested this myself, but you could try:
$DGroups = Get-DistributionGroup -ResultSize Unlimited
$mastertable = foreach($group in $DGroups) {
# initialize a PsCustomObject
$data = [PsCustomObject]#{
Name = $group.Name
DistinguishedName = $group.DistinguishedName
ManagedBy = 'NOT MANAGED'
OwnerSamAccountName = $null
OwnerEmployeeId = $null
}
if ($group.ManagedBy) {
$managedBy = $group.ManagedBy | ForEach-Object { Get-ADUser -Identity $_.DistinguishedName -Properties EmployeeId }
$data.ManagedBy = $managedBy.Name -join ';'
$data.OwnerSamAccountName = $managedBy.SamAccountName -join ';'
$data.OwnerEmployeeId = $managedBy.EmployeeId -join ';'
}
# output this data to be collected in $mastertable
$data
}
$mastertable | Export-Csv 'C:\tmp\managedby.csv' -NoTypeInformation

Return a selectable list in Powershell

I'm writing a powershell script that will search active directory and give me info on users like this:
$fname = Read-Host 'Enter first name'
$lname = Read-Host 'Enter Last Name'
$search = [adsisearcher]"(&(ObjectCategory=Person)(ObjectClass=User)(givenName=$fname)(sn=$lname))"
$users = $search.FindAll()
foreach($user in $users) {
$displayname = $user.Properties['displayname']
"$displayname"
}
That will return a list of users who have the same first and last names:
User1
User2
User3
User4
I'd then like to be able to select which user I want to show further info on, something like this:
Read-Host 'Enter user number'
#input 1 - 4
#returns exchange server name for the selected user:
$msExchHomeServerName = $user.Properties['msExchHomeServerName']
"Exchange server: $msExchHomeServerName"
I can't figure out how to return a selectable list that lets me get further details on that user.
This works for me. I'm more familiar with PSCustomObjects, but you could do this as a hashtable instead, I'm sure (although I think hashtables get funny if you try and use an integer as a key).
And I'm sorry, I'm too lazy to refactor this with ADSI, but hopefully the logic is clear.
If you wanted to, you could return the user properties you might need with your initial LDAP query and add them to the [PSCustomObject] you're creating for each user. Then just pull the properties out of $usertable rather than doing another AD query. (See the second example.)
However, I'm really adamant that if it's more than a few properties for more than a few users, don't try and grab everything at once. I get really sick of lazy LDAP filters with -properties * when you only want one property. In my environment, if I get all the properties on just my account, it's 74 KB. That starts to add up quickly when dragging stuff out of LDAP.
# sort user list by desired attribute below e.g. samaccountname, lastname, etc
$users = get-aduser -filter 'name -like "macdo*"' | sort samaccountname
# create an array to store the user results
$usertable = #()
$no = 0
$users | foreach {
$no++
$o = [PSCustomObject]#{
No = $no
Name = $_.samaccountname
}
$usertable += $o
}
$usertable |sort no
# this is what the table will look like on screen
No Name
-- ----
1 AKMacDonald
2 AMacDonald
3 BMacDonald
4 BMacdonnell
$myint = Read-Host 'Enter user number'
> Enter user number: 29
# Select desired user properties in Get-ADUser below
$ADuser = $usertable | where {$_.no -eq $myin} |select -ExpandProperty Name |
Get-Aduser -Properties msExchHomeServerName
$ADuser
#AD user output
DistinguishedName : CN=BMacDonald,OU=Accounts,DC=example,DC=com
Enabled : False
GivenName : Bruce
Name : BMacDonald
...
If you're grabbing a few extra attributes with your initial AD query, you can store them in the $usertable for quick retrieval.
# grab msExchHomeServerName in this query
$users = get-aduser -filter 'name -like "macdo*"' -properties msExchHomeServerName |
sort samaccountname
# create an array to store the user results
$usertable = #()
$no = 0
$users | foreach {
$no++
$o = [PSCustomObject]#{
No = $no
Name = $_.samaccountname
Exchsrv= $_.msExchHomeServerName
}
$usertable += $o
}
# do a "select" below if you don't want to display everything in $usertable
$usertable |sort no
# $usertable contents
No Name Exchsrv
-- ---- ----
1 AKMacDonald Exch1
2 AMacDonald Exch1
3 BMacDonald Exch2
4 BMacdonnell Exch3
$myint = Read-Host 'Enter user number'
> Enter user number: 29
# Select desired user properties from $usertable
$usertable | where {$_.no -eq $myint} | Select Name,Exchsrv
# output
Name Exchsrv
---- ----
AKMacDonald Exch1
You have to specify the properties that you'd like to load for each user. [adsisearcher] is a type accelerator for DirectorySearcher, so try this:
$filter = "(&(ObjectCategory=Person)(ObjectClass=User)(givenName=$fname)(sn=$lname))"
$propsToLoad = #('displayname', 'msExchHomeServerName')
$search = [System.DirectoryServices.DirectorySearcher]::new($filter, $propsToLoad)
If you want to avoid user selection error, you can use the PromptForChoice method :
$fname = (Read-Host 'Enter first name').Trim()
$lname = (Read-Host 'Enter Last Name').Trim()
$filter = "(&(samAccountType=805306368)(givenName=$fname)(sn=$lname))"
$propsToLoad = #('displayname','samaccountname', 'mail', 'l', 'department', 'msExchHomeServerName')
$search = [System.DirectoryServices.DirectorySearcher]::new($filter, $propsToLoad)
$results=$search.FindAll()
$results[$Host.UI.PromptForChoice( "Choose the namesake you want to see",`
"Type the corresponding SamAccountName", ($results | ForEach-Object `
{ New-Object System.Management.Automation.Host.ChoiceDescription( `
$_.Properties.samaccountname, $_.Properties.department) }), 0)].Properties.Values
This shows you this once you have typed givenName and surName :
Enter first name: Justine
Enter Last Name: Noix
Choose the namesake you want to see
Type the corresponding SamAccountName
[] JNoix [] JuNoix [?] Aide (la valeur par défaut est « JNoix ») : junoix
JuNoix
Justine Noix
LDAP://CN=Justine Noix,OU=R&D,OU=Tests,DC=someDomain,DC=adds
Justine.Noix.RD#someDomain.adds
R&D
SomeCity
mailserver.someDomain.adds
if you type a wrong samAccountName, it re-asks again.
if you don't care about any help or have no department setted in AD, simply replace the last line by :
$results[$Host.UI.PromptForChoice( "Choose the namesake you want to see",`
"Type the corresponding SamAccountName", ($results | ForEach-Object `
{ New-Object System.Management.Automation.Host.ChoiceDescription( `
$_.Properties.samaccountname, "") }), 0)].Properties.Values

Power Shell Output Re-Filter | Get-CalendarProcessing

I'm trying to write a script that shows resource delegates in Outlook 2010 mailboxes. The code for this is:
input > Get-CalendarProcessing -Identity $Alias | where {$_.ResourceDelegates -ne "{}"} | ft *
The output important to me is the Resource and Mailbox identity.
ResourceDelegates : {TEST/A/A Usr, TEST/A/Kelly Besant, TEST/A/A Usr,
Identity : TEST/A/A Usr
I need the names in a standard format and not in the canonical format, how can I convert them?
You can use the canonical name with get-recipeint to resolve to Name, DisplayName, or DN:
Get-CalendarProcessing -Identity $Alias |
where {$_.ResourceDelegates -ne "{}"} |
select -ExpandProperty ResourceDelegates |
get-recipient |
select -ExpandProperty Name
Each ResourceDelegates or Identity object has a name property (EMS required):
$Identity = #{n='Identity';e={$_.Identity.Name}}
$ResourceDelegates = #{n='ResourceDelegates';e={$_.ResourceDelegates | foreach {$_.Name}}}
Get-CalendarProcessing $alias| Select-Object $Identity,$ResourceDelegates

In PowerShell, how can I combine the results of two commands that have a 1-to-1 relashionship?

This particular example is Get-User and Get-Mailbox (Exchange 2010). Get-User returns some of the columns I need, and Get-Mailbox some others. I am having difficulty figuring out how I can combine the results of the two into a single table with the results from both.
Get-User -Filter "..." | Get-Mailbox -Filter "..."
How do I take the results of a command similar to the above and turn it into results similar to below?
FirstName LastName Alias CustomAttribute1
--------- -------- ------ ----------------
Bob Smith bsmith Example
Johnny NoMail
Adam Blye ablye Has a Mailbox
Note that FirstName and LastName are not returned by Get-Mailbox, and conversely Alias and CustomAttributes are not returned from Get-User. Not every user has a mailbox, so sometimes a portion of the columns would be null. But I'm having a devil of a time figuring out the best way to return a combined table like this.
Get the users, save each user in a variable, get the mailbox for each user and then create a new object with properties from both variables
Get-User -Filter ... | Foreach-Object{
$user = $_
$mbx = Get-Mailbox $user
New-Object -TypeName PSObject -Property #{
FirstName = $user.FirstName
LastName = $user.LastName
Alias = $mbx.Alias
CustomAttribute1 = $mbx.CustomAttribute1
}
}
I make a custom object, which may be overkill, but it's the simplest way I've found.
Here's some sample code to play with. Let me know if it generates any trouble or additional questions:
$outputCollection = #()
$users = Get-User -Filter "..."
$mailboxes = Get-Mailbox -Filter "..."
$users | Foreach-Object {
#Associate objects
$userObject = $_
$mailboxObject = $mailboxes | Where-Object {$_.Name -eq $userObject.Name}
#Make a combined object
$outputObject = "" | Select Name, UserAttribute, MailboxAttribute
$outputObject.Name = $userObject.Name
$outputObject.UserAttribute = $userObject.UserAttribute
$outputObject.MailboxAttribute = $mailboxObject.MailboxAttribute
#Add the object to the collection
$outputCollection += $outputObject
}
$outputCollection
Another option that should work is called calculated properties:
Get-User -Filter "..." | Select Name, UserAttribute, #{Name="OtherAttribute"; Expression={(Get-Mailbox $_.Name).MailboxAttribute}}
...note that this will run a new Get-Mailbox command for each entry, potentially increasing execution time
Thank you guys. I spent a hell of a lot of time trying to figure out my own issue and your code helped me get it right. I needed to find all the calendars were the default account was set to none. Below is what I needed up using.
Get-Mailbox | ForEach-Object{
$user = $_
$calPerms = Get-MailboxFolderPermission $user":\calendar" -User Default | Where-Object {$_.AccessRights -eq "none"}
New-Object -TypeName PSObject -Property #{
Name = $user
Permissions = $calPerms.AccessRights
Users = $calPerms.user
}
}
One liner to get FirstName, LastName, Alias and CustomAttribute1:
Get-User | Select Firstname, Lastname, #{Name="Alias"; Expression={(Get-Mailbox $_.Name).Alias}}, #{Name="CustomAttribute1"; Expression={(Get-Mailbox $_.Name).CustomAttribute1}}