I am using the powershell code below to get a list of folders and subfolders on a network share. Is it possible to also display the associated security group with it? For instance Select-Object fullname,securitygroup? And if possible also then grab the list of users that are a member of that group? Thank you!
Output would be like:
\Server\Share\Folder1 Folder1-W John Doe....
Get-ChildItem \\Server\Share | Where { $_.PSIsContainer } | Foreach {Get-Childitem $_.FullName}| Where { $_.PSIsContainer } | Select-Object fullname
Rather than filter for folders after you pull the directory listing, why not filter first? It should speed things up considerably. Then you can run the results through a loop to pull security groups with Get-ACL, and get the members with Get-ADGroupMember at that point. Try this on for size...
$Output = #()
$DirList = GCI \\server\share -directory | %{$_.FullName; GCI $_ -Directory|select -expandproperty FullName}
ForEach($Dir in $DirList){
$ACLs=#()
(get-acl $Dir).accesstostring.split("`n")|?{$_ -match "^(.+?admin(istrators|141))\s+?(\w+?)\s+?(.+)$"}|%{
$ACLs+=[PSCUSTOMOBJECT]#{Group=$Matches[1];Type=$Matches[2];Access=$Matches[3]}
}
ForEach($ACL in $ACLs){
if($Members){Remove-Variable Members}
$Members = Get-ADGroupMember $ACL.Group -ErrorAction SilentlyContinue|%{[string]$_.SamAccountName}
$Output += "$Dir $($ACL.Group) $($ACL.Access) $($Members -join ",")"
}
}
Now, your output doesn't seem very realistic considering what all you want, so I made it one line per group for each folder in this format: such as:
\\Server01\ShareA ShareA-R ReadOnly JohnDoe,JaneSmith
\\Server01\ShareA ShareA-W Read,Write JackDaniels,CaptMorgan
\\Server01\ShareB ShareB-R ReadOnly JohnDoe
That just made more sense to me since you wanted groups split out to the user level. I suppose you could list each person on their own line for each share, but your list is going to be really long. Anyway, you should be able to get something that you want with what I gave you.
I assume that by "associated security group" you mean a group used to grant users permissions to access the folder. There's no way for the OS to identify inherently what purposes the groups in the ACL are being used for, so you need to determine some set of consistent criteria that can be used to identify which groups are "associated security groups".
Some examples:
Are the "associated security groups" always the only security principals with permissions? (If so, that makes things simpler; but it's also very unlikely, because you'll generally have at least BUILTIN\Administrators, Domain Admins, NT AUTHORITY\SYSTEM, and CREATOR OWNER.)
Do the groups follow some naming convention that can be derived from the folder names? For example, I've used a naming convention like ACL_ServerName_ShareName_PermissionsCode (e.g. ACL_HQFP01_Shared-Folder1-M). In that scenario, it's always possible to identify the permissions group names given the share and subfolder names.
Are the groups always the only security principals with explicit (i.e. non-inherited) permissions?
I'm going to take a guess that you're following Microsoft's recommended best practices: that you're using NTFS permissions, and you're not assigning explicit permissions to anything other than domain groups designated for that purpose, which would make these "associated security groups" the only security principals with explicit permissions. In that case, you can include a comma-separated list of these groups like this:
| Select-Object FullName, #{Name = 'AssociatedSecuirtyGroups'; Expression = {((Get-Acl $_).Access | ?{! $_.IsInherited} | Select-Object -ExpandProperty IdentityReference) -join ', '}}
You can get the members of the groups by importing the Active Directory module and using Get-ADGroupMember (or there are more complicated ways to query AD without the module), but exactly how depends on which way you want to "grab" them, because if you can have multiple associated security groups for one folder, then you can't do it in a one line per folder display, at least not without making things very messy.
Related
I am looking into recreating the same results as the the Get-NTFSEffectiveAccess cmdlet provided in the NTFSSecurity module. Unfortunately, I need to re-invent the wheel using just PowerShell (as it's the only thing I know).
For the most part, I feel like I'm on the right track with my code:
$Path = "\\MyFile\Share\Path"
$User = 'Abe'
$ADUC = #(Get-ADUser -Identity $User -Properties DisplayName)
$ACL = Get-Acl -Path $Path
$Groups = $ACL.Access.IdentityReference.Where{$_ -notmatch "BUILTIN"} -replace "AREA52\\",""
foreach ($Group in $Groups) {
if ($ADUC.DistinguishedName -in $((Get-ADGroup -Identity $Group -Properties members).members)) {
[array]$ACL.Access.Where{ $_.IdentityReference -match $Group } |
Select-Object -Property #{
Name = 'DisplayName';
Expression = {
$ADUC.DisplayName
}
},#{
Name = 'GroupName';
Expression = {
$Group
}
}, FileSystemRights, AccessControlType
}
else {
#$ADUC.DisplayName + " not in " + $Group
}
}
. . .but, I am stuck. Stuck in regards to the logic should be. So i'm trying to do the following:
Compare the Groups that the user is in, to one another, to determine what actual rights they have.
The biggest issue, is probably this. We manage folder permissions by groups, and do not add the users directly to the folder witch specific rights.
I am also trying to list if the the groups (users) permission is applies to the current folder, or to the sub-directories as well
Just like the output of Get-NTFSEffectiveAccess.
Example:
Account Access Rights Applies to Type IsInherited Group
------- ------------- ---------- ---- ----------- -----
Abraham Read ThisFolderSubfoldersAndFiles Allow False Grp1
Jrose Read ThisFolderSubfoldersAndFiles Allow False Grp1
QUESTION: Is there a certain way I could compare the groups the user is in to one another, and get the Dominant access to that folder; like in windows Effective Permissions function?
Reasons on why I'd like to re-invent the wheel:
Environment I work in is very strict on modules that are installed on computers and unfortunately, the NTFSSecurity module, is not allowed.
Why not? Trying to become more edumecated:)
Been googling and looking at articles all day with one question on Experts Exchange that had a similar question, but. . . i'm not going to pay for that. haha
Would like to mention that this isn't a task, but a problem as I just can't understand the proper logic to go by here to get this done. Mentioned my both goals, but only asked for assistance with one problem as it may come off as unfair.
I need to run a PowerShell script to verify that a huge list of Active Directory groups exist based on an .xlsx file. I would also like to see the owners of the AD groups if possible.
I can run separate scripts, if needed. Please help.
Reading and writing to an excel file from PowerShell is its own adventure, but one that is heavily documented if you google it.
For the query you are asking, its important to know if you have the group's Display Name or the group's SamAccountName. If you have both, you could put an -OR in the filter.
Here is a quick example of how it could work based on a text list.
$list = 'Cross Functional Team
Security Group
Bobs Team' -split([Environment]::NewLine)
$SelectSplat = #{
Property = #{n='Name';E={$_}},
#{N='Found';e={[Bool](Get-adgroup -Filter {DisplayName -eq $_})}},
#{N='ManagedBy';e={Get-adgroup -Filter {DisplayName -eq $_} -Properties ManagedBy | %{(Get-ADUser -Identity $_.ManagedBy).Name}}}
}
$list | Select-Object #SelectSplat
This is my first post within Stackoverflow, I have for many years just read many fantastic questions, answers and other various posts. I have learned a lot a lot from this fantastic community. I hope now that I have taken the brave step to really sink my teeth into powershell and join this community that I may be able to contribute in someway!
So I have started working on a project which at it's basic core level - list all files that are older than 7 years so they can then review and delete where possible.
I have however broken the whole entire script up into several stages. I am currently stuck at a step in stage 2.
I have been stuck for about 2 days on what to many of you powershell genius's out there may only take 10mins to figure out!
I must apologise for my stupidity and lack of knowledge, my experience with powershell scripting is limited to literally 5 working days, I am currently diving in and learning with books, but I also have a job to do so don't get to learn the easy way!
My script essentially has 3 steps;
Runs a Get-ACL of top Level DATA folders to create a listing of all Groups that have permissions on particular folder. I want to then either export this data or simply hold it for the next step.
Filter this gathered information based off a CSV which contains a Column labelled Role (Role will contain a group that the Folder Manager is exclusively in), and check the inherent member of this exlcusive group (maybe this last bit needs to be another step as well?)
Stores or Exports this list of exclusive members with their relevant folder to then later use as a variable for to send an email with a list of files that need to be deleted.
With the script below I am essentially stuck on Step 2 and how to create a filter from the CSV (or stored variables?) and apply it to the GET-ACL foreach loop. I may be going about this the whole wrong way using regex, and to be honest most of this is copy and paste and reading around the internet where people have done similar tasks. SO again I apologise if this is just a dumb way to go about it from the start!
I want to thank everyone in advance for all help, opinions and advice, I will listen to it all and I will try and take on-board as much as my brain can handle - I promise!
#$RoleList = import-csv "C:\DATA\scripts\GB_CMS\CSV\datafolders_rolelist.csv"
#foreach ($Manager in $RoleList) {
#$FolderManager = $RoleList.Role
$FolderManagers = Import-Csv C:\DATA\scripts\GB_CMS\CSV\datafolders_rolelist.csv | foreach {
New-Object PSObject -prop #{
Folder = $_.Folder;
Manager = $_.'Folder Manager';
Role = $_.Role
}
}
$Role = $FolderManagers.Role
$Role
gci "c:\DATA" | Where {$_.PSIsContainer} | get-acl |
ForEach $_.Name {
[regex]$regex="\w:\\\S+"
$path=$regex.match($_.Path).Value
$_ | select -expand access |
$
where {$_.identityreference -like "$Role"} |
Select #{Name="Path";Expression={$Path}},IdentityReference
}
Thanks,
Daniel.
Bit of a guess at what you want here. e.g. if you have folders
C:\Data\Accounts
C:\Data\Marketing
C:\Data\Sales
You might have permissions
C:\Data\Accounts {'FolderManagers-Accounts', 'Accounts', 'Directors'}
C:\Data\Marketing {'FolderManagers-Marketing', 'Marketing', 'Sales'}
C:\Data\Sales {'FolderManagers-Sales', 'Sales', 'Directors'}
and your CSV is
Name, Role, Email
Alice, FolderManagers-Accounts, alice#example.com
Bob, FolderManagers-Marketing, bob#example.com
And there will be a clear mapping of one (1) row in the CSV to one of the groups in the ACLs.
And you want, from your script:
Identify who to email about "C:\Data\Accounts"
How close am I?
# Import the managers. This will turn the CSV into an array of objects
# no need to do that explicitly
$FolderManagers = Import-Csv C:\DATA\scripts\GB_CMS\CSV\datafolders_rolelist.csv
# This will be a hashtable pairing up folder names with people
# e.g. 'C:\DATA\Accounts' -> Alice
$FolderMap = #{}
# Run through all the folders
GetChildItem -Path "C:\Data" -Directory | ForEach-Object {
# Run through the group/user ACL entries on the folder
foreach ($group in (Get-Acl $_.FullName).Access.IdentityReference)
{
# Look for a matching row in the CSV
$CsvRow = $FolderManagers | Where-Object {$_.Role -match $group}
if (-not $CsvRow)
{
Write-Error "No manager found for folder $_"
}
else
{
# Add to the map
# $_ converts to folder path, C:\DATA\Accounts
# $CsvRow is the person, #{Name=Alice, Role=..., Email=...}
$FolderMap[$_.FullName] = $CsvRow
}
}
}
Then it (the FolderMap) will be
Name Value
---- -----
C:\Data\Accounts {Name='Alice';Role=...
C:\Data\Marketing {Name='Bob';Role=...
you can query it with
$person = $FolderMap["c:\data\Accounts"]
$person.email
and if you really want to export it, maybe
$FolderMap | ConvertTo-Json | Set-Content foldermanagers.json
Nb. I wrote most of this off the top of my head, and it probably won't just run. And that's a problem with big, not very specific questions on StackOverflow.
Auto-generated PS help links from my codeblock (if available):
Import-Csv (in module Microsoft.PowerShell.Utility)
ForEach-Object
Get-Acl (in module Microsoft.PowerShell.Security)
Where-Object
Write-Error (in module Microsoft.PowerShell.Utility)
I am looking for a way to use PowerShell to generate a list of account names from Active Directory in a specific OU and then compare that list to another list generated from a network share containing the user's Home Folder that they are connected to on logon.
The purpose of this would be to compare both lists and then DELETE any folder that is NOT present in the list of account names taken from Active Directory.
The OU I will be using is nested as such:
domainname.org | People | Internal | Users
This OU has roughly 25,000 Names (the ID number of each user).
The directory structure is a little more complicated. It's divided into three main directories and each directory has the location name which then contains the Home Folder of the users.
An example would be:
\\user-storage\Users\Division1\LOC1\USERID
Where USERID is the Name listed in the OU.
All of the users in this OU are in the exact same group as well, so if that makes it easier or helps in any way, that is also a way to go.
I'd use a regex match. Pretty sure you can still do that even with 2500 items.
$UserNames = Get-ADUser -Filter * -SearchBase "OU=Users,OU=Internal,OU=People,DC=domainname,DC=ORG" | Select -ExpandProperty samaccountname
$UserRegex = ($UserNames | ForEach{[RegEx]::Escape($_)}) -join "|"
Get-ChildItem -Path "\\user-storage\Users\*\*\*" -Directory | Where{$_.Name -notmatch $UserRegex} | Remove-Item -Force -WhatIf
So that will look at all of the folder 5 levels deep within the \user-storage\users folder, and check it against the list of users. If it's not found it removes it recursively. I put a -WhatIf on it so that you can test it without losing data. -Force makes it delete the folder even if it has things in it still.
I have a directory with a simple ACL:
The Get-Acl . | Format-List command outputs the following
Path : Microsoft.PowerShell.Core\FileSystem::mypath
Owner : BUILTIN\Administrateurs
Group : AD\Utilisateurs du domaine
Access : AD\GL_test_RW Allow Modify, Synchronize
AD\GL_test_RO Allow ReadAndExecute, Synchronize
If I rename the groups GL_test* with the rename-adobject command, and I if re-run Get-Acl, the group names are not updated !
The SID of the groups, however, are correctly translated if I do something like:
$acl.access[0].IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
But if I translate it back to a name, the old group names are returned !
How can I force Get-Acl to return the correct and new group names ?
How long after you made that change did you re-check that ACL? Are you sure this isn't just replication latency between DC's and it will clear up as soon as all the replicas get in sync?
I got the same problem today.
Get-Acl is displaying the "samaccountname" of groups instead of "name".
But other cmdlet such as "Get-AdPrincipalGroupMembership" display the "name" of groups.
I figured that i had some groups with their "samaccountname" different than their "name".
Get-AdGroup -filter * | Where-Object {$_.name -ne $_.samaccountname} | format-table name, samaccountname}
I know this question is 2years old but think my answer can be usefull.
P-S: excuse my poor english...