Trying to output two variable results from Active Directory to PowerShell and format on one line of a .csv file with each returned variable in separate cells. The input file contains the names of four AD groups. The task is to count the users in each group and return the total number of users.
The goal is to write to the .csv file formatting the output with the ad group name in one cell and the user count in the next cell to the right.
This is a simple script built by starting with reading the file and returning the results to the screen. Attempted to write to the file using Export-Csv with no success. The Add-Content has been the most successful technique.
The following code works part of the way, but the ad group name and the user count is written to the same cell in the .csv file. Earlier attempts wrote the AD group name on a line and the total # of users on the next line.
foreach($object in $groupfile){
$groupName = $object.adgroupname
$groupName = $groupName.Trim()
$users = Get-ADGroupMember -Identity $groupName
$usercount = $users.Count
$groupinfo = ($groupName + " " + $usercount)
# both of the lines below return the information to the screen on on line
Write-Host $groupname, $usercount
Write-Host $groupinfo
# this line returns the information as shown below in the First result
Add-Content -Path $filepath $groupname, $usercount
# this line writes to the file as shown below in the Second result
Add-Content -Path $filepath $groupinfo
}
First result (acceptable for a small number of groups, but a more robust solution is necessary for a larger number of groups.):
ad group name one
357
ad group name two
223
ad group name three
155
ad group name four
71
Second result (both values for the returned variable are in one cell):
ad group name one 357
ad group name two 223
ad group name three 155
ad group name four 71
The goal is to write to the .csv file formatting the output with the ad group name in one cell and the user count in the next cell to the right.
I'm assuming your variable $groupfile is the result of a Import-Csv command.
If I understand the question properly, you could do this:
# loop through the $groupfile rows and collect the results as objects
$result = $groupfile | ForEach-Object {
$groupName = $_.adgroupname.Trim()
[PSCustomObject]#{
'GroupName' = $groupName
'UserCount' = #(Get-ADGroupMember -Identity $groupName).Count
}
}
# display on screen
$result | Format-Table -AutoSize
# export to csv
$result | Export-Csv -Path $filepath -NoTypeInformation -Force
Should output a csv, something like
"GroupName","UserCount"
"ad group name one","357"
"ad group name two","223"
"ad group name three","155"
"ad group name four","71"
Note: the Get-ADGroupMember can return objects of type user, group and computer, so either name the second column ObjectCount of add a Where-Object {$_.objectClass -eq 'user'} clause to the Get-ADGroupMember function to filter only user objects
Hope that helps
Related
I am trying to input a list of users into PowerShell and get a specific security group attached to the user's account. At this current time, I have two pieces - an Excel sheet with multiple pieces of data, and a .txt with just the user's usernames. The script I have currently just inputs the user's usernames from the .txt and gets the security group from their account that matches a specific prefix, however I noticed doing it this way doesn't give any specific order. Even though the users are in a specific order (copied and pasted exactly from the excel document), the actual output doesn't come back well.
So, here's what I'd Like to do now, I just don't know how. I would like to get the content from the Excel document, take all of the usernames and do Get-ADPrincipalGroupMembership like I am now, and then write the security group Back to the line that matches the username. For example, if I looked up the SG for msnow, it would get the SG for msnow and then write the SG back to the row that has msnow, and continues through the list. Instead of just doing an Out-GridView, it would actually write this to the Excel document.
Any help on making this work?
Here is the code I have right now.
Import-Module ActiveDirectory
$Names = Get-Content C:\Temp\Users.txt
$Records = #()
Foreach ($ADUsers in $Names) {
Try {
$SG = Get-ADPrincipalGroupMembership -Identity $ADUsers | Select Name | Where {$_.Name -Like "SG - *"}
$SGName = $SG.Name
}
Catch [ADIdentityNotFoundException] {
$SGName = "User not found"
}
$Records += New-Object PSObject -Property #{"UserName" = $ADUsers;"Security Group" = $SGName}
}
Write-Host "Generating CSV File..."
$Records | Out-GridView
Thank you!
If you save the Excel as CSV, so it will look something like
"UserName","Security Group","InsideInfo"
"bloggsj","","tall guy"
"ftastic","","nothing worth mentioning"
things shouldn't be that hard to do.
$out = 'D:\Test\Updated_usersandgroups.csv'
$csv = Import-Csv -Path 'D:\Test\usersandgroups.csv'
Write-Host "Updating CSV File..."
foreach ($user in $csv) {
try {
$SG = Get-ADPrincipalGroupMembership -Identity $user.UserName -ErrorAction Stop
# if more groups are returned, combine them into a delimited string
# I'm using ', ' here, but you can change that to something else of course
$SGName = ($SG | Where-Object {$_.Name -Like "SG - *"}).Name -join ', '
}
catch [ADIdentityNotFoundException] {
$SGName = "User $($user.UserName) not found"
}
catch {
# something else went wrong?
$SGName = $_.Exception.Message
}
# update the 'Security Group' value
$user.'Security Group' = $SGName
}
Write-Host "Generating updated CSV File..."
$csv | Export-Csv -Path $out -UseCulture -NoTypeInformation
# show output on screen
$csv | Format-Table -AutoSize # or -Wrap if there is a lot of data
# show as GridView (sorts by column)
$csv | Out-GridView
Output in console would then look like
UserName Security Group InsideInfo
-------- -------------- ----------
bloggsj SG - Group1, SG - Group1 tall guy
ftastic SG - Group1 nothing worth mentioning
Note: I don't know what delimiter your Excel uses when saving to CSV file. On my Dutch machine, it uses the semi-colon ;, so if in your case this is not a comma, add the delimiter character as parameter to the Import-Csv cmdlet: -Delimiter ';'
Excel uses whatever is set in your locale as ListSeparator for the delimiter character. In PowerShell you can see what that is by doing (Get-Culture).TextInfo.ListSeparator. On output, the -UseCulture switch will make sure it uses that delimiter so Excel will understand
I have a csv with below eachother multiple job titles so like this:
Job title 1
Job title 2
Job title 3
What I now need is to export the group memberships of the user that has that job title so for example a person with job title 1 has a couple of group memberships. I need those group memberships in a csv. Is it possible to do this automaticly for my whole csv that it does all the job title one by one?
I have this:
Get-ADUser -Filter {title -Like "Medior Functioneel beheerder"} | Get-ADPrincipalGroupMembership | select name
How do I get it so it only does this for one match since we have multiple users with the same job title but I only need it for one user. And how do I export this to an csv preferably on one line. for each job title.
I'd approach it like this:
For each job title:
Retrieve all users with their memberOf values
Select all distinct memberships
Output a custom object with title + list of memberships
Export custom objects to CSV
$csv = #'
Title
Job title 1
Job title 2
Job title 3
'# |ConvertFrom-Csv # you'd use `Import-Csv` here instead
$result = foreach($row in $csv){
# Fetch all relevant users with their `memberOf` attribute value
$Users = Get-ADUser -Filter "title -eq '$($row.Title)'" -Properties memberOf
# Select all distinct memberOf values
$Memberships = $Users.memberOf |Sort -Unique
# Resolve the group names
$GroupNames = ($Memberships |Get-ADGroup).Name
# Output custom object
[pscustomobject]#{
Title = $row.Title
Groups = $GroupNames -join ';'
}
}
# output to CSV
$result |Export-Csv -Path .\output.csv
Here is my scenario,
I wrote a SQL query that extracts user accounts with a null username from our student information system. Lets just assume these are newly enrolled students. I then want to take this list, which has a column of suggested usernames, done by simple concatenation in the SQL query. I want to loop through that csv and check to make sure that username doesn't already exist in AD , if it does, append the next available number to the username.
So in my test environment I have a csv that looks like this. ( I made this up for testing)
StudentID,First,Last,SuggestedUsername
12345,tony,Test,testto
54321,tolly,test,testto
I my test AD environment I already have a student named Tommy Test or Testto, so in this case, my powershell script should tell me Tony Test should be testto1 and Tolly Test should be testto2. Is this making sense?
The meat of my script works, It will read the csv, loop through AD and return testto1 for line 1 of the csv, the problem is it will not read line 2, the script ends
I have been playing around with the arrays in the script but here is what I have so far
Import-module Activedirectory
Add-Pssnapin Quest.ActiveRoles.admanagement
$useraccounts =#()
$useraccounts = import-Csv "Path\Test.csv"
$userbase = Get-QADuser -sizelimit 0 -SearchRoot 'mydomain.com/OU'
foreach ($user in $useraccounts) {
if ($userbase)
{
$userbase = $userbase | Select samaccountname | %{($_ -split "#")[0]}
$UserNumbers = #()
$userbase | % {
if ($_ -Match '\d+')
{
$UserNumbers += $matches[0]
}
}
$MaxUserNumber = ($userNumbers | Measure-Object -max).Maximum
$suggestedUserName = $user+($MaxUserNumber+1)
}
Else
{
$SuggestedUserName = $user
}
}
Write-Host $suggestedUserName
Ok, your loop doesn't appear to be cycling because you aren't using an array of strings as your output, you are just using a string, so it just shows up with the last loop. But if you like my solution that's neither here nor there, because I think I have a better option for you. Just for the sake of simplicity, back up your CSV and then delete the Suggested Name column and run this against that.
$Users = Import-CSV "path\test.csv"
$Users|%{$_|Add-Member UserID ("$($_.last)$($_.first.substring(0,2))")}
$NameConflicts = $Users|group userid|?{$_.count -gt 1}
ForEach($Name in $NameConflicts){
$x=0
if(dsquery user -samid "$($name.name)*"){
$x = Get-ADUser -Filter {samaccountname -like "$($Name.Name)*"}|%{$_.samaccountname -replace "($($Name.name))(\d*)","`$2"}|sort -Descending |select -first 1
}
For($i=if($x -gt 0){0}else{1};$i -lt ($Name.count);$i++){
$Name.Group[$i].UserID = "$($Name.Name)$($i+$x)"
}
}
$Users|group userid|?{$_.count -eq 1}|%{if(dsquery user -samid "$($_.name)"){$_.Group[0].UserID = "$($_.Name)1"}}
$Users|FT -auto
That loads your list, creates potential user names by taking the last name and the first two letters of the first name. Then it groups by that, and finds any of them that have more than one. Then for each of those it checks AD for any existing accounts with names like that, and takes the number off the end of the name, and selects the highest one. Then if it found any already in existence it renames all of the potential user names to append the next available number to the end (if none are found in AD it leaves the first one, and renames the rest of them). Lastly it checks all of the other names, where there is just one user name, and if it is in AD already it adds a 1 to the end of the user id.
This should run faster than your script, because I'm only searching for names that are needed to be checked, and it's filtering at the provider level instead of taking all names, and then filtering through powershell.
I am trying to write a powershell script that will first import from a CSV file. The CSV file will contain the AD employee number attribute, and also the business unit attribute.
The script needs to find the AD user based on employee number attribute from the CSV, then update the business unit attribute for that user also contained in the CSV file. CSV will look like:
0,1
8022651,Sales & Marketing
So far I have been able to lookup the employee number using this:
$EmployeeNumber='8022651'
get-ADUser -Filter {EmployeeNumber -eq $EmployeeNumber}
I know I can use Import-CSV, but don't know how to piece it all together. Any help would be greatly appreciated.
First we need to get the contents of the csv like so
Import-Csv "path to your csv"
If the business unit is located in the Office field we can update it with set-aduser like so
% { set-aduser $_.0 -Office $_.1 }
The % is short for foreach-object, what this essentially does is grab each user one at a time and change the Office field in AD
if we put $_ into a pipeline it will get the previous information passed through so in this case we're grabbing the "0" and "1" headers from the CSV
Once the users Office has been changed it's nice to see each change so we can use write-host like so
write-host "Changed the office of $($_.0) to $($_.1)
Once again we are using $_.0 and $_.1 to get the headings from Import-Csv but because write-host is based on a string we have to put variables into $( ) for them to display correctly.
Put together it is:
Import-Csv "path to your csv" | % {set-ADUser $_.0 -Office $_.1; write-host "Changed the office of $($_.0) to $($_.1)}
This will
Grab the information from your CSV
->then change info in Active Directory for each person based on the 0 and 1 headers
-->then write on the screen who it changed and what to
I hope this made sense, if not let me know in the comments below.
EDIT:
$csv = Import-Csv "path to your csv"
foreach($usr in $csv) {
get-ADUser -Filter {EmployeeNumber -eq $usr.0} | set-ADUser $_ -Office $usr.1
}
EDIT 2:
$csv = Import-Csv "path to your csv"
foreach($usr in $csv) {
$usrToEdit = $usr.0
$editUsr = Get-ADUser -Filter {EmployeeNumber -eq $usrToEdit}
set-aduser -Identity $editUsr.SamAccountName -Office $usr.1
}
I created a CSV with all the group names. The following script reads all the groups names from the "group.csv" and list the group and members.
Script:
Add-PSSnapin Quest.ActiveRoles.ADManagement
$csv = Get-Content "f:\Temp\group.csv"
$result = $csv | foreach-object {
$group=$_
get-qadgroupmember "$_" -sizelimit 0 -indirect | select-object samaccountname,#{n="GroupName";e={$group}}
}
$result | export-csv f:\temp\groupandmem.csv -notypeinformation
There are more than 1000 groups in the "group.csv" with a lot of members in each. The executing of the script stops with a memory problem and nothing is written to the groupandmem.csv because this is done at last.
I have the following questions:
Is is possible to:
- For each group in the "group.csv", list the group from CSV, search the group in the AD, display the members and write the group name and the members to the users groupandmem.csv. Do this for all the groups in the "group.csv".
-The groupandmem.csv is filled as follows:
Row 1 group,member1,members2,members3.......
Row 2 group2,member1,members2 etc.
If you start assigning things to variables then you are preventing powershell from "streaming" the users from one end of the pipe (AD) into the other end (the CSV file.) Instead, structure your pipeline like this:
Get-Content "f:\Temp\group.csv" | foreach-object {
$group = $_ # grab current group name
get-qadgroupmember $group -sizelimit 0 -indirect | `
select-object samaccountname,#{n="GroupName";e={$group}}
} | export-csv f:\temp\groupandmem.csv -notypeinformation
Now there is a true "pipeline" from start to finish: csv | foreach | get | transform | export
Before, you were backing things up by assigning everything into a variable before passing it onto the next command.
Updated: added $group to current capture group name (row)