Remove All Traces of Microsoft SCCM w/ PowerShell (By Force)

SCCM - Problem?

Microsoft’s System Center Configuration Manager (SCCM) seems to usually work pretty well for 95-97% of the computers at the environments I’ve worked in. Unfortunately for the remaining few percentage points of computers that SCCM is *not* working pretty well for when SCCM does break it does so spectacularly with style and pizzazz.

This script was developed for those computers. It first tries to uninstall SCCM gracefully if the installer is present, but regardless of whether it fails or not afterward it will wipe all traces of SCCM from the hard drive and registry. This allows you to do a new “clean” installation of SCCM afterward on machines that would not let you previously reinstall.

We are going to use PowerShell to accomplish this and explain each step in this guide!

Running SCCM Uninstaller

It’s usually a good idea to let SCCM try to uninstall itself even if we are going to forcefully remove everything anyways later. The SCCM uninstaller, being officially supported, knows every trace that should be on there and has a much easier time stopping everything than we will.

I broke my code up into “functions”. Go ahead and create a new PowerShell .ps1 file:

# Attempt to run the SCCM uninstaller
function uninstallSCCM() {
    if (Test-Path -Path "$Env:SystemDrive\Windows\ccmsetup\ccmsetup.exe") {
        # Stop SCCM services
        Get-Service -Name CcmExec -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose
        Get-Service -Name ccmsetup -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose

        # Run the SCCM uninstaller
        Start-Process -FilePath "$Env:SystemDrive\Windows\ccmsetup\ccmsetup.exe" -ArgumentList '/uninstall'

        # Wait for the uninstaller to finish
        do {
            Start-Sleep -Milliseconds 1000
            $Process = (Get-Process ccmsetup -ErrorAction SilentlyContinue)
        } until ($null -eq $Process)

        Write-Host "SCCM uninstallation completed"
    }
}

uninstallSCCM

This piece of the guide isn’t too difficult to explain so we won’t go into too much detail. Basically first we stop SCCM’s services (CCMExec and CCMSetup) and then we launch the uninstaller. If the SCCM uninstaller is present it will always be in the Windows\ccmsetup folder.

The “do” loop just sleeps for 1000 milliseconds and then checks to see if the uninstaller is done. Once it is it writes a line to the host console to let us know the uninstallation has finished. The very last line of the script calls the “uninstallSCCM” function we created above. Pretty simple!

One possible exception to trying the graceful uninstallation first is if the uninstaller isn’t working/freezing/stuck. I’ve seen some computers occasionally where the uninstaller will run and literally never finish even if you leave it overnight. If this is the case you may need to jump straight to manual removal otherwise try letting it finish.

Force Removal of SCCM

Next we are going to forcefully remove all SCCM files, registry traces, certificates, caches, WMI namespaces, etc. Let’s create a new function called “removeSCCM”:

# Forcefully remove all traces of SCCM from the computer
function removeSCCM() {
    # Stop SCCM services
    Get-Service -Name CcmExec -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose
    Get-Service -Name ccmsetup -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose

    # Take ownership of/delete SCCM's client folder and files
    $null = takeown /F "$($Env:WinDir)\CCM" /R /A /D Y 2>&1
    Remove-Item -Path "$($Env:WinDir)\CCM" -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    
    # Take ownership of/delete SCCM's setup folder and files
    $null = takeown /F "$($Env:WinDir)\CCMSetup" /R /A /D Y 2>&1
    Remove-Item -Path "$($Env:WinDir)\CCMSetup" -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    
    # Take ownership of/delete SCCM cache of downloaded packages and applications
    $null = takeown /F "$($Env:WinDir)\CCMCache" /R /A /D Y 2>&1
    Remove-Item -Path "$($Env:WinDir)\CCMCache" -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

First we need to take ownership of the SCCM client/setup/cache folders to avoid getting permission errors when we remove them. After taking ownership we remove all the files recursively with one command using the -Recurse switch of Remove-Item. That’s it for the files, now let’s get the registry:

    # Remove CCM registry keys
    Remove-Item -Path 'HKLM:\SOFTWARE\Microsoft\CCM' -Force -Recurse -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\CCM' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SMS registry keys
    Remove-Item -Path 'HKLM:\SOFTWARE\Microsoft\SMS' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\SMS' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove CCMSetup registry keys
    Remove-Item -Path 'HKLM:\Software\Microsoft\CCMSetup' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\Software\Wow6432Node\Microsoft\CCMSetup' -Force -Confirm:$false -Recurse -Verbose -ErrorAction SilentlyContinue

That’s it for all the registry keys. Let’s remove the services and the WMI namespaces next:

    # Remove CcmExec and ccmsetup services
    Remove-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\CcmExec' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\ccmsetup' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SCCM namespaces from WMI repository
    Get-CimInstance -Query "Select * From __Namespace Where Name='CCM'" -Namespace "root" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue
    Get-CimInstance -Query "Select * From __Namespace Where Name='CCMVDI'" -Namespace "root" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue
    Get-CimInstance -Query "Select * From __Namespace Where Name='SmsDm'" -Namespace "root" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue
    Get-CimInstance -Query "Select * From __Namespace Where Name='sms'" -Namespace "root\cimv2" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue

Next we are going to delete SCCM’s certificates and GUID file (smscfg.ini) and add the closing brace (“}”) by adding these commands:

    # Remove SCCM's smscfg file (contains GUID of previous installation)
    Remove-Item -Path "$($Env:WinDir)\smscfg.ini" -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SCCM certificates
    Remove-Item -Path 'HKLM:\Software\Microsoft\SystemCertificates\SMS\Certificates\*' -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Completed
    Write-Host "All traces of SCCM have been removed"
}

removeSCCM

And that’s it! I’m sure there’s more traces that SCCM leaves that my script potentially aren’t getting but these are the critical pieces that can prevent you from reinstalling.

Final Script

Here is the final script all put together:

# Attempt to run the SCCM uninstaller
function uninstallSCCM() {
    if (Test-Path -Path "$Env:SystemDrive\Windows\ccmsetup\ccmsetup.exe") {
        # Stop SCCM services
        Get-Service -Name CcmExec -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose
        Get-Service -Name ccmsetup -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose

        # Run the SCCM uninstaller
        Start-Process -FilePath "$Env:SystemDrive\Windows\ccmsetup\ccmsetup.exe" -ArgumentList '/uninstall'

        # Wait for the uninstaller to finish
        do {
            Start-Sleep -Milliseconds 1000
            $Process = (Get-Process ccmsetup -ErrorAction SilentlyContinue)
        } until ($null -eq $Process)

        Write-Host "SCCM uninstallation completed"
    }
}

# Forcefully remove all traces of SCCM from the computer
function removeSCCM() {
    # Stop SCCM services
    Get-Service -Name CcmExec -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose
    Get-Service -Name ccmsetup -ErrorAction SilentlyContinue | Stop-Service -Force -Verbose

    # Take ownership of/delete SCCM's client folder and files
    $null = takeown /F "$($Env:WinDir)\CCM" /R /A /D Y 2>&1
    Remove-Item -Path "$($Env:WinDir)\CCM" -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    
    # Take ownership of/delete SCCM's setup folder and files
    $null = takeown /F "$($Env:WinDir)\CCMSetup" /R /A /D Y 2>&1
    Remove-Item -Path "$($Env:WinDir)\CCMSetup" -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    
    # Take ownership of/delete SCCM cache of downloaded packages and applications
    $null = takeown /F "$($Env:WinDir)\CCMCache" /R /A /D Y 2>&1
    Remove-Item -Path "$($Env:WinDir)\CCMCache" -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SCCM's smscfg file (contains GUID of previous installation)
    Remove-Item -Path "$($Env:WinDir)\smscfg.ini" -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SCCM certificates
    Remove-Item -Path 'HKLM:\Software\Microsoft\SystemCertificates\SMS\Certificates\*' -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove CCM registry keys
    Remove-Item -Path 'HKLM:\SOFTWARE\Microsoft\CCM' -Force -Recurse -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\CCM' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SMS registry keys
    Remove-Item -Path 'HKLM:\SOFTWARE\Microsoft\SMS' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\SMS' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove CCMSetup registry keys
    Remove-Item -Path 'HKLM:\Software\Microsoft\CCMSetup' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\Software\Wow6432Node\Microsoft\CCMSetup' -Force -Confirm:$false -Recurse -Verbose -ErrorAction SilentlyContinue

    # Remove CcmExec and ccmsetup services
    Remove-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\CcmExec' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue
    Remove-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\ccmsetup' -Force -Recurse -Confirm:$false -Verbose -ErrorAction SilentlyContinue

    # Remove SCCM namespaces from WMI repository
    Get-CimInstance -Query "Select * From __Namespace Where Name='CCM'" -Namespace "root" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue
    Get-CimInstance -Query "Select * From __Namespace Where Name='CCMVDI'" -Namespace "root" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue
    Get-CimInstance -Query "Select * From __Namespace Where Name='SmsDm'" -Namespace "root" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue
    Get-CimInstance -Query "Select * From __Namespace Where Name='sms'" -Namespace "root\cimv2" -ErrorAction SilentlyContinue | Remove-CimInstance -Verbose -Confirm:$false -ErrorAction SilentlyContinue

    # Completed
    Write-Host "All traces of SCCM have been removed"
}

uninstallSCCM
removeSCCM

If you know of more traces that are missing, especially if they stopped you from reinstalling or can cause a problem that perhaps I have yet to encounter, leave a comment and I will add them!

Further Troubleshooting – WMI

If you still can’t reinstall SCCM and you’re sure it has nothing to do with your environment there are a couple “gotchas” that come up a lot with SCCM you should check for. The first one is your computer’s WMI repository. You can verify this with:

winmgmt /verifyrepository

A good result is that your “WMI repository is consistent” like this:

Verifying a WMI repository with winmgmt
Verifying a WMI repository

If it tells you that the WMI repository is inconsistent your WMI repository is broken on that machine. You can attempt a repair with:

winmmgmt /salvagerepository
winmgmt /verifyrepository

If it came back as consistent now, then the built in tools actually successfully fixed it, nice! If it’s still broken, you did not get lucky and your “good” options are running out. There is another command we can use that resets WMI back to the default state the machine had when it was installed.

Before you try it, I must WARN you, this can sometimes cause problems if you have other applications that have added custom WMI that won’t be there when you reset the WMI repository back to the original default state. It’s not a “safe” command to just run willy-nilly. Specifically:

Rebuilding the WMI repository may result in some third-party products not working until their setup is re-run & their Microsoft Operations Framework re-added back to the repository.

If your only other option is to reimage the machine anyways and you have nothing to lose, YOLO:

winmgmt /resetrepository
winmgmt /verifyrepository

Hopefully that one got it for you but if not you can get really desperate and try rebuilding the WMI .mof files yourself following this article here.

However, if your WMI is this broken that you are manually trying to repair .mof files, it’s definitely time to seriously consider a reimage at this point. It’s way outside the norm to get this far down the list of WMI troubleshooting and still be having problems when there aren’t a dozen other things wrong with that image on there that haven’t been found yet!

If you’re really determined to fix WMI on that machine there’s more you can do but it’s beyond the scope of this article but at least you know the problem and can do some further research here.

Further Troubleshooting – DISM

DISM stands for “Deployment Image Servicing and Management”. This tool helps you manage your Windows image itself. Windows also has it’s own repository of packages and this tool verifies that they are all there and in the condition they should be.

We can run the DISM command to check our Windows image with PowerShell and make sure it’s “Healthy” like this:

Repair-WindowsImage -Online -CheckHealth
Repair-WindowsImage in PowerShell
Repair-WindowsImage in PowerShell

The other possible results are “Repairable” and “Unrepairable”. It’s pretty unusual to encounter straight up fully “unrepairable” ones, most of the ones you are likely to encounter will show as “Repairable”. If it’s unrepairable then it’s absolutely hilariously broken and essentially needs a straight-up reimage at that point.

The CheckHealth command is a great command and only takes a few seconds to run but it only checks the Windows logs for errors. There’s a more comprehensive scan you can perform if you don’t trust the result you got:

Repair-WindowsImage -Online -ScanHealth

The ScanHealth command actually computes all the hashes and checks every single file in the repository one at a time. It can take several minutes or much longer (15-20+ minutes) than that on old machines still using HDDs instead of solid state storage, but if that one comes back clean it’s a pretty definitive result and it’s time to consider other possibilities.

If it shows repairable you can repair it with:

Repair-WindowsImage -Online -RestoreHealth

If the repair was successful there’s one more step you need to do. All we’ve done with the DISM command is fix the repositories Windows uses to update and replace broken files. Now we need to run the System File Checker tool like this to actually replace the damaged files:

sfc /scannow

There’s definitely some problems you can run into when running DISM (different types of errors) but they’re outside the scope of the article and what to do next can be pretty easily found by putting your error into your favorite search engine. You may also feel free to leave a comment with what you’re seeing! Definitely check out my other PowerShell articles as well for more ideas!

Subscribe
Notify of
guest

8 Comments
Inline Feedbacks
View all comments
Ethan Wilson
Ethan Wilson
2 years ago

I’m about to deploy this via Intune lol

Justin
Justin
2 years ago

I added ‘netsh winhttp reset proxy’ at the end (before running the reinstall), to remove any traces from proxies or TOR.

This could be one reason why the CCM client updates gets so out of date.

Shivs
Shivs
2 years ago

Hi,

Thank you very much for your help with this. I was looking for this type of solution but found none until now.

With the force command, the SCCM is removed. I checked the files concerned and found none of them except one which is mentioned in the removal SOP of SCCM provided in my organization.

Please delete files and folders from the path below.
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
Please delete all files whose name started from [19c5cF] which exist in the folder above.

Can you add these files to the script?

Hi,

Also, if you can please help me in below as well

1. Way to run this script remotely.
2. Way to install SCCM via script.

Regards

Shivs
Shivs
2 years ago

Hi,

Thanks for your response. I really wasn’t hoping to get the response, and definitely not that prompt.
That’s why I didn’t come here till now.

The shared script works like a charm. Although, in my environment, the “WinRM service” is not running on the machines. Therefore, I am encountering the below error.

Test1:

Connecting to remote server CWSHPMU1848 failed with the following error message : The client cannot
connect to the destination specified in the request. Verify that the service on the destination is running and is
accepting requests. Consult the logs and documentation for the WS-Management service running on the destination, most
commonly IIS or WinRM. If the destination is the WinRM service, run the following command on the destination to
analyze and configure the WinRM service: "winrm quickconfig". For more information, see the
about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (Test1:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : CannotConnect,PSSessionStateBroken

To resolve that, I had to enable the remote scripting first by “Enable-PSRemoting -Force” on the target machine.

Also, regarding the file removal, At the time of asking questions, I forget to use my brain. Hence the silly question.

All in all, this script will help us in our deployment project. And with your help, we could save some time and manual labor.

Thanks a lot.

Regards,