Adding data to a PowerShell array / Add-Member - powershell

I am trying to write a PowerShell script that will compile together a list of groups in Active Directory along with the members of each group. My ultimate goal is to export this out to a CSV files, so I want the final PowerShell multi-dimensional array to have the following format:
GroupName GroupMember
Domain Admins Henry Doe
Domain Admins Melody Doe
Domain Names Doe Ray Me
Domain Users John Doe
Domain Users Jane Doe
(etc…)
I am using the following code to try and do this:
[array]$arrGroupMemberList = New-Object PSObject
Add-Member -InputObject $arrGroupMemberList -membertype NoteProperty -Name 'GroupName' -Value ""
Add-Member -InputObject $arrGroupMemberList -membertype NoteProperty -Name 'GroupMember' -Value ""
[array]$arrGroupMemberList = #()
[array]$arrGroupNameObjects = Get-ADGroup -Filter * | Where-Object {$_.Name -Like "Domain*"}
If ($arrGroupNameObjects.Count -ge 1)
{
## Cycle thru each group name and get the members
$arrGroupNameObjects | ForEach-Object {
[string]$strTempGroupName = $_.Name
$arrGroupMemberObjects = Get-ADGroupMember $strTempGroupName -Recursive
If ($arrGroupMemberObjects.Count -ge 1)
{
## Cycle thru the group members and compile into the final array
$arrGroupMemberObjects | ForEach-Object {
$arrGroupMemberList += $strTempGroupName, $_.Name
}
}
}
}
My problem is, I keep ending up with the following as my array:
Domain Admins
Henry Doe
Domain Admins
Melody Doe
Domain Names
Doe Ray Me
Domain Users
John Doe
Domain Users
Jane Doe
I've tried a few different ways and I've searched but haven’t found the answer anywhere. I’m sure that it is something simple, but what am I doing wrong? Can I create a multi-dimensional array with the necessary data like I am trying to do? If I use the following instead:
## Cycle thru the group members and compile into the final array
$arrGroupMemberObjects | ForEach-Object {
$arrGroupMemberList[$intIndex].GroupName = $strTempGroupName
$arrGroupMemberList[$intIndex].GroupMember = $_.Name
$intIndex++
I end up with errors like:
Property 'GroupMember' cannot be found on this object; make sure it exists and is settable.
Property 'GroupName' cannot be found on this object; make sure it exists and is settable.
Thanks
**UPDATE**
I may have found out where my problem is, it may be when I am adding the array members. At the end of my PowerShell script, I am adding the following line of code:
$arrGroupMemberList | Get-Member
There are no properties, my elements are not there, even though I added them with Add-Member cmdlet earlier in the script. Am I using the Add-Member cmdlet properly?

Looks like you need to use the following line to add rows to your table (two dimensional array).
$arrGroupMemberList += ,($strTempGroupName, $_.Name)
http://blogs.msdn.com/b/powershell/archive/2007/01/23/array-literals-in-powershell.aspx

I figured out what I was doing wrong - I was using Add-Member incorrectly. I was trying to use Add-Member to add members to a collection, and it doesn't seem to work that way. Something that simple but I really didn't see it discussed anywhere. So I found some examples and did the trial-and-error thing and got it to work. So I wanted to post an update back here in case anyone else has the same issue. The following code works just like I want it to (and will create an array with a list of groups from Active Directory along with the group members in each group):
[array]$arrGroupNameObjects = Get-ADGroup -Filter * | Where-Object {$_.Name -Like "Domain*"}
If ($arrGroupNameObjects.Count -ge 1)
{
## Cycle thru each group name and get the members
$arrGroupNameObjects | ForEach-Object {
[string]$strTempGroupName = $_.Name
$arrGroupMemberObjects = Get-ADGroupMember $strTempGroupName -Recursive
If ($arrGroupMemberObjects.Count -ge 1)
{
## Cycle thru the group members and compile into the final array
$arrGroupMemberObjects | ForEach-Object {
$objGroupMember = New-Object PSObject
Add-Member -InputObject $objGroupMember -membertype NoteProperty -Name 'GroupName' -Value $strTempGroupName
Add-Member -InputObject $objGroupMember -membertype NoteProperty -Name 'GroupMemberName' -Value $_.Name
[array]$arrGroupMemberList += $objGroupMember
}
}
}
}

Related

Building a custom object in powershell (Add-Member)

Trying to build a custom object inside a For-EachObject loop.
Here is the code
$infouser = New-Object -TypeName psobject
(Get-ChildItem -Path "\\$poste\C$\Users").Name | ForEach-Object {
$nomcomplet += Get-ADUser -Identity $_ | select-object -ExpandProperty userprincipalname
Add-Member -InputObject $infouser -Name "Code" -Value $_ -MemberType NoteProperty
Add-Member -InputObject $infouser -Name "Nom complet" -Value $nomcomplet -MemberType NoteProperty
}
$infouser | Out-GridView
What i'm trying to achieve is a custom object containing the usernames in C:\USERS along with their equivalent full e-mail adress from the AD.
What I have works partially, it displays the first one it can add, but it doesn't "append" the others :
Giving the error : "Add-Member : Cannot add a member with the name...because a member with that name already exists. If you want to overwrite the member anyway, use the Force parameter to overwrite it."
I don't want to overwrite, I want to append it to the object so the final object contains all usernames and all adresses.
What am I doing wrong here? Thanks
You need to create an array of psobjects, not a single psobject. You're creating a single object and re-adding the properties X times.
This implicitly creates an array and adds a new psobject for each loop.
$infouser = (Get-ChildItem -Path "\\$poste\C$\Users").Name | ForEach-Object {
[pscustomobject]#{
'Code' = $_
'Nom Complet' = $(Get-ADUser -Identity $_ | select-object -ExpandProperty userprincipalname )
}
}
$infouser | Out-GridView

Powershell - build a custom object with an unknown number of columns

I need to create a CSV that contains all possible emails addresses that an Active Directory user has. The CSV must be in the following format (very rigid API for where their going to be imported to):
Username | EmailAddress1 | EmailAddress2 | EmailAddressN
My script so far looks like this:
$Group = "GroupNAme
$usersObj = #()
$countMax = 0
$GetAdGroup = Get-AdGroup -Identity $Group -Properties *
[array]$members = $GetAdGroup.Members
ForEach ($member in $members) {
$currentUser = get-aduser -Identity $member `
-Properties EmailAddress, ProxyAddresses |
Where {$_.Enabled -eq "True"}
$countTemp = ($currentUser.ProxyAddresses).count
if ($countTemp -gt $countMax){ $countMax = $countTemp}
foreach ($mailAdd in $currentUser.ProxyAddresses) {
$usersOBJ += [pscustomobject]#{
'Username' = $currentUser.SamAccountName;`
'ProxyAddresses' = $mailAdd.SubString(5)
}
}
$usersOBJ | Export-CSV -NoTypeInformation C:\Export.csv
Now my existing Object spits out the Users as follows:
UserName | Emailaddress1
Username | Emailaddress2
Username | EmailsaddressN
I can't seem to make the leap into working out how to create a better object. I can get the max number of ProxyAddresses that occur but I'm not sure how to figure that into building my object and then populating the values of the $currentUser.ProxyAddresses into those columns.
I've read about Hash tables but they don't seem to fit my requirements, usually taking the form:
Username1 | Username2
Emailaddress1 | Emailaddress1
Emailaddress2 | Emailaddress2
Can anyone please point me in the right direction?
Cheers!
You just need to separate the values you're adding a bit. Add the username to a single object before the loop, then add additional properties on an as-needed basis. Finally, add the object to your array to be exported.
Try this:
...
$x = New-Object System.Object
$x | Add-Member –type NoteProperty –Name UserName –Value $currentUser.SamAccountName
$i=0
foreach ($mailAdd in $currentUser.ProxyAddresses) {
$i++
$x | Add-Member –type NoteProperty –Name "Emailaddress$i" –Value $mailAdd.SubString(5)
}
$usersOBJ += $x
Assuming you add all the users to $usersOBJ before exporting the csv, the columns should work perfectly for any number of proxy addresses.

Get AD group members using powershell

I am trying to export groups and their members in following format using powershell.
can somebody help me out here.
Format in CSV:
Group Name | Members
g1 M1
g1 M2
g2 M1
g2 M2
g3 M1
I have got output in CSV format but I am not able to split it out properly.
1st row == DN,member,sAMAccountName
2nd row ==
CN=DSO_ALL_**_AMER_Member_P_17700,OU=PersonalGroups,DC=**,DC=**,DC=**,DC=**,"CN=M123456,OU=Personal,OU=SG,OU=CS,DC=gbl,DC=**,DC=**,DC=**;CN=M123458,OU=Personal,
OU=SG,OU=CS,DC=gbl,DC=**,DC=**,DC=**,DSO_ALL-_**_AMER_Member_P_17700
From the 2nd row I need both member id and group name i.e "M123456" and "M123458"
and group name "DSO_ALL-_**_AMER_Member_P_17700"
Get-ADGroup | Get-ADGroupMember is a good start, however, Get-ADGroupMember does not return group identity, which you pretty much need here. So, you need a little pre-processing and post-processing.
$groups=get-adgroup -filter *
$data=#()
foreach ($group in $groups) {
$gid=$group.name
foreach ($member in (get-adgroupmember -id $group)) {
# now we have both group and member, make an object
$obj=new-object psobject
$obj | add-member -type noteproperty -name "Group Name" -value $gid
$obj | add-member -type noteproperty -name "Member" -value ($member.name)
$data+=$obj
}
}
$data | export-csv file.csv -notypeinformation -encoding utf8
Then you parse your properly prepared CSV. In case you need other attributes, add a respective line of $obj | add-member -type noteproperty.

Method to export objects with varying properties?

I hit a common problem with my scripting lately and decided to throw it into the wild to see how other people deal with this problem.
tl;dr; I want to export objects which have a varying number of properties. eg; object 1 may have 3 IP address but object 2 has 7 IP addresses.
I've evolved to creating a new object with custom properties and then injecting these objects into an array as my method of catching results - happy to hear if there is a better way but this is how I roll. This method works 100% when outputting to the screen as the objects are shown in list format - I've tried a number of export/out-file methods to no avail when I want to capture and store the output for reading in something like Excell.
The following is an example of me building an object and storing it (the function of the code is not important here - just the results it generates):
add-pssnapin Quest.ActiveRoles.ADManagement
$Groups = get-qadgroup AmbigousGroupNameHere-
$UserInfo = #()
ForEach ( $Group in $Groups ) {
$CurrentGroupMembers = get-qadgroupmember $Group
write-host "Processing group:" $Group
ForEach ( $GroupMember in $CurrentGroupMembers ) {
If ( $GroupMember.type -eq "User" ) {
$counter = 1
write-host "Processing member:" $GroupMember
$UserObject = get-qaduser $GroupMember | select SamAccountName,FirstName,LastName
$objUserInfo = New-Object System.Object
$objUserInfo | Add-Member -MemberType NoteProperty -Name SamAccountName -Value $UserObject.SamAccountName
$objUserInfo | Add-Member -MemberType NoteProperty -Name FirstName -Value $UserObject.FirstName
$objUserInfo | Add-Member -MemberType NoteProperty -Name LastName -Value $UserObject.LastName
$GroupMembership = get-qadgroup -ContainsMember $GroupMember | where name -like "AmbigousGroupNameHere-*"
ForEach ( $GroupName in $GroupMembership ) {
$objUserInfo | Add-Member -MemberType NoteProperty -Name CtxGroup$counter -Value $GroupName.SamAccountName
$counter++
}
$UserInfo += $objUserInfo
} else {
write-host "This is a group - we are ignoring it."
}
}
}
$UserInfo | Export-Csv UsersOutput.csv -NoType
From the above - you can see I scale the object property name by 1 for each group. CtxGroup$counter allows me to scale an object for the correct number of groups each user has. Confirmed this works great when outputting to the screen by default. The object is listed and I can see a new property for each group that matches for that user.
Now for the problem. When I export-csv or out-file the file is generated with enough headers based off the first object - so it creates the headings based on the amount of properties the first object has. So lets say the first user has 3 matching groups, it will create heading CtxGroup1, CtxGroup2, CtxGroup3. Great! No.
If the next user has 5 matching groups - only the first three are included in the output and the additional 2 are discarded as we don't have headings for CtxGroup4, CtxGroup5.
How on earth do other people deal with this?
side note; I considered creating my first object as a dummy with a massive amount of object (and hence headings) but well - that is not cool and really makes me feel inefficient.
You can obtain what you want ordering $UserInfo array by the number of properties, it can be done, but it's not so simple, in your case I would add another propertie with the count of groups added:
...
ForEach ( $GroupName in $GroupMembership ) {
$objUserInfo | Add-Member -MemberType NoteProperty -Name CtxGroup$counter -Value $GroupName.SamAccountName
$counter++
}
$objUserInfo | Add-Member -MemberType NoteProperty -Name NbCtxGroup -Value ($counter - 1)
$UserInfo += $objUserInfo
...
And then order descending the array on this propertie :
$UserInfo | Sort-Object -Property NbCtxGroup -Descending | Export-Csv .\F.csv
It's not so nice but it will do the trick.
Have a look at :
$objUserInfo.psobject.Properties | Measure-Object

exchange powershell : finding the active directory office property

I wrote this small script to pull the office property from get-user by piping the exchange mailbox object.
$server = "tms08"
$arrUser = get-mailbox -Server $server |Get-MailboxStatistics |select identity
foreach ( $id in $arrUuser)
{
$office = get-user -Identity $id.Identity |select office
$out += $id.Identity
}
$out
I don't get any output or red errors. just the warning:
WARNING:There is no data to return for
the specifed mailbox
'Globe/MobileElect Usertemplate',
because it has not been logged on to.
WARNING:By default only the first 1000
items are returned. To change the
number of items returned, specify the
parameter "-ResultSize". To return all
items specify "-ResultSize Unilimited"
(Note: REturning all items maytake a
long time and consume a large amount
of memory depending on the actual
number of items). It is not
recommended to store the results in a
variable; instead pipe the results to
another task or script to perform
batch changes.
Any ideas on what might be causing this?
My goal is to develop a script which executes once a day via scheduled task which compiles all mailbox names, mailbox sizes, totalitems, totaldeleted items, along with their office and description fields (from active directory).
I'm guessing the get-qaduser is part of the quest powershell addon. I'll install it locally and give it a try..
the identiy property seems to give a number similar to the guid which looks like
1234as01-4f54-1234-b1df-f1df1df12d2d
I tried running
get-user -identity 1234as01-4f54-1234-b1df-f1df1df12d2d
and it found a name (joey blasio) and recipient type (usermailbox)
then i ran
get-user -Identity 1234as01-4f54-1234-b1df-f1df1df12d2d | select displayname, distinguistedname
Displayname (Joey Blasio ) and DistinguishedName (CN=Joey
Blasio,OU=EWE,DC=BLA-1,DC=net)
It is done by DisplayName
$exchangeservers = Get-MailboxServer
$AllUsers = #()
$AllUsersEmail = #()
foreach ($server in $exchangeservers)
{
$AllUsers += Get-Mailbox -Server $server |Get-MailboxStatistics |select servername,displayname,itemcount,totalitemsize
}
foreach ($user in $AllUsers)
{
$obj = new-object psObject
$mailinfo = get-mailbox -identity $user.displayname |select PrimarySMTPAddress,Office, DistinguishedName
$tmp = [adsi]("LDAP://" + $mailinfo.DistinguishedName)
$obj |Add-Member -MemberType noteproperty -Name "Server Name" -Value $user.ServerName
$obj |Add-Member -MemberType noteproperty -Name "Display Name" -Value $user.DisplayName
$obj |Add-Member -MemberType noteproperty -Name "Item Count" -Value $user.ItemCount
$obj |Add-Member -MemberType noteproperty -Name "Total Item Size" -Value $user.TotalItemSize
$obj |Add-Member -MemberType noteproperty -Name "Email Address" -Value $mailinfo.PrimarySMTPAddress
$obj |Add-Member -MemberType noteproperty -Name "Office" -Value $mailinfo.Office
$obj |Add-Member -MemberType noteproperty -Name "Description" -Value $tmp.description
$AllUsersEmail += $obj
}
$AllUsersEmail |Export-Csv c:\test.csv -NoTypeInformation
I believe the problem is that you're accessing a mailbox that's never been accessed normally. Can you try this with a mailbox that you know the owner has opened and worked with? Or is that already the case?
Also, as I don't have access to my Exchange machine at the moment, can you give me an idea of what the Identity property contains? I'm absolutely certain using a cmdlet like Get-QADUser vs. Get-User in Exchange, will ultimately bring you more satisfaction. We just need to mesh up the right property from Get-MailboxStatistics to something Get-QADUser can consume, so that it can get you the right user.
It might also be a bit helpful to understand what your end goal is - possibly there's an entirely different approach that will get you to where you want to be.