PowerShell script template for ConfigMgr

205_1

I’ve recently been in the UK, where I presented on ConfigMgr and PowerShell. During my presentation, I showed a PowerShell script template that I normally use whenever I’m about to start creating a new script for ConfigMgr. I figured that I’d share this template, in addition to break it down in pieces to explain what it does and when to use what.

Script Template

Copy the script from below and save it as e.g. Template-ConfigMgr.ps1, or whatever you think is suitable.

Within this template, there’s a few things going on in the Begin block. Depending on what the purpose for the script you’re creating is, you may want to leverage all of the sections in the Begin block, or simply just remove those that doesn’t fit in. Most of my scripts always have a parameter called SiteServer, defined in the param() block, used to determine not only the Site Code from the SMS Provider, but also to point out what system to target when using e.g. Get-WmiObject with the ComputerName parameter.

Another useful section in the Begin block, is my custom way of loading the ConfigMgr PowerShell module. When you create a script, it should not have any restrictions in terms of what module it’s using, whether it’s from the old days or the new Cmdlets Library. So what I do is that I attempt to simply just run the Import-Module cmdlet, and if that fails, fall back to the old way of loading the psd1 file. In addition, I’ve also referenced how to load ConfigMgr related assemblies, if that should ever be needed. In most cases, it will not.

I suggest that you copy the whole template, and why not save it as a snippet in PowerShell ISE while you’re at it.

<#
.SYNOPSIS


.DESCRIPTION


.PARAMETER SiteServer
    Site server name with SMS Provider installed.

.PARAMETER ShowProgress
    Show a progressbar displaying the current operation.

.EXAMPLE
    

.NOTES
    FileName:    FileName.ps1
    Author:      Nickolaj Andersen
    Contact:     @NickolajA
    Created:     2016-03-22
    Updated:     2016-03-22
    Version:     1.0.0
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [parameter(Mandatory=$true, HelpMessage="Site server where the SMS Provider is installed.")]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Connection -ComputerName $_ -Count 1 -Quiet})]
    [string]$SiteServer,

    [parameter(Mandatory=$false, HelpMessage="Show a progressbar displaying the current operation.")]
    [switch]$ShowProgress
)
Begin {
    # Determine SiteCode from WMI
    try {
        Write-Verbose -Message "Determining Site Code for Site server: '$($SiteServer)'"
        $SiteCodeObjects = Get-WmiObject -Namespace "root\SMS" -Class SMS_ProviderLocation -ComputerName $SiteServer -ErrorAction Stop
        foreach ($SiteCodeObject in $SiteCodeObjects) {
            if ($SiteCodeObject.ProviderForLocalSite -eq $true) {
                $SiteCode = $SiteCodeObject.SiteCode
                Write-Verbose -Message "Site Code: $($SiteCode)"
            }
        }
    }
    catch [System.UnauthorizedAccessException] {
        Write-Warning -Message "Access denied" ; break
    }
    catch [System.Exception] {
        Write-Warning -Message "Unable to determine Site Code" ; break
    }

    # Load assemblies
    try {
        Add-Type -Path (Join-Path -Path (Get-Item $env:SMS_ADMIN_UI_PATH).Parent.FullName -ChildPath "Microsoft.ConfigurationManagement.ApplicationManagement.dll") -ErrorAction Stop
        Add-Type -Path (Join-Path -Path (Get-Item $env:SMS_ADMIN_UI_PATH).Parent.FullName -ChildPath "Microsoft.ConfigurationManagement.ApplicationManagement.Extender.dll") -ErrorAction Stop
        Add-Type -Path (Join-Path -Path (Get-Item $env:SMS_ADMIN_UI_PATH).Parent.FullName -ChildPath "Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll") -ErrorAction Stop
    }
    catch [System.UnauthorizedAccessException] {
        Write-Warning -Message "Access denied" ; break
    }
    catch [System.Exception] {
        Write-Warning -Message $_.Exception.Message ; break
    }

    # Load ConfigMgr module
    try {
        $SiteDrive = $SiteCode + ":"
        Import-Module -Name ConfigurationManager -ErrorAction Stop -Verbose:$false
    }
    catch [System.UnauthorizedAccessException] {
        Write-Warning -Message "Access denied" ; break
    }
    catch [System.Exception] {
        try {
            Import-Module -Name (Join-Path -Path (($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) -ChildPath "\ConfigurationManager.psd1") -Force -ErrorAction Stop -Verbose:$false
            if ((Get-PSDrive -Name $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) {
                New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer -ErrorAction Stop -Verbose:$false | Out-Null
            }
        }
        catch [System.UnauthorizedAccessException] {
            Write-Warning -Message "Access denied" ; break
        }
        catch [System.Exception] {
            Write-Warning -Message "$($_.Exception.Message). Line: $($_.InvocationInfo.ScriptLineNumber)" ; break
        }
    }

    # Determine and set location to the CMSite drive
    $CurrentLocation = $PSScriptRoot
    Set-Location -Path $SiteDrive -ErrorAction Stop -Verbose:$false

    # Disable Fast parameter usage check for Lazy properties
    $CMPSSuppressFastNotUsedCheck = $true
}
Process {
    if ($PSBoundParameters["ShowProgress"]) {
        $ProgressCount = 0
    }
    # Main code part goes here
}
End {
    Set-Location -Path $CurrentLocation
}

4 Comments

  1. Mike

    Pretty slick! I like it. I’ll have to work it into my scripts. Thanks for sharing.

    Reply
  2. Brett

    Thanks for sharing.

    Still find the PSCmdlets for SCCM a little bit like voodoo. Getting there slowly.

    Reply
  3. Dustin

    This is great! Do you have an example of how you implement the “ShowProgress” switch?

    Reply
  4. Brian Gonzalez

    Have you ever thought about using this wrapper as a base for your template?
    psappdeploytoolkit.com

    -BG

    Reply

Leave a Comment

Your email address will not be published. Required fields are marked *