For those of you who install the SCCM agent in you...
# _general
n
For those of you who install the SCCM agent in your persistent MCS image, how are you generalizing the agent when you seal it? We have had a process in place for a year or so, and up until today it has been flawless for generalizing SCCM. Can't figure out why it's no longer working, and all provisioned VDAs from this new master have the same SCCM client ID/GUID.
r
Could your image have been booted?
If you use an mcs connector it would be after publishing. You might need a layer script to re generalize it.
j
Right out of BIS-F, but we don't run BIS-F on every seal so we pulled this out and run this in our own custom sealing script
Copy code
[string]$appVendor = 'Microsoft'
	[string]$appName = "SCCM Agent"
	[string]$appInstallPath = "$env:windir\CCM"
	[string]$appService = 'CcmExec'
	[string]$appRegKey = "$hklm_software\Microsoft\SystemCertificates\SMS\Certificates"
	$CryptoPath = "C:\ProgramData\Microsoft\Crypto"
	$CryptoKey = "Keys"
	$OldCrpytoKey = "KeysOLD"
	$CryptoKeyPath = $CryptoPath + "\" + $CryptoKey
	$OldCrpytoKeyPath = $CryptoPath + "\" + $OldCrpytoKey


Remove-Item -Path "$env:windir\SMSCFG.ini" -Force -ErrorAction SilentlyContinue
Remove-Item -Path HKLM:\Software\Microsoft\SystemCertificates\SMS\Certificates\*  -Force
Remove-Item -Path "C:\ProgramData\Microsoft\Crypto\KeysOLD" -Force -Recurse
Get-CimInstance -Namespace root\ccm\locationservices -Class TrustedRootKey | Remove-CimInstance
Get-CimInstance -Namespace root\ccm\invagt -Class InventoryActionStatus | Where-Object { $_.InventoryActionID -eq "{00000000-0000-0000-0000-000000000001}" } | Remove-CimInstance
Get-CimInstance -Namespace root\ccm\scheduler -Class CCM_Scheduler_History | Where-Object { $_.ScheduleID -eq "{00000000-0000-0000-0000-000000000001}" } | Remove-CimInstance
Rename-Item -Path $CryptoKeyPath -NewName $OldCrpytoKey -Force
New-Item -Path $CryptoKeyPath -ItemType Directory
Get-Acl -Path $OldCrpytoKeyPath | Set-Acl -Path $CryptoKeyPath

function Remove-CCMCache {
		[CmdletBinding()]
		$UIResourceMgr = New-Object -ComObject UIResource.UIResourceMgr
		$Cache = $UIResourceMgr.GetCacheInfo()
		$CacheElements = $Cache.GetCacheElements()
		foreach ($Element in $CacheElements) {
			Write-BISFLog -Msg "$appVendor $appName deleted Cache Element with PackageID $($Element.ContentID)"
			Write-BISFLog -Msg "from folder $($Element.Location)"
			$Cache.DeleteCacheElement($Element.CacheElementID)
		}
}
r
I do the following workaround for non persistent (to keep sccm agent in the master installed for patching), but maybe you can consider this: 1. in the master i uninstall SCCM Agent via my sealing script 2. in the same script i setup a scheduled task to install SCCM agent (via Script) 3. the scheduled task runs at computer startup as system 4. the script in the task checks if the hostname matches my master if yes it installs the sccm agent if not then it exists (its already the nonpersistent vdi) 5. when starting again the master it install the sccm agent fresh
n
Interesting. Looks like BIS-F is doing mostly the same thing, but perhaps I'll add the missing steps to my own. This is what we have been using for over a year now:
Copy code
$Log = "C:\Core\logs\Generalize.log"

Function Write-ToLog {
	Param (
		[Parameter(Mandatory = $True, ValueFromPipeline = $True)] [String]$Message,
		[Parameter(Mandatory = $False)] [Bool]$ErrTrap = $False
	)
	$Message = [DateTime]::Now.ToString("[MM/dd/yyy HH:mm:ss]")+ " $($Env:UserDomain)\$($Env:Username): " + $Message
	If ($ErrTrap) {
		Write-Host $Message -ForegroundColor Red -BackgroundColor Yellow
	} Else {
		Write-Host $Message -ForegroundColor Green
	}
	$Message | Out-File $Log -Append
}

Write-ToLog "Stopping the CM client"
Get-Service -Name "CcmExec" | Stop-Service -WarningAction SilentlyContinue -ErrorVariable StopCcm | Out-Null
If ((Get-Service -Name "CcmExec").Status -ne "Stopped") {
	Write-ToLog "Terminating the CcmExec process"
	Get-Process -Name "CcmExec" | Stop-Process -Force | Out-Null
}

Write-ToLog "Changing the CcmExec service to 'Automatic (Delayed Start)'"
$Proc = Start-Process -FilePath "sc.exe" -ArgumentList "config CcmExec Start= Delayed-Auto" -WorkingDirectory $PSScriptRoot -Wait -PassThru

Write-ToLog "Deleting the SMS Certs"
$Proc = Start-Process -FilePath "Certmgr.exe" -ArgumentList "/del /all /c /s /r localmachine SMS" -WorkingDirectory $PSScriptRoot -Wait -PassThru

Write-ToLog "Deleting the SMS RSA Keyfile"
Remove-Item "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\19c5cf9c7b5dc9de3e548adb70398402_9e2ae6f6-0938-42e2-a85a-4ddfaa4b92cf" -Force -ErrorAction SilentlyContinue | Out-Null

Write-ToLog "Deleting SmsCfg.ini"
Remove-Item "C:\Windows\SmsCfg.ini" -Force -ErrorAction SilentlyContinue | Out-Null


Write-ToLog "Validating Generalization success"
$Output += Invoke-Command -ScriptBlock { sc.exe qc CcmExec }
$i = New-Object -TypeName PSObject
$Output | Select-String -Pattern "START_TYPE" | ForEach-Object {
	Add-Member -InputObject $i -MemberType NoteProperty -Name (([String]$_).Trim() -Split "         :")[0] -Value (([String]$_).Trim() -Split "         :")[1] | Out-Null
}
$SvcStart = $i.START_TYPE

$Certs - Get-ChildItem HKLM:\Software\Microsoft\SystemCertificates\SMS\Certificates
$Cfg = Get-Item "C:\Windows\SmsCfg.ini" 2>$Null
If (!($Certs) -and (!($Cfg)) -and ($SvcStart -like "*DELAYED*")) {
	Write-ToLog "Generalization succeeded!"
	Write-ToLog "Shutting down device in 20 seconds"
	Start-Process -FilePath "shutdown.exe" -ArgumentList "/s /t 20" -NoNewWindow -PassThru | Out-Null
} Else {
	Write-ToLog "Generalization failed!" -ErrTrap $True
}
Exit
@Rob Zylowski This is for our persistent W11 image, so no app layering. The MCS process will boot the master to run sysprep, which is one reason we set the CcmExec service to Delayed Start, but other than that, no booting. Script shuts down the VM, and when I run my Azure snapshot script, that deallocates the VM in Azure and handles the disk copy to the other region and creates the snapshots in our subs.
r
That shouldnt be an issue there is no network access during the prep step.
n
I figured. We do it with other agents like CyberArk, which requires no network access to generate a new GUID.
Testing the BIS-F script on a provisioned VDA... shouldn't this also generalize this agent after a reboot? Same SCCM GUID even when using it. I'm using this to validate:
Copy code
((Get-WmiObject -Namespace root\ccm -query "Select ClientID from CCM_Client").ClientID).Split(':')[1]
r
If your doing persistent use a flag file to only run once
n
Not sure what you mean here.
This must have been a fluke, because I ran the same TS on a new master and then provisioned some VDAs, and they are getting unique SCCM IDs.
r
On a persistent vm you dont want to create a new guid every boot.
n
Yeah, this runs immediately after the TS completes, outside of the TS. It's the last step before the VM shuts down. Then that VM is used to create the snapshot that I use for the catalog. This is only done in the master.
I was just messing around with the one VDA trying to troubleshoot.