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 }
Have you ever thought about using this wrapper as a base for your template?
psappdeploytoolkit.com
-BG
This is great! Do you have an example of how you implement the “ShowProgress” switch?
Thanks for sharing.
Still find the PSCmdlets for SCCM a little bit like voodoo. Getting there slowly.
Pretty slick! I like it. I’ll have to work it into my scripts. Thanks for sharing.