Category: ConfigMgr

System Center Configuration Manager

Silent patching and controlled reboots

Patching silently and installing applications without any user interaction… This is really hard to do and it’s really hard to get compliant machines if you do not force a reboot every now and then.
Then, if you force the user to reboot with a short timeout they will not be to happy.
So… to solve this I took some inspiration from a couple of blogposts some scripts and then some of my knowledge and put together a recipe that I think work’s really nice. 🙂

All in all, this results in a nice popup (only when a reboot is needed) that gives the user a good amount of time to decide when to reboot.
With this in place you can push out updates and applications silently and then just sit back and wait for the users to reboot when they want to.

So, this is what you need to do…

Copy the following files to %ProgramFiles%\RebootIfNeeded

Create a Scheduled Task that runs once or twice every day (I have it set at 08:00 and 13:00 every weekday), and on that task create an with the following configuration:
Program: %ProgramFiles%\RebootIfNeeded\hstart64.exe

/NOCONSOLE /WAIT ""%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -File "%ProgramFiles%\RebootIfNeeded\RebootIfNeeded.ps1""

(Tip: If using GPP, set item level targeting to check that the PS1-file exist before creating the task)

The script will check for pending reboots and if the computer havn’t rebooted for XX days.
You can add support for more languages, just extend the hashtable $restartDescriptions

    $maxBootAgeDays = 35,
    $restartTimeOut = (9 * 60), # 9 hours
    $restartMaxPostpone = (48 * 60), # 48 hours
    $restartDescriptions = @{
        "en-US" = "Your computer needs to restart to receive the latest updates.";
        "sv-SE" = "Din dator behöver startas om för att få de senaste uppdateringarna.";
    $defaultLanguage = "en-US"

Function Get-PendingReboot {
	# Local HKLM
	$HKLM = [UInt32] "0x80000002"
	$wmiRegistry = [WMIClass] "\\.\root\default:StdRegProv"

    $PendingReboot = $false

	# CBS - Reboot Required ?
	$RegSubKeysCBS = $wmiRegistry.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")
	if ($RegSubKeysCBS.sNames -contains "RebootPending") {
        Write-Verbose "Component Based Servicing have a reboot pending"
		$PendingReboot = $true
	# Windows Update - Reboot Required?
	$RegistryWUAU = $wmiRegistry.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
	if ($RegistryWUAU.sNames -contains "RebootRequired") {
        Write-Verbose "Windows Update have a reboot required"
		$PendingReboot = $true

	## Pending FileRenameOperations ?
	$RegSubKeySM = $wmiRegistry.GetMultiStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations")
	If ($RegSubKeySM.sValue) {
        $RegSubKeySM.sValue | ForEach-Object { 
        	If ($_.Trim() -ne '') {
        		Write-Verbose "Pending FileRename operation: $($_)"
		$PendingReboot = $true

	# ConfigMgr - Pending reboot ?
	TRY {
	    $CCMClientSDK = Invoke-WmiMethod -NameSpace "ROOT\ccm\ClientSDK" -Class "CCM_ClientUtilities" -Name "DetermineIfRebootPending" -ErrorAction Stop

		If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) {
            Write-Verbose "ConfigMgr have reboot pending"
            $PendingReboot = $true
	} CATCH {
        Write-Verbose "Cant talk to ConfigMgr Agent"

    Write-Verbose "Pending reboot: $($PendingReboot)"
    Return $PendingReboot

Function Check-OldBootAge {
    PARAM (
        $maxAgeDays = 35

    $BootTime = Get-WmiObject  Win32_Operatingsystem
    [Int]$days = (New-TimeSpan -Start $boottime.ConvertToDateTime($boottime.LastBootUpTime) -End (Get-Date)).TotalDays

    if ($days -ge $maxAgeDays) {
        Write-Verbose "Boot age is $($days) days (more than $($maxBootAgeDays)), reboot required"
        Return $true
    } else {
        Write-Verbose "Boot age is $($days) days (less than $($maxBootAgeDays))"
        Return $false

    Return $days

Function Get-UserLanguage {
    Return [String] ([System.Threading.Thread]::CurrentThread).CurrentUICulture.Name

# ------------------------------------------------------------------------------------------------------------
# Main script

if ( (Get-WmiObject -Query "SELECT ProductType FROM Win32_OperatingSystem").ProductType -eq 1) {

    If ( (Get-Process "ShutdownTool" -ErrorAction SilentlyContinue) ) {
        Write-Host "Already running ShutdownTool"
    } else {
        If ((Check-OldBootAge -maxAgeDays $maxBootAgeDays) -or (Get-PendingReboot)) {
            Write-Host "Reboot is required, calling restart utility"

            $userLanguage = Get-UserLanguage
            Write-Verbose "Language: $($userLanguage)"

            # Find description
            $Description = $restartDescriptions[$userLanguage]
            if ($Description -eq $null) {
                $Description = $restartDescriptions[$defaultLanguage]

            $timeOutSeconds = ($restartTimeOut*60) - 1

            Write-Verbose "Restart timeout: $($timeOutSeconds) seconds"
            Write-Verbose "Max postpone: $($restartMaxPostpone) minutes"
            Write-Verbose "Description: $($Description)"

            If ((Test-Path ".\ShutdownTool.exe") -eq $false) {
                Throw "Cant find ShutdownTool.exe"
            } else {
                Write-Verbose "Calling restart with ShutdownTool"
                .\ShutdownTool.exe /g:$userLanguage /d:"$Description" /t:$timeOutSeconds /m:$restartMaxPostpone /r /c

            # /g - Language
            # /d - description
            # /t - countdown in sec
            # /m - max postpone in min
            # /r - reboot instead of shutdown
            # /c - force & remove abort-btn

} else {
    Write-Verbose "Not a client OS"
# Done!

Refresh ConfigMgr content where it’s needed

This script will check for content that needs to be refreshed, in this case its content of types like packages, applications, drivers, etc that have the state Retrying or Failed on one or more DPs.
When the script find some content error it will refresh on that DP.

    $sccmServer = "",
    $sccmSiteCode = "ABC",
    $failStates = "2, 3, 5, 6", # Retrying and Failed (Both Install and Removal)
    $packageTypes = "0, 3, 4, 8, 257, 258" # Not checking 5 (SUP) due to automatic deployments

Write-Host "Searching for failed content distributions"
ForEach ($FailedDist in (Get-WmiObject -ComputerName $sccmServer -Namespace "ROOT\SMS\Site_$($sccmSiteCode)" -Query "SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE State IN ($($failStates)) AND PackageType IN ($($packageTypes))" | Sort-Object PackageID)) {
    # Figure out servername from NalPath
    $failedServer = $FailedDist.ServerNALPath.Substring($FailedDist.ServerNALPath.LastIndexOf("]")+3).Trim("\")

    # Get the distribution points that content wouldn't distribute to
    ForEach ($FailedDPDist in (Get-WmiObject -ComputerName $sccmServer -Namespace "ROOT\SMS\Site_$($sccmSiteCode)" -Query "SELECT * FROM SMS_DistributionPoint WHERE SiteCode='$($FailedDist.SiteCode)' AND PackageID='$($FailedDist.PackageID)' AND ServerNALPath LIKE '%$($failedServer)%'") ) {
        # Refresh content on the selected DP
        Write-Host "Refreshing $($FailedDPDist.PackageID), type $($FailedDist.PackageType) in state $($FailedDist.State) on $($failedServer)"
        $FailedDPDist.RefreshNow = $true
        $FailedDPDist.Put() | Out-Null

Write-Host "Done!"

Export / Import boot image drivers (needed before ADK upgrade)

If you want to deploy Windows 10 you probably need to upgrade your ADK… and when you have done your upgrade you can’t see any drivers on boot images in the ConfigMgr console.

So, to get your “old” drivers in to your new boot image, export them to a XML-file before the upgrade and then when the upgrade is done just import them.

The two functions you need

Function Export-BootImageDrivers {
    PARAM (
        [String] $ImageId,
        [String] $ExportXml
    $drivers = @{}
    (Get-CMBootImage -Id $ImageId).ReferencedDrivers | ForEach-Object {
        Write-Verbose "Found driver ID - $($_.Id)"

        $drivers.Add($_.Id, $_.SourcePath)

    $drivers | Export-Clixml -Path $ExportXml

Function Import-BootImageDrivers {
    PARAM (
        [String] $ImageId,
        [String] $ExportXml

    $BootImage = Get-CMBootImage -Id $ImageId
    $drivers = Import-Clixml -Path $ExportXml
    $drivers.GetEnumerator() | ForEach-Object {
        Write-Verbose "Adding driver ID - $($_.Name)"
        Set-CMDriver -Id $_.Name -AddBootImagePackage $BootImage -UpdateDistributionPointsforBootImagePackage $false -Force

First run the export

Export-BootImageDrivers -ImageId "ABC00123" -ExportXml "C:\Stuff\drivers.xml"

Then when the upgrade is done, import them

Import-BootImageDrivers -ImageId "ABC00345" -ExportXml "C:\Stuff\drivers.xml"

Written by Comments Off on Export / Import boot image drivers (needed before ADK upgrade) Posted in ConfigMgr

Copy drivers from one boot image to another

When you have a new ConfigMgr boot image ready but are missing some drivers from an old one… might be hard to find them in a larger structure.

… Powershell to the rescue! 🙂

Function Copy-BootImageDrivers {
    PARAM (
        $from, $to

    $boot = Get-CMBootImage -ID $to

    (Get-CMBootImage -Id $from).ReferencedDrivers | ForEach-Object {
        Write-Verbose "Copying $($_.Id) to $($to)"
        Set-CMDriver -Id $_.Id -AddBootImagePackage $boot -UpdateDistributionPointsforBootImagePackage $false


#Example use
Copy-BootImageDrivers -from "ABC00123" -to "ABC00456"

Exclude updates during OS Deployment

With A LOT of inspiration from a blogpost by The Deploymentguys I wrote a couple of scripts that do not require internet access during OSD.

First, I have a script that pulls the KB and extracts KB-numbers to an XML-file.
Second, there is a script you run during OSD that reads the XML-file(s) and create thre TS env variable(s).

The script to update the XML-file from the online KB.

    [string] $KB = "2894518"

$url = "$($KB)"
    Write-Host "Retrieving list from $($url)"
    $result = Invoke-WebRequest $url -ErrorAction Stop
    THROW "Error retrieving KBs from $($url)"

$ExcludeKBs = @()
$result.AllElements | Where Class -eq "plink" | ForEach-Object {
    $pos = $_.innertext.indexof('/kb/') + 3

    #If Valid KB Hyperlink
    if ($pos -gt 3) {
        #String Cleansing, final ExcludeKB = 1234567
        $ExcludeKB = $_.innertext.Substring($pos,$_.innertext.Length-$POS).Trim().Replace('/','').Replace(')','').Trim()

        Write-Host "Found KB to exclude: $($ExcludeKB)"
        $ExcludeKBs += $ExcludeKB

if ($ExcludeKBs.Length -ne 0) { 
    $xmlPath = (Join-Path (Split-Path $MyInvocation.MyCommand.Definition -Parent) "exclude-auto-KB$($KB).xml")
    Write-Host "Exporting list to $($xmlPath)"
    $ExcludeKBs | Export-Clixml -Path $xmlPath

    Write-Host "Exit with code 0"
    Exit 0
} else {
    Write-Host "Exit with error code 99 (Didnt find any KBs)"
    Exit 99

Then the script to run during deployment.

    [string] $xmlFiles = "exclude-*.xml"

    $tsEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction SilentlyContinue
    Write-Host "Cant create TS Environment"
    $tsEnv = $null

$ExcludeKBs = @()
Get-ChildItem -Path "$(Split-Path $MyInvocation.MyCommand.Definition -Parent)\*" -Include $xmlFiles | Foreach-Object {
    Write-Host "Importing KBs from $($_.FullName)"
    $ExcludeKBs += Import-Clixml -Path $_.FullName

$i = 1
$ExcludeKBs | Sort-Object -Unique | ForEach-Object {
    # Build variable number with zero-padding
    $tsi = "000$($i)"
    $tsi = $tsi.Substring(($tsi.ToString().Length - 3), 3)

    if ($tsEnv -ne $null) {
        Write-Host "Adding TS Variable:  WUMU_ExcludeKB$($tsi) = $($_)"
        $tsEnv.Value("WUMU_ExcludeKB$($tsi)") = $_
    } else {
        Write-Host "Cant add TS Variable:  WUMU_ExcludeKB$($tsi) = $($_)"

    $i ++

if ($tsEnv -eq $null) {
    Write-Host "Exit with error code 99 (Missing TS Environment)"
    Exit 99
} else {
    Write-Host "Exit with code 0"
    Exit 0

And, as a bonus you can specify multiple XML-files with updates you want to exclude… Name a file “exclude-blaha.xml” and let it have a content like this:

<Objs Version="" xmlns="">

Then drop it in the same folder as the other XML and you should be good to go.

Written by Comments Off on Exclude updates during OS Deployment Posted in ConfigMgr

Create Site Roles Collections

Quick and easy way to create device collections based on site roles:

$wmiParams = @{
    "Namespace" = "root\SMS\site_ABC";
    "Query" = "SELECT RoleName FROM SMS_SystemResourceList"

Get-wmiobject @wmiParams  | Group-Object RoleName | ForEach-Object {
    Write-Verbose "Creating collection for role $($_.Name)"
    $newCollection = New-CMDeviceCollection -Name "ConfigMgr-Role $($_.Name)" -LimitingCollectionID "SMS00001" -RefreshType Periodic -RefreshSchedule (New-CMSchedule -RecurInterval Days -RecurCount 4 -Start (Get-Date))
    $query = "SELECT * FROM SMS_R_System WHERE SMS_R_System.SystemRoles = '$($_.Name)'"
    Add-CMDeviceCollectionQueryMembershipRule -CollectionId $newCollection.CollectionID -QueryExpression $query -RuleName "CMRole-$($_.Name)"

You will end up with collections like:
– ConfigMgr-Role SMS Distribution Point
– ConfigMgr-Role SMS Device Management Point
– ConfigMgr-Role … and so on …

Stand Alone Media and USB 3

I’m testing some Stand Alone USB Media for deployment of Windows 7 and 8…

Ran in to a few problems…

First off, it’s not to easy to find a USB-Stick with at least 32 Gb that is bootable.
We found that Kingston DataTraveler R3.0 (rubber like casing) works OK to boot from…

Second, keep the volume size under 32 GB.
Since it will be a FAT32 Volume you need to create a partition at 32 (or less) GB. (Remember that it needs to be active)

Third, when using a USB3 port on the computer you will probably run in to problems if you try to install USB3-drivers.
Workaround is to plug the stick in to a USB2 port.

Fourth, when only having USB3 ports you can run in to issues accessing the files.
A simple workaround is to get a simple USB-Hub that uses USB2… with that you will downgrade your USB3-stick to a USB2-stick and everything works just fine. 🙂

Fifht, when using custom scripts in MDT you might run in to issues if you use “Start in” and then point out something like “%deployroot%\MyScripts” as folder and a command line like “cscript script.vbs”
To solve this, use a command line like “cscript %DeployRoot%\MyScripts\script.vbs” and empty out the “Start in” folder.

Written by Comments Off on Stand Alone Media and USB 3 Posted in ConfigMgr

Get filename in ConfigMgr 2012 ContentLib

In ConfigMgr 2007 it was kind of convinient to be able to edit files directly on a DP, in ConfigMgr 2012 that isn’t to easy if you are using Content Library.

There are a few ways to find out where the files are actually stored, here is one way:

(Will give you the path to somefile.xml in package ABC01234)

	$siteCode = "ABC",
	$FileName = "somefile.xml",
	$PackageID = "ABC01234",
	$ContentLib = "D:\SCCMContentLib"
Import-Module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1')
Set-Location "$($siteCode):"

$package = Get-CMPackage -ID $PackageID
$hash = (Get-Content "$($ContentLib)\DataLib\$($package.PackageID).$($package.StoredPkgVersion)\$($FileName).INI" | Where-Object { $_ -like "Hash=*" }).Replace("Hash=", "")
$storePath =  Join-Path "$($ContentLib)\FileLib" "$($hash.Substring(0,4))\$($hash)"

$sourcePath = Join-Path $package.PkgSourcePath $FileName

Write-Host "Source: $($sourcePath)"
Write-Host "Store : $($storePath)"

Will result in something like this:

Source: \\server\share\path\to\package source\somefile.xml
Store : D:\SCCMContentLib\FileLib\A123\A1234567890ABCDEF1234567890ABCDEF

And with this you can edit the XML-file directly on the store instead of editing source, update DPs, wait for processing, wait some more…

… but, I’m not saying that I recommend anyone to edit files directly in the store. 😉

ConfigMgr Package Status Reports

Found a nice idea for a report on Eswar Koneti’s blog. That query combined with some info from a blogpost by Jörgen Nilsson will give you two reports to dig into status of packages.

Status of Distribution Points with Package Compliance

	CDR.PkgCount AS Targeted,
	CDR.NumberInstalled AS Installed,
	CDR.PkgCount-CDR.NumberInstalled AS NotInstalled,
	PSd.SiteCode AS ReportingSite,
	ROUND((100 * CDR.NumberInstalled/CDR.pkgcount), 2) AS Compliance

	v_ContentDistributionReport_DP CDR LEFT JOIN v_PackageStatusDistPointsSumm PSd

This report can be linked into the next one (using DPNalPath as a parameter)

Package Compliance on a single Distribution Point

Updated 2013-10-08 Join in tables instead of Select Case on State and PackageType

	v_ContentDistribution.State AS StateNo,
	DPStatusInfo.StateName AS State,
	v_ContentDistribution.PkgID AS PackageID,
	v_ContentDistribution.PackageType AS PackageTypeNo,
	SMSPackageTypes.Name AS PackageType,
	SUBSTRING(v_ContentDistribution.Path,CHARINDEX(']', v_ContentDistribution.Path)+1, LEN(v_ContentDistribution.Path) - CHARINDEX(']', v_ContentDistribution.Path)-1) AS PackagePath,

	v_ContentDistribution LEFT JOIN DPStatusInfo ON v_ContentDistribution.State = DPStatusInfo.State
	LEFT JOIN SMSPackageTypes ON v_ContentDistribution.PackageType = SMSPackageTypes.PackageTypeID

WHERE DistributionPoint = @DistributionPoint

This report need a parameter for DistributionPoint, to list all in a drop-down, use the query below on the parameter. (If you want to use the report without going thru a link)

	SiteCode + ' - ' + SUBSTRING(ServerNALPath,CHARINDEX(']\\', ServerNALPath)+3, LEN(ServerNALPath) - CHARINDEX(']\\', ServerNALPath)-3) AS DistributionPoint
FROM v_DistributionPoint

Update ConfigMgr packages with Hotfix-information

When you install a hotfix and/or a cumulative update in ConfigMgr you can select the option to let the installer create some packages.

But, those packages are missing some info… For instance Manufacturer and Version.

A quick and dirty SQL update will do the trick.

	Version = LEFT(Replace(Source, '\\\SMS_ABC\hotfix\', ''), 9),
	Manufacturer = 'Microsoft',
	Language = 'All'
WHERE Source LIKE '\\\SMS_ABC\Hotfix%'

This is of course not supported… but afaik it works. 😀

If you want to see what would be updated, run this first

	Version AS OrgVersion,
	LEFT(Replace(Source, '\\\SMS_ABC\hotfix\', ''), 9) AS NewVersion,
	Manufacturer AS OrgManufacturer,
	'Microsoft' AS NewManufacturer,
	Language AS OrgLanguage,
	'All' AS NewLanguage
FROM SMSPackages_G
WHERE Source LIKE '\\\SMS_ABC\hotfix\%'

(And yes, you need to replace servername and sitecode)

Get-ADSites and create Site Based Collections

Missing an easy way to get AD-Sites from Powershell?

They are listed under Sistes/Configuration with the objectClass = Site. So a simple LDAP-query does the trick.

Get-ADSites {
	Return Get-AdObject -LdapFilter "(ObjectClass=site)" -SearchBase "CN=Sites,CN=Configuration,$((Get-AdDomain).DistinguishedName)"

Then, with these sites it’s easy to create Device Collections in ConfigMgr based on what AD-Site the client reports.

Get-ADSites | ForEach-Object {
	$newCollection = New-CMDeviceCollection -Name "AD-Site $($_.Name)" -LimitingCollectionID "SMS00001" -RefreshType Periodic -RefreshSchedule (New-CMSchedule -RecurInterval Days -RecurCount 1 -Start (Get-Date))
	$query = "SELECT * FROM SMS_R_System WHERE SMS_R_System.ADSiteName = '$($_.Name)'"
	Add-CMDeviceCollectionQueryMembershipRule -CollectionId $newCollection.CollectionID -QueryExpression $query -RuleName "ADSite-$($_.Name)"

Remove all direct memberships from collections

If you are using direct memberships to speed up ConfigMgr, you probably want to clean it up when your collection query is good to go…

The problem is to find all direct memberships since Get-CMUserCollectionDirectMembershipRule doesn’t allow wildcards. But there is a WMI-class with all members…

Function Remove-AllDirectMemberships {
		[string] $sccmSite = "ABC",
		[string] $collectionNameFilter = "SomePrefix*"

	Get-CMUserCollection -Name $collectionNameFilter | ForEach-Object {
		$Collection = $_
		Write-host "$($Collection.Name)"
		Get-WmiObject -Class $_.MemberClassName -Namespace "ROOT\SMS\Site_$($sccmSite)" | Foreach-Object {
			If ($_.IsDirect -eq $true ) {
				Write-host "- Removing $($_.ResourceID)"
				Remove-CMUserCollectionDirectMembershipRule -CollectionId $Collection.CollectionID -ResourceId $_.ResourceID -Force

Load ConfigMgr 2012 Powershell Modules

If you want to load the modules for Configuration Manager 2012 outside of the Admin Console there are a few prereqs… You need a 32 Bit Powershell prompt and you need to run is at admin and of course you need the module.

When writing a script it’s probably a good idea to check that the user that runs the script have the prereqs fulfilled.

This is one way to do it:

# Check if you are a local admin
If ((New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -eq $false) {
	Throw "Need to run as Administrator"

# Check that youre not running X64
if ([Environment]::Is64BitProcess -eq $True) {
	Throw "Need to run at a X86 PowershellPrompt"

# Test the path and load ConfigMgr cmdlets
If ($Env:SMS_ADMIN_UI_PATH -eq $null) {
	Throw "Missing SMS_ADMIN_UI_PATH environment variable"
$cmModulePath = $Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + "\ConfigurationManager.psd1"
If ((Test-Path $cmModulePath) -eq $false) {
	Throw "Can't find $($cmModulePath)"
Write-Verbose "Loading ConfigMgr Modules"
Import-Module $cmModulePath

# Now you are good to go...
Get-Command -Module ConfigurationManager

# You probably need to set location to the site before you start to play around...
Set-Location "ABC:"

And here is the version i use in my profile to load the modules… A bit more compressed and without the Throw lines so I can use the same profile with or without the prereqs fulfilled.

If ( `
		((New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -eq $true) `
		-and `
		([Environment]::Is64BitProcess -eq $false) `
		-and `
		($Env:SMS_ADMIN_UI_PATH -ne $null)
	) {
	$cmModulePath = $Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + "\ConfigurationManager.psd1"
	If ((Test-Path $cmModulePath)) {
		Write-Verbose "Loading ConfigMgr Modules"
		Import-Module $cmModulePath

Not sure where youre profile is located?

$profile | Format-List -Force
# Easy way to edit it:
PowerShell_ISE.exe $profile

Logon Scripts in Powershell – Part4: Trigger ConfigMgr client actions

With the ConfigMgr agent in place on your client’s you probably want to force it to start some client actions on logon to speed up deployment of new applications.

This function will work with the ConfigMgr 2007 (on x86) and 2012 agent. (The reason for not working on a Win7 x64 and ConfigMgr 2007 is the lack of X64 support).

Function Run-ConfigMgrActions {
		Trigger ConfigMgr client actions
		[string] $actionFilter1 = "Application Global Evaluation Task*",
		[string] $actionFilter2 = "Request ? Evaluate*"

	Write-Verbose "Run-ConfigMgrActions: Start actions with filter '$($actionFilter1)' or '$($actionFilter2)'"
	TRY {
		(New-Object -ComObject CPApplet.cpAppletMgr).GetClientActions() | Where-Object {$_.Name -like $actionFilter1 -or $_.Name -like $actionFilter2} | Sort-Object Name | ForEach-Object {
			Write-Verbose "Run-ConfigMgrActions: Starting ConfigMgr action: $($_.Name)"
		Write-Verbose "Run-ConfigMgrActions: Can't find and/or trigger ConfigMgr Agent"

Update ConfigMgr Site Description

I did an install of a secondary site and accidently put in the wrong description…

Anyway, easy to fix with some SQL commands.

If you use this you can see the current sitenames and descriptions (change CM_XYZ to your database name):

SELECT SiteCode, SiteName, SiteServerName
FROM CM_XYZ..SC_SiteDefinition

And here is the way to update it (Change to you database name and the site code of the site you want to change)

UPDATE SC_SiteDefinition
SET SiteName = 'My Site Description'

FYI: When running this you will se “Updated X rows… Updated Y rows…” and so on.