SCCM; PowerShell; И очень медленная работа Add-CMDeviceCollectionDirectMembershipRule

… или простая задача но много букв.

Время от времени возникает вопрос — «Надо добавить в коллекцию пару сотен девайсов, а командлет Add-CMDeviceCollectionDirectMembershipRule делает это ну оооочень медленно». И приводят пример вроде этого:

$Names = "a*"
$CollName = "Test collection"
Get-CMDevice -Name $Names | Foreach-Object {
    Add-CMDeviceCollectionDirectMembershipRule -CollectionName $CollName -ResourceId $_.ResourceID
}

Смотрим описание командлета:

Get-Help Add-CMDeviceCollectionDirectMembershipRule
NAME
    Add-CMDeviceCollectionDirectMembershipRule
    
SYNTAX
    Add-CMDeviceCollectionDirectMembershipRule -CollectionId <string> -ResourceId <int[]> ...
    Add-CMDeviceCollectionDirectMembershipRule -CollectionId <string> -Resource <IResultObject[]> ...

Самое ценное тут “-ResourceId <int[]>” и “-Resource <IResultObject[]>”, что означает, что в качестве параметра принимается массив объектов. Т.е. для ускорения работы просто перепишем код следующим образом:

$Names = "a*"
$CollName = "Test collection"
Add-CMDeviceCollectionDirectMembershipRule -CollectionName $CollName -ResourceId (Get-CMDevice -Name $Names -Fast).ResourceID

И всё бы ничего, но есть ограничение – не больше 563 ResourceID за один раз. Почему так и что за цифра такая 563? Дело в том, что при использовании командлета Add-CMDeviceCollectionDirectMembershipRule и передачи ему параметра ResourceID командлет формирует запрос на получение ресурсов, перебирая весь массив ResourceID через “OR”

SELECT * FROM SMS_Resource WHERE ( ResourceID = 16777219 ) OR ( ResourceID = 16777222 ) OR ...

А длина строки запроса не может превышать 16384 символа. Отсюда и ограничение. Могли бы конечно сэкономить на пробелах, но помогло бы не сильно.

Ради спортивного интереса можно написать добавление ресурсов пачками по 563 ResourceID:

$BatchBy = 563
$CurrentStep = 0
$Names = "a*"
$CollName = "Test collection"
$AllResourceID = (Get-CMDevice -Name $Names -Fast).ResourceId
while ($CurrentStep -lt $AllResourceID.Count) {
    $Batch = @($AllResourceID | Select-Object -First $BatchBy -Skip $CurrentStep)
    Add-CMDeviceCollectionDirectMembershipRule -CollectionName $CollName -ResourceId $Batch
    $CurrentStep += $BatchBy
}

…но проще использовать “-Resource <IResultObject[]>”:

$Names = "a*"
$CollName = "Test collection"
Add-CMDeviceCollectionDirectMembershipRule -CollectionName $CollName -Resource (Get-CMDevice -Name $Names -Fast)

Вообще не рекомендуется использовать большое количество правил Direct Membership, но это вам решать Smile

Так же, я не использую командлеты SCCM в скриптах, которые планируется использовать долгое время и/или на разных версиях SCCM, т.к. от версии к версии командлеты меняют, добавляют или удаляют параметры и т.д. Хотите сделать скрипт надолго – пишите код используя WMI классы SCCM, все эти командлеты всё равно являются обёртками над этими классами.

Реклама
Запись опубликована в рубрике PowerShell, SCCM, Tricks. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s