【问题标题】:Add items into a collection array dynamically将项目动态添加到集合数组中
【发布时间】:2019-10-07 19:31:31
【问题描述】:

好的。这就是我想要做的。我基本上是想通过从 AD 和 SQL 数据库导入东西来在 powershell 中创建一个二维数组。我将在脚本后面使用数组来写入、更新和删除数据库中的行。我遇到的问题是将所有内容都放入一个变量中。

当我运行我的代码时,它会一遍又一遍地将同一个用户添加到所需的数组中。 $Table 变量中创建的最后一项被写入 $ToWrite 内的每个实例。

我尝试在将所有变量输入 $Table 后暂停,将 $Table 写入控制台,然后将 $ToWrite 写入控制台。 $Table 在每个循环中都会正确更改,但同样,一旦它写入 $ToWrite,它就会覆盖每个实例。我已经尝试了多种方法,例如 .add()、PsCustomObject[] 等。我现在只是卡住了。

这是我的半功能代码:

$AllPOCs = Get-ADGroupMember 'ALL POC'
$POCs = @()

$Counter = 0

$AllPOCs | ForEach-Object {
    $Name = $AllPOCs[$Counter].SamAccountName

    $TestPOC = Invoke-Sqlcmd -Query "SELECT * FROM TABLE WHERE CLIENT = '$Name'" -ServerInstance "SERVER\INSTANCE"

    if ($TestPOC -eq $null) {
        $POCs += Get-ADUser $Name -Properties * |
                 select -Property SamAccountName, GivenName, Surname, SID, EmailAddress
    }
    $Counter += 1
}

$ToWrite = @()
$Counter = 0
$SEQUENCE = Invoke-Sqlcmd -Query "Select TABLEFIELD FROM DATABASE WHERE NAME = 'FIELDID'" -ServerInstance "SERVER\INSTANCE"
$SEQUENCE = $SEQUENCE.RECNUM + 1
$Table = "" | select SEQUENCE, LASTUSER, GROUP, CLIENT, FNAME, NAME, EMAILID, USEDEPT, USELOCATION, CREATEDFROMSSD, DISPLAYCLIENTCOMMENTS, _INACTIVE_, WINUSERID, SELFSERVICEACCESS, SELFSERVICELICENSE, WIAENABLED, SID

#everything works correctly up to here

$POCs | ForEach-Object {
    $Table.SEQUENCE = $SEQUENCE
    $Table.LASTUSER = 'SYSTEMACCOUNT'
    $Table.GROUP = 1
    $Table.CLIENT = $POCs[$Counter].SamAccountName.ToUpper()
    $Table.FNAME = $POCs[$Counter].GivenName.ToString()
    $Table.Name = $POCs[$Counter].surname.ToString()
    $Table.EmailID = 'SMTP:{' + $POCs[$Counter].EmailAddress.ToString() + '}' + 
    $POCs[$Counter].EmailAddress.ToString()
    $Table.USEDEPT = 0
    $Table.USELOCATION = 0
    $Table.CREATEDFROMSSD = 0
    $Table.DISPLAYCLIENTCOMMENTS = 0
    $Table._INACTIVE_ = 0
    $Table.WINUSERID = '\DOMAIN' + $POCs[$Counter].SamAccountName.ToString()
    $Table.SELFSERVICEACCESS = 'TYPE'
    $Table.SELFSERVICELICENSE = 1
    $Table.WIAENABLED = 1
    $Table.SID = $POCs[$Counter].SID.ToString()

    $ToWrite += $Table #THIS DOESN'T WORK PROPERLY.
    $SEQUENCE += 1
    $Counter += 1
}

输出示例:

序号:1206 上一个用户:系统帐户 组 : 1 客户:用户名 FNAME : 名字 姓名:姓氏 EMAILID : SMTP:{EMAIL}EMAIL 使用日期:0 使用位置:0 创建自SSD:0 显示客户评论:0 _不活跃_:0 WINUSERID:域\用户名 自助服务访问:类型 自助服务许可证:1 支持:1 SID:S-1-Z-XX-CCCCCCCCCC-YYYYYYYYY-VVVVVVVVVV-125121 序号:1206 上一个用户:系统帐户 组 : 1 客户:用户名 FNAME : 名字 姓名:姓氏 EMAILID : SMTP:{EMAIL}EMAIL 使用日期:0 使用位置:0 创建自SSD:0 显示客户评论:0 _不活跃_:0 WINUSERID:域\用户名 自助服务访问:类型 自助服务许可证:1 支持:1 SID:S-1-Z-XX-CCCCCCCCCC-YYYYYYYYY-VVVVVVVVVV-125121 序号:1206 上一个用户:系统帐户 组 : 1 客户:用户名 FNAME : 名字 姓名:姓氏 EMAILID : SMTP:{EMAIL}EMAIL 使用日期:0 使用位置:0 创建自SSD:0 显示客户评论:0 _不活跃_:0 WINUSERID:域\用户名 自助服务访问:类型 自助服务许可证:1 支持:1 SID:S-1-Z-XX-CCCCCCCCCC-YYYYYYYYY-VVVVVVVVVV-125121

有什么想法吗?

【问题讨论】:

  • 您不需要计数器来查找循环中的当前对象,使用 $_ 例如$所有POC | ForEach-Object { $Name = $_.SamAccountName ....etc

标签: powershell multidimensional-array


【解决方案1】:

问题是您一遍又一遍地更新同一个对象$Table,并将对同一对象的引用添加到输出数组$ToWrite - 所有这些因此元素最终指向唯一的 $Table 对象,该对象在该点的属性值包含在 last 迭代中分配的属性值。

this answer 中详细解释了该问题,其中显示了使用 自定义类 的可能解决方案,可在 PowerShell v5 及更高版本中使用。

没有自定义类的解决方案要求您在每次迭代中克隆您的自定义 $Table 对象:

# Create a new instance with the same properties:
$Table = $Table.psobject.Copy()

注意:这种克隆技术仅适用于自定义对象,即[System.Management.Automation.PSCustomObject] 的实例,例如由Select-Object cmdlet 和文字语法创建的实例[pscustomobject] @{ ... }

也就是说,因为您要在循环中分配自定义对象的 所有 属性,所以预先创建 模板 对象没有任何好处 - 相反,只需在循环中使用文字自定义对象创建语法[pscustomobject] @{ ... } (PSv3+),它会在每个循环中隐式创建一个 new 实例迭代。


此外,您的解决方案还可以简化,因为让 PowerShell 为您创建数组既简单又高效,只需收集在一个变量中输出多个对象的命令的输出。

这是一个将所有内容放在一起的简化示例:

# Loop over the input and instantiate a new custom object
# in each iteration, then let PowerShell collect the results
# in array variable $ToWrite
[array] $ToWrite = 1..3 | ForEach-Object {
  # Instantiate and output a new custom object in each iteration.
  [pscustomobject] @{
    PropA = "ValueA-$_"
    PropB = "ValueB-$_"
  }
}

# Output the resulting array
$ToWrite

注意:[array] 类型约束仅在您需要确保$ToWrite 是始终 一个数组时才需要;没有它,如果恰好只有一个 single 循环迭代并因此输出对象,$ToWrite 将按原样存储该输出对象,而不是包装在数组中(此行为是 PowerShell 管道的基础)。

上面的结果如下,表明创建了不同的对象:

PropA    PropB
-----    -----
ValueA-1 ValueB-1
ValueA-2 ValueB-2
ValueA-3 ValueB-3

【讨论】:

    【解决方案2】:

    为了说明 - 这里有一个很大的警告,我在家所以无法测试任何这些,但它应该给你一个想法:

    $AllPOCs = Get-ADGroupMember 'ALL POC'
    
    $Table = $AllPOCs | ForEach-Object {
        $Name = $_.SamAccountName
        $TestPOC = Invoke-Sqlcmd -Query "SELECT * FROM TABLE WHERE CLIENT = '$Name'" -ServerInstance "SERVER\INSTANCE"
    
        If($TestPOC -eq $null) {
            $POC = get-aduser $Name -Properties * | select -Property SamAccountName, GivenName, Surname, SID, EmailAddress 
            $SEQUENCE = Invoke-Sqlcmd -Query "Select TABLEFIELD FROM DATABASE WHERE NAME = 'FIELDID'" -ServerInstance "SERVER\INSTANCE"
            $SEQUENCE = $SEQUENCE.RECNUM + 1
            [pscustomobject]@{SEQUENCE = $SEQUENCE;
                            LASTUSER = 'SYSTEMACCOUNT';
                            GROUP = 1;
                            CLIENT = $_.ToUpper();
                            FNAME = $_.GivenName.ToString();
                            Name = $_.surname.ToString();
                            EmailID = 'SMTP:{' + $_.EmailAddress.ToString() + '}' + $_.EmailAddress.ToString();
                            USEDEPT = 0;
                            USELOCATION = 0;
                            CREATEDFROMSSD = 0;
                            DISPLAYCLIENTCOMMENTS = 0;
                            _INACTIVE_ = 0;
                            WINUSERID = '\DOMAIN' + $_.SamAccountName.ToString();
                            SELFSERVICEACCESS = 'TYPE';
                            SELFSERVICELICENSE = 1;
                            WIAENABLED = 1;
                            SID = $_.SID.ToString()}
            $SEQUENCE += 1
        }
    }
    

    上面也可以简化,但我尽量保持与您现有的代码相似

    【讨论】:

    • 确实:在每次迭代中使用文字语法 [pscustomobject] @{ ... } 隐式构造一个新的自定义对象实例是最好的方法 (+1)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    • 2021-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多