【问题标题】:"This row already belongs to this table" when adding data to a table using POWERSHELL使用 POWERSHELL 向表中添加数据时“该行已属于该表”
【发布时间】:2014-04-23 02:57:16
【问题描述】:

下午好 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)

这在我将“嵌套组” For Each 循环放在那里之前有效,我只是对为什么会破坏它感到困惑,除非我在这里遗漏了一些明显的东西。当我删除它时:

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

一切正常,我错过了什么?

【问题讨论】:

    标签: windows excel powershell


    【解决方案1】:

    您正在运行 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 脚本块中定义 $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 脚本块中添加一行:

    $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
    

    但那是我。

    Edit2:好的,第二轮!我看到了变化,但肯定还有一些问题。您遇到的问题是将行添加到表中。好的,可以理解。以下是我看到的一些问题:

    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"
    

    好的,它正在循环访问它为嵌套组“高级用户”提取的条目。我们将简化此操作,并假设此嵌套组中没有嵌套其他组,这是另一个问题。

    该列表中的第 1 项是 Marcia Winkle,她的广告描述为“Payroll”,用户名为 MWinkle。循环发现了这一点并将她的所有信息分配给$strGroupMember

    接下来,它会更新 $row2,并替换 Nested 值,将“未嵌套”替换为“来自嵌套组:高级用户”(我们正在使用的组)。

    然后它将$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
    }
    

    【讨论】:

    • 哇 @TheMadTechnician 感谢您非常彻底的回复。我会尝试将它们放在一个数组中,我会尝试你的方式,并报告任何问题。
    • 在实施您的解决方案后,我尝试了一些事情,添加了一行代码:$strGroupMember = Get-aduser -Identity $Group -property description,但输出仍然相同。所以我仔细查看了我的代码并重新安排了一些事情,但事情仍然没有按预期工作。新代码,实施了您的建议并稍微重新排列,位于此处:pastebin.com/zmrHdfJM 我查看了数组,并为 HASH 表返回了很多结果......这些在 Powershell 中是否相同?抱歉这么多问题,我想掌握它
    • HashTables 是 PS 中一种特殊的数组。我个人认为嘿,脚本专家!博客对新人很有用,您可能想查看this post 了解一些数组基础知识。您愿意尝试自己理解和做事,这让我想在合理的范围内提供帮助。我会看看你的代码并回复你。
    • 感谢您的链接!我刚刚通读它,我找到了嘿,脚本专家!非常有用且易于理解。读完之后,我开始寻找关于 HASH 表的文章,看起来哈希表或数组都可以解决这个问题。由于最终目标最终是 .CSV 或 Sharepoint 易于消化的其他内容,因此我愿意接受您对 Array vs Hash table 的想法以及为什么一个最适合我。感谢您的帮助,我真的很感激!
    猜你喜欢
    • 1970-01-01
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多