Get ConfigMgr Collection rules

I’m in the process of installing Forefront Endpoint Protection and wanted to look at some of the collection queries that was created… but with the ConfigMgr console you cant view them…

So Powershell it is.

Did a function that you can use on any collection (with subcollections) to view the WQL.

Import-Module SCCM\SCCM-Functions -Force
Function Get-CollectionRules {
        PARAM (
                $parentCollection,
                $spacer,
                $sccm
        )

        $subCollections = Get-SCCMSubCollections -SccmServer $sccm -CollectionID $parentCollection

        if ($subCollections -ne $null) {
                $subCollections | ForEach-Object {
                        $collection = Get-SCCMCollection -Filter "CollectionID='$($_.subCollectionID)'" -SccmServer $sccm
                        Write-Host "$($spacer) Name: " -ForegroundColor Yellow -NoNewline
                        Write-Host "$($collection.CollectionID) - $($collection.Name)"

                        $collectionRule = (Get-SCCMCollectionRules -SccmServer ( Connect-SCCMServer ) -CollectionID $collection.CollectionID)
                        if ($collectionRule -ne $null) {
                                Write-Host "$($spacer)Limit: " -ForegroundColor Yellow -NoNewline
                                if ($collectionRule.LimitToCollectionID.Length -gt 0) {
                                        Write-Host "$($collectionRule.LimitToCollectionID)" -ForegroundColor White
                                } else {
                                        Write-Host "" -ForegroundColor Gray
                                }

                                Write-Host "$($spacer)  WQL: " -ForegroundColor Yellow -NoNewline
                                Write-Host "$($collectionRule.QueryExpression)"
                        } else {
                                Write-Host "$($spacer)" -ForegroundColor Gray
                        }
                        Write-Host ""

                        Get-CollectionRules -parentCollection $_.subCollectionID -spacer "   $($spacer)" -sccm $sccm
                }
        }
}

Get-CollectionRules -parentCollection "XYZ00123" -spacer "" -sccm (Connect-SCCMServer)

A small warning: It will loop all of the subcollections, and the subcollections subcollections, and so on…


InstallShield – No Log

Ok… It’s kind of hard to find any information on how to completely remove the need for a logfile when installing a InstallShield based setup file.

You can use:
-f2[some\path\to\a\LogFile]
To say where you want the logfile to go.

But… If you completely want to silence it use:
-f2x

It’s that simple, but it isn’t that simple to find the information.


Change Source-paths in ConfigMgr

I’m in the process of moving tons of packages to a new source.

So… I did a few new functions to my Powershell Module https://snowland.se/sccm-posh/ :-)

Update-SCCMDriverPkgSourcePath -sccmserver (Connect-SCCMServer) -currentPath "\\OLDSERVER\Source\DriverPackages" -newPath "\\NEWSERVER\Source\DriverPackages"
Update-SCCMPackageSourcePath -sccmserver (Connect-SCCMServer) -currentPath "\\OLDSERVER\Source\Packages" -newPath "\\NEWSERVER\Source\Packages"
Update-SCCMDriverSourcePath -sccmserver (Connect-SCCMServer) -currentPath "\\OLDSERVER\Source\DriverImport" -newPath "\\NEWSERVER\Source\DriverImport"

Oh… and I found some additional updates posted in German by Stefan Ringler … I don’t understand that many words of German, but I can read Powershell. :-P

Anyway, I included the updates in the module… thanks Stefan for sharing.


ConfigMrg Native Mode and site signing certificate

After trying to switch to native mode in ConfigMgr we got some errors from SMS_POLICY_PROVIDER saying “SMS Policy Provider has failed to sign one or more policy assignments. It will retry this operation automatically.”

Strange since we did follow a (this one) step-by-step guide from Microsoft.

After a few searches on Google and TechNet I found out that I needed to add a few lines in the request-file… FriendlyName and KeyLength…

[NewRequest]
FriendlyName = "ConfigMgr Site Signing ABC"
Subject = "CN=The site code of this site server is ABC"
MachineKeySet = True
KeyLength = 2048

[RequestAttributes]
CertificateTemplate = ConfigMgrSiteServerSigningCertificate

Then I requested a new cert with that file and used the new certificate instead… and a few minutes later SMS_POLICY_PROVIDER says “SMS Policy Provider successfully updated a settings policy and a settings policy assignment.”

:-)


Manufacturer / Model Collections with hierarchy

The last post made a flat structure of collections with “Manufacturer – Model”, in this post the script creates a hierarchy with (almost) the same collections.


The Model-collections queries are limited to the parent Manufacturer-collection.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                                                            Rikard Ronnkvist / snowland.se
#  Usage:
#   Download and install https://snowland.se/sccm-posh/
#   Save the file as CreateMM-collections-Hierarchy.ps1
#   PS:>.\CreateMM-collections-Hierarchy.ps1 -rootCollectionName "Name Of Some Collection"
#
#  2010-03-24   Rikard Ronnkvist    First snowland.se release
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PARAM (
        [string] $rootCollectionName = $(throw "rootCollectionName required."),
        [string] $hostName = (Get-Content env:computername),
        [switch] $Verbose,
        [Switch] $WhatIf
)

if ($verbose.IsPresent) {
        $VerbosePreference = 'Continue'
} Else {
        $VerbosePreference = 'SilentlyContinue'
}

Import-Module SCCM\SCCM-Functions -Force

Write-Verbose "Connect to SCCM-server $($hostName)"
$sccm = Connect-SCCMServer -HostName $hostName

Write-Host "Get root collection: ""$($rootCollectionName)"""
$rootCollection = Get-SCCMCollection -filter "Name='$($rootCollectionName)'" -sccmserver $sccm
if (!$rootCollection) {
        throw "Cant find ""$($rootCollectionName)"""
}
Write-Host "Found collection: $($rootCollection.CollectionID)"

Function checkAndCreate ($CollectionName, $ParentCollectionID, $wql, $limit = $null) {
        Write-Host "Checking ""$($CollectionName)""" -ForegroundColor Cyan
        $newCollection = Get-SCCMCollection -filter "Name='$($CollectionName)'" -sccmserver $sccm

        if (!$newCollection) {
                if (!$WhatIf.IsPresent) {
                        Write-Host "Creating collection: ""$($CollectionName)"""
                        $newCollection = New-SCCMCollection -name "$($CollectionName)" -SccmServer $sccm -parentCollectionID $ParentCollectionID -refreshDays 1 -Verbose
                } else {
                        Write-Host "What if: Creating collection: ""$($CollectionName)""" -ForegroundColor Red
                }

                if (!$WhatIf.IsPresent) {
                        Write-Verbose "Adding rule with WQL: $wql"
                        Add-SCCMCollectionRule -queryExpression $wql -Server $sccm -collectionID $newCollection.CollectionId -queryRuleName $CollectionName -limitToCollectionId $limit
                } else {
                        Write-Host "What if: Adding collection rule to new collection with wql: $($wql)" -ForegroundColor Red
                }
        } else {
                Write-Host "Found collection ""$($CollectionName)"""
        }

        return $newCollection
}

Write-Host "Lookup Manufacturer and Model"
$Manufacturer = Get-wmiobject -query "SELECT DISTINCT Manufacturer FROM SMS_G_System_COMPUTER_SYSTEM" -computername $Sccm.Machine -namespace $Sccm.Namespace | Sort-Object Manufacturer, Model
$Manufacturer | ForEach-Object {
        $wql = "SELECT * FROM SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_COMPUTER_SYSTEM.Manufacturer = '$($_.Manufacturer)'"
        $ManufacturerCollection = checkAndCreate -collectionName $_.Manufacturer -ParentCollectionID $rootCollection.CollectionId -wql $wql -limit $null

        $Model = Get-wmiobject -query "SELECT DISTINCT Model FROM SMS_G_System_COMPUTER_SYSTEM WHERE Manufacturer = '$($ManufacturerCollection.Name)'" -computername $Sccm.Machine -namespace $Sccm.Namespace | Sort-Object Manufacturer, Model
        $Model | ForEach-Object {
                $wql = "SELECT * FROM SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_COMPUTER_SYSTEM.Model = '$($_.Model)'"
                $ModelCollection = checkAndCreate -collectionName $_.Model -ParentCollectionID $ManufacturerCollection.CollectionId -wql $wql -limit $ManufacturerCollection.CollectionId
        }
}

Manufacturer / Model Collections

You have probably created one or two collections that points to a specific Manufacturer and/or Model.

Well, this script will look in to your SCCM-database and create that kind of collections for you.

First you need my SCCM Module for PowerShell
Then I created a collection named “000 – Manufacturer – Model”
Copy and paste the code below to a file, save it as CreateMM-collections.ps1
Run with at least one param, -rootCollectionName
Example: .\CreateMM-collections.ps1 -rootCollectionName “000 – Manufacturer – Model”

The script support the -WhatIf and -Verbose parameters… might be good to have when testing.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                                                            Rikard Ronnkvist / snowland.se
#  Usage:
#   Download and install https://snowland.se/sccm-posh/
#   Save the file as CreateMM-collections.ps1
#   PS:>.\CreateMM-collections.ps1 -rootCollectionName "Name Of Some Collection"
#
#  2010-03-23   Rikard Ronnkvist    First snowland.se release
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PARAM (
        [string] $rootCollectionName = $(throw "rootCollectionName required."),
        [string] $hostName = (Get-Content env:computername),
        [switch] $Verbose,
        [Switch] $WhatIf
)

if ($verbose.IsPresent) {
        $VerbosePreference = 'Continue'
} Else {
        $VerbosePreference = 'SilentlyContinue'
}

Import-Module SCCM\SCCM-Functions -Force

Write-Verbose "Connect to SCCM-server $($hostName)"
$sccm = Connect-SCCMServer -HostName $hostName

Write-Host "Get root collection: ""$($rootCollectionName)"""
$rootCollection = Get-SCCMCollection -filter "Name='$($rootCollectionName)'" -sccmserver $sccm
if (!$rootCollection) {
        throw "Cant find ""$($rootCollectionName)"""
}
Write-Host "Found collection: $($rootCollection.CollectionID)"

Write-Host "Lookup Manufacturer and Model"
$ManufacturerModel = Get-wmiobject -query "SELECT DISTINCT Manufacturer, Model FROM SMS_G_System_COMPUTER_SYSTEM" -computername $Sccm.Machine -namespace $Sccm.Namespace | Sort-Object Manufacturer, Model
$ManufacturerModel | ForEach-Object {
        $mmCollectionName = "$($_.Manufacturer) - $($_.Model)"
        Write-Host "Checking ""$($mmCollectionName)""" -ForegroundColor Cyan

        $mmCollection = Get-SCCMCollection -filter "Name='$($mmCollectionName)'" -sccmserver $sccm

        if (!$mmCollection) {
                if (!$WhatIf.IsPresent) {
                        Write-Host "Creating collection: ""$($mmCollectionName)"""
                        $newMmCollection = New-SCCMCollection -name "$($mmCollectionName)" -SccmServer $sccm -parentCollectionID $rootCollection.CollectionID -refreshDays 1
                } else {
                        Write-Host "What if: Creating collection: ""$($mmCollectionName)""" -ForegroundColor Red
                }

                $wql = "SELECT * FROM SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_COMPUTER_SYSTEM.Manufacturer = '$($_.Manufacturer)'  AND SMS_G_System_COMPUTER_SYSTEM.Model = '$($_.Model)'"
                if (!$WhatIf.IsPresent) {
                        Write-Verbose "Adding rule with WQL: $wql"
                        Add-SCCMCollectionRule -queryExpression $wql -Server $sccm -collectionID $newMmCollection.CollectionId -queryRuleName $mmCollectionName
                } else {
                        Write-Host "What if: Adding collection rule to new collection with wql: $($wql)" -ForegroundColor Red
                }
        } else {
                Write-Host "Found collection"
        }
}

SCCM Module for PowerShell

In a post a few days ago I mentioned “some slightly modified functions from Michael Niehaus“.

Well… Why not share them.

Save this as a module, load it and play around.

2010-03-26 – Moved to https://snowland.se/sccm-posh/

Some examples on what you can do:

# List all available SCCM commands
Get-SCCMCommands

# Create an SCCM-Connection to the local server
$sccm = Connect-SCCMServer -Verbose

# Create a new collection with a collection rule
$newCollection = New-SCCMCollection -SccmServer $sccm -name "Some Collection Name" -Verbose
Add-SCCMCollectionRule -Server $sccm -collectionID $newRoot.CollectionId -queryExpression "SELECT * FROM SMS_R_System" -queryRuleName "All Systems" -Verbose

# Count files in the inboxes
$sccm | Get-SCCMInboxes

# Get a package
$MyPackage = Get-SCCMPackage -server $sccm -filter "Name = 'Some Package Name'"

If you have some comments, ideas and things to add… Comment this post or shoot me an .


Add text to images with PowerShell

Been working on some server deployment lately and had some problems with the WinPE… so to not get to confused when using different PE’s to boot up the servers we added some image-information on the background.

Did that in MS Paint… but how fun is that? :-P

Here is a cool function that add some text to a image (Original code from http://www.ravichaganti.com/blog/?p=1012)

Function AddTextToImage {
        # Orignal code from http://www.ravichaganti.com/blog/?p=1012
        [CmdletBinding()]
        PARAM (
                [Parameter(Mandatory=$true)][String] $sourcePath,
                [Parameter(Mandatory=$true)][String] $destPath,
                [Parameter(Mandatory=$true)][String] $Title,
                [Parameter()][String] $Description = $null
        )

        Write-Verbose "Load System.Drawing"
        [Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null

        Write-Verbose "Get the image from $sourcePath"
        $srcImg = [System.Drawing.Image]::FromFile($sourcePath)

        Write-Verbose "Create a bitmap as $destPath"
        $bmpFile = new-object System.Drawing.Bitmap([int]($srcImg.width)),([int]($srcImg.height))

        Write-Verbose "Intialize Graphics"
        $Image = [System.Drawing.Graphics]::FromImage($bmpFile)
        $Image.SmoothingMode = "AntiAlias"

        $Rectangle = New-Object Drawing.Rectangle 0, 0, $srcImg.Width, $srcImg.Height
        $Image.DrawImage($srcImg, $Rectangle, 0, 0, $srcImg.Width, $srcImg.Height, ([Drawing.GraphicsUnit]::Pixel))

        Write-Verbose "Draw title: $Title"
        $Font = new-object System.Drawing.Font("Verdana", 24)
        $Brush = New-Object Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(255, 0, 0,0))
        $Image.DrawString($Title, $Font, $Brush, 10, 10)

        if ($Description -ne $null) {
                Write-Verbose "Draw description: $Description"
                $Font = New-object System.Drawing.Font("Verdana", 12)
                $Brush = New-Object Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(120, 0, 0, 0))
                $Image.DrawString($Description, $Font, $Brush, 10, 50)
        }

        Write-Verbose "Save and close the files"
        $bmpFile.save($destPath, [System.Drawing.Imaging.ImageFormat]::Bmp)
        $bmpFile.Dispose()
        $srcImg.Dispose()
}

With that piece of code and some slightly modified functions from Michael Niehaus you can do some cool stuff…

$taskSequence = "Server Deployment Task Sequence"

Import-Module Misc\Image-Functions.psm1
Import-Module SCCM\SCCM-Functions.psm1

$sccm = Connect-SCCMServer
$taskSequence = Get-TaskSequencePackage -SccmServer $sccm -filter "Name = '$taskSequence'"
$BootImage = Get-BootImagePackage -SccmServer $sccm -filter "PackageID = '$($taskSequence.BootImageID)'"
$DescriptionText = "Version:`t$($BootImage.Version)`nPackageID:`t$($BootImage.PackageID)`n`n$($BootImage.Description)"

AddTextToImage -sourcePath "X:\Path\WinPE-Background-Source.bmp" -destPath "X:\Path\WinPE-Background-To-Inject.bmp" -Title $BootImage.Name -Description $DescriptionText

Shouldn’t be that hard to auto-inject the BMP to the WIM file…


PSOL: Count files in SCCM-inboxes – Version 3

A bit more simple version of the last script… this time as a PowerShell oneliner.

Get-ChildItem \\MYSERVER\SMS_C01\inboxes -Recurse | Group-Object Directory | Where { $_.Count -gt 1 }  | Sort-Object Count -Descending | Format-Table Count, Name -AutoSize

SCCM Console Extensions – Parameters

OK, so now you know the GUID for the right-click tool… but what about passing parameters?

There are a few standard SUB’s (parameters) that you can use, some are listed in this post: https://snowland.se/2008/05/28/sccm-console-extensions/

But if you take the example of GUID 5fb29b42-5d11-4642-a6c9-24881a7d317e that you can find under Software Distribution Packages / Packages / Some package / Package Status / Site Server / Right click on a distribution point

Say that you want to pass the server-name or the path to the package…

First off, open the E:\Program Files\Microsoft Configuration Manager\AdminUI\XmlStorage\ConsoleRoot\AdminConsole.xml in some editor.

Then search for the GUID and you will find something like this.


  
    
      
        
          
            SMS_PackageStatusDetailSummarizer
          
          SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE PackageID='##SUB:PackageID##' AND SiteCode='##SUB:SiteCode##'
          SMS_PackageStatusDistPointsSummarizer
        
      
    
  

A few lines below the GUID you find SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE Packa… Copy that line and replace/clean it up so that it is a valid WMI-query.
Will look something like:

SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE PackageID='XYZ00123' AND SiteCode='XYZ'

Next step is to start some WMI-browser and connect to root\SMS\site_XYZ and run the query and take a look at the columns.
(I like to use WMI Explorer)

In the query above you will have columns like ServerNALPath, SourceNALPath, SourceVersion this is what you are looking for. :-)

Use them in your extensions like this:


        myScript.vbs
        ##SUB:ServerNALPath## ##SUB:SourceNALPath## ##SUB:SourceVersion##


Next Page »