共用方式為


Windows PowerShellShell 权限

Don Jones

下载这篇文章的代码: PowerShell2008_02.exe (151KB)

在讨论 Windows PowerShell 时,最常见的问题就是有关权限的问题,特别是外壳程序是否会自动更改权限以及如何更改。尽管目录和注册表权限也会经常出现,但文件权限可能是最常提及的问题。当涉及权限和几乎

所有命令行或脚本界面(包括 Windows PowerShellTM 和 VBScript)的问题时,我这里既有好消息,也有坏消息。

坏消息是在 Windows® 中,权限天生就很复杂,Windows PowerShell 在这方面的能力也非常有限。这个问题的根源在于在 Windows 操作系统中,出现权限问题时都会涉及多个对象,无论是在文件系统、Active Directory®、注册表还是任何其他位置,情况都是如此。

首先是资源本身,例如,目录对象、文件或文件夹。接下来是附加到资源的“访问控制列表”(ACL) 对象。ACL 由一个或多个“访问控制项”对象即 ACE 对象组成。ACE 本质上是将安全主体(用户或组,同时也是另一种对象)与权限(如读取或完全控制)和允许或拒绝状态联系在一起的一个对象。所以至少包括五种对象:资源、ACL、ACE、主体以及权限。

每种类型的资源对应的权限类型也各不相同,这就使得权限问题变得更为复杂。例如,目录对象包含管理访问单个对象属性的复杂权限。比较而言,文件权限要相对简单一些。

而且从技术来说,当涉及到审核时,复杂性将成倍增加。每个资源实际上有两个 ACL。第一个是“自由访问控制列表”(DACL),它负责管理对资源的访问。第二个是“安全访问控制列表”(SACL),它负责控制对资源的审核。操作这些权限意味着需要处理一大堆相当复杂的编程对象,而只有类似 Windows PowerShell 这样的外壳程序可以简化这个复杂的过程。

受限于 .NET Framework

尚未得到足够信息?

要获得更多 Windows PowerShell 资源,包括提供搜索功能的 cmdlet 库以及 Don Jones 和其他 Windows PowerShell 专家的联系方式,请访问 www.PowerShellCommunity.org

Windows PowerShell 的特性使问题变得更为复杂。Windows PowerShell 是在 Microsoft® .NET Framework 的基础上构建的,它使用 .NET Framework 的基础类来表示和处理权限。这些 .NET Framework 基础类旨在为软件开发人员提供更加精细准确的权限控制。当然,“精细准确”含义甚广,而且通常意味着“非常复杂”。

此外,.NET Framework 并没有在每种 Windows 资源类型中都提供代表其权限的类。例如,虽然 .NET Framework 提供了操作文件安全性的类,但它却未提供操作共享文件夹安全性的类。由此可知,Windows PowerShell 并不能操作每种类型的 Windows 资源的权限。简单地说,Windows PowerShell 的功能受限于 .NET Framework 所提供的能力。

外壳程序中的权限

Windows PowerShell 中的权限管理由两个 cmdlet 派生而来:Get-ACL 和 Set-ACL。如您所料,Get-ACL 从资源中检索 ACL。然后您就可以根据需要修改 ACL 并使用 Set-ACL 将其写回到资源中。这两个 cmdlet 都是通用 cmdlet,而且都依赖于 PSDrive 提供程序的 Windows PowerShell 系统。因此从理论上说,只要 PSDrive 提供程序具备理解给定资源类型的能力和修改此类资源权限的能力,那么这两个 ACL cmdlet 就可以操作任何类型的资源。Windows PowerShell 中包含的 FileSystem 和 Registry PSDrive 提供程序支持通过这两个 ACL cmdlet 进行权限管理。(其他 PSDrive 提供程序可能不支持。)

图 1 所示的示例脚本能够指定开始目录、安全主体和权限。然后,脚本会将为该主体指定的权限应用到指定目录中的所有文件和文件夹。该脚本还将对子目录执行递归操作。

Figure 1 将主体权限应用到目录中的文件和文件夹

#ChangeACL.ps1
$Right="FullControl"

#The possible values for Rights are 
# ListDirectory, ReadData, WriteData 
# CreateFiles, CreateDirectories, AppendData 
# ReadExtendedAttributes, WriteExtendedAttributes, Traverse
# ExecuteFile, DeleteSubdirectoriesAndFiles, ReadAttributes 
# WriteAttributes, Write, Delete 
# ReadPermissions, Read, ReadAndExecute 
# Modify, ChangePermissions, TakeOwnership
# Synchronize, FullControl

$StartingDir=Read-Host "What directory do you want to start at?"
$Principal=Read-Host "What security principal do you want to grant" `
"$Right to? `n Use format domain\username or domain\group"

#define a new access rule.
#note that the $rule line has been artificially broken for print purposes.
#it needs to be one line. the online version of the script is properly
#formatted.
$rule=new-object System.Security.AccessControl.FileSystemAccessRule
($Principal,$Right,"Allow")

foreach ($file in $(Get-ChildItem $StartingDir -recurse)) {
  $acl=get-acl $file.FullName
 
  #Add this access rule to the ACL
  $acl.SetAccessRule($rule)
  
  #Write the changes to the object
  set-acl $File.Fullname $acl
  }

该脚本的实质在于它在变量 $rule 中定义了新的访问规则。为此,我将使用一个“原始”的 .NET Framework 类,它可能是 Windows PowerShell 权限管理中最复杂的部分。该脚本随后使用 Get-ACL 依次检索每个文件和文件夹中的 ACL、使用 ACL 的 SetAccessRule 方法应用新规则,并使用 Set-ACL 将修改后的 ACL 写回到资源中。

实际上,尽管包含许多类似从 ACL 删除 ACE 这样相对复杂的操作,但脚本并不复杂。依我所见,使脚本看上去比较复杂的原因是它包含了太多的步骤:获取 ACL、定义规则、修改 ACL 及写入 ACL。单独一条命令无法一次完成所有任务。并且由于我希望修改多个文件中的 ACL,所以不得不将所有内容都放在一个 foreach 循环中,而使用 Get-ChildItem 来实际访问所有的文件和文件夹。

我将采用最简单的方式

本月 Cmdlet:Get-QADUser

如果您打算管理 Active Directory,那么这个 cmdlet 是必备工具。它没有内置在 Windows PowerShell 中,但它作为 Quest Software 软件中 ActiveRoles Management Shell for Active Directory (www.quest.com/activeroles-server/arms.aspx) 的一部分提供了免费下载。

安装了该管理单元后,您就可以使用 Get-QADUser 从目录中检索用户对象。当然,只要直接运行该 cmdlet 就可以返回所有用户,但这对大多数管理任务来说帮助并不大。但是 cmdlet 允许您指定筛选条件,在域控制器上应用这些条件就可以只将您所关注的用户返回给 Windows PowerShell。使用这种技术比先获得所有用户然后再使用 Where-Object cmdlet 进行筛选要快得多。例如,Get-QADUser -l Redmond 只返回属性“l”包含“Redmond”的用户。(顺便说一下,属性“l”代表位置,在 GUI 中是城市列表。)您可以通过管道将这些用户传入其他 cmdlet 以生成 HTML 报告、将其分配给某个组甚至可以直接将其删除。

我认为我举的这个例子并不复杂,但我知道许多管理员喜欢用更为简便的方法来处理权限。也许他们希望一次性从一组文件夹中删除特定的用户组,而不希望编写类似图 1 中所示的多步骤脚本。

幸运的是,Windows PowerShell 确实提供了一种处理权限的简单方法,而且您可能已经很熟悉这种方法了。

Windows PowerShell 不会让您放弃既有的可靠处理方法。您仍然可以使用为简化处理不同类型的权限而专门设计的各种命令行工具,如 Dsacls.exe、Cacls.exe 和 Xcacls.exe。虽然其语法与 Windows PowerShell cmdlet 所使用的标准化语法完全不同,但这些命令行实用工具不需要继续在命令行模式下使用与原来在 cmd.exe 解释器中类似的特定方法运行。您可以使用 Windows PowerShell 来自动化这些实用工具。

我曾遇到过一些人(我称其为“纯粹主义者”),他们坚持认为在 Windows PowerShell 中使用老式命令行实用工具是不合适的。我不太赞同他们的逻辑。我的目的就是完成工作,如果最简单的途径是使用一个 10 年前的命令行实用工具,那我肯定会使用。我可不会仅仅为了显得“更纯粹”而多花时间试图以特定的方法完成工作。Microsoft Windows PowerShell 团队也持有类似的观点。如果现有的工具能够完成工作,Windows PowerShell 就允许您在外壳程序中运行该工具。何必要从头开始呢?

图 2 显示了一小段摘自我写的《Windows PowerShell:**TFM》(SAPIEN Press, 2006) 中的脚本,它使用 Windows PowerShell 来自动执行 Cacls.exe。此脚本只是一段演示代码,如果您希望使其成为真正的自动化工具,那还需要进行调整。但它确实演示了 Windows PowerShell 脚本收集信息并用其启动 Cacls.exe 的过程,就好像 Cacls.exe 是一个原生 Windows PowerShell 命令一样。(尽管此脚本通过提示用户输入来收集信息,但它也可以从文件或数据库中读取参数。)

Figure 2 自动执行 Cacls.exe

#SetPermsWithCACLS.ps1
# CACLS rights are usually
# F = FullControl
# C = Change
# R = Readonly
# W = Write

$StartingDir=Read-Host "What directory do you want to start at?"
$Right=Read-Host "What CACLS right do you want to grant? Valid choices are F, C, R or W"
Switch ($Right) {
  "F" {$Null}
  "C" {$Null}
  "R" {$Null}
  "W" {$Null}
  default {
    Write-Host -foregroundcolor "Red" `
    `n $Right.ToUpper() " is an invalid choice. Please Try again."`n
    exit
  }
}

$Principal=Read-Host "What security principal do you want to grant?" `
"CACLS right"$Right.ToUpper()"to?" `n `
"Use format domain\username or domain\group"

$Verify=Read-Host `n "You are about to change permissions on all" `
"files starting at"$StartingDir.ToUpper() `n "for security"`
"principal"$Principal.ToUpper() `
"with new right of"$Right.ToUpper()"."`n `
"Do you want to continue? [Y,N]"

if ($Verify -eq "Y") {

 foreach ($file in $(Get-ChildItem $StartingDir -recurse)) {
  #display filename and old permissions
  write-Host -foregroundcolor Yellow $file.FullName
  #uncomment if you want to see old permissions
  #CACLS $file.FullName
  
  #ADD new permission with CACLS
  CACLS $file.FullName /E /P "${Principal}:${Right}" >$NULL
  
  #display new permissions
  Write-Host -foregroundcolor Green "New Permissions"
  CACLS $file.FullName
 }
}

已经了解了权限问题?

听说曾有人争论过 Windows PowerShell 在处理权限问题方面存在缺陷,因为它没有提供能够对权限进行简单、通用管理的原生 cmdlet。我不同意这种说法。首先,这种说法通常来自具有很深的 UNIX 背景的管理员,而且事实上 Windows 权限系统要远比 UNIX 使用的复杂。正是由于系统的复杂性使得 Windows PowerShell 也变得很复杂。但这并不是 Windows PowerShell 的问题。

另外,Windows PowerShell 实际上允许您利用已有的优秀命令行实用工具来使用一些简化的工具,正如我在文中展示的那样。确实,.NET Framework 需要加以扩展才可以对整个 Windows 平台进行更全面的权限管理。但总的说来,Windows PowerShell 能够为您提供两方面的便利:简化的权限管理和对精细而准确的管理工具的访问。

Don Jones 是《TechNet 杂志》**的特约编辑,并且是《Windows PowerShell:**TFM》(SAPIEN Press, 2007) 的合著者。他主要讲授 Windows PowerShell(请参阅 www.ScriptingTraining.com),可通过 www.ScriptingAnswers.com 网站与其联系。

© 2008 Microsoft Corporation 与 CMP Media, LLC.保留所有权利;不得对全文或部分内容进行复制.