下午好,Stack Overflow。
我正在尝试使用Powershell自动化一些基于纸张的流程。我们已经有了一个Powershell解决方案,其输出是Excel电子表格,但为了规划未来,我们认为CSV输出比Excel更容易使用。
我们正在做的非常基本,我们正在接触AD中的组的所有者,在文本文件中指定。对于列出的每个组,我们循环并将项添加到表中。这是问题所在,我对Powershell来说还是一个新手,并且我正在彻底解决“for each”语句中出现的问题。
我遇到以下错误:
Exception calling "Add" with "1" argument(s): "This row already belongs to this table."
At line:77 char:17
+ $table2.Rows.Add <<<< ($row2)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
我觉得分享我正在使用的代码是合适的:
import-module activedirectory
$strGroupList = get-content "C:\Users\MYUSERNAME\Documents\Group Audit\audit.txt"
$strDate = Get-Date
foreach ($strGroup in $strGroupList)
{
$strGroupMember = Get-aduser -Identity $Group -property description
$tabName = "GroupAuditTable"
#Create the Table Object
$table = New-Object system.Data.DataTable "$tabName"
$table2 = New-Object system.Data.DataTable "$tabName2"
#define columns for row 1
$col1 = New-Object system.Data.DataColumn $strGroup,([string])
$col2 = New-Object system.Data.DataColumn $strDate,([string])
#define columns for row 2
$col3 = New-Object system.Data.DataColumn Name,([string])
$col4 = New-Object system.Data.DataColumn Description, ([string])
$col5 = New-Object system.Data.DataColumn NetworkID, ([string])
$col6 = New-Object system.Data.DataColumn Nested, ([string])
#Add the columns to row 1
$table.columns.add($col1)
$table.columns.add($col2)
#Add the columns to row 2
$table2.columns.add($col3)
$table2.columns.add($col4)
$table2.columns.add($col5)
$table2.columns.add($col6)
#create a row
$row = $table.NewRow()
$row2 = $table2.NewRow()
#create an additional row for the titles of columns
$rowTitles = $table.NewRow()
$rowTitles2 = $table2.NewRow()
$strGroupDetails = Get-ADGroupMember -identity $strGroup
foreach ($Group in $strGroupDetails)
{
########################################################################## Check for nested groups
if($Group.ObjectClass -eq "group")
{
$strGroupDetails = Get-ADGroupMember -identity $Group #-Recursive
$strNestedGroupName = $Group.name
########################################################################## List members of nested groups
foreach($strNestedGroup in $strGroupDetails)
{
#$strNestedGroupName = $Group.name
$strGroupMember = Get-aduser -Identity $StrNestedGroup -property description
$row2.Name = $strGroupMember.name
$row2.Description = $strGroupMember.description
$row2.NetworkID = $strGroupMember.SamAccountName
$row2.Nested = "(From NESTED GROUP: " + $strNestedGroupName
$table2.Rows.Add($row2)
}
}
else
{
#enter data into row 2
$row2.Name = $strGroupMember.name
$row2.Description = $strGroupMember.description
$row2.NetworkID = $strGroupMember.SamAccountName
$row2.Nested = "Not Nested"
#Add the row to the table
$table.Rows.Add($row)
#Add the row to the second table
$table2.Rows.Add($row2)
#Display the table
$table | format-table -AutoSize
$table2 | format-table -AutoSize
}
}
}
$tabCsv = $table | export-csv C:\Users\MYUSERNAME\Desktop\Audit\GroupAudit.csv -noType
$tabCsv2 = $table2 | export-csv C:\Users\MYUSERNAME\Desktop\Audit\GroupAudit_2.csv -noType
就是这样,非常基本的东西。
错误在第77行:
$table2.Rows.Add($row2)
在我把'嵌套组'放在那里的每个循环之前,这是有效的,我很困惑为什么会破坏它,除非我在这里遗漏了一些明显的东西。当我删除它:
foreach ($Group in $strGroupDetails)
{
########################################################################## Check for nested groups
if($Group.ObjectClass -eq "group")
{
$strGroupDetails = Get-ADGroupMember -identity $Group #-Recursive
$strNestedGroupName = $Group.name
########################################################################## List members of nested groups
foreach($strNestedGroup in $strGroupDetails)
{
#$strNestedGroupName = $Group.name
$strGroupMember = Get-aduser -Identity $StrNestedGroup -property description
$row2.Name = $strGroupMember.name
$row2.Description = $strGroupMember.description
$row2.NetworkID = $strGroupMember.SamAccountName
$row2.Nested = "(From NESTED GROUP: " + $strNestedGroupName
$table2.Rows.Add($row2)
}
}
else
{
#enter data into row 2
事情按预期工作,我缺少什么?
答案 0 :(得分:2)
您正在运行ForEach,第一件事是一个If子句,您在其中定义$ strGroupMember,您在Else子句中引用相同的If / Then。在这里,这是简化的:
IF($Group.ObjectClass -eq "group"){
<do stuff>
$strGroupMember = get-aduser $strnestedgroup <more parameters>
$row2.stuff = $strgroupmember.stuff
}
Else{
$row2.stuff = $strgroupmember.stuff
}
但是你根本没有在else scriptblock中定义$ strgroupmember。所以它然后添加最后一个组中的最后一个,并且它已经有了该条目,因此它会抛出错误。
使用虚假数据....组是管理员,它包含1个组(“Payroll”,其中包含1个成员,“John”)和2个用户(“Jim”和“Sally”)。
ForEach($Item in get-adgroupmember "Administrators"){
if($Item.ObjectClass -eq "group"){ #Payroll is a group, it gets processed here
ForEach($User in $Item){
$Userdata = Get-ADUser $User #Returns Jim's AD info
$Row2.name = $Userdata.name
$Row2.description = $Userdata.description
$Table2.add($Row2) #Adds John to the table
}
}
Else{ #if not a group, process root users here, should process Jim and Sally
$Row2.Name = $Userdata.name #$Userdata still contains John's info
$Row2.Description = $Userdata.Description #$Userdata still contains John's info
$Table2.add($Row2) #attempts to add John to the table again
}
希望一切都有意义。或者至少足够你看到问题了。修复?在你的Else scriptblock中添加一行:
$strGroupMember = Get-aduser -Identity $Group -property description
编辑:我创建一个数组,创建用户对象并将它们添加到数组中,然后遍历嵌套组并将该组添加到它应用的每个用户对象,然后推送将这些数据放入表中,这样你最终得到的结果如下:
Name Description NetworkID Nested
John John Smith JSmith Payroll,HR
Mark Mark Jones MJones Not Nested
Mary Mary Anderston MAnderson HR
但那就是我。
编辑2:好的,第2轮!我看到了变化,但仍然存在一些问题。您遇到的问题是向表中添加行。好的,可以理解的。这是我看到的一些问题:
foreach($strNestedGroup in $strGroupDetails)
{
#$strNestedGroupName = $Group.name
$strGroupMember = Get-aduser -Identity $StrNestedGroup -property description
$row2.Nested = "(From NESTED GROUP: " + $strNestedGroupName
$table2.Rows.Add($row2)
}
好的,对于嵌套组中的每个项目,查询AD并将结果存储在$strGroupMember
中。然后将$row2.nested
更新为当前组的名称,并将$row2
作为新行添加到表中。所以,让我们说我们进入这个循环,$row2
就是这样:
$row2.Name = "John Smith"
$row2.Description = "Director of HR"
$row2.NetworkID = "JSmith"
$row2.Nested = "Not Nested"
好的,它循环遍历为嵌套组“Power Users”提取的条目。我们将简化并假设没有嵌套在这个嵌套组中的其他组,这是另一个问题。
该名单上的第1项是Marcia Winkle,她有“Payroll”的AD描述,以及MWinkle的用户名。循环找到并将所有信息分配给$strGroupMember
。
接下来它更新$row2
,并替换Nested
值,将“Not Nested”替换为“From nested group:Power Users”(我们正在使用的组)。
然后它将$row2
添加到$table2
,创建一行:
Name Description NetworkID Nested
John Smith Director of HR JSmith From nested group: Power Users
好的,完成了!该小组的下一名成员是Ethel Jones。她也有Payroll的描述,她的用户名是EJones。循环从AD中提取,并用它们替换$strGroupMember
的任何现有值。不重要的是,我们似乎并没有在最后一个循环中使用任何这些信息,但这不是剧本的关注,它只是通过!
接下来,我们再次更新$row2.Nested
,将“从嵌套组:高级用户”更改为“来自嵌套组:超级用户”......呵呵,和以前一样,但是好的,你是老板。继续前进!
现在它尝试向表中添加另一行,但是这里是我们收到错误的地方:这是与上次完全相同的数据,因为$ row2中的任何内容都没有真正更改,它仍然是:
Name Description NetworkID Nested
John Smith Director of HR JSmith From nested group: Power Users
你知道我要去哪里吗?我看到的下一个问题是你在这里做了一个If / Then / Else循环,但是你试图在Then部分添加行,但不是在Else部分。在这里,采取这种意识形态并相应地更新您的代码:
If (Is a Group) Then
For Each Member of the group, do this
query AD to get user details
Update the $row2 variable with the user's details and the current group
Add $row2 to the table
End For Each loop
Else (if it is NOT a group)
query AD to get the user's details
Update the $row2 variable with the user's details and the current group
Add $row2 to the table
End Else section
这应该可以清除您当前的错误。它不会递归多个级别的组,因此如果组内的组中存在组,则会错过人员。如:
Main Group
--->Nested Group
--->Another Nested Group
->Billy Mac
这将包括第一个嵌套组和第二个嵌套组,但除非他代表其他地方,否则Billy Mac不会在你的列表中出现。
至于我的解决方案,我昨晚写了大部分内容,所以今天我完成了。这应该做你想要的我想的。它创建一个空数组,然后用递归找到的每个用户的对象填充它。然后它循环遍历所有嵌套组,并将该组的名称添加到其中每个用户的对象的Nested属性中。然后它将该数组输出为每个处理组的CSV文件。
import-module activedirectory
#Define a function to add a group's name to its members Nested field recursivly.
Function GetNestedMembers{
Param($Group)
ForEach($Item in (Get-ADGroupMember $Group)){
if($Item.ObjectClass -eq "group" -and $Global:SubGroups -inotcontains $Item.name){
$Global:SubGroups += $Item.name.tostring()
GetNestedMembers $Item
}else{
$AllMembers|?{$_.Name -match $Item.Name -and !($_.nested -match $group.name)}|%{$_.Nested = "$($_.Nested), $($Group.Name.tostring())"}
}
}
}
$GroupList = get-content "C:\Users\MYUSERNAME\Documents\Group Audit\audit.txt"
ForEach($Entry in $GroupList){
$SubGroups = @()
#Create an empty array
$AllMembers = @()
#Populate it with all recursive members of the group
ForEach($Person in (Get-ADGroupMember $Entry -Recursive)){
$User = Get-ADUser $Person -Property description
$AllMembers += New-Object PSObject -Property @{
Name = $Person.Name
Description = $User.Description
NetworkID = $Person.SamAccountName
Nested = $Null
}
}
$CurrentGroup = Get-ADGroupMember $Entry
#Mark root members as direct group members in the Nested field
$AllMembers|?{($CurrentGroup | ?{$_.ObjectClass -ne "group"}).name -contains $_.Name}|%{$_.Nested = "Direct Member"}
#Iterate through all nested groups
$CurrentGroup | ?{$_.ObjectClass -eq "group"} | %{GetNestedMembers $_}
#If the output path doesn't exist, make it quietly.
If(!(Test-Path "C:\Users\MYUSERNAME\Documents\Group Audit\groups\")){$null = New-Item "C:\Users\MYUSERNAME\Documents\Group Audit\groups\" -ItemType directory}
#Output to CSV
$AllMembers |%{if($_.nested){$_.nested = $_.nested.TrimStart(", ")};$_} | Select Name, Description, NetworkID, Nested | Export-csv "C:\Users\MYUSERNAME\Documents\Group Audit\groups\$Entry.csv" -NoTypeInformation
}