I am building a Windows Service. It needs to run a command using current user privileges and delete all stored credentials which matches a substring - e.g. "MYSTRING".
I have invoked other modules in CreateProcessAsUser method which does work. However, invoking a cmd.exe module and passing complex command seems to be tricky.
I am probably missing some escape characters or some additional command line arguments, causing complex command to fail to run successfully. If I invoke my service I can see cmd prompt starting, but it does not execute the command.
I did try to troubleshoot it. I tested it in the command cmd prompt directly, which works.
Here are the examples:
Directly from cmd prompt:
FOR /F "usebackq tokens=1* delims=: " %i in (`cmdkey /list^|findstr MYSTRING`) do cmdkey /delete:%j
Same command fails when executed via the run box
:
cmd.exe /K FOR /F "usebackq tokens=1* delims=: " %%i in (`cmdkey /list^|findstr MYSTRING`) do cmdkey /delete:%%j
I tried adding double quotes, escaping special characters, but somehow it is not working. Below are such examples.
cmd.exe /K "FOR /F ^"usebackq tokens=1* delims=: ^" %%i in (`cmdkey /list^|findstr ADAL`) do cmdkey /delete %%j"
cmd.exe /K "FOR /F ^"usebackq tokens=1* delims^=: ^" %%i in (^`cmdkey /list^|findstr ADAL^`) do cmdkey /delete %%j"
Thanks in advance for your help.
Edit:
Based on tukan's input I was able to run the command from run box. However, when I try the same in the C# code, it is throwing error in the command prompt.
Error in command prompt (process created by service):
tokens = 1 * delims =: " was unexpected at this time.
Below is the C# method.
public static bool ClearCredsCache()
{
var hUserToken = IntPtr.Zero;
var startInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
//String cmdLine = "cmd.exe \"FOR / F \"usebackq tokens=1* delims=: \" %%i in (`cmdkey / list ^| findstr MYSTRING`) do cmdkey / list %%j\"& pause";
String cmdLine = "cmd.exe /K FOR /F \"usebackq tokens = 1 * delims =: \" %i in (`cmdkey /list^|findstr MYSTRING`) do cmdkey /delete:%j";
//String cmdLine = null;
String appPath = "cmd.exe";
String workDir = null;
bool visible = true;
startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
try
{
if (!GetSessionUserToken(ref hUserToken))
{
throw new CredMgmtException(CredMgmtException.medium, "StartProcessAsCurrentUser: GetSessionUserToken failed.");
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
startInfo.lpDesktop = null;
if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
throw new CredMgmtException(CredMgmtException.medium, "StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
}
if (!CreateProcessAsUser(hUserToken,
appPath, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
false,
dwCreationFlags,
pEnv,
workDir, // Working directory
ref startInfo,
out procInfo))
{
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
throw new CredMgmtException(CredMgmtException.medium, "StartProcessAsCurrentUser: CreateProcessAsUser failed. Error Code -" + iResultOfCreateProcessAsUser);
}
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
}
finally
{
CloseHandle(hUserToken);
if (pEnv != IntPtr.Zero)
{
DestroyEnvironmentBlock(pEnv);
}
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
}
//stdOut.
// CredMgmtUtil.WriteEvent("Startupinfo=" + startInfo.hStdOutput)
return true;
}