'Remove an entry from credential manager for all users on Windows
I am currently implementing a "remove settings" for all users in a Windows uninstaller and came over an issue I am not even sure is possible to solve.
The application stores credential entries for the current user using the CredentialManager (keymgr.dll). Let's call the target of the credential "X". On uninstall all credentials with stored with target "X" should be removed on all users. The uninstaller of course requires administrator privileges but still I find it very difficult to accomplish this.
For the current user that command is generally solved via cmdkey /delete=:X from a command prompt. As far as I know cmdkey.exe /list only helps to list entries for the current user and can't remove local entries from another user.
I have learned that the credentials are stored as OS files under the C:\Users\_user_\AppData\Local\Microsoft\Credentials folder, but I can't know which files are the entries I want to delete and removing all would be dangerous for other applications. Also I assume removing OS files will be dangerous and could have limitations (extra UAC prompt?) as well.
Runas command is the closest shot I got but because it requires the password of the user it becomes very difficult and not something I would want in the uninstaller. I also would need a way to get the username and domain for each user and iterate them.
I would prefer to use either cmd or powershell for this.
Solution 1:[1]
The cmdkey.exe utility when run from a batch file or a PowerShell command may encounter two issues related to special characters. 1. If run from a batch file, if the credential has "(" or ")" without the double quotes, that is left and right paren, that credential will not be removed. 2. If the credential name aka targetname, has a hyphen surronded by spaces the cmdkey will not remove or create a a credential with that string " - ".
There are a few powershell modules written to try and do this, but the only one i found that handles this exceptions was on Github https://github.com/bamcisnetworks/BAMCIS.CredentialManager
BAMCIS.CredentialManager
Using this i was able to create credentials to set up a test environment with parens or hyphens, but more importantly to remove them by gathering the users list of cached credentials using the modules command and then passing the information in the command to the remove command to remove ALL cached credentials.
One caveat. After removing the command, after some period of time two cached credentials dynamically reappear.
So to address frequent user lock out issues i am going to try and deploy this using SCCM under user context at logoff. Otherwise a system restart after removing the credentials may be needed. Here is a prototype script that imports the module and then uses it to remove all cached credentials, As always, test, test, test and use at your own risk!
Clear-host
import-Module "$PSScriptRoot\BAMCIS.CredentialManager\BAMCIS.CredentialManager.psd1"
$L = Get-CredManCredentialList -ErrorAction SilentlyContinue
If($L -eq $null)
{
Write-host "No Cached Credentials found to remove, no action taken"
$LASTEXITCODE = 0
Write-host "The last exit code is $LASTEXITCODE"
}
Else
{
ForEach($cred in $L)
{
Write-host "`tProcessing...`n"
Write-host "$($cred.TargetName.ToString())`n"
Write-host "$($cred.Type.ToString())`n`n"
$R = Remove-CredManCredential -TargetName $($cred.TargetName.ToString()) -Type $($cred.Type.ToString()) -Force
}
$L = Get-CredManCredentialList -ErrorAction SilentlyContinue -ErrorVariable $Cred_Error
If($L -eq $null)
{
Write-host "All Cached Credentials removed, program Complete"
$LASTEXITCODE = 0
Write-host "The last exit code is $LASTEXITCODE"
}
Else
{
Write-host "WARNING: One or more Cached Credentials were not removed, program Complete"
$LASTEXITCODE = 1
}
}
Solution 2:[2]
Batch, elevated cmd prompt:
To find the main ones, lists any with MS.O, Micro and teams:
for /f "tokens=1-4 Delims=:=" %A in ('cmdkey /list ^| findstr Target: ^| findstr /i "MS.O Micro Teams"') do @echo %D
This deletes all the entries for teams:
for /f "tokens=1-4 Delims=:=" %A in ('cmdkey /list ^| findstr /i teams') do @cmdkey /delete:%D
If you want to include this as a script the syntax will be slightly different. Double the %%A %%D vars
Solution 3:[3]
Ran into similar issue, clearing old credentials for non domain joined devices. Created logon task to clear credentials. In my case was looking for particular file server, so not to clear all creds by accident. Because of syntax issue when piping string expressions into task, was easier to create reference .ps1 then reference in task. Pushed this script through Intune....
# Full path of the file
$file = 'C:\script\clearcreds.ps1'
#If the file does not exist, create it.
if (-not(Test-Path -Path $file -PathType Leaf)) {
try {
$null = New-Item -Path "C:\ProgramData\CentraStage\Packages" -Name
"clearcreds.ps1" -ItemType "file" -Value 'cmdkey /list | ForEach-Object{if($_ -
like "*Target:*" -and $_ -like "*fileserver*"){cmdkey /del:($_ -replace " ","" -replace "Target:","")}}'
Write-Host "The file [$file] has been created."
}
catch {
throw $_.Exception.Message
}
}
#######################################
#Create ScheduledTask to Run at log on.
#######################################
$schtaskName = "Clear Cached Creds "
$schtaskDescription = "Clears Cached Creds for each user at logon."
$trigger = New-ScheduledTaskTrigger -AtLogOn
$class = cimclass MSFT_TaskEventTrigger root/Microsoft/Windows/TaskScheduler
#Execute task in users context
$principal = New-ScheduledTaskPrincipal -GroupId "S-1-5-32-545" -Id "Author"
$action3 = New-ScheduledTaskAction -Execute 'Powershell.exe' "-File C:\script\clearcreds.ps1"
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$null=Register-ScheduledTask -TaskName $schtaskName -Trigger $trigger -Action $action3 -Principal $principal -Settings $settings -Description
$schtaskDescription -Force
Start-ScheduledTask -TaskName $schtaskName
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Rui Jarimba |
| Solution 3 | jarred power |
