I'm writing a script to copy permissions from one directory structure and reapply them to another. I can't simply use icacls \\my\path\* /save file.acl /T
as I need to make a number of tweaks between the save and the restore, for which it's simpler to work with PowerShell's (Get-ACL $path).Access
output.
In doing this I'm trying to map the output of this (i.e. FileSystemRights) to their equivalent icacls permissions; I'll then wrap the comma separated list of permissions in parenthesis to apply via icacls.
[string[]]$rights = $InputObject.FileSystemRights -split '\s*,\s*' # note: FileSystemRights here is just a string rather than having been converted to ENUM, as I've just pulled it straight from CSV
switch ($rights) {
'AppendData' {'AD'}
#'ChangePermissions' {'?'}
#'CreateDirectories' {'?'}
'CreateFiles' {'WD'} # duplicate of WriteData
'Delete' {'DE'} # or D?
'DeleteSubdirectoriesAndFiles' {'DC'}
'ExecuteFile' {'X'}
'FullControl' {'F'}
'ListDirectory' {'RD'} #duplicate of read data
'Modify' {'M'}
'Read' {'R'} # or GR?
'ReadAndExecute' {'RX'}
'ReadAttributes' {'RA'}
'ReadData' {'RD'}
'ReadExtendedAttributes' {'REA'}
'ReadPermissions' {'RC'}
'Synchronize' {'S'}
'TakeOwnership' {'WO'}
#'Traverse' {'?'} # or does this mean to specify the /T option? Not really a permission
'Write' {'W'} # or GW?
'WriteAttributes' {'WA'}
'WriteData' {'WD'}
'WriteExtendedAttributes' {'WEA'}
Default {Write-Warning "Could not find icacls permission for file system right: '$_'"} # Note: This may also occur if we get a numeric value for the rights instead of a comma separated list of enum names. Once I've got the mapping I'll code a fix to handle that scenario too.
}
I'm unsure of the mapping above; in some cases I couldn't work out what the equivalent value would be (e.g. ChangePermissions
, CreateDirectories
, Traverse
) and in others there are multiple possibilities (e.g. should Read
/Write
map to R
/W
or GR
/GW
; or is there no difference)? I've checked documentation and searched the web, but most explanations of these permissions don't go into more detail than giving names for these abbreviations.
When I say I need to make a number of tweaks, I'm exporting permissions from an old file share on an old domain, and importing them to a new domain, so I need to map a number of the accounts from the old domain's user to the SID used in the new domain (we have a SIDHistory, but are aiming to do things cleanly, rather than relying on this long term). There are also some groups in the new domain which are equivalents of groups from the old domain, but have no relationship (i.e they're not migrated from the old domain; though they're serving essentially the same functional purpose. Editing the output of the ICACLS saved info is complex since the structure's quite minimal. It's not impossible, but more fiddly than I feel comfortable with.
The reason I need to map things back from the PS/.Net output to the icacls format is because the target share is on Azure Files (with AADDS enabled); so Set-ACL
doesn't work, whilst icacls
does.
I've created similar logic for the inheritance piece already:
[string[]]$if = $InputObject.InheritanceFlags -split '\s*,\s*'
[string[]]$pf = $InputObject.PropagationFlags -split '\s*,\s*'
switch ($if) {
'ContainerInherit' {'(CI)'}
'ObjectInherit' {'(OI)'}
}
switch ($pf) {
'InheritOnly' {'(IO)'}
'NoPropagateInherit' {'(NP)'}
}
if ($InputObject.IsInherited) {
'(I)'
}
For anyone unfamiliar with PowerShell's switch statement; functionality is able to process each item in an array; hence there being no need for logic to loop through each right in $rights
. More info here.
I just realised there's an easy way to see where FileSystemRights
contains duplicates. The below code identifies these. This solved my issue with Traverse
and CreateDirectories
.
[Enum]::GetNames([System.Security.AccessControl.FileSystemRights]) |
sort |
%{[PSCustomObject]@{
Name = $_
FSR = ([System.Security.AccessControl.FileSystemRights]$_)
}} |
ft -AutoSize
This shows that I can reuse some of the existing values
Name FSR
---- ---
AppendData AppendData
ChangePermissions ChangePermissions
CreateDirectories AppendData <-- i.e. AD
CreateFiles CreateFiles
Delete Delete
DeleteSubdirectoriesAndFiles DeleteSubdirectoriesAndFiles
ExecuteFile ExecuteFile
FullControl FullControl
ListDirectory ReadData <-- i.e. RD
Modify Modify
Read Read
ReadAndExecute ReadAndExecute
ReadAttributes ReadAttributes
ReadData ReadData
ReadExtendedAttributes ReadExtendedAttributes
ReadPermissions ReadPermissions
Synchronize Synchronize
TakeOwnership TakeOwnership
Traverse ExecuteFile <-- i.e. X
Write Write
WriteAttributes WriteAttributes
WriteData CreateFiles <-- i.e. WD
WriteExtendedAttributes WriteExtendedAttributes
Whilst working out how to convert what I'd believe to be invalid numeric values (i.e. thinking they were made up of enum values; though for some reason not resolving when cast [System.Security.AccessControl.FileSystemRights]268435456
) I came across this post, then from that found this one.
Given the info there, and my findings on the duplicate values in my previous update, I've now written the mapping as this:
[string[]]$rights = $InputObject.FileSystemRights -split '\s*,\s*' # note: FileSystemRights here is just a string rather than having been converted to ENUM, as I've just pulled it straight from CSV
switch ($rights) {
'-2147483648' {'GR'}
'268435456' {'GA'}
'536870912' {'GE'}
'1073741824' {'GW'}
'AppendData' {'AD'}
'ChangePermissions' {'WDAC'}
'CreateDirectories' {'AD'} # duplicate of AppendData
'CreateFiles' {'WD'} # duplicate of WriteData
'Delete' {'DE'} # or D?
'DeleteSubdirectoriesAndFiles' {'DC'}
'ExecuteFile' {'X'}
'FullControl' {'F'}
'ListDirectory' {'RD'} # duplicate of read data
'Modify' {'M'}
'Read' {'R'}
'ReadAndExecute' {'RX'}
'ReadAttributes' {'RA'}
'ReadData' {'RD'}
'ReadExtendedAttributes' {'REA'}
'ReadPermissions' {'RC'}
'Synchronize' {'S'}
'TakeOwnership' {'WO'}
'Traverse' {'X'} # duplicate of ExecuteFile
'Write' {'W'}
'WriteAttributes' {'WA'}
'WriteData' {'WD'}
'WriteExtendedAttributes' {'WEA'}
Default {Write-Warning "Could not find icacls permission for file system right: '$_'"} # Note: This may also occur if we get a numeric value for the rights instead of a comma separated list of enum names. Once I've got the mapping I'll code a fix to handle that scenario too.
}
For resolving ChangePermissions to WDAC I just used Get-ACL
and Set-ACL
to assign only the ChangePermissions
access to a unique user on a folder, then used icacls
to query that folder's rights.