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
}
Nickolaj Andersen
Principal Consultant and Enterprise Mobility MVP. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows deployments and Automation. In 2015 Nickolaj was awarded as PowerShell Hero by the community for his script and tools contributions. Author of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService and a frequent speaker at user groups.

(219)

comments
  • Mike
    Posted at 22:07 July 25, 2016
    Mike
    Reply
    Author

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

  • Brett
    Posted at 14:26 July 26, 2016
    Brett
    Reply
    Author

    Thanks for sharing.

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

  • Dustin
    Posted at 15:51 July 29, 2016
    Dustin
    Reply
    Author

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

  • Brian Gonzalez
    Posted at 18:12 August 29, 2016
    Brian Gonzalez
    Reply
    Author

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

    -BG

  • Leave a Reply