Good Afternoon,
I searched through this forum and a few others combining ideas and trying different angles but haven't figured this out. If this has been answered, and I suck at searching, I am sorry and please let me know.
End Goal of script: have an excel file with columns for the AD properties Name, Office, Org, and most importantly a seperate column for each group a user is a member of.
The problem I am running into is creating a new column for each/every group that a user has. Not all users have the same amount of groups. Some have 10 some have 30 (yes 30, our AD is a mess).
Here is what I have done so far, and the spot that I am having difficulty with is towards the end:
$scoop = get-content C:\temp\SCOOP.txt ##This is a text file with a list of user id's, to search AD with
$outfile = 'C:\temp\SCOOP_ID.csv'
$ou = "OU=Humans,OU=Coupeville,DC=ISLANDS" #This is the searchbase, helps AD isolate the objects
Clear-Content $outfile #I clear content each time when I am testing
Foreach($ID in $scoop){
##AD Search filters##
$filtertype = 'SamAccountName'
$filter1 = $ID
##End AD Search filters##
##AD Search --MY MAIN ISSUE is getting the MemberOF property properly
$properties = get-aduser -SearchBase $ou -Filter {$filtertype -eq $filter1} -Properties Name,Office,Organization,MemberOf | select Name,Office,Organization,MemberOf
##AD Search ## Turns the MemberOf property to a string, I tried this during my testing not sure if objects or strings are easier to work with
#$properties = get-aduser -SearchBase $ou -Filter {$filtertype -eq $filter1} -Properties Name,Office,Organization,MemberOf | select Name,Office,Organization, #{n='MemberOf'; e= { $_.memberof | Out-String}}
#Attempt to specify each property for the output to csv
$name = $properties.Name
$office = $properties.Office
$org = $properties.Organization
$MemberOf = $properties.MemberOf
$membersArray = #()
foreach($mem in $MemberOf){ $membersArray += $mem }
###This is what I typically use to export to a CSV - I am sure there are other maybe better ways but this one I know.
$Focus = [PSCustomObject]#{}
$Focus | Add-Member -MemberType NoteProperty -Name 'Name' -Value $name -Force
$Focus | Add-Member -MemberType NoteProperty -Name 'Office' -Value $office -Force
$Focus | Add-Member -MemberType NoteProperty -Name 'Org' -Value $org -Force
$Focus | Add-Member -MemberType NoteProperty -Name 'Groups' -Value $MemberOf -Force
<########################
#
# Main ISSUE is getting the $memberOf variable, which contains all of the users groups, into seperate columns in the csv. To make it more plain, each column would be labeled 'Groups', then 'Groups1', and so on.
I have tried a few things but not sure if any were done properly or what I am messing up. I tried using $memberof.item($i) with a FOR loop but couldnt figure out how to send each
item out into its own Add-Member property.
#
#######################>
##Final Output of the $Focus Object
$Focus | Export-Csv $outfile -Append -NoTypeInformation
}
I came up with this solution, simply loop $MemberOf and add a unique name.
$MemberOf = #('a','b','c','d','e','f') #example
$Focus = [PSCustomObject]#{}
$Focus | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'test' -Force
$i=0; $MemberOf | % {
$i++
$Focus | Add-Member -MemberType NoteProperty -Name "Group $i" -Value $_ -Force
}
$Focus | Export-Csv xmgtest1.csv -Append -Force -NoTypeInformation
However this doesn't work in your case, since you run this code once per user and there's no "awareness" of the entire set. So you would (in your existing architecture) need to ensure that the largest number of groups is added first.
You can fix this by creating the CSV all at once (only other option would be to constantly load/unload the csv file).
First, add $csv = #() to the top of your file.
Then, after you finish creating $Focus, add it to $csv.
Finally, you may remove -Append.
The slimmed down version looks like this:
$csv = #()
#Foreach($ID in $scoop){ etc..
$MemberOf = #('a','b','c','d','e','f') #example
$Focus = [PSCustomObject]#{}
$Focus | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'test' -Force
#$Focus | Add-Member etc ...
$i=0; $MemberOf | % {
$i++
$Focus | Add-Member -MemberType NoteProperty -Name "Group $i" -Value $_ -Force
}
$csv += $Focus
# } end of Foreach($ID in $scoop)
$csv | Export-Csv xmgtest1.csv -NoTypeInformation
Hope this helps.
Related
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
I'm having some trouble copying data from 1 CSV and pasting it into a template of another one.
The template has specific column names.
and the csv file I have with the data, I'm able to get each column, but I am having trouble pasting it into a the template.
I'm trying to copy the following data from 1 csv to the template and here are the columns
email --> internal_customer_ID
givenname --> first_name
surname --> last_name
mail --> email_address
mobilephone --> mobile_phone_1
officePhone --> landline_phone_1
Here is my current code.
#Clear Screen
CLS
#The path we are working with (use the path where we execute this script from)
$global:path = Split-Path $script:MyInvocation.MyCommand.Path
$DataFile = $path + "\dataFile.csv"
$ExportedFileCSV = $path + "\PopulatedTemplate.csv"
#Export the data file with our user info
Get-ADGroupMember -Identity SomeGroup | Get-ADUser -Properties * | Select-Object -Property GivenName, SurName, Mail, MobilePhone, OfficePhone | Export-Csv -path $DataFile -NoTypeInformation -Force
$dataInput = Import-Csv $DataFile
$dataOutput = Import-Csv $ExportedFileCSV
$dataInput | ForEach-Object {
$newData = $_
$dataOutput |
Add-Member -MemberType NoteProperty -Name "internal_customer_ID" -Value $newData.Mail -PassThru -Force|
Add-Member -MemberType NoteProperty -Name "landline_phone_1" -Value $newData.OfficePhone -PassThru -Force|
Add-Member -MemberType NoteProperty -Name "email_address" -Value $newData.Mail -PassThru -Force|
Add-Member -MemberType NoteProperty -Name "mobile_phone_1" -Value $newData.MobilePhone -PassThru -Force|
Add-Member -MemberType NoteProperty -Name "last_name" -Value $newData.SurName -PassThru -Force|
Add-Member -MemberType NoteProperty -Name "first_name" -Value $newData.GivenName -PassThru -force
} | Export-CSV $ExportedFileCSV
If I can avoid exporting the datafile in the first place and just appending the result from the
Get-ADGroupMember -Identity SomeGroup | Get-ADUser -Properties * | Select-Object -Property GivenName, SurName, Mail, MobilePhone, OfficePhone
Straight to the csv template, that would work for my needs too, I just wasn't sure how to do that.
Your line reading $dataOutput | Add-Member ... is the problem, I think. Add-Member is for adding an attribute to a single object, but $dataOutput at this point is a collection of objects. I think the interpreter thinks you're trying add a member attribute to an object array.
Try creating a new object for each output record, then do an Export-CSV -append onto your output CSV file.
I think something like this should work:
$dataInput | ForEach-Object {
$newData = $_
$newRecordProperties = [ordered]#{
"internal_customer_ID"=$newData.Mail
"landline_phone_1" = $newData.OfficePhone
"email_address" = $newData.Mail
"mobile_phone_1" = $newData.MobilePhone
"last_name" = $newData.SurName
"first_name" = $newData.GivenName
}
$newRecord = new-object psobject -Property $newRecordProperties
Write-Output $newRecord
} | Export-CSV $ExportedFileCSV -Append
As long as the columns names in the output CSV are the same as your new record object, I think it should be okay. I am not sure what happens if the columns in $ExportedFileCSV are in a different order than the $newRecord being exported, so I added [ordered] to the hash table. You may want to test this yourself.
For the second part of your question, pipe-lining the whole thing, something like this is probably what you're after:
Get-ADGroupMember -Identity SomeGroup |
Get-ADUser -Properties * |
Select-Object -Property #(
#{label="internal_customer_ID"; expression={$_.Mail}}
#{label="email_address"; expression={$_.Mail}}
#{label="landline_phone_1"; expression={$_.OfficePhone}}
#{label="first_name"; expression={$_.GivenName}}
#{label="last_name"; expression={$_.SurName}}
#{label="mobile_phone_1"; expression={$_.MobilePhone}}
) |
Export-Csv $ExportedFileCSV -Append
Select-Object above creates a custom object with the attribute name and attribute value matching label and the result of expression. Again, re-order to match the order the CSV columns should be in.
Hi guys im using this command to count Users inside a specific OU
$datum=get-date -Format MM-yyyy
$norm=(get-aduser -SearchBase "OU=Normal,OU=Benutzer und Computer,DC=my,DC=domain" -filter *|where {$_.enabled -eq "True"}).count
$spec=(get-aduser -SearchBase "OU=Special,OU=Benutzer und Computer,DC=my,DC=Domain" -filter *|where {$_.enabled -e "True"}).count
I mail myself the results monthly with Send-MailMessage
Now i want to save the results in a continuous Excel / CSV file. I found some faqs but i cant figure out how to export it the right way.
I would like to add the numbers i get it in 3 different colums automatically.
/ Date / Special / Normal /
Whats the best way to do it?
Here is one way to do it:
[PsCustomObject]#{Date=$datum;Normal=$norm;Special=$spec} |
Export-Csv .\Data.csv -NoTypeInformation -Append
I assumed that by 'continuous' you meant that you were going to write to the same CSV over and over, hence the -Append. Remove that if you want each attempt to over-write any existing data.
You can use a PSCustomObject to achieve it like this -
$datum = get-date -Format MM-yyyy
$norm =(get-aduser -SearchBase "OU=Normal,OU=Benutzer und Computer,DC=my,DC=domain" -filter *|where {$_.enabled -eq "True"}).count
$spec =(get-aduser -SearchBase "OU=Special,OU=Benutzer und Computer,DC=my,DC=Domain" -filter *|where {$_.enabled -e "True"}).count
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "Date" -Value $datum
$obj | Add-Member -MemberType NoteProperty -Name "ADUserNormal" -Value $norm
$obj | Add-Member -MemberType NoteProperty -Name "ADUserSpecial" -Value $spec
$obj | Export-Csv $env:USERPROFILE\Desktop\File.csv -NoTypeInformation
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
I have a small script which retrieves the LastLogonTimestamp and the SAMAccount for all users in a particular OU in AD and converts the timestamp to a date and extracts just the date from the string. That part works fine. I then would like to output that to a CSV so it may be opened in Excel and be perfectly formated into columns and look all pretty.
I have tried ConvertTo-Csv and Export-Csv but have been uncuccessful. The problem is I am new to Powershell. This is my first script and I don't fully understand how this works. My script is probably terribly messy and illogical but it does the job so far.
Please help. Thanks.
$userlist = Get-ADUser -SearchBase "OU=IT,DC=whatever,DC=com,DC=au" -Filter * -Properties * | Select-Object -Property Name,LastLogonTimestamp,SAMAccountName | Sort-Object -Property Name
$userlist | ForEach-Object {
$last = $_.LastLogonTimestamp;
$ADName = $_.SAMAccountName;
$tstamp = w32tm /ntte $last;
if($tstamp.Length -lt "40"){}else
{
$ADDate = [DateTime]::Parse($tstamp.Split('-')[1]).ToString("dd/MM/yyyy")
write-host $ADDate;
write-host $ADName;
}
}
You will have to create objects for each user and pipe those to the Export-CSV cmdlet:
$usersList | %{
# current logic
$user = new-object psobject
$user | add-member -membertype noteproperty -name LastLogon -value $last
$user | add-member -membertype noteproperty -name ADName -value $ADName
$user | add-member -membertype noteproperty -name ADDate -value $ADDate
$user
} | export-csv test.csv -notype
Alternative syntax for populating the object:
$properties = #{"LastLogon" = $last; "ADName" = $ADName; "ADDate" = $ADDate}
$user = new-object psobject -property $properties