I'm writing an uninstaller, and as part of the process, I want to clean up caches, temporary files, etc. for all local users. The app will run elevated for this to work.
The files I'm looking for are found in special folders such as AppData\Local
, so I need the paths. For the currently logged in user, this is trivial to do with Environment.GetFolderPath
. However, this won't work for a different user.
According to referencesource.microsoft.com, GetFolderPath
ultimately calls into SHGetFolderPath
, which in turn wraps SHGetKnownFolderPath
. Both of those Win32 APIs do have an optional hToken
parameter which lets me specify an account token.
And, indeed, this will work:
private static string GetFolderPath(Guid knownfolderid, string user, string domain, string password)
{
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
SafeTokenHandle safeTokenHandle;
if (!LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle))
throw new System.Security.Authentication.InvalidCredentialException();
IntPtr pPath;
SHGetKnownFolderPath(knownfolderid,
0,
safeTokenHandle.DangerousGetHandle(),
out pPath);
string result = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
return result;
}
…but it's impractical for my uses, of course — I don't want the admin who uninstalls something to have to know and supply each username and password.
So:
- is there a way to get an appropriate access token without needing to know the user's credentials?
- failing that, is there a different way to accomplish my goal? Reading the information from the registry seems unsafe, as does hardcoding the folder names, of course.