如何从托管在IIS上的WCF服务启动进程?

8

我希望能够从内部网络客户端在WCF服务端运行一个进程。在我的情况下,客户端请求服务器在提供的凭据下在服务器机器上创建一个新进程。WCF服务托管在IIS 7.5上,我使用以下代码启动进程。

var processInfo = new ProcessStartInfo("C:\\Windows\\System32\\notepad.exe")
{
    UserName = "some user",
    Password = MakeSecureString("some password"),
    UseShellExecute = false,
    LoadUserProfile = true
};

Process process = Process.Start(processInfo);

如果我将WCF服务作为自托管的控制台应用程序在管理员用户下运行,并且我看到记事本在另一个用户下启动,则此代码有效。但是在IIS上失败,没有异常,但进程立即终止。
process.HasExited = true;
process.ExitCode = -1073741502;

在IIS上,WCF应用程序在具有管理员权限的用户下运行,并在web.config中定义了完全信任。我无法使用自托管应用程序,因为它不支持易于连续交付(如使用IIS Web农场的WebDeploy)。
问题:如何从在IIS上托管的WCF服务中启动服务器端进程?
编辑: 我偶然发现了这个post,其中有类似的问题,我尝试了那里的所有方法,包括使用Process.Start和P/Invoke的CreateProcessWithLogonW和CreateProcessAsUser的所有可能变体,我还尝试授予用户附加权限。但是,所有这些都无法正常工作,错误消息与该人发布的相同。

有没有带完整源代码示例的最终解决方案? - Kiquenet
这是不可能的,除非使用肮脏的技巧。我没有做。 - oleksii
我没有表达清楚。你不能这样做。即使尝试使用CreateProcessWithLogonWCreateProcessAsUser进行身份验证,操作系统也不支持此操作,因为它被视为安全漏洞,所以你无法合法地使其工作。恶意软件可以这样做,但我不是那个领域的专家,而且安全漏洞通常会很快得到修补。 - oleksii
3个回答

4

问题是,如果你在控制台应用程序中托管WCF服务,那么会为该用户创建一个Windows会话(已登录的用户和加载的Windows资源管理器),而记事本将在该用户的UI中打开并显示,因此您可以在UI中看到它。

当您在IIS中托管WCF服务时,它是一个服务器,IIS不需要或允许用户交互,并且即使没有用户登录也能工作;在这种情况下,没有UI来托管记事本或其他启用UI的应用程序,您可以执行进程以进行处理或其他批处理作业,但不能呈现Windows UI应用程序,因为资源管理器未加载并且没有地方呈现您进程的UI。


1
我想在IIS中托管WCF服务(使用AppPool中的用户A),并在调用我的命令行EXE(而非UI)时模拟另一个用户B。有什么建议吗?也许不可能。 - Kiquenet

1

这是我用来调用GnuPGP进行加密的方法。你的设置如何比较?

private int ExecuteCommand(string arguments, string passPhrase, int timeout)
        {
            Process processObject;
            ProcessStartInfo pInfo = new ProcessStartInfo(_executablePath, arguments);


            pInfo.CreateNoWindow = true;
            pInfo.UseShellExecute = false;

            pInfo.RedirectStandardInput = true;
            pInfo.RedirectStandardOutput = true;
            pInfo.RedirectStandardError = true;
            processObject = Process.Start(pInfo);

            if (!string.IsNullOrEmpty(passPhrase))
            {
                processObject.StandardInput.WriteLine(passPhrase);
                processObject.StandardInput.Flush();
            }

            string result = processObject.StandardOutput.ReadToEnd();
            string error = processObject.StandardError.ReadToEnd();

            if (!processObject.WaitForExit(timeout))
            {
                throw new TimeoutException("GnuPG operation timeout. Waited " + timeout + " milliseconds ");
            }

            int exitcode = processObject.ExitCode;

            Error = error;
            Output = result;

            return exitcode;

        }

不,这并不能帮助解决问题。在 processObject = Process.Start(pInfo); 这行代码之后,HasExited 属性已经被设置为 true。 - oleksii
实际上,我正在使用一个测试工具来测试其他软件检测进程启动的能力。 - oleksii
然后使用一个没有用户界面的简单程序进行测试。 - John Saunders
@DustinDavis,您是否在托管在IIS中的WCF服务中调用ExecuteCommand? - Kiquenet

1

有一个应用程序池设置,可以确保它加载用户配置文件。

loadUserProfile Optional Boolean attribute.

Specifies whether IIS loads the user profile for the application pool identity. Setting    
this value to false causes IIS to revert to IIS 6.0 behavior. IIS 6.0 does not load the 
user profile for an application pool identity.

The default value is false.

除了作为具有足够权限的域用户身份可能会起作用吗?我知道至少需要一个用户配置文件。

话虽如此,这是一个有点奇怪的架构。似乎更好的架构是拥有一个持久进程,比如一个Windows服务,网站与之通信,但我不确定您的限制是什么。

希望能有所帮助。


感谢您的回答。这很有道理。使用IIS,通过WebDeploy交付产品会更容易,因为我可以创建一个Web Farm。话虽如此,我尝试了Win Service,但在那里遇到了同样的问题。我正在倒退到命令行托管和脚本部署,因为在IIS上配置这个过程很痛苦。 - oleksii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接