SCCM Collections - Hash Table or Array? [1..10]

Welcome Forums General PowerShell Q&A SCCM Collections - Hash Table or Array? [1..10]

This topic contains 7 replies, has 3 voices, and was last updated by

 
Participant
1 week, 3 days ago.

  • Author
    Posts
  • #113839

    Participant
    Points: 0
    Rank: Member

    Hello I'm working on a script to add multiple collections to a master collection in SCCM.  The catch is that I don't want to add all of them at the same time.  First, I get the master collection.

    
    $CurrentMonth = Get-Date -UFormat %b
    
    $MonthlyUpdatesCollection = (Get-CMDeviceCollection).Name | ? {$_ -like "*Sec.Updates*$CurrentMonth*Workstations*"}
    
    

    Then I have a bunch of lines to add each collection that I want added.

    
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId "XYZ00123"
    
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId "XYZ00456"
    
    Start-Sleep -Seconds 7200
    
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId "XYZ00789"
    
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId "XYZ00321"
    
    

    So then I thought.. instead of having a bunch of lines with the same thing basically... that I could create a hash table (maybe that's my mistake, maybe I should just use a simple array?)

    
    $CollectionIDs = @{
    
    1="XYZ00123"
    
    2="XYZ00456"
    
    3="XYZ00789"
    
    4="XYZ00321"
    
    5="XYZ00654"
    
    6="XYZ00987"
    
    }
    
    

    From here though I haven't been able to use [1..3] for instance to just add the first 3 collections.  I've tried

    
    
    
    

    $CollectionIDs[1..3].Values | Foreach

    $CollectionIDs.Values[1..3] | Foreach

    
    

    I still consider myself a novice at PowerShell so maybe I'm completely off base and should use something totally different.

    In a nutshell.. I want to do a ForEach but not go through the entire hash table or array, I want to be able to select the first 3 and add them, then wait, then select the middle 3 and add them and then the last 3.

    Let me know what you think.  Thank you in advance!

     

     

     

  • #113842

    Participant
    Points: 0
    Rank: Member

    Sorry for the formatting, I tried to fix it and failed!

  • #113869

    Participant
    Points: 0
    Rank: Member

    The below code will do chunks of 3 and wait three minutes, and then do the next 3.  If you want to change how many go at a time, you can simply change the " if ($i -eq 3)" line to If ($i -eq ).

    This code uses a plain old array.  It also assumes that you have a number in your array divisible by 3 and doesn't do any error checking or validation before attempting the Add-CMDeviceCollectionIncludeMembershipRule command.

    I would consider it a start- not the final solution.

    Hopefully this helps.

    $CurrentMonth = Get-Date -UFormat %b
    
    $MonthlyUpdatesCollection = "MyUpdateCollection" #(Get-CMDeviceCollection).Name | ? {$_ -like "*Sec.Updates*$CurrentMonth*Workstations*"}
    
    $arrCollectionIDs= @("XYZ00123", "XYZ00456", "XYZ00789", "XYZ00321", "XYZ00654", "XYZ00987", "XYZ01321", "XYZ01654", "XYZ01987")
    
    $i = 1
    
    ForEach ($ID in $arrCollectionIDs)
     {
      Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId "$ID"
      if ($i -eq 3)
       {
        Start-sleep -Seconds 180
        $i = 0
       }
      $i++
    }

     

  • #113870

    Participant
    Points: 0
    Rank: Member

    Weird, I tried to edit my post and I think it messed up a couple of your preformatted text examples.

    The below code will do chucks of 3 and wait 3 minutes between.  It assumes your array is divisible by 3, and will not validate that it has data before attempting to run the sccm command.  You can change the number it does before pausing by changing the line " if ($i -eq 3)" to some other number.

    I would consider this a start- not the complete code

    $CurrentMonth = Get-Date -UFormat %b
    
    $MonthlyUpdatesCollection = "MyUpdateCollection" #(Get-CMDeviceCollection).Name | ? {$_ -like "*Sec.Updates*$CurrentMonth*Workstations*"}
    
     
    
    $arrCollectionIDs= @("XYZ00123", "XYZ00456", "XYZ00789", "XYZ00321", "XYZ00654", "XYZ00987", "XYZ01321", "XYZ01654", "XYZ01987")
    
     
    
    $i = 1
    
    ForEach ($ID in $arrCollectionIDs)
    
    {
    
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId "$ID"
    
     
    
    if ($i -eq 3)
    
    {
    
    Start-sleep -Seconds 180
    
    $i = 0
    
    }
    
    $i++
    
    }
  • #113893

    Participant
    Points: 37
    PublishedHelping Hand
    Rank: Member

    This maybe a copy paste issue, but the line spaces, Which I cleaned out will not allow this to work as planned
    I am only use the format to make this easy to copy.

    $CollectionIDs = @{
    1="XYZ00123"
    2="XYZ00456"
    3="XYZ00789"
    4="XYZ00321"
    5="XYZ00654"
    6="XYZ00987"
    }
    
    $CollectionIDs | ft -a
    
    
    Name Value   
    ---- -----   
    6    XYZ00987
    5    XYZ00654
    4    XYZ00321
    3    XYZ00789
    2    XYZ00456
    1    XYZ00123
    

    Note that the collection is last in is first and the output use the array is as expected

    $CollectionIDs[1..3] | ft -a
    
    XYZ00123
    XYZ00456
    XYZ00789
    

    So, you could simply brute force this, this way...

    $CollectionIDs[1..3] | 
    % {
        "Processing $_"
    }
    
    Start-sleep -Seconds 180
    
    $CollectionIDs[4..6] | 
    % {
        "Processing $_"
    }
    

    … or take a more elegant way, as this is what it sounds like you are trying to do.

    Divide a collection into multiple smaller collections in ConfigMgr 2012 via PowerShell

  • #113896

    Participant
    Points: 0
    Rank: Member

    Thank you for your help!  I decided to go with a simple array as you did.  I'm sure Hash Table has certain advantages but I just don't know how to work well with them yet.

    
    #Connect to SCCM Site
    $SiteCode = "XYZ" # Site code
    $ProviderMachineName = "XYZSCCM1.XYZ.local" # SMS Provider machine name
    $initParams = @{}
    if((Get-Module ConfigurationManager) -eq $null) {
    Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams
    }
    if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
    New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
    }
    Set-Location "$($SiteCode):\" @initParams
    #Sets Current Month Variable
    $CurrentMonth = Get-Date -UFormat %b
    $MonthlyUpdatesCollection = (Get-CMDeviceCollection).Name | ? {$_ -match "Test.Add.Collections"}
    #Array of Collection IDs to be added to Monthly Collection
    $CollectionIDs = @(
    "XYZ007B5"       #0
    "XYZ0078A"       #1
    "XYZ007D8"       #2
    "XYZ007F9"       #3
    "XYZ007C0"       #4
    "XYZ007B3"       #5
    "XYZ007FA"       #6
    "XYZ007C8"       #7
    "XYZ007CD"       #8
    "XYZ007C4"       #9
    "XYZ007C4"       #10
    "XYZ007B4"       #11
    "XYZ00773"       #12
    "XYZ007F0"       #13
    "XYZ007E5"       #14
    "XYZ007C5"       #15
    "XYZ007C3"       #16
    "XYZ007E4"       #17
    "XYZ007F7"       #18
    "XYZ0075D"       #19
    )
    $CollectionIDs[0..10] | ForEach {
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId $($_)
    }
    Start-Sleep -Seconds 60
    Invoke-CMDeviceCollectionUpdate -Name "$MonthlyUpdatesCollection"
    Start-Sleep -Seconds 300
    $CollectionIDs[11..14] | ForEach {
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId $($_)
    }
    Start-Sleep -Seconds 60
    Invoke-CMDeviceCollectionUpdate -Name "$MonthlyUpdatesCollection"
    Start-Sleep -Seconds 300
    $CollectionIDs[15..16] | ForEach {
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId $($_)
    }
    Start-Sleep -Seconds 60
    Invoke-CMDeviceCollectionUpdate -Name "$MonthlyUpdatesCollection"
    Start-Sleep -Seconds 300
    $CollectionIDs[17..19] | ForEach {
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionName "$MonthlyUpdatesCollection" -IncludeCollectionId $($_)
    }
    Start-Sleep -Seconds 60
    Invoke-CMDeviceCollectionUpdate -Name "$MonthlyUpdatesCollection"
    
    

    This is what I went with.  The main point of this is because 2 months ago I added All Workstations at once and it screwed up WSUS for some reason.

    My next question is... does anyone know if the Invoke-CMDeviceCollectionUpdate is good enough to add the members to the collection so that they will get policy and start downloading updates?

    
    Invoke-CMDeviceCollectionUpdate -Name "$MonthlyUpdatesCollection"
    
    

     

    Or should I add a RequestRefresh via WMI so that collection members get policy?

    
    $CollectionQuery = Get-WmiObject -Namespace "Root\SMS\Site_$SiteCode" -Class SMS_Collection `
    -ComputerName $ProviderMachineName -ErrorAction STOP -Filter "Name='$MonthlyUpdatesCollection'"
    $CollectionQuery.RequestRefresh()
    
    
  • #113897

    Participant
    Points: 37
    PublishedHelping Hand
    Rank: Member

    Understood, on taking the brute force way, but as to the rest of your query. It's more about how WSUS and SCCM works that PS specifically. So, sure we can handle the PS proper stuff, but the moment you get into MS product / SKU specific features, all of which have there on modules / cmdlets, etc., unless we are SME's (I've personally not touched SC since v2007) in those topics, that's more of a challenge to answer, for obvious reasons.

    Rule of thumb though. If you already have policies (SCCM / GPO, etc.) in play and working as designed, there is little reason to spend any cycles trying to out think it, unless there is a real reason to.

    Invoke-CMDeviceCollectionUpdate is specifically an SCCM thing, not PS proper default cmdlet set.

  • #113912

    Participant
    Points: 0
    Rank: Member

    I guess it really depends on if you want your clients to check in as quickly as possible or if you want them to do their regular randomized check in.  If you are trying to get them to all check in for the maintenance window, you might want to do it so the machines get policy refreshes.

    Depending on how many machines your SCCM environment manages, having all machines check in at the same time can really affect the performance (depending on your architecture, network, and, sometimes, which way the wind is blowing ) and make responses and downloads seem sluggish.

    -m

You must be logged in to reply to this topic.