Is there a way to export the variable in a ForEach loop to my CSV output on each line - powershell

I am attempting to run a script against our AD that spits out the AD Users in a group, for all the groups in a list. Essentially attempting to audit the groups to find the users. I have a functioning script, except I have no way to determine when the output of one group ends, and where the output of the next begins.
I have tried looking for previous examples, but nothing fits exactly the method I am using, and with me just dipping my toes into powershell I have not been able to combine other examples with my own.
$groups = Get-Content "C:\Folder\File_with_lines_of_ADGroup_Names.txt"
foreach ($group in $groups) { Get-ADGroupMember -Identity "$group" | Where-Object { $_.ObjectClass -eq "user" } | Get-ADUser -Property Description,DisplayName | Select Name,DisplayName,Description,$group | Export-csv -append -force -path "C:\Folder\File_of_outputs.csv" -NoTypeInformation }
Right now the problem lies with getting the $group variable to be exported along with the Name, DisplayName, and Description of each user returned. This is the best way I can think of to tag each user's group and keep all the results in a single file. However, only the first line of results works which is the HEADERS of the CSV, and everything after it is either listed as "Microsoft.ActiveDirectory.Management.ADPropertyValueCollection"or simply blank after the first group of results.
Hoping someone can show me how to easily add my variable $group to the output for each user found for filtering/pivoting purposes.
Thanks and let me know if you have questions.

I believe what you are after are calculated properties on your select statement.
Select Name,DisplayName,Description,$group
Should Probably be something like
Select Name,DisplayName,Description,#{n='Group'; e={$group};}
See also https://serverfault.com/questions/890559/powershell-calculated-properties-for-multiple-values

Related

How do I pass a parameter down the pipeline to a function that doesn't accept pipeline input?

I've got a text file that contains a list of user identities. I want to pass each member on that list to Get-csMeetingMigrationStatus and get back UserPrincipalName, Status and LastMessage. From there I want to output to gridview as an eyes on test for migration status.
I'd like to do this in one pipeline but can't work it out. I know that Get-csMeetingMigrationStatus does not take pipeline input for its parameter -identity so I have to use another means of passing that parameter to the function. I've done things like this before and am wondering if the fact that the list of users is an import from a text file rather than an array created from scratch is the cause.
I needed to get this working asap so thought I'd just put it all in a foreach loop as below. I know the example below doesn't give me all I want regards output but even the sample below fails.
$UserDetails = Get-Content -path c:\test.txt
foreach ($ud in $UserDetails) {
Get-csMeetingMigrationStatus -identity $ud | Select-Object Userprincipalname, status, lastmessage
}
When I run the above the return for the first identity is the property headers for my connect-microsoftteams connection.
Subsequent iterations return a blank line. For each iteration of the foreach loop, if I copy and paste the command in the foreach statement into the terminal window and run it, the correct information for each user is displayed. I don't understand how that can be.
Ultimately I'd like to push all this down a single pipeline and output to gridview.
If anyone can assist with either problem above I'd appreciate it as I've tried sorting this for a good number of hours now and can't find a solution.
Thanks
Use the ForEach-Object cmdlet:
Get-Content -path c:\test.txt |ForEach-Object {
Get-CsMeetingMigrationStatus -identity $_ | Select-Object Userprincipalname, status, lastmessage
} |Out-GridView
Nesting the pipeline inside ForEach-Object means that we can supply another downstream cmdlet (in this case Out-GridView) with whatever output is produced by it (unlike with the foreach(){} loop statement)

Creating PowerShell Script templates for easy group management

First of all thanks for the help to the other users, because of that I learned a lot.
I have a problem that there are lots of user templates in my company (Lots of different group settings depending operation). Because of that I want to make it easy for my colleges to assign user to Operations.
I think about a solution that My colleges enter the user and Group to a CSV file, then the script goes trough the CSV lines, detects the Operation, and go to the operations TXT file to get the group info, then add the user.
The files are:
UserAndOperation.csv and it includes 2 columns, first one is user second one is Operation
Then the TXT files are added, in them the Groups are added for every line (I also wanted to make only one Operation csv that first column is operation name and the second one is groups that has to be added, and separated by "," but that scared my eye :D ).
this is the Frankenstein code that I created:
Import-Csv ".\UserAndOperation.csv" | ForEach-Object {get-aduser $_.User | if($_.Operation = "Operation1"){
$Groups = Get-Content .\operation1.txt
foreach($group in $groups)
{Add-ADPrincipalGroupMembership -Identity $_.User -MemberOf $Group}
}
elseif ($_.Operaiton = "Operation2"){
$Groups = Get-Content .\operation2.txt
foreach($group in $groups)
{Add-ADPrincipalGroupMembership -Identity $_.User -MemberOf $Group}
}
And goes for each operation
}
It gives an error that it don't recognize the if and elseif statements.
I don't know how to proceed, could anyone help me with fixing it ?
Thanks and best Regards.
You can't pipe results into an if statement.
e.g.
get-aduser $_.User | if($_.Operation
You also have a typo in:
$_.Operaiton
I would suggest to clean up the code a bit by trying to put statements one per line, so as to not confuse yourself, outputting debug statements, etc..
As has already been pointed out, you can't shove arbitrary control flow statements like if into the middle of a pipeline statement.
Beyond that, your intended if/else approach will mean a lot of repeated code, making the script harder to maintain.
You could use a hashtable (#{}) to "map" the operation name to the relevant file name, this way you only need to write the loop to add the group memberships once:
# map the Operation column value to the relevant file path
$operations = #{
'Operation1' = 'path\to\operation1.txt'
'Operation2' = 'path\to\operation2.txt'
'Operation3' = 'path\to\operation3.txt'
}
Import-Csv ".\UserAndOperation.csv" | ForEach-Object {
$User = Get-ADUser $_.User
$Groups = Get-Content $operations[$_.Operation]
foreach($Group in $Groups){
Add-ADPrincipalGroupMembership -Identity $User -MemberOf $Group
}
}

Powershell pipeline objects from import-csv headaches

We have a big audit coming up, and we want to be sure that all termed employees' AD computer accounts have been deactivated. I have a .csv that has a unique identifier that we use - our schema includes that ID in the middle of the ADcomputer Name property. I am having enormous trouble correctly piping the imported csv objects and their property to the filter. I think. I'm not entirely sure. This is something like what I've been trying.
Import-Csv termname.csv | ForEach-Object
{ Get-ADComputer -Filter { Name -Contains "$($_.id)" } } |
Export-Csv termcomp.csv -NoTypeInformation
This "script" pulled a total of no content, while I KNOW that when I test
Get-ADComputer -Filter { Name -Contains $id }
where $id is that unique ID, I get hits on AD Computer objects. Likewise, testing this block
Import-Csv termname.csv | ForEach-Object { Get-ADComputer { Name -Contains $_.id }
PowerShell's error is:
..."Property 'id' not found in object of type: 'System.Management.Automation.PSCustomObject'.
I think that I am misapprehending what precisely is an "object" in this case. Is the whole imported array an object, with a property of .id? Or is each row its own object, with a .id property? And, either way, why has PowerShell such strong objections to a pipeline object, which is, after all, its primary job?
Is there an entirely better way to go about this whole process? Am I somehow overthinking the whole mess?
UPDATE
As requested, sample contents of the csv file. Taking the suggestion to use wildcards instead, I've put the wildcards into the .csv itself, which, again, may not be the most elegant solution. But as long as it works! Here's the sample, copied from Notepad++
id
*rstarr56*
*jlennon58*
*pmcartney74*
*gharrison68*
So it looks like your CSV file does not have an "ID" heading in it, causing that not to be an available property, easy fix there is to confirm the contents of the CSV file, if everything looks correct try running Import-Csv termname.csv | ForEach-Object { Write-Host $_.id } to confirm that the property is coming across correctly. However you will also have trouble using -Contains here as that operator is meant to check if an array contains a particular value, you'll need to use Name -Like "*$($_.id)*"
After hours of digging, I found an answer here:
Import-CSV and Foreach to use Get-ADUser
Thanks especially to Mike for some great thinking about -Like and how to test the success of the code.
The line that ended up working was:
Import-Csv termname.csv | ForEach-Object {
Get-ADComputer -Filter "Name -Like '*$($_.id)*'"
} | Export-Csv termout.csv
Apparently, Powershell hates {{}}.
Thanks again, all!

Powershell Query AD to export emails of all users in .txt file?

I would like to write a PS script that exports a .csv for all users that are specified in a separate .txt file. So, for instance, I could create a text file that has
Timmy Turner
Silly Sally
Then, when the script is ran, it searches AD for those two users and exports a CSV with their first name, last name, and email address.
I originally got hung up a bit on how the "Get-ADUser" filter worked, but I produced something semi-usable. However, what I've come up with just asks who you are searching for and then uses that. I think it would be much easier to just have it reference a pre-made text file, especially when searching for a large number of users. Or, there may be an even easier way to do this that I am not thinking of. Here is what I currently have:
$SamAc = Read-Host 'What is the first and last name of the person you would like to search for?'
$filter = "sAmAccountname -eq ""$SamAc"""
Get-ADUser -Filter $filter -Properties FirstName, LastName, EmailAddress | select FirstName, LastName, EmailAddress | Export-CSV "C:\Scripts\PS_ADQuery\Email_Addresses.csv"
I feel like the "Get-Content" cmdlet is close to what I am looking for, but I can't seem to get it to function correctly. I may be going in the totally wrong direction, though.
I found the answer. It turns out I even had the AD properties totally wrong. Take my comments with a grain of salt since I may not fully understand the processes behind each line of code, but this does exactly what I was looking to do.
#creates a $users variable for each username listed in the users.txt file. the ForEach
#command allows you to loop through each item in the users.txt array. the scriptblock
#nested into the ForEach command queries each username for specific properties.
$users = ForEach ($user in $(Get-Content C:\Scripts\PS_ADQuery\users.txt)) {
Get-AdUser $user -Properties GivenName,sn,mail
}
#takes the $users variable defined by the ForEach command and exports listed properties
#to a csv format.
$users |
Select-Object GivenName,sn,mail |
Export-CSV -Path C:\Scripts\PS_ADQuery\output.csv -NoTypeInformation

Import Member Group attribute from AD to .csv

I am using ActiveRoles Management Shell under Windows XP , Powershell ver 2 for retreiving Group data from AD and exporting it to csv file.Everything works well apart from getting member list it is so long that the program is writing in excel cells under member column System.String[] each time.How can I make it write whole list there , is it possible ? I could actually have only the name of the member don't need whole connection path.Is there a possibility to get from group field member only name ?
get-QADGroup -SearchRoot 'ou=User,ou=Groups,ou=PL,dc=test,dc=com'| Select-Object -property name,sAMAccountName,description,groupType,member|Export-Csv -path Y:\csv\groups.csv
Ok, as Matt suggested you want an expression in your Select statement. I would use something like this:
#{l="Members";e={$_.Members -join ", "}}
Which when inserted into your one-liner looks like:
get-QADGroup -SearchRoot 'ou=User,ou=Groups,ou=PL,dc=test,dc=com'| Select-Object -property name,sAMAccountName,description,groupType,#{l='Members';e={$_.member -join ", "}}|Export-Csv -path Y:\csv\groups.csv -NoTypeInfo
I also added -NoTypeInfo to the export to skip the annoying lead line telling you it's a PSCustomObject or some such and actually just get your data (and headers).
I don't have access to the quest cmdlets so I will provide a solution based on cmdlets from the activedirectory
Get-ADUser -Filter * -SearchBase "OU=Employees,DC=Domain,DC=Local" -Properties memberof |
Select-Object name,#{Name="Groups";Expression={$_.MemberOf |
ForEach-Object{(Get-ADGroup -Identity $_).Name + ";"}}} |
Export-Csv C:\temp\TEST.CSV -Append
To make sense of this by line:
Should be self explanatory. Get all users in the OU defined. You would need to change this to suit your needs.
The select statement appears normal until you reach the calculated property Groups.
What continues from the previous line is cycling through every group that an individual user is a memberof and get the friendly name of the group (MemberOf returns DistinguishedName's). At the end of every group add a ";" as to not interfere with the CSV that will be made later.
Append to a csv file.
For brevity I didnt include all the extra properties that you included in your Select-Object statement. You would obviously need to add those back as the need fits.
Since you have the use the Quest cmdlets you could just change member in your select statement to the following:
#{Name="Groups";Expression={$_.member | ForEach-Object{"$_;"}}}
I cannot test if this will work. It is based on the assumption that member contains a simple name as supposed to a distinguishedname