Optimizing SCCM Deployments: Remove device from collection after OSD

Hey You

I hope you’re having a wonderful week, just as I am because I just solved an issue that I have been having. This one REALLY needed me to think outside the box.

Setup

Let me start with the setup. I deploy Microsoft Windows (OSD) using System Center Configuration Manager… I mean Microsoft Endpoint Configuration Manager… I mean Microsoft Configuration Manager… I can’t keep up with all those name changes, so I will be referring to it as SCCM (because I’m old school).

Because of security reasons that I won’t mention here, I demand that the machine should be added to SCCM using the COMPUTERNAME and MAC Address before it is deployed. This eliminates the need for a prompt for the computer name during OSD or needing to have a script to name the computer.

I also have a deployment called “Windows 10 x64 deployment” in which all machines that are going to be deployed need to be a direct member of this collection. This ensures that rogue machines cannot be deployed.

Are you with me so far? Because it’s going to go deeper down the rabbit hole as we continue.

Scenario

Here’s where things get interesting: once a machine is deployed, it isn’t removed from the “Windows 10 x64 deployment” device collection. You might wonder, “Who cares?”

Well, I do!

Not removing the machine from the collection means any user could potentially PXE boot into the Windows PE boot image and start a new OSD deployment. Besides this big security flaw, the device collection has about 2,000 members, which seems like a significant waste, doesn’t it? This is a problem I’m determined to solve.

I have read https://www.systemcenterdudes.com/sccm-remove-collection-osd, which is an awesome article by the System Center Dudes (maybe they should also change their names?) and it does work… but… also it doesn’t. Let me explain:

ASSUMING THAT YOU HAVE READ THE ARTICLE OF THE SYSTEM CENTER DUDES, IF NOT SKIP THIS PART:

For this script to work it needs to get the machine name up front; however, the machine name is asked up front during OSD and stored into a variable. This is not the case in my situation because the computer name has already been defined before.

So when I do try a env:COMPUTERNAME it will use the SCCM server computer name and not the machine computer name because the SCCM server is running the script.

ASSUMING THAT YOU HAVE NOT READ THE ARTICLE OF THE SYSTEM CENTER DUDES:

Can’t give it the computer name of the machine in order for the script to work.

Solution

I know that this might not be THE best solution, but it’s the one I took so in my opinion it’s THE best solution.

I kept the first part regarding the Status Filter Rules described by the System Center Dudes.

Status Filter Rules

  1. Open the SCCM Console
  2. Go to Administration \ Site \ Status Filter Rules (Top ribbon)
  3. Enter the following values in “Status Filter Rules”
    1. Name: Remove Client after OSD
    2. Component: Task Sequence Manager
    3. Message ID: 11171

In the action tab :

    1. Check Report to the event log – This will be helpful for troubleshooting.
    2. Check the Run a program option as follow: C:Windows\SysWOW64\WindowsPowerShellv1.0\powershell.exe -ExecutionPolicy ByPass “<path to your script>NameOfTheScript.ps1

What this does is that when a machine has succesfully been deployed it will trigger the SCCM to run a powershell script.

Why?

You’ll find out in a minute.

Task Sequence

I added another step in the Task Sequence. It’s a powershell script that does the following:

$computerName = $env:COMPUTERNAME

New-Item - Path "\\SCCMSRV01\Software\OSD\Scripts\RemoveDeviceCollection\Log\computers\$computerName" -ItemTpe File

You might have noticed that I created a folder in the SCCM folder called “RemoveDeviceCollection”. This script takes the computername of the machine and creates a file with the computername without extension.

So let’s say your computername is PST1704, it will create a file called “PST1704” in that location.

Why?

You’ll find out in a minute

Powershell

This is that minute. You might recall the “Status Filter Rules” in which we defined a Powershell script. This is that script:

# I want logging so here I define the location for logging
$logFile = "\\SCCMSRV01\software\OSD\Scripts\RemoveDeviceCollection\log\deployLog.txt"
$logBackup = "\\SCCMSRV01\software\OSD\Scripts\RemoveDeviceCollection\log\deployLog.bak"

# I don't want the log to be very big so here I check if the log file exceeds 1 MB
if (Test-Path -Path $logFile) {

    $logFileSize = (Get-Item -Path $logFile).Length

    # Check if log file is bigger than 1 MB
    if ($logFileSize -gt 1MB) {
        
        # If the log file IS too big it should create a backup file. 
        # Before doing that it does need to check if a backup file already exists
        if (Test-Path -Path $logBackup) {
            
            Remove-Item -Path $logBackup -Force

        }

        # Rename log file to .bak
        Rename-Item -Path $logFile -NewName $logBackup

    }

}

# Here I start the LOG which technically is only 3 lines. 
Start-Transcript -Path $logFile -Append

# Collection ID voor "Windows 10 x64 Deployment"
$collectionID = "P050317A"

# Folder of all computer names
$folderName = "\\SCCMSRV01\software\OSD\Scripts\RemoveDeviceCollection\log\computers"

# Convert all files to computernames
$computerNames = Get-ChildItem -Path $folderName | ForEach-Object { $_.BaseName}

forEach ($computerName in $computerNames) {

    # Connect to the SCCM Server. Notice that I don't define the SCCM server.
    # It's all automagically done
    Import-Module (Join-Path $(Split-Path $env:SMS_ADMIN_UI_PATH) ConfigurationManager.psd1)
    cd ((Get-PSDrive -PSProvider CMSite).Name + ":")
    
    # Remove from Device Collection
    Remove-CMDeviceCollectionDirectMembershipRule -CollectionId $collectionID -ResourceName $computerName -Force
    Write-Output "Machine $computerName deleted from collection 'Windows 10 x64 Deployment'"

    # Back to local (not the SCCM server).
    CD C:

    # Remove the computername file. Need to tidy up
    Remove-Item -Path $folderName\$computerName -Force
    Write-Output "file $computerName deleted from $folderName"

}

# Stop log
Stop-Transcript

Conclusion

As mentioned before, this might not be the best way to do it but I am pretty satisfied with this solution.

In a nutshell:

  1. The Task Sequence creates a file with the name of the computer without extension
  2. The task sequence manager reports to the SCCM server triggering a powershell script when a deployment is succesfull
  3. The scripts checks if the log file exceeds 1MB, if so make a backup of it
  4. Start logging
  5. Check the file with the computername
  6. Remove the computer from the device collection
  7. Delete the file
  8. End logging

Cheers,

Engin