发布于 

PowerShell 修改文件夹及文件权限

准备

先快速准备一下实验环境,建用户要管理员权限,建议全程管理员权限。

1
2
3
4
# 新建测试的用户、文件夹、文件;
New-LocalUser -Name "tjxwork" -NoPassword
New-Item -Path "D:\TestAcl\tjxwork1\tjxwork2" -ItemType Directory
New-Item -Path "D:\TestAcl\tjxwork1\tjxwork2\tjxwork3.txt" -ItemType File

相关背景信息:

我的计算机名是 XinPC

使用的用户名是 Xin

获取文件夹、文件的权限

1
2
3
4
5
$FolderPath = "D:\TestAcl\tjxwork1\tjxwork2"
$FolderAcl = Get-Acl -Path $FolderPath

$FilePath = "D:\TestAcl\tjxwork1\tjxwork2\tjxwork3.txt"
$FileAcl = Get-Acl -Path $FilePath

查看获取到的权限

直接看就这样,Path 路径、Owner 就是所有者,Access 就是控制条目,但是不够详细。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PS C:\Users\Xin> $FolderAcl | Format-List  

Path : Microsoft.PowerShell.Core\FileSystem::D:\TestAcl\tjxwork1\tjxwork2
Owner : XINPC\None
Group : XINPC\None
Access : BUILTIN\Administrators Allow FullControl
BUILTIN\Administrators Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
NT AUTHORITY\SYSTEM Allow 268435456
NT AUTHORITY\Authenticated Users Allow Modify, Synchronize
NT AUTHORITY\Authenticated Users Allow -536805376
BUILTIN\Users Allow ReadAndExecute, Synchronize
BUILTIN\Users Allow -1610612736
Audit :
......

我们还是直接看详细的权限吧,这个才是这篇文章的重点。

因为列出来的继承权限太多了,所以了这里只挑出了 Administrators 的做演示。

文件夹的详细权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PS C:\Users\Xin> $FolderAcl.Access | Where-Object {$_.IdentityReference -eq "BUILTIN\Administrators"}

FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : None
PropagationFlags : None

FileSystemRights : 268435456
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : InheritOnly

文件的详细权限

1
2
3
4
5
6
7
8
PS C:\Users\Xin> $FileAcl.Access | Where-Object {$_.IdentityReference -eq "BUILTIN\Administrators"}

FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : None
PropagationFlags : None

文件夹和文件的区别

首先说一下重点的区别,

正常情况下,在文件的权限里面 InheritanceFlagsPropagationFlags 这两个项都是 None 的。

因为这两个项是决定继承属性的,文件没有这个选项。所以给文件设权限的时候这两个设 None,或者省略也行。

下面我就只用文件夹 $FolderAcl 的来演示了。

D:\TestAcl\tjxwork1的权限界面

权限属性解释

权限属性作用

为了方便理解我就用资源管理器里文件和文件夹的属性 - 安全里面的字眼来解释了。

FileSystemRights : 权限,可以用逗号分隔,多个权限会自动合并成相当效果的组合权限
AccessControlType : 允许 *Allow\ 拒绝Deny*
IdentityReference : 主体,用户或者组,写成 计算机名 \ 用户、域名 \ 用户、域名 \ 组 之类的
IsInherited : 启用继承 *True\ 禁用继承False,就是父级文件夹传下来的继承权限
InheritanceFlags : 应用于 (继承标志),
None* 不传播任何子容器 / 对象,*ContainerInherit传播到子容器 (目录),ObjectInherit* 传播到子对象 (文件)
PropagationFlags : 应用于 (传播标志),*None* 此文件夹和所有子容器 / 对象,*InheritOnly所有子容器 / 对象,NoPropagateInherit * 此文件夹和第一层子容器 / 对象

FileSystemRights 的参数可以看这里

值 (数值) 作用
AppendData 4 指定将数据追加到文件末尾的权限。
ChangePermissions 262144 更改权限:指定更改与文件或文件夹关联的安全和审核规则的权限。
CreateDirectories 4 创建文件夹 / 附加数据:指定用于创建文件夹的权限。此权限需要 Synchronize 值。
CreateFiles 2 创建文件 / 写入数据:指定创建文件的权限。 此权限需要 Synchronize 值。
Delete 65536 删除:指定删除文件夹或文件的权限。
DeleteSubdirectoriesAndFiles 64 指定删除文件夹和该文件夹中包含的所有文件的权限。
ExecuteFile 32 执行文件:指定运行应用程序文件的权限。
FullControl 2032127 完全控制:指定对文件夹或文件进行完全控制以及修改访问控制和审核规则的权限。 此值表示允许对文件进行任何操作的权限,并且它是此枚举中的所有权限的组合。
ListDirectory 1 列出文件夹 / 读取数据:指定读取目录内容的权限。
Modify 197055 修改:指定读、写、列出文件夹内容、删除文件夹和文件以及运行应用程序文件的权限。 此权限包括 ReadAndExecute 权限、Write 权限和 Delete 权限。
Read 131209 读取:指定以只读方式打开和复制文件夹或文件的权限。 此权限包括 ReadData 权限、ReadExtendedAttributes 权限、ReadAttributes 权限和 ReadPermissions 权限。
ReadAndExecute 131241 读取和执行:指定以只读方式打开和复制文件夹或文件以及运行应用程序文件的权限。 此权限包括 Read 权限和 ExecuteFile 权限。
ReadAttributes 128 读取属性:指定从文件夹或文件打开和复制文件系统特性的权限。 例如,此值指定查看文件创建日期或修改日期的权限。 这不包括读取数据、扩展文件系统属性或访问和审核规则的权限。
ReadData 1 读取数据:指定打开和复制文件或文件夹的权限。 这不包括读取文件系统属性、扩展文件系统属性或访问和审核规则的权限。
ReadExtendedAttributes 8 读取扩展属性:指定从文件夹或文件打开和复制扩展文件系统特性的权限。 例如,此值指定查看作者和内容信息的权限。 这不包括读取数据、文件系统属性或访问和审核规则的权限。
ReadPermissions 131072 读取权限:指定从文件夹或文件打开和复制访问和审核规则的权限。 这不包括读取数据、文件系统特性或扩展文件系统特性的权限。
Synchronize 1048576 指定应用程序是否能够等待文件句柄,以便与 I/O 操作的完成保持同步。 当允许访问时自动设置该值,当拒绝访问时自动排除它。相当于 “ReadAndExecute, Write”
TakeOwnership 524288 指定更改文件夹或文件的所有者的权限。 请注意:资源的所有者对该资源拥有完全权限。
Traverse 32 指定列出文件夹的内容以及运行该文件夹中所包含的应用程序的权限。
Write 278 写入:指定创建文件夹和文件以及向文件添加数据或从文件移除数据的权限。 此权限包括 WriteData 权限、AppendData 权限、WriteExtendedAttributes 权限和 WriteAttributes 权限。
WriteAttributes 256 写入属性:指定打开文件系统特性以及将文件系统特性写入文件夹或文件的权限。 这不包括写入数据、扩展特性以及写入访问和审核规则的功能。
WriteData 2 写入数据:指定打开和写入文件或文件夹的权限。 这不包括打开和写入文件系统特性、扩展文件系统特性或访问和审核规则的权限。
WriteExtendedAttributes 16 写入扩展属性:指定打开文件夹或文件的扩展文件系统特性以及将扩展文件系统特性写入文件夹或文件的权限。 这不包括写入数据、特性或访问和审核规则的功能。

FileSystemRights 枚举 (System.Security.AccessControl) | Microsoft Learn

FileSystemRights 的数字值是什么意思?

FileSystemRights 的真正参数是 32 位的掩码,数字值是转化为十进制的形式,单词形式的参数是为了人类的可读性。(很复杂的权限组合可能只有数字?)

那为什么明明有对应单词的数值也要用数值来表示?兼容性?偷懒?微软的屎山代码?这个我没查到准确的信息。

268435456 : FullControl

-536805376 : Modify, Synchronize

-1610612736 : ReadAndExecute, Synchronize

Windows PowerShell 进阶 (36) Get-Acl 获取的权限是数字是什么意思【超速蜗牛的博客】 (gitee.io)

InheritanceFlags PropagationFlags 的参数组合可以看这里

此图来自[小林野夫](https://www.cnblogs.com/cdaniu/)的博客

此图来自【windows 访问控制】十一、C# 实操 对象 System.Security.AccessControl 命名空间 - 小林野夫 - 博客园 (cnblogs.com)

添加、修改权限

先说一下 ACL 和 ACE 是什么?以及它们的关系?

Get-Acl 这个方法从文件 \ 文件夹获取到包含多条规则的这个对象叫 ACL。

这个对象用.Access 访问看到的,里面单独的一条规则叫 ACE。

ACL 里面往往是包含了多条的 ACE。

ACE: Access Control Entry 访问控制条目
ACL: Access Control List 访问控制列表

ACL 可以有零个或多个 ACE 组成

访问控制条目 - Win32 apps | Microsoft Learn

添加和修改权限的方法

添加修改权限有两个可以用的方法,.AddAccessRule().SetAccessRule()

只看名字的话 .AddAccessRule() 这个是用来加的,.SetAccessRule() 这个是用来改的。

在你没加过相同条目的权限的情况下,两个命令在添加权限的时候用起来没有什么区别。

但是你想加的那条权限已经存在了,你又不知道,你再想加权限的时候.AddAccessRule() 这个方法只能把各个属性的值往大了改,比如权限由只读改成完全控制这种,往小改是不生效的。

这可能会导致错误的权限设置,考虑这两个命令的功能的类似,以及.AddAccessRule() 在已经存在相同的权限规则时的不确定性。

建议大部分情况下,无论是添加还是修改权限都直接使用.SetAccessRule()

创建权限的访问控制条目,添加到访问控制列表

1
2
3
4
5
6
7
8
9
# 假设我的本地计算机名或者加入的域是XinPC,账号或者组是tjxwork,那我应该用的 "XINPC\tjxwork",但为了方便你们直接实验我就直接用 $env:COMPUTERNAME 了,不用改命令也能测试。
$DomainOrComputerName = $env:COMPUTERNAME

# 新建了一条权限规则(ACE),
# "计算机名\tjxwork" 本地的tjxwork用户,"FullControl" 完全控制 ,"ContainerInherit,ObjectInherit", "None" 应用于:此文件夹、子文件夹和文件,"Allow" 允许
$AccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule("$DomainOrComputerName\tjxwork", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")

# 把新建的一条权限规则(ACE)加进从文件获取的ACL对象里面
$FolderAcl.SetAccessRule($AccessRule)

这时候可以看一下 $FolderAcl ,看看权限规则是不是已经添加进去了。

1
2
3
4
5
6
7
8
9
10
PS C:\Users\Xin> $FolderAcl.Access

FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : XINPC\tjxwork
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None

......

可以看到最上面一行已经多了一条作用于 XINPC\tjxwork 的规则了。IsInherited : False 这表示不是继承得来的属性。

访问控制列表应用到文件夹上

确定规则没问题了,就可以应用到文件夹上了

1
2
# 把修改过的ACL设置到文件夹里面,只有到了Set-Acl这一步才会生效,之前随便怎么折腾都没关系。
Set-Acl -Path $FolderPath -AclObject $FolderAcl

再看一下文件夹现在的权限

1
2
3
4
5
6
7
8
9
PS C:\Users\Xin> (Get-Acl -Path $FolderPath).Access

FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : XINPC\tjxwork
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
......

已经正常应用到文件夹上了

删除权限

删除权限的方法

也是有两个方法 .RemoveAccessRule() .PurgeAccessRules()

.RemoveAccessRule() 是用来删除单条的权限的 (ACE),你要需要像添加权限一样,提供具体的参数。

.PurgeAccessRules() 是用来删除某个用户 \ 组的所有权限的。

删除单条权限

1
2
3
4
5
6
7
8
9
# 考虑前面在测试命令的时候,$FolderAcl 可能已经改得乱七八糟了,还是重新获取一次吧

$FolderPath = "D:\TestAcl\tjxwork1\tjxwork2"
$FolderAcl = Get-Acl -Path $FolderPath

$DomainOrComputerName = $env:COMPUTERNAME
$AccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule("$DomainOrComputerName\tjxwork", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")

$FolderAcl.RemoveAccessRule($AccessRule)

看一下效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PS C:\Users\Xin> $FolderAcl | Format-List  

Path : Microsoft.PowerShell.Core\FileSystem::D:\TestAcl\tjxwork1\tjxwork2
Owner : XINPC\Xin
Group : XINPC\None
Access : BUILTIN\Administrators Allow FullControl
BUILTIN\Administrators Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
NT AUTHORITY\SYSTEM Allow 268435456
NT AUTHORITY\Authenticated Users Allow Modify, Synchronize
NT AUTHORITY\Authenticated Users Allow -536805376
BUILTIN\Users Allow ReadAndExecute, Synchronize
BUILTIN\Users Allow -1610612736
......

翻一下发现已经没有 tjxwork 那条权限了

确定没问题的话,记得应用到文件夹

1
Set-Acl -Path $FolderPath -AclObject $FolderAcl

删除特定用户或者组的权限

先快速加两条权限做为测试

1
2
3
4
5
6
7
8
9
10
$FolderPath = "D:\TestAcl\tjxwork1\tjxwork2"
$FolderAcl = Get-Acl -Path $FolderPath

$DomainOrComputerName = $env:COMPUTERNAME

$AccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule("$DomainOrComputerName\tjxwork", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
$FolderAcl.SetAccessRule($AccessRule)

$AccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule("$DomainOrComputerName\tjxwork", "Write", "ContainerInherit,ObjectInherit", "None", "Deny")
$FolderAcl.SetAccessRule($AccessRule)

先看一下权限

1
2
3
4
5
6
7
8
9
10
11
12
PS C:\Users\Xin> $FolderAcl | Format-List 

Path : Microsoft.PowerShell.Core\FileSystem::D:\TestAcl\tjxwork1\tjxwork2
Owner : XINPC\Xin
Group : XINPC\None
Access : XINPC\tjxwork Deny Write
XINPC\tjxwork Allow FullControl
BUILTIN\Administrators Allow FullControl
BUILTIN\Administrators Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
NT AUTHORITY\SYSTEM Allow 268435456
......

可以看到有两条 XINPC\tjxwork 的权限了

假设我们想把 XINPC\tjxwork 的权限全都删除掉

1
2
$Account = New-Object System.Security.Principal.NTAccount("$DomainOrComputerName\tjxwork")
$FolderAcl.PurgeAccessRules($Account)

看一下效果

1
2
3
4
5
6
7
8
9
10
PS C:\Users\Xin> $FolderAcl | Format-List 

Path : Microsoft.PowerShell.Core\FileSystem::D:\TestAcl\tjxwork1\tjxwork2
Owner : XINPC\Xin
Group : XINPC\None
Access : BUILTIN\Administrators Allow FullControl
BUILTIN\Administrators Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
NT AUTHORITY\SYSTEM Allow 268435456
......

可以看到 XINPC\tjxwork 都已经删除掉了

确定没问题的话,记得应用到文件夹

1
Set-Acl -Path $FolderPath -AclObject $FolderAcl

按条件批量删除

你也可以这样删除,更灵活自由一点,这里我要删除所有显式权限,只保留继承权限

1
2
3
4
5
6
7
8
9
10
11
12
13
$FolderPath = "D:\TestAcl\tjxwork1\tjxwork2"
$FolderAcl = Get-Acl -Path $FolderPath

# 获取所有 IsInherited 为 $False 的权限条目,也就是所有不是继承权限的权限
$AceList = $FolderAcl.Access | Where-Object {$_.IsInherited -eq $False}

# 循环删除
foreach ($Ace in $AceList) {
$FolderAcl.RemoveAccessRule($Ace)
}

# 应用到文件夹
Set-Acl -Path $FolderPath -AclObject $FolderAcl

禁用继承 / 启用继承

如果你上面有尝试去删除继承权限发现是删除不了的。

可以用.SetAccessRuleProtection() 来修改 禁用继承 / 启用继承

要传入两个布尔参数,

第一个参数:$true 阻止继承权限 (禁用继承), $false 不阻止继承的权限 (启用继承)

第二个参数:$true $ 保留继承的权限,将其转换为显式权限, $false 不保留继承的权限

阻止继承权限 (禁用继承),不保留已经继承的权限

1
$FolderAcl.SetAccessRuleProtection($true,$false)

阻止继承权限 (禁用继承),保留继承的权限,将其转换为显式权限

1
$FolderAcl.SetAccessRuleProtection($true,$true)

不阻止继承的权限 (启用继承),后面那项 $true,$false 都没影响了。

1
2
$FolderAcl.SetAccessRuleProtection($false,$true)
$FolderAcl.SetAccessRuleProtection($false,$false)

试一下 阻止继承权限 (禁用继承),不保留已经继承的权限

1
2
3
4
5
6
7
8
9
PS C:\Users\Xin> $FolderAcl.SetAccessRuleProtection($true,$false)
PS C:\Users\Xin> $FolderAcl | Format-List

Path : Microsoft.PowerShell.Core\FileSystem::D:\TestAcl\tjxwork1\tjxwork2
Owner : XINPC\Xin
Group : XINPC\None
Access :
Audit :
......

这样继承的权限就全都没有了

只要你没 Set-Acl 都还可以继续加权限上去的,就算 Set-Acl 了,用 Owner 所有者账号权限也还是可以改权限的,不过一般建议还是保留继承的权限可能会好一点,容错率高一点。

确定没问题的话,记得应用到文件夹

1
Set-Acl -Path $FolderPath -AclObject $FolderAcl

参考链接

Windows PowerShell 进阶 (34) How to Manage File System ACLs【超速蜗牛的博客】 (gitee.io)

【windows 访问控制】十一、C# 实操 对象 System.Security.AccessControl 命名空间 - 小林野夫 - 博客园 (cnblogs.com)

使用 PowerShell 更改 NTFS 安全权限・蓝色 42 (blue42.net)

使用 PowerShell 修改 NTFS 权限 - vGemba.net


原文作者:tjxwork
原文链接:https://www.tjxblog.com/blog/2023-0007
发布时间:2023-02-18