动态将项目添加到集合数组中

时间:2019-10-04 17:43:28

标签: powershell multidimensional-array

好的。这就是我想要做的。我基本上是试图通过从AD和SQL数据库导入内容在powershell中制作2D数组。稍后,我将在脚本中使用数组写入,更新和删除数据库中的行。我遇到的问题是将所有内容都放入一个变量中。

当我运行代码时,它会反复将同一用户添加到所需的数组中。创建到$ 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
}

输出示例:

SEQUENCE              : 1206
LASTUSER              : SYSTEMACCOUNT
GROUP                 : 1
CLIENT                : USERNAME
FNAME                 : FIRSTNAME
NAME                  : LASTNAME
EMAILID               : SMTP:{EMAIL}EMAIL
USEDEPT               : 0
USELOCATION           : 0
CREATEDFROMSSD        : 0
DISPLAYCLIENTCOMMENTS : 0
_INACTIVE_            : 0
WINUSERID             : DOMAIN\USERNAME
SELFSERVICEACCESS     : TYPE
SELFSERVICELICENSE    : 1
WIAENABLED            : 1
SID                   : S-1-Z-XX-CCCCCCCCCC-YYYYYYYYY-VVVVVVVVVV-125121

SEQUENCE              : 1206
LASTUSER              : SYSTEMACCOUNT
GROUP                 : 1
CLIENT                : USERNAME
FNAME                 : FIRSTNAME
NAME                  : LASTNAME
EMAILID               : SMTP:{EMAIL}EMAIL
USEDEPT               : 0
USELOCATION           : 0
CREATEDFROMSSD        : 0
DISPLAYCLIENTCOMMENTS : 0
_INACTIVE_            : 0
WINUSERID             : DOMAIN\USERNAME
SELFSERVICEACCESS     : TYPE
SELFSERVICELICENSE    : 1
WIAENABLED            : 1
SID                   : S-1-Z-XX-CCCCCCCCCC-YYYYYYYYY-VVVVVVVVVV-125121

SEQUENCE              : 1206
LASTUSER              : SYSTEMACCOUNT
GROUP                 : 1
CLIENT                : USERNAME
FNAME                 : FIRSTNAME
NAME                  : LASTNAME
EMAILID               : SMTP:{EMAIL}EMAIL
USEDEPT               : 0
USELOCATION           : 0
CREATEDFROMSSD        : 0
DISPLAYCLIENTCOMMENTS : 0
_INACTIVE_            : 0
WINUSERID             : DOMAIN\USERNAME
SELFSERVICEACCESS     : TYPE
SELFSERVICELICENSE    : 1
WIAENABLED            : 1
SID                   : S-1-Z-XX-CCCCCCCCCC-YYYYYYYYY-VVVVVVVVVV-125121

有什么想法吗?

2 个答案:

答案 0 :(得分: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] @{ ... }

也就是说,由于您要在循环中分配自定义对象的 all 个属性,因此预先创建 template 对象没有任何好处-相反,只需在循环内部使用文字自定义对象创建语法[pscustomobject] @{ ... }(PSv3 +) ,即可隐式创建一个 new 实例在每次迭代中


此外,您的解决方案可以简化,因为让PowerShell通过为变量创建多个对象的命令收集输出,使PowerShell为您创建数组既简单又有效。。 / p>

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

# 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类型约束。没有它,如果碰巧只是一个循环迭代,因此输出对象,$ToWrite会按原样存储该输出对象,而不是包装在数组中(此行为对于PowerShell的管道)。

上面的代码产生了以下内容,表明创建了不同的对象:

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

答案 1 :(得分:1)

为了说明-此处需要说明的是,我在家里,所以无法测试其中任何一个,但是它应该给您一个想法:

$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
    }
}

上面的内容也可以简化,但我尝试使其与您的现有代码相似