I'm trying to find all folders which do not inherit permissions.
This seems to work, sorta:
DIR "C:\temp" -directory -recurse | GET-ACL | select -ExpandProperty Access | ? -property IsInherited -eq $false
...but it leaves out the actual folder name.
How do I include folder names in the final output? It gets a little tricky for me because I need to filter on a property on an object (Access) within an object (whatever GET-ACL returns).
Any ideas?
Scratch that, I'm an idiot.
DIR "C:\temp" -directory -recurse | GET-ACL | where {$_.Access.IsInherited -eq $false}
I think other answers don't really match your request: the commands suggested give you all non-inherited access rule, but also an inheriting folder may have such rules.
I was looking for a better way to achieve your same goal, but at the moment this is the only way I've found:
Get-ChildItem C:\temp -recurse | Select #{Name='Path';Expression={$_.FullName}},#{Name='InheritedCount';Expression={(Get-Acl $_.FullName | Select -ExpandProperty Access | Where { $_.IsInherited }).Count}} | Where { $_.InheritedCount -eq 0 } | Select Path
The concept is: if a folder has at least 1 inherited access rule, then inheritance is enabled, if it has 0 inherited rules, inheritance is disabled.
All answers still seem like a workaround to me. I found this solution to actually answer the question asked (folders only):
$folders = gci -recurse C:\My\Path\Here
foreach ($path in $folders)
{
if ($path.PSIsContainer -eq $false)
{
continue
}
if ((get-acl $path.fullname).AreAccessRulesProtected -eq $true)
{
$path.fullname
}
}
For the .AreAccessRulesProtected property of the returned get-acl object:
True = inheritance has been disabled
False = inheritance is still enabled
Source for .AreAccessRulesProtected property:
https://petri.com/identify-folders-with-blocked-inheritance-using-powershell
I also confirmed with my own testing that this is the correct property for folder inheritance.
You can use Add-Member to add the path as a property on each ACE object:
dir c:\temp -Directory -Recurse | ForEach-Object {
$Path = $_.FullName
try {
Get-Acl $Path |
select -ExpandProperty Access |
where { $_.IsInherited -eq $false } |
Add-Member -MemberType NoteProperty -Name Path -Value $Path -PassThru
}
catch {
Write-Error $_
}
}
I also wrapped Get-Acl in a try block because it throws terminating errors.
Luca's answer gave me false positives for folders with [ in their names. Not sure why.
Adapted Rohn's script to print how many acls are actually not inherited from the parent. If folder has some out of all - it means the inheritance is enabled but some permissions are added manually, if all out of all - it means the inheritance is disabled.
Write-Output "`nNoninheritable permissions:`n"
dir "E:\Projects" -Directory -Recurse | ForEach-Object {
$Path = $_.FullName
try {
$TotalACLs = (Get-Acl $Path | select -ExpandProperty Access).Count
$InheritedCount = (Get-Acl $Path | select -ExpandProperty Access | where { $_.IsInherited -eq $false } | Add-Member -MemberType NoteProperty -Name Path -Value $Path -PassThru | Select Path).Count
if ($InheritedCount) {
Write-Output $InheritedCount" out of "$TotalACLs" in "$Path
}
}
catch {
Write-Error $_
}
}
The example result:
Noninheritable permissions:
2 out of 7 in E:\Projects\Active Project
2 out of 8 in E:\Projects\Active Projects\Claire\7. CHRISTMAS\
4 out of 4 in E:\Projects\Active Projects\Closed
Projects\Andrea\IT\14.07 Kath - CIMS
Related
I want to remove ALL AD User objects from a directory/folder security.
So, this maybe a stupid post and i appologise if it is...but basically i want to recurse through a directoery and remove all user objects from permissions. Folder permissions should be secured using groups, buit occasionally there are user onjects directly being added to folders breaking the rules. I've got a simple little script that works great for specific users, but i'm having trouble setting this to use a variable, eg all domain user accounts. If i specify the $user variable as an AD search for instance it just doesnt work, eg $USER = 'Get-ADuser -filter * -Server 'DOMAIN -properties SamAccountName | Select SamAccountName
I'm assumign this doesnt like the variable field set this way. Any help or advise much appreciated. Thanks.
$filepath = 'C:\Temp\ACLTesting'
$user = 'DOMAIN\USER'
Get-ChildItem $filePath -Recurse -Directory | ForEach-Object {
$acl = Get-Acl -Path $_.FullName
$acl.Access | Where-Object {
$_.IdentityReference.Value -eq $user
} | ForEach-Object {
$acl.RemoveAccessRule($_) | Out-Null
}
Set-Acl -Path $_.FullName -AclObject $acl
}
Unfortunately still cant get this to work using user variables... am i missing something or is this not a possible function? Thanks....
Putting this to one side for now as still cant get it to work and other things have cropped up to look at. Will revisit this at somepoint though. Any suggestions always welcome. Thanks.
Slightly modifying what you posted, try this …
$filepath = 'C:\Temp\ACLTesting'
$DomainUsers = (Get-ADUser -Filter *).SamAccountName
ForEach ($DomainUser in $DomainUsers)
{
Get-ChildItem $filePath -Recurse -Directory |
ForEach-Object {
$acl = Get-Acl -Path $_.FullName
$acl.Access |
Where-Object {
$_.IdentityReference.Value -eq $DomainUser
} |
ForEach-Object {
$acl.RemoveAccessRule($_) | Out-Null
}
Set-Acl -Path $_.FullName -AclObject $acl
}
}
At work we have a folder with lots of subfolders named like "MeyerS". (Lastname and the first letter of surname)
When I take a look at Get-ChildItem $path | Get-Acl the username equals the subfolder-name. But there is also a "SCHUELER\" in front of "MeyerS". This is what the output looks like a.e.: SCHUELER\MeyerS Allow Write, ReadAndExecute, Synchronize
Some subfolders don't have this kind of username. Now I want to output all these subfolders without this username- "combination".
With my first codesnippet I get all of them, but I really just want these specific ones.
I checked some similar questions, and found something. I modified it, but it shows all subfolders just without SCHUELER\MeyerS. I think I just need a small push to the right way.
The code so far:
$path = "R:\HOME"
$folders = Get-ChildItem $path | where {$_.psiscontainer}
foreach ($folder in $folders){
$domain = "domname"
$aclname = "ACLname"
$aclfullname ="$domain\$aclname"
Get-Acl | select -ExpandProperty Access | where {$_.identityreference -notcontains $aclfullname}
Write-Host $folder.FullName}
Short note: I tried a lot of variations with -noteq or -notlike.
What do I have to change?
If there is already an answer I really didn't know.
Sometimes it's really hard to enunciate yourself in another language. I hope you get my point.
Thanks.
$path = "R:\HOME"
$folders = Get-ChildItem $path | where {$_.psiscontainer}
foreach ($folder in $folders)
{
$domain = "domname"
$aclname = "ACLname"
$aclfullname ="$domain\$aclname"
$FoldersWithAclFullName = $null
$FoldersWithAclFullName = Get-Acl -Path $Folder `
| Select-Object -ExpandProperty Access `
| Where-Object -Property IdentityReference -ne -Value $aclfullname
if ( -not $FoldersWithAclFullName )
{
Write-Host $folder.FullName
}
}
I've check other posts and even following those I can't get this to function.
I'm trying to pull all of the ACL information from a drive but exclude the Windows folder.
This is the code I'm using, but it always tries to include the folder. Can someone tell me why this isn't working?
I've also tried Where-Object.
$containers = Get-ChildItem -Path $Path -Recurse -Exclude $exclude |
? {$_.FullName -notmatch '\\windows\\?'}
Main Code:
function Get-PathPermissions {
param ( [Parameter(Mandatory=$true)] [System.String]${Path} )
begin {
$root = Get-Item $Path
($root | Get-Acl).Access |
Add-Member -MemberType NoteProperty -Name "Path" -Value $($root.fullname).ToString() -PassThru
}
process {
$exclude = #('C:\Windows\*')
$containers = Get-ChildItem -Path $Path -Recurse -Exclude $exclude |
? {$_.psIscontainer -eq $true}
if ($containers -eq $null) {break}
foreach ($container in $containers)
{
(Get-Acl $container.FullName).Access |
? { $_.IsInherited -eq $false } |
Add-Member -MemberType NoteProperty -Name "Path" -Value $($container.fullname).ToString() -PassThru
}
}
}
Get-PathPermissions $args[0]
Filtering with -notmatch '\\windows\\?' should work. I'd use the full path, though, to avoid potential undesired exclusions:
$containers = Get-ChildItem -Path $Path -Recurse |
? { $_.FullName -notmatch '^c:\\windows\\?' -and $_.PSIsContainer}
On PowerShell v3 or newer you can also use the -Directory switch for restricting the results to directories:
$containers = Get-ChildItem -Path $Path -Recurse -Directory |
? { $_.FullName -notmatch '^c:\\windows\\?' }
Couple points about the -Exclude parameter. While it does not explicitly mention it in the documentation it seems to work based on file and directory names.... not the full paths themselves. As a result of that point it does not, in any way, work recursively with directories which I think is your actual conundrum.
Since C:\Windows\* is not a valid directory name that is why it is not filtering anything. Jisaak's suggestion of changing $exclude to just "windows" did work in a sense. If you looked at your output you would have noticed that the actual "c:\windows" folder was missing. What you are actually having a problem with is that exclude does nothing for the sub folders of C:\windows which I will guess is what you intended.
There is another SO post about how -Exclude basically sucks. It can be useful as long as you understand its limitations. Ansgar's answer covers the way around that. It will make sure nothing in the tree of C:\windows ends up in your results.
I need to get a list of all the folders owners on a shared network drive. However, I want to limit the recursion to just 3 folders deep (some of our users will create folders several levels deep, despite us telling them not to). I've found the below script, and slightly modified it to just give folder owner (it originally returned a lot more information for ACLs), but it still goes down through every folder level. How can I modify this to only return 3 folder levels?
$OutFile = "C:\temp\FolderOwner.csv" # indicates where to input your logfile#
$Header = "Folder Path;Owner"
Add-Content -Value $Header -Path $OutFile
$RootPath = "G:\" # which directory/folder you would like to extract the acl permissions#
$Folders = dir $RootPath -recurse | where {$_.psiscontainer -eq $true}
foreach ($Folder in $Folders){
$Owner = (get-acl $Folder.fullname).owner
Foreach ($ACL in $Owner){
$OutInfo = $Folder.Fullname + ";" + $owner
Add-Content -Value $OutInfo -Path $OutFile
}
}
You should be able to add a '*' to your path for each level. For example, this should return items three levels deep under C:\Temp:
dir c:\temp\*\*\*
Here's a sample function you can use (it's written for PowerShell v3 or higher, but it can be modified to work for version 2):
function Get-FolderOwner {
param(
[string] $Path = "."
)
Get-ChildItem $Path -Directory | ForEach-Object {
# Get-Acl throws terminating errors, so we need to wrap it in
# a ForEach-Object block; included -ErrorAction Stop out of habit
try {
$Owner = $_ | Get-Acl -ErrorAction Stop | select -exp Owner
}
catch {
$Owner = "Error: {0}" -f $_.Exception.Message
}
[PSCustomObject] #{
Path = $_.FullName
Owner = $Owner
}
}
}
Then you could use it like this:
Get-FolderOwner c:\temp\*\*\* | Export-Csv C:\temp\FolderOwner.csv
If you're after all items up to and including 3 levels deep, you can modify the function like this:
function Get-FolderOwner {
param(
[string] $Path = ".",
[int] $RecurseDepth = 1
)
$RecurseDepth--
Get-ChildItem $Path -Directory | ForEach-Object {
# Get-Acl throws terminating errors, so we need to wrap it in
# a ForEach-Object block; included -ErrorAction Stop out of habit
try {
$Owner = $_ | Get-Acl -ErrorAction Stop | select -exp Owner
}
catch {
$Owner = "Error: {0}" -f $_.Exception.Message
}
[PSCustomObject] #{
Path = $_.FullName
Owner = $Owner
}
if ($RecurseDepth -gt 0) {
Get-FolderOwner -Path $_.FullName -RecurseDepth $RecurseDepth
}
}
}
And use it like this:
Get-FolderOwner c:\temp -RecurseDepth 3 | Export-Csv C:\temp\FolderOwner.csv
Any help?
resolve-path $RootPath\*\* |
where { (Get-Item $_).PSIsContainer } -PipelineVariable Path |
Get-Acl |
Select #{l='Folder';e={$Path}},Owner
I have the following snippet of code from a script, used in order to get the NTFS permissions on file shares.
if ($ComputerName -eq '.'){
$Path = $Folder
}
else {
$Path = "\\$ComputerName\$Folder"
}ls
if ($OutputFile){
Get-Childitem $Path -Recurse:$Recurse | ForEach-Object {Get-Acl $_.FullName} | Select-Object #{Name="Path";Expression={$_.PSPath.Substring($_.PSPath.IndexOf(":")+2) }},#{Name="Type";Expression={$_.GetType()}},Owner -ExpandProperty Access | Export-CSV $OutputFile -NoTypeInformation
}
else{
Get-Childitem $Path -Recurse:$Recurse | ForEach-Object {Get-Acl $_.FullName} | Select-Object #{Name="Path";Expression={$_.PSPath.Substring($_.PSPath.IndexOf(":")+2) }},#{Name="Type";Expression={$_.GetType()}},Owner -ExpandProperty Access | Format-Table -AutoSize
}
At the moment when I run this I am able to generate a report on the NTFS permissions, however I would like to make the code recurse one extra folder deeper in a file share. My problem however is I only know of methods to completely recurse through all folders or get the current folders in a path.
For example assume I had a folder called 'test' and inside of test there were two other folders called 'temp1' and 'temp2', with there being one more folder inside of temp2 called 'extra.' I'd want it to get the NTFS permissions for 'test' and then go one level farther and report permissions for 'temp1' and 'temp2,' but I would not want it to get 'extra.'
EDIT:
if ($OutputFile){
gci c:\|%{if($_.PSIsContainer){GCI $_.FullName|get-acl};$_|get-acl}|Select-Object #{Name="Path";Expression={$_.PSPath.Substring($_.PSPath.IndexOf(":")+2) }},#{Name="Type";Expression={$_.GetType()}},Owner -ExpandProperty Access | sort PSParentPath|Export-CSV $OutputFile -NoType
}
You can manually recurse 1 level easily enough. Try this on for size:
if ($ComputerName -eq '.'){
$Path = $Folder
}
else {
$Path = "\\$ComputerName\$Folder"
}ls
if ($OutputFile){
gci c:\|%{if($_.PSIsContainer){GCI $_.FullName|get-acl};$_|get-acl}|sort PSParentPath|Export-CSV $OutputFile -NoType
}
else{
gci c:\|%{if($_.PSIsContainer){GCI $_.FullName|get-acl};$_|get-acl}|sort PSParentPath|FT -Auto
}
Something like this will go down to a depth of one folder
Get-Childitem $path | %{get-childitem -path $_.fullname}