Fun with ConfigMgr 2007 and PowerShell

I needed some PowerShell practice this evening, so I did some experimentation to figure out how to interact with the ConfigMgr provider via PowerShell and WMI.  As a result of that experimentation, I’ve put together a module that you might find useful, if nothing else as a good example of how to do similar activities yourself.

A few notes:

  • I am using PowerShell v2 CTP 3 (download from https://www.microsoft.com/downloads/details.aspx?FamilyID=c913aeab-d7b4-4bb1-a958-ee6d7fe307bc&DisplayLang=en) for this, and it will not work with PowerShell v1 because I am using modules and advanced functions.
  • Because this is a PowerShell script, you’ll need to save the text below locally on your computer and make sure you’ve set the execution policy to something like “RemoteExecute”.  (The script isn’t signed.)
  • The script doesn’t currently support credentials for connecting to the ConfigMgr site – you can add that if you want, but I prefer to use the credentials of the currently-logged-on account.
  • Presently the script only does queries.  Creating and updating items are a little more dangerous (and as you can see below, deletes are trivial).

Here’s a brief description of each of the functions included in the module:

  • Connect-SCCMServer [-serverName <name>] [-siteCode <siteCode>]

    The Connect-SCCMServer method handles the details of connecting to the ConfigMgr provider (properly, by following the link from the site server to the provider server).  If you don’t specify a server name, the script will assume the local machine.  If you don’t specify a site code, it will use the default site code on the machine.  The resulting connection details (provider server name, site code, namespace path) are saved in global variables so that the other functions don’t require specifying all the same details.  (Yes, it gets a bit tiring to type those over and over again.

  • Get-SCCMObject -class <className> [-filter <filterText>]

    The Get-SCCMObject method is the base routine used for retrieving items from ConfigMgr.  Specify the class name (e.g. SMS_Package) and an optional filter (the where clause to insert in the WQL, e.g. “Name=’ABCD’”).  This function is used by all the other functions, so you don’t need to use this one directly if you don’t want to.

  • Get-SCCMPackage

  • Get-SCCMCollection

  • Get-SCCMAdvertisement

  • Get-SCCMDriver

  • Get-SCCMDriverPackage

  • Get-SCCMTaskSequence

  • Get-SCCMSite

  • Get-SCCMImagePackage

  • Get-SCCMOperatingSystemInstallPackage

  • Get-SCCMBootImagePackage

    These methods all take an optional “-filter” parameter (see above) and retrieve a list of the specified type of items.

  • Get-SCCMSiteDefinition

    This retrieves the site definition properites, used by the next function.

  • Get-SCCMIsR2

    This returns true if the site is running ConfigMgr R2 and false if it isn’t.

You can do fancier things with these too, if you want to get creative.  For example, assume you want to delete all drivers.  You could do something like this:

Import-Module C:\SCCM.PSM1

Connect-SCCMServer -serverName MYSERVER

Get-SCCMDriver  | % {$_.Delete()}

Here’s the actual script.

--- Snip ---

function Connect-SCCMServer {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $serverName,
        [Parameter(Position=2)] $siteCode
    )

    # Clear the results from any previous execution

    Clear-Variable -name sccmServer -errorAction SilentlyContinue
    Clear-Variable -name sccmNamespace -errorAction SilentlyContinue
    Clear-Variable -name sccmSiteCode -errorAction SilentlyContinue
    Clear-Variable -name sccmConnection -errorAction SilentlyContinue

    # If the $serverName is not specified, use "."

    if ($serverName -eq $null -or $serverName -eq "")
    {
        $serverName = "."
    }

    # Get the pointer to the provider for the site code

    if ($siteCode -eq $null -or $siteCode -eq "")
    {
        Write-Verbose "Getting provider location for default site on server $serverName"
        $providerLocation = get-wmiobject -query "select * from SMS_ProviderLocation where ProviderForLocalSite = true" -namespace "root\sms" -computername $serverName -errorAction Stop
    }
    else
    {
        Write-Verbose "Getting provider location for site $siteName on server $serverName"
        $providerLocation = get-wmiobject -query "select * from SMS_ProviderLocation where SiteCode = '$siteCode'" -namespace "root\sms" -computername $serverName -errorAction Stop
    }

    # Split up the namespace path

    $parts = $providerLocation.NamespacePath -split "\\", 4
    Write-Verbose "Provider is located on $($providerLocation.Machine) in namespace $($parts[3])"
    $global:sccmServer = $providerLocation.Machine
    $global:sccmNamespace = $parts[3]
    $global:sccmSiteCode = $providerLocation.SiteCode

     # Make sure we can get a connection

    $global:sccmConnection = [wmi]"${providerLocation.NamespacePath}"
    Write-Verbose "Successfully connected to the specified provider"
}

function Get-SCCMObject {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $class,
        [Parameter(Position=2)] $filter
    )

    if ($filter -eq $null -or $filter -eq "")
    {
        get-wmiobject -class $class -computername $sccmServer -namespace $sccmNamespace
    }
    else
    {
        get-wmiobject -query "select * from $class where $filter" -computername $sccmServer -namespace $sccmNamespace
    }
}

function Get-SCCMPackage {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_Package $filter
}

function Get-SCCMCollection {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_Collection $filter
}

function Get-SCCMAdvertisement {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_Advertisement $filter
}

function Get-SCCMDriver {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_Driver $filter
}

function Get-SCCMDriverPackage {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_DriverPackage $filter
}

function Get-SCCMTaskSequence {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_TaskSequence $filter
}

function Get-SCCMSite {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_Site $filter
}

function Get-SCCMImagePackage {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_ImagePackage $filter
}

function Get-SCCMOperatingSystemInstallPackage {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_OperatingSystemInstallPackage $filter
}

function Get-SCCMBootImagePackage {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1)] $filter
    )

    Get-SCCMObject SMS_BootImagePackage $filter
}

function Get-SCCMSiteDefinition {

    # Refresh the site control file

    Invoke-WmiMethod -path SMS_SiteControlFile -name RefreshSCF -argumentList $sccmSiteCode -computername $sccmServer -namespace $sccmNamespace

    # Get the site definition object for this site

    $siteDef = get-wmiobject -query "select * from SMS_SCI_SiteDefinition where SiteCode = '$sccmSiteCode' and FileType = 2" -computername $sccmServer -namespace $sccmNamespace

    # Return the Props list
    $siteDef | foreach-object { $_.Props }
}

function Get-SCCMIsR2 {

    $result = Get-SCCMSiteDefinition | ? {$_.PropertyName -eq "IsR2CapableRTM"}
    if (-not $result)
    {
        $false
    }
    elseif ($result.Value = 31)
    {
        $true
    }
    else
    {
        $false
    }
}

--- Snip ---

Save the text between the “--- Snip ---” lines (without actually including those lines) to a file named “SCCM.PSM1”.  Then run PowerShell (either the GUI or command line interfaces), load the script, connect to the site, and run a query or two:

Import-Module C:\SCCM.psm1

Connect-SCCMServer -serverName MYSERVER -siteCode CEN

Get-SCCMPackage | out-GridView

Get-SCCMDriver -filter "DriverProvider='Broadcom' "

All of this is warm-up for MMS 2009 at the end of this month…