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.
Related
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
Over the course of time, our organization has gone through some profile name changs (i.e. when a person marries) and there has not been a standard of also renaming the user's home directory. So we have users like MarySmith whose directories are like C:\USERS\MaryJones. No problem thus far, but now we would like to clean these up to avoid confusion. (MarySmith / MaryJones used here are for illustrative purposes only.) We are beginning to go through some security measures and elimination of this "confusion" plays a part in the process.
So our first step, was to identify the cases where this has taken place. On the Domain Controllers, we issued a PowerShell command like this, for an initial Proof of Concept:
get-ADUser MarySmith -properties * | Export-CSV -path C:\SOME\PATH.csv
What we found was that there is no mention there of the MaryJones folder at all. There is a HomeDirectory property, but it's empty.
Digging a little further, in Active Directory Users and Computers (ADUC) when we pull up properties for the user, we also don't see a difference for Profile Path, Login script, Home Folder ... all empty. And yet when the user (MarySmith) logs in, the NTUSER.DAT file in C:\USERS\MaryJones gets updated.
Who can help us understand how to retrieve the correct information, and maybe along the way how Windows keeps track of the fact that those names are associated? I'm convinced if we could retrieve this association we could eliminate some problems.
Thanks,
Dennis
Thanks to the suggestions of #Lee_Daily and #Thomas in the comments on the question, we've come up with a workable solution (there are a few that would not translate (caught nicely by the Try/Catch - looking into that - will update answer when understood).
UPDATE The ones that would not translate, were due to NTUSER.DAT files remaining on the system after their associated users had been removed from the directory. ***
Here are the relevant pieces of the script that we came up with:
$FOLDERS = Get-ChildItem -Path "C:\users\"
ForEach ($FOLDER in $FOLDERS) {
$NTUSER = $FOLDER.FullName + "\NTUSER.DAT"
if (Test-Path $NTUSER) { # Profile file exists
$SID = (Get-CimInstance -ClassName Win32_UserProfile | Where-Object {$_.LocalPath -like $FOLDER.FullName}).sid
$USEROBJ = New-Object System.Security.Principal.SecurityIdentifier($SID)
if ($USEROBJ -ne $NULL) {
try {
$USERNAME = $USEROBJ.Translate( [System.Security.Principal.NTAccount]).Value
}
catch [exception] {
$USERNAME = $NULL
}
}
if ($USERNAME -eq $Null) {
Write-Host "Couldn't resolve user for $SID $FOLDER "
}
else {
#Here we have a valid NTUSER path, and a profile name.
#Now we can make miracles happen.
A-Miracle-Happens($FOLDER.FullName, $USERNAME)
}
}
}
Thanks, Guys.
I need to recreate hundreds of distribution groups in a new (O365) environment. I’ve no access to the source system other than to work with their techs to provide them scripts that they’ll run for me.
I wrote a script to spit out the names of all the lists that my users are members of (security and distribution). I’d like to write another to cycle through each distribution group and provide me with details of that group. I don’t see how to do that.
I see that Set-DistributionGroup will happily let me set the AcceptMessagesOnlyFromDLMembers (and a million other fields) but I don’t see that Get_DistributionGroup will output those values for me. How do I do this to ensure I’m not recreating an open group for HR that should have been MemberJoinRestriction enabled (for example)?
Thanks in advance.
Okay so I'm not a PowerShell guy (obvs.), but here's what I wrote that works. I'm sure I'm not taking advantage of PowerShell at all here, so wanna suggest how I could improve? Like why did I have to use $temp? Quicker to check the array first before I Get-ADGroup again? etc.
# Start with a user list, get the groups eash is a part of, get information about the group
# if it is mail-enabled then add it to an array, remove duplicates, then store all the
# information about that DistributionGroup into a .csv
$groups = #()
ForEach ($user in $(Get-Content c:\Users\sid.sowder\Desktop\CEGusers.txt)) {
$MyGroups = Get-ADuser $user -Properties * | select memberof -ExpandProperty memberof
ForEach ($MyGroup in $MyGroups) {
$temp = Get-ADGroup $MyGroup -Properties *
if ($temp.mail -ne $null) {
$groups += $temp.SamAccountName
}
}
}
$groups = $groups | sort -unique
Foreach ($group in $groups) {
Get-DistributionGroup -Identity $group |
Select * |
Export-CSV C:\Users\Sid.Sowder\Desktop\distlistdetail.csv -NoTypeInformation -Append
}
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 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.