【问题标题】:Running user process cmd.exe from Windows C# services从 Windows C# 服务运行用户进程 cmd.exe
【发布时间】:2017-12-14 07:34:19
【问题描述】:

我正在构建 Windows 服务。它需要使用当前用户权限运行命令并删除与子字符串匹配的所有存储凭据 - 例如“神秘”。

我已经在 CreateProcessAsUser 方法中调用了其他模块,这些模块确实有效。但是,调用 cmd.exe 模块并传递复杂的命令似乎很棘手。

我可能遗漏了一些转义字符或一些额外的命令行参数,导致复杂的命令无法成功运行。如果我调用我的服务,我可以看到 cmd 提示符正在启动,但它不执行命令。

我确实尝试解决它。我直接在命令cmd提示符下测试了一下,效果很好。

以下是示例:

直接从 cmd 提示符:

FOR /F "usebackq tokens=1* delims=: " %i in (`cmdkey /list^|findstr MYSTRING`) do cmdkey /delete:%j

通过run box 执行相同的命令时失败:

cmd.exe /K FOR /F "usebackq tokens=1* delims=: " %%i in (`cmdkey /list^|findstr MYSTRING`) do cmdkey /delete:%%j

我尝试添加双引号,转义特殊字符,但不知何故它不起作用。下面是这样的例子。

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"

提前感谢您的帮助。

编辑:

根据 tukan 的输入,我能够从运行框运行命令。但是,当我在 C# 代码中尝试相同的操作时,它会在命令提示符中引发错误。

命令提示错误(服务创建的进程):

tokens = 1 * delims =: " 在这个时候是出乎意料的。

下面是C#方法。

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;
        }

【问题讨论】:

  • 你为什么在第二个命令中加倍%
  • 不清楚,你想要什么。提供一些 c# 代码,如果它确实是一个 c# 问题。您可能需要 @ 运算符 string mystring = @"String, which doesnt resolve escapesequences, C:\stuff stays C:\stuff";
  • @PetSerAl 是的,我添加了 %%。命令:cmd.exe /K FOR /F "usebackq tokens=1* delims=:" %%i in (cmdkey /list^|findstr MYSTRING) do cmdkey /delete:%%j
  • @FrankM 当然我可以添加 C# 代码。但我觉得,由于命令本身在运行框中不起作用,因此调试 C# 代码毫无意义。请提出建议。
  • Thx :) 您的 tukans cmdline 副本有更多空格,这可能会导致错误:(yours)tokens = 1 * delims =: vs (tukans)tokens=1* delims=: visual studio 有时会这样做(在粘贴时添加空格)

标签: c# windows for-loop cmd createprocessasuser


【解决方案1】:

我确实从 run box 对其进行了测试,它在 Windows 7 x64 上运行良好且没有错误。

cmd.exe /K FOR /F "usebackq tokens=1* delims=: " %i in (`cmdkey /list^|findstr tukan`) do echo "test"

两种方式(cmd.exerun box)都会正确产生两条回声线。

你有什么窗户?如果你在cmd.exe 中执行只是cmdkey /list^|findstr ADAL 你会得到什么?

【讨论】:

  • 我使用的是 Windows 7
  • @Indranil:因此该行将正常工作,因为我也有 Windows 7。请在执行任何实际操作之前使用echo 命令运行测试。
  • 我尝试了完整的命令,它的工作。双 % 是问题所在。接下来我会尝试从C#服务方法并确认。
  • FOR 命令在批处理文件中时,您只需要将% 加倍即可。
  • @Indranil 如果您希望命令提示符 (cmd.exe) 在执行后存在,您需要将cmd.exe /K 中的开关换成cmd.exe /C。最后你不需要任何额外的命令。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
相关资源
最近更新 更多