使用POWERSHELL向表中添加数据时,“此行已属于此表”

时间:2014-04-21 21:52:05

标签: windows excel powershell

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

事情按预期工作,我缺少什么?

1 个答案:

答案 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
}