powershellwmiwqlget-wmiobject

PowerShell WMI/WQL to get information from SCCM - optimisation


This is a case where what I have works fine but I can't help but feel there must be a faster way to do this. I'm doubting my structure here. Do you see a faster way this could be done? The foreach takes a while since it has to query many times. The goal is to have an array that shows the computer's ($poste) collections (name and objectpath).

$poste = "p1234"

$SiteCode = "PRX"
$SiteServer = "SSX"

$ResourceID = Get-WmiObject -Namespace root\sms\site_$SiteCode -Computer $SiteServer -Class SMS_R_SYSTEM -Filter "Name='$poste'" |
              Select-Object -ExpandProperty ResourceID
$CollectionIDs = Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class sms_fullcollectionmembership -Filter "ResourceID ='$resourceID'" |
                 Select-Object -expand CollectionID

foreach ($CollectionID in $CollectionIDs) {
    $query = @"
SELECT * FROM SMS_Collection
WHERE SMS_Collection.CollectionID='$CollectionID'
"@

[array]$CollectionNamesPath += Get-WmiObject -Namespace root\sms\site_$SiteCode -Computer $SiteServer -Query $query |
                               Select-Object name,ObjectPath |
                               Sort-Object -Property Name
} 

$CollectionNamesPath | Out-GridView

Solution

  • This is likely the cleanest version of your existing code:

    $poste = "p1234"
    $SiteCode = "PRX"
    $SiteServer = "SSX"
    $ResourceID = Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class SMS_R_SYSTEM -Filter "Name='$poste'" -Property ResourceID | Select-Object -ExpandProperty ResourceID
    $CollectionIDs = Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class sms_fullcollectionmembership -Filter "ResourceID='$resourceID'" -Property CollectionID | Select-Object -ExpandProperty CollectionID
    
    $CollectionNamesPath = foreach ($CollectionID in $CollectionIDs) {
        $Query = "Select Name, ObjectPath From SMS_Collection Where SMS_Collection.CollectionID='$CollectionID'"
        Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Query $Query | Select-Object Name, ObjectPath | Sort-Object -Property Name
    } 
    
    $CollectionNamesPath | Out-GridView
    

    You could also try this, though I'm not sure how well WQL supports it:

    $poste = "p1234"
    $SiteCode = "PRX"
    $SiteServer = "SSX"
    $ResourceID = Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class SMS_R_SYSTEM -Filter "Name='$poste'" -Property ResourceID | Select-Object -ExpandProperty ResourceID
    $CollectionIDs = Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class sms_fullcollectionmembership -Filter "ResourceID='$resourceID'" -Property CollectionID | Select-Object -ExpandProperty CollectionID
    
    $Query = "Select CollectionID, Name, ObjectPath From SMS_Collection Where" + $($($CollectionIDs | ForEach-Object { " SMS_Collection.CollectionID='$_' " }) -join 'or')
    
    $CollectionNamesPath = Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Query $Query |
        Sort-Object -Property CollectionID, Name |
        Select-Object Name, ObjectPath
    
    $CollectionNamesPath | Out-GridView
    

    You may be able to do something like this:

    Get-CimInstance -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class SMS_R_SYSTEM -Filter "Name='$poste'" -KeyOnly |
        Get-CimAssociatedInstance -ComputerName $SiteServer -ResultClassName sms_fullcollectionmembership -KeyOnly |
        Get-CimAssociatedInstance -ComputerName $SiteServer -ResultClassName SMS_Collection |
        Sort-Object -Property CollectionID, Name |
        Select-Object Name, ObjectPath
    

    When it works it's fantastic. However, in my experience working with Get-CimAssociatedInstance is an uneven experience at best, doubly so when working on remote computers.