Created
August 25, 2025 14:15
-
-
Save Bill-Stewart/5446ca84167a30d89d46cb984d65a0f6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Clear-SmartcardCache.ps1 | |
Written by Bill Stewart | |
We have seen some instances where a user gets a new smartcard certificate and | |
they are unable to log on due to cached data in the local registry. | |
The purpose of this script is to remove this cached data from the registry | |
to fix this prompt. The script makes a backup copy of the registry subkey to | |
a user-selectable folder before it deletes anything. | |
1. Uses reg.exe to make a backup copy of the registry subkey containing the | |
cached data to a user-selectable folder | |
2. Stops the following services: | |
* CertPropSvc (Certificate Propagation) | |
* SCardSvr (Smart card) | |
3. Removes the following registry value: | |
* Key: HKEY_LOCAL_MACHINE | |
* Subkey: SOFTWARE\Microsoft\Cryptography\Calais\Cache | |
* Value: Cache | |
4. Prompts to reboot the computer | |
Version history: | |
2025-08-25 | |
* Initial version | |
#> | |
#requires -version 3 | |
#requires -RunAsAdministrator | |
[CmdletBinding()] | |
param( | |
[String] | |
$BackupPath, | |
[Switch] | |
$NonInteractive, | |
[Switch] | |
$Overwrite | |
) | |
$SCRIPT_TITLE = "Clear Smartcard Cache" | |
$BACKUP_FILE_NAME = "CachedSmartcardData.reg" | |
$REG_SUBKEY = "SOFTWARE\Microsoft\Cryptography\Calais\Cache" | |
$REG_VALUE = "Cache" | |
$WINDOWS_FOLDER = [Environment]::GetFolderPath([Environment+SpecialFolder]::Windows) | |
$ERROR_FILE_NOT_FOUND = 2 | |
$ERROR_PATH_NOT_FOUND = 3 | |
$ERROR_ALREADY_EXISTS = 183 | |
$ERROR_CANCELLED = 1223 | |
$MB_YESNO = 4 | |
$MB_ICONERROR = 0x10 | |
$MB_ICONQUESTION = 0x20 | |
$MB_ICONINFORMATION = 0x40 | |
$MB_DEFBUTTON2 = 0x100 | |
$MB_IDYES = 6 | |
$wshShell = New-Object -ComObject "WScript.Shell" | |
function OutMessage { | |
param( | |
[String] | |
$message | |
) | |
if ( $NonInteractive ) { | |
Write-Host $message | |
} | |
else { | |
$null = $wshShell.Popup($message,0,$SCRIPT_TITLE,$MB_ICONINFORMATION) | |
} | |
} | |
function OutError { | |
param( | |
[String] | |
$message, | |
[Management.Automation.ErrorCategory] | |
$category | |
) | |
if ( $NonInteractive ) { | |
Write-Error $message -Category $category | |
} | |
else { | |
$null = $wshShell.Popup($message,0,$SCRIPT_TITLE,$MB_ICONERROR) | |
} | |
} | |
function BrowseFolder { | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0)] | |
[String] | |
$dialogTitle, | |
[Parameter(Position = 1)] | |
[String] | |
$initialDirectory, | |
[Parameter(Position = 2)] | |
[Switch] | |
$showNewFolderButton | |
) | |
$BIF_RETURNONLYFSDIRS = 0x01 | |
$BIF_NEWDIALOGSTYLE = 0x40 | |
$BIF_NONEWFOLDERBUTTON = 0x200 | |
$options = $BIF_RETURNONLYFSDIRS -bor $BIF_NEWDIALOGSTYLE | |
if ( -not $showNewFolderButton ) { | |
$options = $options -bor $BIF_NONEWFOLDERBUTTON | |
} | |
[IntPtr] $hWnd = [Diagnostics.Process]::GetCurrentProcess().MainWindowHandle | |
try { | |
$shellApp = New-Object -ComObject Shell.Application | |
$folder = $shellApp.BrowseForFolder($hWnd,$dialogTitle,$options,$initialDirectory) | |
if ( $null -ne $folder ) { | |
$folder.Self.Path | |
} | |
} | |
catch { | |
} | |
} | |
function TestRegistryValue { | |
param( | |
[String] | |
$path, | |
[String] | |
$value | |
) | |
$null -ne (Get-ItemProperty $Path $value -ErrorAction SilentlyContinue) | |
} | |
if ( -not (TestRegistryValue "HKLM:\$REG_SUBKEY" $REG_VALUE) ) { | |
$message = "Smartcard cache registry value already cleared." | |
OutMessage $message | |
exit | |
} | |
$reg = Join-Path (Join-Path $WINDOWS_FOLDER "System32") "reg.exe" | |
if ( -not (Test-Path $reg) ) { | |
OutError "File not found - '$reg'" "ObjectNotFound" | |
exit $ERROR_FILE_NOT_FOUND | |
} | |
if ( -not $BackupPath ) { | |
if ( $NonInteractive ) { | |
$BackupPath = $WINDOWS_FOLDER | |
} | |
else { | |
$params = @{ | |
dialogTitle = "Select folder for smartcard cache backup file" | |
initialDirectory = $WINDOWS_FOLDER | |
} | |
$BackupPath = BrowseFolder @params | |
if ( -not $BackupPath ) { exit } | |
} | |
} | |
else { | |
$BackupPath = (Resolve-Path $BackupPath -ErrorAction SilentlyContinue).ProviderPath | |
} | |
if ( -not (Test-Path $BackupPath) ) { | |
OutError "Backup folder not found - '$BackupPath'" "ObjectNotFound" | |
exit $ERROR_PATH_NOT_FOUND | |
} | |
$BackupFilePath = Join-Path $BackupPath $BACKUP_FILE_NAME | |
if ( Test-Path $BackupFilePath ) { | |
if ( $NonInteractive ) { | |
if ( -not $Overwrite ) { | |
Write-Host "Smartcard cache backup file already exists." | |
exit $ERROR_ALREADY_EXISTS | |
} | |
} | |
else { | |
if ( $wshShell.Popup("Smartcard cache backup file already exists. Overwrite?", | |
0,$SCRIPT_TITLE,$MB_YESNO -bor $MB_ICONQUESTION -bor $MB_DEFBUTTON2) -ne $MB_IDYES ) { | |
exit $ERROR_CANCELLED | |
} | |
} | |
} | |
& $reg EXPORT "HKLM\$REG_SUBKEY" $BackupFilePath /y | |
$result = $LASTEXITCODE | |
if ( $result -ne 0 ) { | |
OutError ("REG EXPORT command returned error code {0}" -f $result) "InvalidResult" | |
exit $result | |
} | |
if ( -not (Test-Path $BackupFilePath) ) { | |
OutError "Smartcard cache backup file not found - '$BackupFilePath'" "ObjectNotFound" | |
exit $ERROR_FILE_NOT_FOUND | |
} | |
$serviceNames = "CertPropSvc","SCardSvr" | |
$serviceNames | Stop-Service -Verbose | |
Remove-ItemProperty "HKLM:\$REG_SUBKEY" $REG_VALUE -ErrorAction SilentlyContinue | |
if ( TestRegistryValue "HKLM:\$REG_SUBKEY" $REG_VALUE ) { | |
$errorMessage = "Registry value not removed - 'HKLM\$REG_SUBKEY\$REG_VALUE'" | |
OutError $errorMessage "ResourceExists" | |
exit $ERROR_ALREADY_EXISTS | |
} | |
if ( -not $NonInteractive ) { | |
$answer = $wshShell.Popup("Reboot now?", | |
0,$SCRIPT_TITLE,$MB_YESNO -bor $MB_ICONQUESTION -bor $MB_DEFBUTTON2) | |
} | |
else { | |
$answer = $MB_IDYES | |
} | |
if ( $answer -eq $MB_IDYES ) { | |
Restart-Computer -Force | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment