好吧,让我们从头开始!很好,您实际上声明了一个参数。您可能需要考虑的是为参数设置默认值。我要做的是使用当前目录,它方便地有一个自动变量
$PWD
(我认为这是PowerShell工作目录的缩写)。
Param([string]$filePath = $PWD)
现在,如果提供了路径,它将使用该路径,但如果没有提供路径,它只使用当前文件夹作为默认值。
版本检查正常。我很确定有更优雅的方法可以做到这一点,但老实说,我从来没有做过任何版本检查。
现在,您正在查询找到的每个组和用户的AD(经过一些筛选后,已授予)。我建议我们跟踪小组和成员,这样我们只需为每个小组查询一次AD。它可能不会节省很多时间,但如果任何组被多次使用,它会节省一些时间。为此,我们将创建一个空哈希表来跟踪组及其成员。
$ADGroups = @{}
现在开始了一个糟糕的趋势。。。写入文件,然后将这些文件读回。输出到文件、保存配置或在当前PowerShell会话之外需要的其他操作都可以,但写入文件只是为了将其读回当前会话只是一种浪费。相反,您应该将结果保存到变量中,或者直接使用它们。因此,与其获取文件夹列表,不如将其直接导入
Get-Acl
,失去了我们要做的
ForEach
循环文件夹。请注意,我添加了
-Directory
切换,使其仅查看文件夹并忽略文件。这发生在提供者级别,因此您将从
Get-ChildItem
这边
ForEach($Folder in (Get-ChildItem $filePath -Recurse -Directory)){
现在,您想输出文件夹的路径和一行。这很容易,因为我们没有放弃文件夹对象:
$Folder.FullName
'-'*$Folder.FullName.Length
接下来,我们将获取当前文件夹的ACL:
$ACLs = Get-Acl -Path $Folder.FullName
这就是事情变得复杂的地方。我从ACL中获取了组名,但我将您的
Where
语句,并且还添加了一个检查,以查看它是否是允许规则(因为在其中包含拒绝规则只会让人困惑)。我用过
?
这是的别名
哪里
以及
%
这是的别名
ForEach-Object
。你可以在管道后安装一个自然的管路制动器,所以我这样做是为了便于阅读。我在每一行都对我正在做的事情进行了评论,但如果有任何让人困惑的地方,请告诉我你需要澄清什么。
$Groups = $ACLs.Access | #Expand the Access property
?{ $_.IsInherited -eq $false -and $_.AccessControlType -eq 'Allow' -and $_.IdentityReference -notmatch 'BUILTIN|NT AUTHORITY|CREATOR|-----|Identity'} | #Only instances that allow access, are not inherited, and aren't a local group or special case
%{$_.IdentityReference -replace 'JAC.*?\\'} | #Expand the IdentityReference property, and replace anything that starts with JAC all the way to the first backslash (likely domain name trimming)
Select -Unique #Select only unique values
现在,我们将遍历这些组,首先输出组名和一行。
ForEach ($Group in $Groups){
$Group
'-'*$Group.Length
对于每个组,我将检查哈希表上的键列表,看看我们是否已经知道其中的成员。如果在那里找不到组,我们将查询AD并将组添加为键,将成员添加为关联值。
If($ADGroups.Keys -notcontains $Group){
$Members = Get-ADGroupMember $Group -Recursive -ErrorAction Ignore | % Name
$ADGroups.Add($Group,$Members)
}
现在我们已经确定了组成员,我们将显示它们。
$ADGroups[$Group]
我们可以关闭
ForEach公司
与组相关的循环,由于这是当前文件夹循环的结束,我们将在输出中添加一个空行,并关闭该循环
}
"`n"
}
所以我写了这个,然后在我的C:\temp文件夹中运行它。它确实告诉我需要清理该文件夹,但更重要的是,它告诉我大多数文件夹都没有任何非继承权限,因此它只会给我一个带下划线的路径,一个空行,然后移动到下一个文件夹,这样我就有了很多类似的内容:
C:\Temp\FolderA
---------------
C:\Temp\FolderB
---------------
C:\Temp\FolderC
---------------
这对我来说似乎没什么用处。如果是给你的,那么就用我上面的句子。我个人选择获取ACL,检查组,然后如果没有组,则移动到下一个文件夹。以下是其结果。
Param([string]$filePath = $PWD)
$Version=$PSVersionTable.PSVersion
if ($Version.Major -lt 3) {Throw "Powershell version out of date. Please update powershell." }
#Create an empty hashtable to track groups
$ADGroups = @{}
#Get a recursive list of folders and loop through them
ForEach($Folder in (Get-ChildItem $filePath -Recurse -Directory)){
# Get ACLs for the folder
$ACLs = Get-Acl -Path $Folder.FullName
#Do a bunch of filtering to just get AD groups
$Groups = $ACLs |
% Access | #Expand the Access property
where { $_.IsInherited -eq $false -and $_.AccessControlType -eq 'Allow' -and $_.IdentityReference -notmatch 'BUILTIN|NT AUTHORITY|CREATOR|-----|Identity'} | #Only instances that allow access, are not inherited, and aren't a local group or special case
%{$_.IdentityReference -replace 'JAC.*?\\'} | #Expand the IdentityReference property, and replace anything that starts with JAC all the way to the first backslash (likely domain name trimming)
Select -Unique #Select only unique values
#If there are no groups to display for this folder move to the next folder
If($Groups.Count -eq 0){Continue}
#Display Folder Path
$Folder.FullName
#Put a dashed line under the folder path (using the length of the folder path for the length of the line, just to look nice)
'-'*$Folder.FullName.Length
#Loop through each group and display its name and users
ForEach ($Group in $Groups){
#Display the group name
$Group
#Add a line under the group name
'-'*$Group.Length
#Check if we already have this group, and if not get the group from AD
If($ADGroups.Keys -notcontains $Group){
$Members = Get-ADGroupMember $Group -Recursive -ErrorAction Ignore | % Name
$ADGroups.Add($Group,$Members)
}
#Display the group members
$ADGroups[$Group]
}
#output a blank line, for some seperation between folders
"`n"
}