Intune Initial Scripts Backup
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
<#
|
||||
|
||||
.Description
|
||||
Script to detect if there is any trace of SCCM agent.
|
||||
Will check for CcmExec service and registry keys for services, SMS Certs, and MDM Authority.
|
||||
|
||||
.Notes
|
||||
Source: https://github.com/robertomoir/remove-sccm/blob/master/remove-sccmagent.ps1
|
||||
Source: https://www.optimizationcore.com/deployment/sccm-client-complete-remove-uninstall-powershell-script/
|
||||
Source: https://jamesachambers.com/remove-microsoft-sccm-by-force/
|
||||
Source: https://github.com/ChadSimmons/Scripts/blob/default/ConfigMgr/Troubleshooting/Remove-ConfigMgrClient.ps1
|
||||
|
||||
#>
|
||||
|
||||
#region Settings
|
||||
|
||||
$Error.Clear()
|
||||
$Result = 0
|
||||
$DetectSummary = ""
|
||||
|
||||
#New lines, easier to read Agentexecutor Log file.
|
||||
Write-Host "`n`n"
|
||||
|
||||
#endregion Settings
|
||||
|
||||
#region Functions
|
||||
Function Test-IfServiceExistExit1 {
|
||||
|
||||
Param
|
||||
(
|
||||
[string]$ServiceName
|
||||
)
|
||||
|
||||
$DetectSummary = ""
|
||||
|
||||
$Service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
||||
|
||||
If ($null -eq $Service) {
|
||||
Write-Host "Service $ServiceName was not found."
|
||||
}
|
||||
else {
|
||||
Write-Warning "Service $ServiceName exists."
|
||||
if (-not ($DetectSummary -eq "")) { $DetectSummary += ", " }
|
||||
$DetectSummary += "$ServiceName service exists"
|
||||
return 1, $DetectSummary
|
||||
}
|
||||
return 0, $DetectSummary
|
||||
}
|
||||
|
||||
Function Test-IfRegKeyExistExit1 {
|
||||
|
||||
Param
|
||||
(
|
||||
[string]$RegKeyPath
|
||||
)
|
||||
|
||||
$DetectSummary = ""
|
||||
|
||||
$RegKey = Get-Item -Path $RegKeyPath -ErrorAction SilentlyContinue
|
||||
|
||||
if ($null -eq $RegKey) {
|
||||
Write-Host "Registry Key $RegKeyPath was not found."
|
||||
}
|
||||
else {
|
||||
Write-Warning "$RegKeyPath exists."
|
||||
if (-not ($DetectSummary -eq "")) { $DetectSummary += ", " }
|
||||
$DetectSummary += "$RegKeyPath exists"
|
||||
return 1, $DetectSummary
|
||||
}
|
||||
return 0, $DetectSummary
|
||||
}
|
||||
|
||||
#endregion Functions
|
||||
|
||||
#region Main
|
||||
|
||||
#Look for the services related to SCCM client.
|
||||
$Services = ("CcmExec", "CCMSetup", "smstsmgr", "CmRcService")
|
||||
|
||||
foreach ($Serv in $Services) {
|
||||
# Verify that services do not exist
|
||||
$result, $serviceSummary = Test-IfServiceExistExit1 $Serv
|
||||
if ($result -eq 1) {
|
||||
$Result = 1
|
||||
}
|
||||
$DetectSummary += $serviceSummary
|
||||
}
|
||||
|
||||
#Verify that all registry keys from SCCM agent do not exist.
|
||||
$RegServicesPath = "HKLM:\SYSTEM\CurrentControlSet\Services"
|
||||
$RegSoftwarePath = "HKLM:\SOFTWARE\Microsoft"
|
||||
$RegSoftwareWowPath = "HKLM:\SOFTWARE\Wow6432Node\Microsoft"
|
||||
$RegSmsCertsPath = "HKLM:\SOFTWARE\Microsoft\SystemCertificates\SMS\Certificates"
|
||||
|
||||
$RegServices = (
|
||||
"$RegServicesPath\CcmExec",
|
||||
"$RegServicesPath\CCMSetup",
|
||||
"$RegServicesPath\smstsmgr",
|
||||
"$RegServicesPath\CmRcService",
|
||||
"$RegSoftwarePath\CCM",
|
||||
"$RegSoftwarePath\CCMSetup",
|
||||
"$RegSoftwarePath\SMS",
|
||||
"$RegSoftwarePath\DeviceManageabilityCSP",
|
||||
"$RegSoftwareWowPath\CCM",
|
||||
"$RegSoftwareWowPath\CCMSetup",
|
||||
"$RegSoftwareWowPath\SMS",
|
||||
"$RegSmsCertsPath\*"
|
||||
)
|
||||
|
||||
foreach ($RegService in $RegServices) {
|
||||
# Verify that Registry Keys do not exist
|
||||
$result, $regKeySummary = Test-IfRegKeyExistExit1 $RegService
|
||||
if ($result -eq 1) {
|
||||
$Result = 1
|
||||
}
|
||||
$DetectSummary += $regKeySummary
|
||||
}
|
||||
|
||||
#New lines, easier to read Agentexecutor Log file.
|
||||
Write-Host "`n`n"
|
||||
|
||||
# Return result
|
||||
if ($Result -eq 0) {
|
||||
Write-Host "OK $([datetime]::Now) : SCCM not found."
|
||||
Exit 0
|
||||
} else {
|
||||
Write-Host "WARNING $([datetime]::Now) : $DetectSummary"
|
||||
Exit 1
|
||||
}
|
||||
|
||||
#endregion Main
|
||||
@@ -0,0 +1,612 @@
|
||||
<#
|
||||
|
||||
.Description
|
||||
Script to remove SCCM agent from PCs
|
||||
|
||||
Completly based on James Chambers and Chad Simmons powershell scripts to remove the SCCM agent.
|
||||
Updated with other scripts and testing.
|
||||
|
||||
$ccmpath is path to SCCM Agent's own uninstall routine.
|
||||
|
||||
.Notes
|
||||
|
||||
Script created or based on the following:
|
||||
|
||||
Source: https://github.com/robertomoir/remove-sccm/blob/master/remove-sccmagent.ps1
|
||||
Source: https://www.optimizationcore.com/deployment/sccm-client-complete-remove-uninstall-powershell-script/
|
||||
Source: https://jamesachambers.com/remove-microsoft-sccm-by-force/
|
||||
Source: https://github.com/ChadSimmons/Scripts/blob/default/ConfigMgr/Troubleshooting/Remove-ConfigMgrClient.ps1
|
||||
|
||||
#>
|
||||
|
||||
#region Functions
|
||||
|
||||
function Test-IsAdmin {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks if the current user has administrative privileges.
|
||||
|
||||
.DESCRIPTION
|
||||
Function determines whether the current user has administrative privileges by attempting to create a new WindowsPrincipal object and checking the IsInRole method for the "Administrator" role.
|
||||
If the check fails, it throws an exception indicating the lack of administrative privileges.
|
||||
|
||||
.EXAMPLE
|
||||
Test-IsAdmin
|
||||
If the current user has administrative privileges, the function completes without any output. If not, it throws an exception.
|
||||
|
||||
.NOTES
|
||||
This function should be called at the beginning of scripts that require administrative privileges to ensure proper execution.
|
||||
|
||||
#>
|
||||
|
||||
try {
|
||||
# Create a new WindowsPrincipal object for the current user
|
||||
$currentUser = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
|
||||
# Check if the current user is in the "Administrators" role
|
||||
if (-not $currentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw "Script needs to run with Administrative privileges."
|
||||
}
|
||||
} catch {
|
||||
throw "Must be run with Administrative priviliges."
|
||||
}
|
||||
}
|
||||
|
||||
function Stop-WinService {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Stops a specified Windows service if it exists and is running.
|
||||
|
||||
.DESCRIPTION
|
||||
Function checks if a specified Windows service exists and retrieves its status. If the service is running,
|
||||
it attempts to stop it. Includes error handling to catch and throw any issues encountered, with specific messages
|
||||
for services that do not exist.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
The name of the Windows service to stop.
|
||||
|
||||
.EXAMPLE
|
||||
Stop-WinService -ServiceName "wuauserv"
|
||||
Attempts to stop the Windows Update service if it exists and is running.
|
||||
|
||||
.NOTES
|
||||
This function requires administrative privileges to stop Windows services.
|
||||
#>
|
||||
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName
|
||||
)
|
||||
|
||||
try {
|
||||
# Check if the service exists
|
||||
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
||||
|
||||
if ($null -eq $service) {
|
||||
throw "Service '$ServiceName' does not exist."
|
||||
}
|
||||
|
||||
# Check if the service is running
|
||||
if ($service.Status -eq 'Running') {
|
||||
# Attempt to stop the service
|
||||
Write-Host "Stopping service '$ServiceName'..."
|
||||
Stop-Service -Name $ServiceName -Force -ErrorAction Stop
|
||||
Write-Host "Service '$ServiceName' stopped successfully."
|
||||
} else {
|
||||
Write-Host "Service '$ServiceName' is not running."
|
||||
}
|
||||
} catch {
|
||||
throw "$_"
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-RegKey {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Deletes a specified registry key and its subkeys.
|
||||
|
||||
.DESCRIPTION
|
||||
This function removes a specified registry key from the Windows Registry, including all its subkeys and values.
|
||||
It includes error handling to catch and throw any issues encountered during the operation.
|
||||
|
||||
.PARAMETER RegKeyPath
|
||||
The path of the registry key to delete.
|
||||
|
||||
.EXAMPLE
|
||||
Remove-RegKey -RegKeyPath "HKLM:\SOFTWARE\MyApp"
|
||||
Deletes the "MyApp" key and all its subkeys and values from the HKEY_LOCAL_MACHINE\SOFTWARE path.
|
||||
|
||||
.NOTES
|
||||
This function requires administrative privileges to modify the Windows Registry.
|
||||
#>
|
||||
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$RegKeyPath
|
||||
)
|
||||
|
||||
try {
|
||||
# Check if the registry key exists
|
||||
if (Test-Path -Path $RegKeyPath) {
|
||||
# Attempt to remove the registry key
|
||||
Write-Host "Removing registry key '$RegKeyPath'..."
|
||||
Remove-Item -Path $RegKeyPath -Recurse -Force -Confirm:$false -ErrorAction Stop
|
||||
Write-Host "Registry key '$RegKeyPath' removed successfully."
|
||||
} else {
|
||||
Write-Host "Registry key '$RegKeyPath' does not exist."
|
||||
}
|
||||
} catch {
|
||||
throw "Error removing registry key '$RegKeyPath'"
|
||||
}
|
||||
}
|
||||
|
||||
function Clear-Files {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Deletes specified files or folders, including subdirectories, and takes ownership if necessary.
|
||||
|
||||
.DESCRIPTION
|
||||
This function iterates through an array of file paths, taking ownership of each file or directory and then deleting it.
|
||||
It ensures both files and subdirectories are removed, handling any errors encountered during the process.
|
||||
|
||||
.PARAMETER FilePaths
|
||||
An array of file paths to delete. These can be files or directories.
|
||||
|
||||
.EXAMPLE
|
||||
$filesToDelete = @("C:\Temp\File1.txt", "C:\Temp\Folder1")
|
||||
Clear-Files -FilePaths $filesToDelete
|
||||
|
||||
.NOTES
|
||||
This function requires administrative privileges to take ownership and delete files or directories.
|
||||
#>
|
||||
param (
|
||||
[string[]]$FilePaths
|
||||
)
|
||||
|
||||
foreach ($FilePath in $FilePaths) {
|
||||
try {
|
||||
# Take ownership of the file or folder
|
||||
$null = takeown.exe /F "$FilePath" /R /A /D Y 2>&1
|
||||
|
||||
# Delete the file or folder, including subdirectories
|
||||
Remove-Item -Path $FilePath -Force -Recurse -ErrorAction Stop
|
||||
|
||||
Write-Host "Successfully deleted: $FilePath"
|
||||
} catch {
|
||||
Write-Host "Error deleting $($FilePath)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-WmiNamespace {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes a specified WMI namespace.
|
||||
|
||||
.DESCRIPTION
|
||||
This function checks if a specified WMI namespace exists and removes it if found. It uses CIM (Common Information Model) cmdlets
|
||||
to query and delete the WMI namespace. Errors are handled silently to ensure smooth execution.
|
||||
|
||||
.PARAMETER WmiName
|
||||
The name of the WMI namespace to be removed.
|
||||
|
||||
.PARAMETER WmiNameSpace
|
||||
The parent namespace where the specified WMI namespace resides.
|
||||
|
||||
.EXAMPLE
|
||||
Remove-WmiNamespace -WmiName "ccm" -WmiNameSpace "root\ccm"
|
||||
|
||||
.NOTES
|
||||
Ensure the script runs with administrative privileges to modify WMI namespaces.
|
||||
|
||||
.SOURCE
|
||||
References:
|
||||
- https://learn.microsoft.com/en-us/powershell/scripting/overview?view=powershell-7.1
|
||||
- https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-powershell-cim-cmdlets?view=powershell-7.1
|
||||
|
||||
#>
|
||||
param (
|
||||
[string]$WmiName,
|
||||
[string]$WmiNameSpace
|
||||
)
|
||||
|
||||
try {
|
||||
# Query for the specified WMI namespace
|
||||
$WmiRepository = Get-CimInstance -query "SELECT * FROM __Namespace WHERE Name='$WmiName'" -Namespace "$WmiNameSpace" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check if the namespace exists
|
||||
if ($null -ne $WmiRepository) {
|
||||
Write-Host "Found WMI Repository $WmiName, removing..."
|
||||
|
||||
# Remove the WMI namespace
|
||||
Get-CimInstance -query "SELECT * FROM __Namespace WHERE Name='$WmiName'" -Namespace "$WmiNameSpace" | Remove-CimInstance -Confirm:$false -ErrorAction SilentlyContinue
|
||||
}
|
||||
else {
|
||||
Write-Host "WMI Repository $WmiName not found"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
throw "Error udpating WMI namespace."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Verify-SccmClientDelete {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the deletion of the SCCM client by checking for the absence of specific services and files.
|
||||
|
||||
.DESCRIPTION
|
||||
Checks if the SCCM (System Center Configuration Manager) client has been successfully deleted from the system.
|
||||
It does this by verifying the absence of the SCCM client service (`CcmExec`) and the SCCM setup file (`ccmsetup.exe`).
|
||||
If neither the service nor the setup file is found, the deletion is considered successful.
|
||||
If either the service or the setup file still exists, appropriate warnings are issued, and the function sets an exit code indicating failure.
|
||||
|
||||
.PARAMETER None
|
||||
|
||||
.EXAMPLE
|
||||
$exitCode = Verify-SccmClientDelete
|
||||
Write-Host "Exit Code: $exitCode"
|
||||
|
||||
.NOTES
|
||||
This function requires administrative privileges to check the existence of services and files.
|
||||
Ensure that the script is run with appropriate permissions to avoid errors.
|
||||
|
||||
#>
|
||||
# Variables to store the SCCM service name and file path
|
||||
$SccmService = "CcmExec"
|
||||
$SccmFilePath = "$Env:WinDir\ccmsetup\ccmsetup.exe"
|
||||
$ExitCode = 0
|
||||
|
||||
try {
|
||||
# Attempt to retrieve the SCCM service
|
||||
$CCMexecService = Get-Service -Name $SccmService -ErrorAction SilentlyContinue
|
||||
# Attempt to retrieve the SCCM setup file
|
||||
$CCMexecSetupFile = Get-Item -Path $SccmFilePath -ErrorAction SilentlyContinue
|
||||
|
||||
# Check if both the service and the setup file do not exist
|
||||
if (($null -eq $CCMexecService) -and ($null -eq $CCMexecSetupFile)) {
|
||||
# SCCM Client deletion confirmed.
|
||||
Write-Host "Confirmation. SCCM client service does not exist!"
|
||||
}
|
||||
else {
|
||||
# Check if the SCCM service still exists
|
||||
if ($null -ne $CCMexecService) {
|
||||
# Set exit code for existing service
|
||||
$ExitCode = 90 # 0x431 ERROR_SERVICE_EXISTS / The specified service already exists.
|
||||
Write-Warning "Service $CCMexecService still exists, completing with failure $ExitCode"
|
||||
}
|
||||
|
||||
# Check if the SCCM setup file still exists
|
||||
if ($null -ne $CCMexecSetupFile) {
|
||||
# Set exit code for existing file
|
||||
$ExitCode = 91 # The specified file still exists.
|
||||
Write-Warning "File $CCMexecSetupFile still exists, completing with failure $ExitCode"
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
# Handle any errors that occur during the check
|
||||
throw "Error verifying SCCM client deletion."
|
||||
}
|
||||
|
||||
# Return the exit code
|
||||
return $ExitCode
|
||||
}
|
||||
|
||||
function Start-CompleteIntuneSync {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Initiates an Intune sync session and verifies its completion through Event Viewer logs.
|
||||
|
||||
.DESCRIPTION
|
||||
This function performs an Intune sync by creating and starting an MDM session using Windows.Management.MdmSessionManager.
|
||||
It waits for 60 seconds to allow the sync process to initiate. It then checks for specific events in the Event Viewer
|
||||
to confirm the sync's start and completion: Looks for events 208 and 209 in the "Applications and Services Logs > Microsoft > Windows > DeviceManagement-Enterprise-Diagnostics-Provider > Admin".
|
||||
The function returns the time these events were logged, or "Not found" if the events are not present.
|
||||
|
||||
The Journey:
|
||||
Initial approach used `intunemanagementextension://syncapp` protocol as suggested by Jannik Reinhard's blog (https://jannikreinhard.com/2022/07/31/summary-of-the-intune-management-extension/). However, this method did not yield consistent results across different devices
|
||||
Focus then shifted to leveraging the `Windows.Management.MdmSessionManager` class, known for managing Mobile Device Management (MDM) sessions. The use of `[Windows.Management.MdmSessionManager,Windows.Management,ContentType=WindowsRuntime]` to create and start an MDM session was adopted based on documentation and community blogs:
|
||||
- https://oofhours.com/2024/03/30/when-does-a-windows-client-sync-with-intune/
|
||||
|
||||
Note: There was an initial attempt to use `Add-Type -AssemblyName "Windows.Management"` which resulted in an error indicating the assembly could not be found. This led to the realization that direct referencing and instantiation of the Windows Runtime type was necessary.
|
||||
|
||||
.REFERENCES
|
||||
- "Intune Management Extension" by Jannik Reinhard: https://jannikreinhard.com/2022/07/31/summary-of-the-intune-management-extension/
|
||||
- "When Does a Windows Client Sync with Intune?" by Michael Niehaus: https://oofhours.com/2024/03/30/when-does-a-windows-client-sync-with-intune/
|
||||
|
||||
.PARAMETER None
|
||||
|
||||
.EXAMPLE
|
||||
Start-CompleteIntuneSync
|
||||
|
||||
.NOTES
|
||||
This function requires administrative privileges to access Event Viewer logs.
|
||||
Make sure to run this script with appropriate permissions.
|
||||
#>
|
||||
|
||||
# Initialize variables for event checking
|
||||
$eventLog = "Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin"
|
||||
$syncStartEventID = 208
|
||||
$syncCompleteEventID = 209
|
||||
$syncStartTime = Get-Date
|
||||
|
||||
# Log the start of the sync attempt
|
||||
Write-Host "Starting Intune sync at $syncStartTime"
|
||||
|
||||
try {
|
||||
# Create and start the MDM session using Windows.Management.MdmSessionManager
|
||||
[Windows.Management.MdmSessionManager,Windows.Management,ContentType=WindowsRuntime] > $null
|
||||
$session = [Windows.Management.MdmSessionManager]::TryCreateSession()
|
||||
$session.StartAsync() | Out-Null
|
||||
|
||||
# Wait for 60 seconds to allow the sync to initiate
|
||||
Start-Sleep -Seconds 60
|
||||
|
||||
# Check for the sync start event in Event Viewer
|
||||
$syncStartEvent = Get-WinEvent -LogName $eventLog | Where-Object { $_.Id -eq $syncStartEventID -and $_.TimeCreated -ge $syncStartTime }
|
||||
if ($syncStartEvent) {
|
||||
Write-Host "Sync start event (ID $syncStartEventID) found."
|
||||
$syncStartEventTime = $syncStartEvent.TimeCreated
|
||||
} else {
|
||||
Write-Host "Sync start event (ID $syncStartEventID) not found."
|
||||
$syncStartEventTime = "Not found"
|
||||
}
|
||||
|
||||
# Check for the sync complete event in Event Viewer
|
||||
$syncCompleteEvent = Get-WinEvent -LogName $eventLog | Where-Object { $_.Id -eq $syncCompleteEventID -and $_.TimeCreated -ge $syncStartTime }
|
||||
if ($syncCompleteEvent) {
|
||||
Write-Host "Sync complete event (ID $syncCompleteEventID) found."
|
||||
$syncCompleteEventTime = $syncCompleteEvent.TimeCreated
|
||||
} else {
|
||||
Write-Host "Sync complete event (ID $syncCompleteEventID) not found."
|
||||
$syncCompleteEventTime = "Not found"
|
||||
}
|
||||
|
||||
# Return details of the sync process
|
||||
return @{
|
||||
SyncStartEvent = $syncStartEventTime
|
||||
SyncCompleteEvent = $syncCompleteEventTime
|
||||
SyncStartTime = $syncStartTime
|
||||
}
|
||||
} catch {
|
||||
throw "Error during Intune sync process. "
|
||||
}
|
||||
}
|
||||
|
||||
function WriteAndExitWithSummary {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Writes a summary of the script's execution to the console and then exits the script with a specified status code.
|
||||
|
||||
.DESCRIPTION
|
||||
The function takes a status code and a summary string as parameters. It writes the summary along with the current date and time to the console using Write-Host.
|
||||
After writing the summary, it exits the script with the given status code. If the given status code is below 0 (negative) it changes exit status code to 0.
|
||||
|
||||
.PARAMETER StatusCode
|
||||
The exit status code to be used when exiting the script.
|
||||
0: OK
|
||||
1: FAIL
|
||||
Other: WARNING
|
||||
|
||||
.PARAMETER Summary
|
||||
The summary string that describes the script's execution status. This will be written to the console.
|
||||
|
||||
.EXAMPLE
|
||||
WriteAndExitWithSummary -StatusCode 0 -Summary "All operations completed successfully."
|
||||
|
||||
.EXAMPLE
|
||||
WriteAndExitWithSummary -StatusCode 1 -Summary "Error: SCCM client removal failed."
|
||||
|
||||
.NOTES
|
||||
Last Modified: August 27, 2023
|
||||
Author: Manuel Nieto
|
||||
#>
|
||||
|
||||
param (
|
||||
[int]$StatusCode,
|
||||
[string]$Summary
|
||||
)
|
||||
|
||||
# Combine the summary with the current date and time.
|
||||
$finalSummary = "$([datetime]::Now) = $Summary"
|
||||
|
||||
# Determine the prefix based on the status code.
|
||||
$prefix = switch ($StatusCode) {
|
||||
0 { "OK" }
|
||||
1 { "FAIL" }
|
||||
default { "WARNING" }
|
||||
}
|
||||
|
||||
# Easier to read in log file
|
||||
Write-Host "`n`n"
|
||||
|
||||
# Write the final summary to the console.
|
||||
Write-Host "$prefix $finalSummary"
|
||||
|
||||
# Easier to read in log file
|
||||
Write-Host "`n`n"
|
||||
|
||||
# Exit the script with the given status code.
|
||||
if ($StatusCode -lt 0) {$StatusCode = 0}
|
||||
Exit $StatusCode
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Main
|
||||
|
||||
# Initialize
|
||||
$Error.Clear() # Clear any previous errors.
|
||||
$t = Get-Date # Get current date and time.
|
||||
$CCMpath = "$Env:WinDir\ccmsetup\ccmsetup.exe" # Path to SCCM setup executable.
|
||||
$verifyBeginResult # Variable to store beginning SCCM verification result.
|
||||
$verifyEndResult # Variable to store ending SCCM verification result.
|
||||
$summary = "" # Initialize summary string.
|
||||
$StatusCode = 0 # Initialize status code to zero.
|
||||
|
||||
# New lines, easier to read Agentexecutor Log file.
|
||||
Write-Host "`n`n"
|
||||
#Log start time.
|
||||
Write-Host "SCCM Agent cleanup start time: $t"
|
||||
|
||||
try {
|
||||
#Test Admin rights
|
||||
Test-IsAdmin
|
||||
|
||||
# Confirm if SCCM client is present.
|
||||
$verifyBeginResult = Verify-SccmClientDelete
|
||||
|
||||
# Only execute if we have confirmation that SCCM client exists.
|
||||
if ($verifyBeginResult -gt 0) {
|
||||
|
||||
# Stopping SCCM services.
|
||||
try {
|
||||
#Stop SCCM services.
|
||||
Stop-WinService CcmExec
|
||||
Stop-WinService ccmsetup
|
||||
Stop-WinService smstsmgr
|
||||
Stop-WinService CmRcService
|
||||
$summary += "SCCM services stopped. "
|
||||
} catch {
|
||||
$summary += "Error stopping SCCM services: $_ "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
# Remove SCCM client.
|
||||
try {
|
||||
# Remove SCCM client.
|
||||
if (Test-Path $CCMpath) {
|
||||
Write-Host "Found $CCMpath, Uninstalling SCCM agent. `n"
|
||||
#Start Uninstall, Included -WorkingDirectory to Start-Process cmdlet as Workaround to error when working directory has characters "[" "]"
|
||||
Start-Process -WorkingDirectory $Env:WinDir -FilePath $CCMpath -ArgumentList "/uninstall" -Wait -NoNewWindow
|
||||
# wait for exit
|
||||
$CCMProcess = Get-Process ccmsetup -ErrorAction SilentlyContinue
|
||||
try {
|
||||
$CCMProcess.WaitForExit()
|
||||
} catch {}
|
||||
$summary += "SCCM client removed. "
|
||||
}
|
||||
else {
|
||||
$summary += "SCCM client not found. "
|
||||
}
|
||||
} catch {
|
||||
$summary += "Error removing SCCM client. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
# Removing services from registry
|
||||
try {
|
||||
# Remove Services from Registry.
|
||||
$CurrentPath = "HKLM:\SYSTEM\CurrentControlSet\Services"
|
||||
Remove-RegKey "$CurrentPath\CcmExec"
|
||||
Remove-RegKey "$CurrentPath\CCMSetup"
|
||||
Remove-RegKey "$CurrentPath\smstsmgr"
|
||||
Remove-RegKey "$CurrentPath\CmRcService"
|
||||
$summary += "SCCM services removed from registry. "
|
||||
} catch {
|
||||
$summary += "Error removing SCCM services from registry: $_. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
try {
|
||||
# Remove SCCM Client from Registry
|
||||
$CurrentPath = "HKLM:\SOFTWARE\Microsoft"
|
||||
Remove-RegKey "$CurrentPath\CCM"
|
||||
Remove-RegKey "$CurrentPath\CCMSetup"
|
||||
Remove-RegKey "$CurrentPath\SMS"
|
||||
$CurrentPath = "HKLM:\SOFTWARE\Wow6432Node\Microsoft"
|
||||
Remove-RegKey "$CurrentPath\CCM"
|
||||
Remove-RegKey "$CurrentPath\CCMSetup"
|
||||
Remove-RegKey "$CurrentPath\SMS"
|
||||
$summary += "SCCM client registry keys removed. "
|
||||
} catch {
|
||||
$summary += "Error removing SCCM client registry keys: $_. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
try {
|
||||
# Remove WMI Namespaces
|
||||
Remove-WmiNamespace "ccm" "root"
|
||||
Remove-WmiNamespace "sms" "root\cimv2"
|
||||
$summary += "SCCM WMI namespaces removed. "
|
||||
} catch {
|
||||
$summary += "Error removing SCCM WMI namespaces: $_. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
try {
|
||||
# Reset MDM Authority
|
||||
Write-Host "MDM Authority, reviewing and deleting registry key if necessary"
|
||||
$CurrentPath = "HKLM:\SOFTWARE\Microsoft"
|
||||
Remove-RegKey "$CurrentPath\DeviceManageabilityCSP"
|
||||
$summary += "MDM authority reset. "
|
||||
} catch {
|
||||
$summary += "Error resetting MDM authority. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
try {
|
||||
# Remove Folders and Files
|
||||
$CurrentPath = "$Env:WinDir"
|
||||
Clear-Files "$CurrentPath\CCM"
|
||||
Clear-Files "$CurrentPath\ccmsetup"
|
||||
Clear-Files "$CurrentPath\ccmcache"
|
||||
Clear-Files "$CurrentPath\SMSCFG.ini"
|
||||
Clear-Files "$CurrentPath\SMS*.mif"
|
||||
$summary += "SCCM related files and folders removed. "
|
||||
} catch {
|
||||
$summary += "Error removing SCCM files and folders: $_. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
try {
|
||||
# Remove SCCM certificates
|
||||
$CurrentPath = "HKLM:\SOFTWARE\Microsoft\SystemCertificates\SMS\Certificates"
|
||||
Remove-RegKey "$CurrentPath\*"
|
||||
$summary += "SCCM certificates removed. "
|
||||
} catch {
|
||||
$summary += "Error removing SCCM certificates: $_. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
try {
|
||||
# Confirm if SCCM client was removed.
|
||||
$verifyEndResult = Verify-SccmClientDelete
|
||||
if ($verifyEndResult -eq 0) {
|
||||
$summary += "SCCM client removal verified. "
|
||||
} else {
|
||||
$StatusCode = $verifyEndResult
|
||||
$summary += "SCCM client removal failed with code $verifyEndResult. "
|
||||
}
|
||||
} catch {
|
||||
$summary += "Error verifying SCCM client removal: $_. "
|
||||
$StatusCode = -2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch {
|
||||
# Log error and set status code to failure
|
||||
$summary += "Execution Error: $_ "
|
||||
$StatusCode = 1
|
||||
}
|
||||
|
||||
# Perform Intune sync and log the result. Only if no errors.
|
||||
if ($StatusCode -le 0) {
|
||||
try {
|
||||
$syncDetails = Start-CompleteIntuneSync
|
||||
$summary += "Intune sync request: $($syncDetails.SyncStartTime), Start: $($syncDetails.SyncStartEvent), Completed: $($syncDetails.SyncCompleteEvent). "
|
||||
} catch {
|
||||
$summary += "Error during Intune sync. "
|
||||
}
|
||||
}
|
||||
|
||||
# Write the summary and exit with the appropriate status code
|
||||
WriteAndExitWithSummary -StatusCode $StatusCode -Summary $summary
|
||||
|
||||
#Finished!
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1,22 @@
|
||||
<H1> SCCM Agent remove via Proactive Remediations v1.0 </H1>
|
||||
|
||||
Removes SCCM Client via MEM Intune Proactive Remediation.
|
||||
I used it to move co-managed devices to Intune managed devices in an environment where SCCM was no longer present.
|
||||
|
||||
This script is based on the original work from the following sources:
|
||||
|
||||
remove-sccmagent.ps1
|
||||
Author: Robert M.
|
||||
source: https://github.com/robertomoir/remove-sccm/blob/master/remove-sccmagent.ps1
|
||||
|
||||
Remove-ConfigMgrClient.ps1
|
||||
Author: Chad Simmons
|
||||
Source: https://github.com/ChadSimmons/Scripts/blob/default/ConfigMgr/Troubleshooting/Remove-ConfigMgrClient.ps1
|
||||
|
||||
Remove All Traces of Microsoft SCCM w/ PowerShell (By Force)
|
||||
Author: James A. chambers
|
||||
Source: https://jamesachambers.com/remove-microsoft-sccm-by-force/
|
||||
|
||||
SCCM Client Complete Uninstall / Remove + Powershell Script
|
||||
Source: https://www.optimizationcore.com/deployment/sccm-client-complete-remove-uninstall-powershell-script/
|
||||
|
||||
Reference in New Issue
Block a user