I have a script which adds users to Teams from a .csv, but there are likely to be additions/removals which will need to be accounted for in the first weeks after creation.
# Read team users from CSV file
$TeamUsers = Import-CSV "File_Path"
$i = 0
# Group the objects by their TeamDesc property, so we only query each group once
$TeamUsers | Group-Object TeamDesc | ForEach-Object {
# Get the GroupId of this Group
$groupId = (Get-Team -DisplayName $_.Name).GroupId
# If the Group couldn't be found, just skip below logic
if(-not $groupId) { return }
# If the Group could be found, create a hashtable for future splatting
$params = #{ GroupId = $groupId }
# now we can enumerate each object in each group of objects
foreach($user in $_.Group) {
try {
# create a hashtable for splatting progress
$progress = #{
PercentComplete = $i++ / $TeamUsers.Count * 100
Activity = 'Adding Users to MS Teams!!'
Status = 'Working on Team: "{0}" and User: "{1}"' -f $_.Name, $user.UserPrincipleName
}
Write-Progress #progress
# add this user with this role to the hashtable
$params['User'] = $user.UserPrincipleName
$params['Role'] = $user.Role
Add-TeamUser #params
}
catch {
('Error occurred for {0} - {1}' -f $user.TeamName, $user.UserPrincipleName),
$_.ToString() | Write-Warning
}
}
}
Currently, I can add users to the Team by adding their user information to the .csv but I want to be able to remove users if they are not found in the file. I found, in another answer, this selection:
$validUsers = Import-Csv 'C:\path\to\your.csv' | Select-Object -Expand dn
$invalidUsers = Get-ADGroupMember 'groupname' |
Where-Object { $validUsers -notcontains $_.distinguishedName }
Remove-ADGroupMember 'groupname' $invalidUsers -WhatIf
I am unsure of the best way to include this. Where in my current script can I incorporate checking for and removing users NOT found in a .csv from the populated Teams?
Can you please try the below logic:
[array]$teams = "T1","T2","T3"
$users = gc C:\temp\UserList.txt
foreach ($user in $users) {
$user = ($user -split "#")[0] # SamAccountName from UPN
foreach($t in $teams) {
$tMems = Get-AdGroupMember $t |select -exp SamAccountName
if ($tMems -match $user) {
RemoveAdGroupMember $t $user
}
}
}
Related
I have to print the permissions of a user for a specific folder. Below, I have a working code. However it only scans if the user has been specifically given permissions. Now I also want to check, if a group of which the user is a member of, has permissions on the folder.
I thought about listing all groups in which my user is a MemberOf and then add them into a Generic List. Afterwards, I will execute the following code for each entry of this list.
$User = "testumgebung\cbruehwiler"
$Path = "T:\"
# Generic list object to store output in
$List = New-Object System.Collections.Generic.List[System.Object]
# Fields we want in list, an array of calculated properties.
$OutputFields = #(
#{name="Item" ; expression={$_.Path.split(':',3)[-1]}}
#{name="Rights" ; expression={$Right.FileSystemRights}}
#{name="AccessType" ; expression={$Right.AccessControlType}}
# #{name="User" ; expression={$User}}
)
# Store all objects in variable
$FileSystemObjects = Get-ChildItem $Path -Recurse | ForEach-Object {Get-Acl $_.FullName}
# Iterate through every object
foreach ($Item in $FileSystemObjects) {
# Iterate through every individual user right within each object
# Add it to our list if it matchers our $User
foreach ($Right in $Item.Access) {
if ($Right.IdentityReference -eq $User) {
$List.Add(($Item | Select-Object $OutputFields))
}
}
}
$List | Out-File C:\Users\cbruehwiler\Desktop\PermissionCheck.txt
My list prints the folder name, the different permissions and if it has access or not. I don't really want to change the structure too much.
I found a solution.
Import-Module ActiveDirectory
$User = "Testumgebung\cbruehwiler"
$UserOhneDomain = "cbruehwiler"
$Path = "T:\"
$List = New-Object System.Collections.Generic.List[System.Object]
$Groups = Get-ADPrincipalGroupMembership $UserOhneDomain
$GroupArrayList = New-Object System.Collections.ArrayList
foreach ($Group in $Groups)
{
$GroupArrayList.Add($Group.Name) | Out-Null
}
# Fields we want in list, an array of calculated properties.
$OutputFields = #(
#{name="Item" ; expression={$_.Path.split(':',3)[-1]}}
#{name="Rights" ; expression={$Right.FileSystemRights}}
#{name="AccessType" ; expression={$Right.AccessControlType}}
# #{name="User" ; expression={$User}}
)
$FileSystemObjects = Get-ChildItem $Path -Recurse | ForEach-Object {Get-Acl $_.FullName}
foreach ($Item in $FileSystemObjects) {
foreach ($Right in $Item.Access) {
if ($Right.IdentityReference -eq $User)
{
$List.Add(($Item | Select-Object $OutputFields))
}
}
}
foreach ($Item in $FileSystemObjects) {
foreach ($Right in $Item.Access) {
foreach ($GroupArrayItem in $GroupArrayList){
if ($Right.IdentityReference -eq ("TESTUMGEBUNG\" + $GroupArrayItem))
{
$List.Add(($Item | Select-Object $OutputFields))
}
}
}
}
$List | Out-File C:\Users\cbruehwiler\Desktop\PermissionCheck.txt
This Script checks all rights from a user on a file or share including all of the groups the user is a member of.
You just have to enter the user once with the "DOMAIN\username" variant and once with the "username" variant.
Hope this helps
I have listed users in our AD with this:
Get-ADUser -Filter * -Properties department |
Where-Object {$_.department -Like "F0*"} |
Select sAMAccountName, department
It outputs all users of interest.
Now I wanna go through these users and find all of them that are managers of one or several Exchange distribution Groups. And have an output with username and name of distribution Group(s) , is this possible?
As Paxz already commented, you should go 'the other way' on this. If you want to get names and departments of managers of distribution groups, start with getting those first.
Something like this would probably do it:
# get the distribution groups where the ManagedBy property is set
Get-DistributionGroup | Where-Object { $_.ManagedBy } | ForEach-Object {
# then go through all possible listed managers and get their DisplayName and Department
foreach ($id in $_.ManagedBy) {
try {
# use '-ErrorAction Stop' to make sure the catch block is entered upon failure
$manager = Get-AdUser -Identity $id -Properties DisplayName, Department -ErrorAction Stop
$mgrName = $manager.DisplayName
$mgrDept = $manager.Department
}
catch {
# output failed result(s)
$mgrName = 'Obsolete user'
$mgrDept = 'Unknown'
}
# output the result(s) as PSObjects
New-Object -TypeName PSObject -Property #{
'Distribution Group' = $_.Name
'Manager' = $mgrName
'Department' = $mgrDept
}
}
}
If you would like to store the results in a csv file, you can extend the script to something like this:
$fileName = '<Enter the full path and filename here for the output csv file>'
# collect all results in an array
$results = #()
Get-DistributionGroup | Where-Object { $_.ManagedBy } | ForEach-Object {
foreach ($id in $_.ManagedBy) {
try {
# use '-ErrorAction Stop' to make sure the catch block is entered upon failure
$manager = Get-AdUser -Identity $id -Properties DisplayName, Department -ErrorAction Stop
$mgrName = $manager.DisplayName
$mgrDept = $manager.Department
}
catch {
# output failed result(s)
$mgrName = 'Obsolete user'
$mgrDept = 'Unknown'
}
$results += New-Object -TypeName PSObject -Property #{
'Distribution Group' = $_.Name
'Manager' = $mgrName
'Department' = $mgrDept
}
}
$results | Export-Csv -Path $fileName -UseCulture -NoTypeInformation -Force
I have the below working script that checks if a large list of users in a CSV file are a member of an AD group and writes the results to results.csv.
Not sure how to convert the script so I can change $group = "InfraLite" to $group = DC .\List_Of_AD_Groups.CSV.
So the script doesn't just return matches for one AD group but so it returns matches for the 80 AD groups contained in the List_of_AD_groups.csv also. Writing a YES/NO for each AD group in a new column in the CSV (or if that's not possible creating a seperate .csv file for each group with results would do also.
I could do this manually by changing the value of $group and export file name, and re-running the script 80 times but must be a quick was with PS to do this?
e.g. results.csv:
NAME AD_GROUP1 AD_GROUP2 AD_GROUP80 etc etc.
user1 yes no yes
user2 no no yes
user3 no yes no
echo "UserName`InfraLite" >> results.csv
$users = GC .\user_list.csv
$group = "InfraLite"
$members = Get-ADGroupMember -Identity $group -Recursive |
Select -ExpandProperty SAMAccountName
foreach ($user in $users) {
if ($members -contains $user) {
echo "$user $group`tYes" >> results.csv
} else {
echo "$user`tNo" >> results.csv
}
}
I played with this for a while, and I think I found a way to get you exactly what you were after.
I think Ansgar was on the right path, but I couldn't quite get it to do what you were after. He mentioned that he didn't access to an AD environment at the time of writing.
Here is what I came up with:
$UserArray = Get-Content 'C:\Temp\Users.txt'
$GroupArray = Get-Content 'C:\Temp\Groups.txt'
$OutputFile = 'C:\Temp\Something.csv'
# Setting up a hashtable for later use
$UserHash = New-Object -TypeName System.Collections.Hashtable
# Outer loop to add users and membership to UserHash
$UserArray | ForEach-Object{
$UserInfo = Get-ADUser $_ -Properties MemberOf
# Strips the LPAP syntax to just the SAMAccountName of the group
$Memberships = $UserInfo.MemberOf | ForEach-Object{
($_.Split(',')[0]).replace('CN=','')
}
#Adding the User=Membership pair to the Hash
$UserHash.Add($_,$Memberships)
}
# Outer loop to create an object per user
$Results = $UserArray | ForEach-Object{
# First create a simple object
$User = New-Object -TypeName PSCustomObject -Property #{
Name = $_
}
# Dynamically add members to the object, based on the $GroupArray
$GroupArray | ForEach-Object {
#Checking $UserHash to see if group shows up in user's membership list
$UserIsMember = $UserHash.($User.Name) -contains $_
#Adding property to object, and value
$User | Add-Member -MemberType NoteProperty -Name $_ -Value $UserIsMember
}
#Returning the object to the variable
Return $User
}
#Convert the objects to a CSV, then output them
$Results | ConvertTo-CSV -NoTypeInformation | Out-File $OutputFile
Hopefully that all makes sense. I commented as much of it as I could. It would be very simple to convert to using ADSI if you didn't have RSAT installed on whatever machine you're running this on. If you need that let me know, and I'll make some quick modifications.
I've also tossed a slightly modified version of this in a Gist for later reference.
The trivial solution to your problem would be to wrap your existing code in another loop and create an output file for each group:
$groups = Get-Content 'C:\groups.txt'
foreach ($group in $groups) {
$members = Get-ADGroupMember ...
...
}
A more elegant approach would be to create a group mapping template, clone it for each user, and fill the copy with the user's group memberships. Something like this should work:
$template = #{}
Get-Content 'C:\groups.txt' | ForEach-Object {
$template[$_] = $false
}
$groups = #{}
Get-ADGroup -Filter * | ForEach-Object {
$groups[$_.DistinguishedName] = $_.Name
}
Get-ADUser -Filter * -Properties MemberOf | ForEach-Object {
$groupmap = $template.Clone()
$_.MemberOf |
ForEach-Object { $groups[$_] } |
Where-Object { $groupmap.ContainsKey($_) } |
ForEach-Object { $groupmap[$_] = $true }
New-Object -Type PSObject -Property $groupmap
} | Export-Csv 'C:\user_group_mapping.csv' -NoType
I found this script online. It was original designed to get all members of one security group and if there are nested group it will write to the host the nested group name and members in hierarchy form.
I tweaked it to import AD security groups from a CSV file and to export the results to CSV with table format. CSV files has two security group with both security groups has nested groups. Script will only list the users in the second security group and it doesn't list the nested security group.
CSV File format:
Groupname groupad name
test.testdl office\test.testdl test.testdl
test.testsg office\test.testsg test.testsg
Import-Module ActiveDirectory
$GroupList = #{}
$Table = #()
$Record = #{
"Name" = ""
"nested" = ""
"domain" = ""
"userName" =""
}
function Get-GroupHierarchy {
param()
$searchGroups = Import-Csv -Path C:\temp\ad1.csv
foreach ($item in $searchGroups) {
$groupMember = Get-ADGroupMember -Identity $item.Groupname |
Select-Object name, samaccountname, distinguishedName, objectClass
}
}
foreach ($member in $groupMember) {
$username = $member.samaccountname
$distinguishedName = $member.distinguishedName
$dc = [regex]::Match($distinguishedName,'DC=([^,|$]+)').Groups[1].Value
$domainuser = '{0}\{1}' -f $dc, $username
$Record."userName" = $member.samaccountname
$Record."Name" = $member.name
$Record."nested" = $member.objectclass
$Record."Domain" = $domainuser
$objRecord = New-Object PSObject -Property $Record
$Table += [array]$objrecord
if ($member.ObjectClass -eq "group") {
$GroupList.add($member.name, $member.name)
Get-GroupHierarchy $member.name
}
Get-GroupHierarchy
}
$Table | Export-Csv "C:\temp\SecurityGroups01.csv" -NoTypeInformation
Error message:
Get-ADGroupMember : Cannot validate argument on parameter 'Identity'. The
argument is null or empty. Provide an argument that is not null or empty, and
then try the command again.
At line:1 char:48
+ $groupMember = Get-ADGroupMember -Identity $item.name | Select-Object name, ...
+ ~~~~~~~~~~
I Know it has been ages since you asked this question. But i was working last week on something similar and obtained some results through some work. I saw this question here working on that piece of work and thought to share my work if it can help somebody.
$members = Get-ADGroupMember 'GroupName'
foreach ($member in $members){
if ($member.objectClass -eq 'Group')
{$NestGroupUsers = Get-ADGroupMember $member | select name, objectclass }
Else {
$hash = [pscustomobject]#{
'name' = $member.name
'objectclass' = $member.objectClass
}
$hash | Export-Csv C:\users.csv -Append -NoTypeInformation
}
}
$NestGroupUsers |Export-Csv C:\users.csv -Append -NoTypeInformation
I have list of accounts as below in a text file-
AccountName
Mahin\user1
Mahin\user2
Mahin\group5
user12
usert1
groupt3
This way, I have around 400 accounts (mix of various users and some groups),
as you can see from above, some accounts have format as <Domain>\<AccountName>
and some with just <AccountName>.
I was trying to find a way to segregate users and groups from this list,
how can I achieve this using powershell?
Looking for something like
AccountName, IsUser, IsGroup, IsExists
Mahin\user1,1,0,1
Mahin\user2,1,0,1
Mahin\group5,0,1,1
user12,1,0,1
usert1,,,0 //-> This Account DOES NOT EXIST, so, IsUser, IsGroup and IsExists (0) can be empty or some distiguishable number
groupt3,,,0 //-> This Account DOES NOT EXIST, so, IsUser, IsGroup and IsExists (0) can be empty or some distiguishable number
So far, I know how to get members of various groups using below script, but not sure of above part.
$groups = Get-Content "C:\AD\groups.txt"
$resultsarray =#()
foreach ($group in $groups) {
$resultsarray += Get-ADGroupMember -Id $group | select
samaccountname,name,#{Expression={$group};Label="Group Name"}
}
$resultsarray| Export-csv -path "C:\AD\output\GroupMembers.csv" -notypeinformation
Note: Im not very familiar with the Active Directory Cmdlets, there is probably a better solution for this.
However, I would retrieve all users and groups first, then iterate over your text file and try to find any user or group:
$users = Get-ADUser -filter *
$groups = Get-ADGroup -filter *
Get-Content 'YOUR_FILE_PATH'| ForEach-Object {
$adObject = $_ -replace '(.*)\\(.*)', '$2#$1' # fix search string
if ($users | Where { $_.SamAccountName -eq $adObject -or
$_.UserPrincipalName -like "$adObject*"} )
{
[PSCustomObject]#{
AccountName = $_
IsUser = $true
IsGroup = $false
Exist = $true
}
}
elseif ($groups | Where Name -eq $adObject)
{
[PSCustomObject]#{
AccountName = $_
IsUser = $false
IsGroup = $true
Exist = $true
}
}
else
{
[PSCustomObject]#{
AccountName = $_
IsUser = $false
IsGroup = $false
Exist = $false
}
}
} | Export-csv -path "C:\output\GroupMembers.csv" -notypeinformation
On my AD I have to transform Mahin\group5 to group5#Mahin and search for group5#Mahin*, thats why I replace the string within the script.