powershellcsvcollectionssccmcomputer-name

How do I find the Collection Membership Information with PowerShell


I have the following code, but I get an "Invalid Namespace" error constantly, I am pretty sure I am entering the correct information.

If you have another way of doing this, it's also accepted.

Param(
    $SiteCode,
    $SourceFile,
    $Destination = "$env:USERPROFILE\DESKTOP\Computers.csv"
)


$Computers = Get-Content $SourceFile
$EmptyArray = @()

foreach($computer in $computers)
{
    $ResourceIDQuery = Get-WmiObject -Namespace "root\sms\site_$SiteCode" -Class SMS_R_SYSTEM -Filter "Name='$computer'"

    $CollectionQuery = Get-WmiObject -Namespace "root\sms\site_$SiteCode" -Class SMS_CollectionMember_a -filter "ResourceID='$($ResourceIDQuery.ResourceId)'"

    foreach($Item in $CollectionQuery)
    {
        $DObject = New-Object PSObject
            $Dobject | Add-Member -MemberType NoteProperty -Name "Computer" -Value $computer 
            $Dobject | Add-Member -MemberType NoteProperty -Name "ResID" -Value $($ResourceIDQuery.ResourceId)
            $Dobject | Add-Member -MemberType NoteProperty -Name "CollID" -Value $($Item.CollectionId)
            $Dobject | Add-Member -MemberType NoteProperty -Name "DirectOrNot" -Value $($Item.IsDirect)
        $EmptyArray += $Dobject
    }
}

$EmptyArray | ConvertTo-Csv -NoTypeInformation | Out-File $Destination

Solution

  • Rather than connecting to each computer and extracting the information (slow) get it from the straight from the database....

    [CmdletBinding()]
    param ( 
            [string] $hosts = "",
            [string] $sccmsrv = "",
            [Parameter(Mandatory=$False,Position=3)]
            [string] $path = ""
        )
    
    $usage =  "USAGE: List-AdvertCollMembershipSCCM.ps1 -sccmsrv SCCMSERVER -hosts 'host1 host2 host3' -path 'c:\temp\Outfile.csv'"
    
    if ($host -and $sccmsrv){
    
    Write-Host ""       
    Write-Host -ForegroundColor Yellow "SCCM Server: $sccmsrv"
    Write-Host -ForegroundColor Yellow "Looking at hosts: $hosts"
    
    
      #### Function for executing a SQL query with integrated authentication  
      function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){  
        $objConnection = New-Object System.Data.SqlClient.SqlConnection  
        $objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"  
        $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection  
        trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}   
        $SqlCmd.Connection.Open()  
    
        if ($SqlCmd.Connection.State -ine 'Open') {  
           $SqlCmd.Connection.Close()  
           return  
        }  
        $dr = $SqlCmd.ExecuteReader()  
    
        #get the data  
        $dt = new-object "System.Data.DataTable"  
        $dt.Load($dr)  
        $SqlCmd.Connection.Close()  
        $dr.Close()  
        $dr.Dispose()  
        $objConnection.Close()  
        return $dt  
      }  
    
      # read the SCCM site name of the SCCM site server  
      $site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode  
    
      # enumerating SQL server name for the given SCCM site server  
      $sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmsrv  
      [string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\\w+\\$")  
      $sccmSQLServer = $tmpstr.replace("\", "")  
      $objColl = @()  
    
      #### Collate the host list.  
      $hostlist = @($Input)  
      if ($hosts) {  
        if($hosts -imatch " "){  
           $hostsArr = @($hosts.split(" "))
           $hostlist += $hostsArr  
        }  
        else{  
           $hostlist += $hosts  
        }  
      }  
    
      # going through the list of hosts  
      foreach($srv in $hostlist){  
        $memberQuery = "SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name', dbo.v_Collection.CollectionID, dbo.v_FullCollectionMembership.IsDirect "  
        $memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID "  
        $memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"  
    
        # running sql query to enumerate list of collections the computer is member of  
        $membership = execSQLQuery $sccmSQLServer "SMS_$site" $memberQuery  
    
        # if we have a result, go through it and build an object collection with the computer name and the collection(s) it is member of  
        if($membership){  
           foreach($enumColl in $membership){
    
            $sObject = $enumColl | select Hostname, ResourceID, "Collection Name", CollectionID, IsDirect
            $objColl +=$sObject
    
           }  
        }  
      }
    
    
    if ($objColl){
        if ($path){
            $objColl | ft -AutoSize
            Write-Host -ForegroundColor Yellow "Exporting to results to: $path"
            $objColl | Export-Csv $path -NoTypeInformation
        }
        else{
        $objColl | ft -AutoSize
        Write-Host -ForegroundColor Green "Use the -path argument in the command line to export output to csv to display"
        Write-Host -ForegroundColor Green "the 'IsDirect' Information"
        Write-Host ""
        }
    }
    Else {
        foreach ($Hostname in $hostlist){
        Write-Host ""
        Write-Host -ForegroundColor Yellow "The host $hostname is not a member of any collection"
        }
    Write-Host -ForegroundColor Yellow "Check you have entered the correct hostname and try again"
    }
    }
    else {
    
        Write-Host ""
        Write-Host -ForegroundColor Yellow $usage
    }
    

    Execution:-

    PS C:\> ListSCCMCollections.ps1 -sccmsrv SCCMSERVER -hosts host1,host2,host3 -path "c:\temp\Outfile.csv"
    

    or

    PS C:\> Get-Content hostlist.txt | ListSCCMCollections.ps1 -sccmsrv SCCMSERVER -path c:\temp\Outfile.csv
    

    Getting the requested info straight from SQL:-

    SELECT     dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name', dbo.v_Collection.CollectionID, 
                          dbo.v_FullCollectionMembership.IsDirect
    FROM         dbo.v_FullCollectionMembership INNER JOIN
                          dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN
                          dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID
    WHERE     (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('Hostname'))
    

    This script can be used with any SQL query on the SCCM database. All you need to do is update the SQL query in the script. i.e. the $memberQuery array (if you spread the query over a couple of lines like below, be sure to leave a space at the end of each line with exception to the last).

    For example; If you'd like the script to show the clients collections with live advertisements assigned to them change the SQL query in the $memberQuery array to:-

    $memberQuery = "SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name',dbo.v_Collection.CollectionID, dbo.v_FullCollectionMembership.IsDirect, dbo.v_Advertisement.AdvertisementID, dbo.v_Advertisement.AdvertisementName "  
    $memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID INNER JOIN dbo.v_Advertisement ON dbo.v_Collection.CollectionID = dbo.v_Advertisement.CollectionID "  
    $memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"  
    

    and the $sObject variable to:-

    $sObject = $enumColl | select Hostname, ResourceID, "Collection Name", CollectionID, IsDirect, AdvertisementID, AdvertisementName
    

    Complete script to view client collections with live advisements (execution the same as before):-

    [CmdletBinding()]
    param ( 
            [string] $hosts = "",
            [string] $sccmsrv = "",
            [Parameter(Mandatory=$False,Position=3)]
            [string] $path = ""
        )
    
    $usage =  "USAGE: List-AdvertCollMembershipSCCM.ps1 -sccmsrv SCCMSERVER -hosts 'host1 host2 host3' -path 'c:\temp\Outfile.csv'"
    
    if ($host -and $sccmsrv){
    
    Write-Host ""       
    Write-Host -ForegroundColor Yellow "SCCM Server: $sccmsrv"
    Write-Host -ForegroundColor Yellow "Looking at hosts: $hosts"
    
    
      #### Function for executing a SQL query with integrated authentication  
      function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){  
        $objConnection = New-Object System.Data.SqlClient.SqlConnection  
        $objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"  
        $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection  
        trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}   
        $SqlCmd.Connection.Open()  
    
        if ($SqlCmd.Connection.State -ine 'Open') {  
           $SqlCmd.Connection.Close()  
           return  
        }  
        $dr = $SqlCmd.ExecuteReader()  
    
        #get the data  
        $dt = new-object "System.Data.DataTable"  
        $dt.Load($dr)  
        $SqlCmd.Connection.Close()  
        $dr.Close()  
        $dr.Dispose()  
        $objConnection.Close()  
        return $dt  
      }  
    
      # read the SCCM site name of the SCCM site server  
      $site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode  
    
      # enumerating SQL server name for the given SCCM site server  
      $sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmsrv  
      [string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\\w+\\$")  
      $sccmSQLServer = $tmpstr.replace("\", "")  
      $objColl = @()  
    
      #### Collate the host list.  
      $hostlist = @($Input)  
      if ($hosts) {  
        if($hosts -imatch " "){  
           $hostsArr = @($hosts.split(" "))
           $hostlist += $hostsArr  
        }  
        else{  
           $hostlist += $hosts  
        }  
      }  
    
      # going through the list of hosts  
      foreach($srv in $hostlist){  
        $memberQuery = "SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name',dbo.v_Collection.CollectionID, dbo.v_FullCollectionMembership.IsDirect, dbo.v_Advertisement.AdvertisementID, dbo.v_Advertisement.AdvertisementName "  
        $memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID INNER JOIN dbo.v_Advertisement ON dbo.v_Collection.CollectionID = dbo.v_Advertisement.CollectionID "  
        $memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"  
    
        # running sql query to enumerate list of collections the computer is member of  
        $membership = execSQLQuery $sccmSQLServer "SMS_$site" $memberQuery  
    
        # if we have a result, go through it and build an object collection with the computer name and the collection(s) it is member of  
        if($membership){  
           foreach($enumColl in $membership){
    
            $sObject = $enumColl | select Hostname, ResourceID, "Collection Name", CollectionID, IsDirect, AdvertisementID, AdvertisementName
            $objColl +=$sObject
    
           }  
        }  
      }
    if ($objColl){
        if ($path){
            $objColl | ft -AutoSize
            Write-Host -ForegroundColor Yellow "Exporting to results to: $path"
            $objColl | Export-Csv $path -NoTypeInformation
        }
        else{
        $objColl | ft -AutoSize
        Write-Host -ForegroundColor Green "Use the -path argument in the command line to export output to csv to display"
        Write-Host -ForegroundColor Green "the header 'AdvertisementName'"
        Write-Host ""
        }
    }
    Else {
        foreach ($Hostname in $hostlist){
        Write-Host ""
        Write-Host -ForegroundColor Yellow "The host $hostname is not a member of any collection with live advertisements"
        }
    Write-Host -ForegroundColor Yellow "Check you have entered the correct hostname and try again"
    }
    }
    else {
    
        Write-Host ""
        Write-Host -ForegroundColor Yellow $usage
    }