Добавить элементы в массив коллекции динамически - PullRequest
1 голос
/ 04 октября 2019

Хорошо. Вот что я пытаюсь сделать. Я в основном пытаюсь создать двумерный массив в powershell, импортируя данные из AD и базы данных SQL. Я собираюсь использовать массив для записи, обновления и удаления строк в базе данных позже в сценарии. Проблема, с которой я сталкиваюсь, заключается в том, чтобы собрать все в одну переменную.

Когда я запускаю свой код, он снова и снова добавляет одного и того же пользователя в нужный массив. Самый последний элемент в созданной переменной $ Table записывается для каждого отдельного экземпляра в $ ToWrite.

Я попытался сделать паузу после ввода всех переменных в $ Table, записи $ Table в консоль и записи $Переписать на консоль. $ 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 ]

1 голос
/ 04 октября 2019

Чтобы проиллюстрировать - здесь большое предостережение, я дома, поэтому не могу проверить ничего из этого, но это должно дать вам представление:

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

Вышесказанное также можно упростить, но я 'мы пытались сохранить его похожим на ваш существующий код

1 голос
/ 04 октября 2019

Проблема в том, что вы обновляете один и тот же объект, $Table, снова и снова и добавляете ссылки на этот же объект в выходной массив, $ToWrite - все элементы которогопоэтому в конечном итоге указываем на единственный объект $Table, значения свойств которого в этой точке содержат значения, которые были назначены в итерации last .

Проблема подробно описана в этот ответ , в котором показано возможное решение с использованием пользовательских классов , доступных в PowerShell v5 и более поздних версиях.

Решение без пользовательских классов требует от вас клон ваш пользовательский $Table объект в каждой итерации :

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

Примечание : этот метод клонирования работает только так, как ожидается с пользовательских объектов , т. Е. Экземпляров [System.Management.Automation.PSCustomObject], таких как созданные с помощью Select-Object командлета и литерального синтаксиса [pscustomobject] @{ ... }

При этом , поскольку вы присваиваете все свойства вашего пользовательского объекта вВ вашем цикле нет смысла создавать шаблон объект заранее - вместо этого просто используйте буквальный синтаксис создания пользовательских объектов [pscustomobject] @{ ... } (PSv3 +) внутри цикла , который неявно создает новый экземпляр в каждой итерации .


Кроме того, ваше решение может быть оптимизировано, поскольку оно и проще, и эффективнеечтобы 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
...