Reputation: 39
I'm trying to obtain a simple report about Folder Security that I have to use in official documentation that need to be easy and clear for non-technical people.
I have found and adapt some code, but generic access rights are displayed as number so completely not-easy to explain and report
Function Get-Folder($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")|Out-Null
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.Description = "Select a folder"
$foldername.rootfolder = "MyComputer"
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
$IntPath = Get-Folder
$FolderPath = dir -Directory -Path $IntPath -Recurse -Force
$FolderName = Get-Item -Path $IntPath | Select-Object -ExpandProperty Name
$date = Get-Date -UFormat %Y%m%d_%H%M%S
$Report = @()
Foreach ($Folder in $FolderPath) {
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]@{'FolderName'=$Folder.FullName;'AD Group or User'=$Access.IdentityReference;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
$Report | Export-Csv -path $env:USERPROFILE\Desktop\"$FolderName"_"$date".csv
# 268435456 --> FullControl
# -536805376 --> Modify, Synchronize
# -1610612736 --> ReadAndExecute, Synchronize
I would find a solution that will translate in the final CSV the number in the commments.
Upvotes: 2
Views: 800
Reputation: 61028
Changing your code like below works for me (PS version 5.1 of Windows 10 Pro):
function Get-Folder($initialDirectory) {
# [System.Reflection.Assembly]::LoadWithPartialName() is deprecated
Add-Type -AssemblyName System.Windows.Forms
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
$dialog.Description = "Select a folder"
$dialog.rootfolder = "MyComputer"
if($dialog.ShowDialog() -eq "OK") {
$folder += $dialog.SelectedPath
}
$dialog.Dispose()
return $folder
}
$SelectedPath = Get-Folder
$FolderName = Get-Item -Path $SelectedPath | Select-Object -ExpandProperty Name
$FolderPath = Get-ChildItem -Directory -Path $SelectedPath -Recurse -Force
$date = '{0:yyyyMMdd_HHmmss}' -f (Get-Date)
$outputFile = "$env:USERPROFILE\Desktop\$FolderName_$date.csv"
# collect the objects returned
$Report = foreach ($Folder in $FolderPath) {
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access) {
[PSCustomObject]@{
'FolderName' = $Folder.FullName
'AD Group or User' = $Access.IdentityReference
'Permissions' = $Access.FileSystemRights.ToString()
'Inherited' = $Access.IsInherited
}
}
}
# output on screen
$Report | Format-Table -AutoSize
# export to csv file
$Report | Export-Csv -Path $outputFile -NoTypeInformation
If for some reason you still get numeric values instead of strings for the FileSystemRights
, you can use a switch like this to convert the numbers to descriptive strings:
# collect the objects returned
$Report = foreach ($Folder in $FolderPath) {
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access) {
# see https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.filesystemrights
$permissions = switch($Access.FileSystemRights.value__) {
2032127 { 'FullControl '; break}
1179785 { 'Read '; break}
1180063 { 'Read, Write '; break}
1179817 { 'ReadAndExecute '; break}
1245631 { 'ReadAndExecute, Modify, Write '; break}
1180095 { 'ReadAndExecute, Write '; break}
268435456 { 'FullControl (Sub Only) '; break}
-1610612736 { 'ReadAndExecute, Synchronize '; break}
-536805376 { 'Modify, Synchronize '; break}
default { $Access.FileSystemRights.ToString()}
}
[PSCustomObject]@{
'FolderName' = $Folder.FullName
'AD Group or User' = $Access.IdentityReference
'Permissions' = $permissions
'Inherited' = $Access.IsInherited
}
}
}
The above is a listing of the most common file permissions. File objects can have a lot more permission values set in the Access Mask Format flags value.
The System.Security.AccessControl.FileSystemRights
enumeration stores these values, mapping the most common values to human readable words:
Name Value ---- ----- ListDirectory 1 ReadData 1 WriteData 2 CreateFiles 2 CreateDirectories 4 AppendData 4 ReadExtendedAttributes 8 WriteExtendedAttributes 16 Traverse 32 ExecuteFile 32 DeleteSubdirectoriesAndFiles 64 ReadAttributes 128 WriteAttributes 256 Write 278 Delete 65536 ReadPermissions 131072 Read 131209 ReadAndExecute 131241 Modify 197055 ChangePermissions 262144 TakeOwnership 524288 Synchronize 1048576 FullControl 2032127
Looking at the AccessMask in above link, you can encounter values that aren't in this enumeration and in order to translate all of this into words, you could try something like below.
It uses the System.Security.AccessControl.FileSystemRights
enumeration sorted in reverse order by Value
and stored in a variable $FileSystemRights
.
Variable $value
is the numeric value you obtained from $Access.FileSystemRights.value__
.
$PermsList = [System.Collections.Generic.List[string]]::new()
#if ($value -band 0xF1000000) {
# Generic access rights (bits 24..31)
if ($value -band 0x80000000) { [void]$PermsList.AddRange([string[]]('Read', 'ReadAttributes', 'ReadExtendedAttributes', 'Synchronize'))} # GENERIC_READ
if ($value -band 0x40000000) { [void]$PermsList.AddRange([string[]]('Write', 'WriteAttributes', 'WriteExtendedAttributes', 'Synchronize'))} # GENERIC_WRITE
if ($value -band 0x20000000) { [void]$PermsList.AddRange([string[]]('ReadAndExecute', 'ReadAttributes', 'ReadPermissions'))} # GENERIC_EXECUTE
if ($value -band 0x10000000) { [void]$PermsList.Add('FullControl')} # GENERIC_All
if ($value -band 0x1000000) { [void]$PermsList.Add('ChangePermissions')} # Right to access SACL
#}
# Standard access and Object specific rights (bits 0..23)
$value = $value -band 0xFFFFFF
$FileSystemRights | ForEach-Object {
if (($value -band $_.Value)) { [void]$PermsList.Add($_.Name) }
}
($PermsList.ToArray() | Select-Object -Unique) -join ', '
The values you mention in the comment would return:
-2147483648 --> 'Read, ReadAttributes, ReadExtendedAttributes, Synchronize'
-268435456 --> 'Read, ReadAttributes, ReadExtendedAttributes, Synchronize, Write, WriteAttributes, WriteExtendedAttributes, ReadAndExecute, ReadPermissions, FullControl'
-1073741760 --> 'Read, ReadAttributes, ReadExtendedAttributes, Synchronize, Write, WriteAttributes, WriteExtendedAttributes, FullControl, DeleteSubdirectoriesAndFiles'
Hope this explains more about the different file object permissions.
Upvotes: 2