如何启动一个进程以从 Windows 服务运行 bat 文件

Posted

技术标签:

【中文标题】如何启动一个进程以从 Windows 服务运行 bat 文件【英文标题】:How can I start a process to run a bat file from a windows service 【发布时间】:2016-08-23 00:30:11 【问题描述】:

尝试从 Windows 服务运行 bat 文件。 代码如下:

try
            
                SecureString securePwd = new SecureString();
                foreach (char c in pwd)
                
                    securePwd.AppendChar(c);
                
                Process process = new Process();
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.FileName = @"CMD.exe";  //The file in that DIR.
                process.StartInfo.WorkingDirectory = @"C:\";
                process.StartInfo.Arguments = @"/C " + filePath;
                process.StartInfo.Verb = "runas";
                process.StartInfo.UserName = user;
                process.StartInfo.Password = securePwd;
                process.Start();
            
            catch (Exception ex)
            
                EventLog myEventLog = new EventLog  Source = "MoC LaneUpdate" ;
                myEventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
            

我已经验证了相同的代码在非服务中运行时是否有效。我也没有收到错误消息,但是 .bat 文件没有运行,至少在我当前的用户会话中没有出现。我的文件是否在后台会话中运行?如何在 startinfo 中指定的用户中运行批处理文件?

【问题讨论】:

“它似乎没有出现在我当前的用户会话中” - 对我来说听起来很正常,假设您实际上将服务代码作为服务运行。在不同用户的凭据下运行不会改变没有显示控制台窗口的登录会话这一事实,就像您在自己的登录会话中“以管理员身份”运行程序时一样,该程序仍然使用您的会话用户界面。您有什么证据表明批处理文件实际上并未执行?是什么让您认为您发布的代码应该做的不是它正在做的事情? 对,但是我的批处理文件应该完成的任务永远不会完成。我不担心看不到 cmd 提示符。 您可以配置服务以允许与桌面交互。安装服务后,转到服务屏幕和服务属性菜单的登录选项卡。选中允许服务与桌面交互复选框。 哦。你的代码看起来不错。只是为了好玩,你能写一个 bat 文件来创建一个文本文件,如果它被调用,它会给你留下具体的证据吗?然后,如果你有你的服务调用,你肯定会知道它正在调用一个 bat 文件。 到目前为止,您对批处理文件的执行所做的唯一明确声明是“它似乎没有出现在我当前的用户会话中”。正如我所说,这是正常的,因此该陈述不代表任何类型的问题陈述。请改进问题,以便您有一个实际的问题陈述;确认批处理文件实际上没有运行,然后编辑问题,以便您提供一个好的minimal reproducible example 可靠地重现该问题。 【参考方案1】:

对于运行 Windows 服务的桌面应用程序,服务需要创建用户进程

服务是在session 0中创建的,在哪里不允许图形界面它们不显示,正在必须在用户登录的部分创建一个进程(0除外)。

为此需要使用windows api的资源。

以下 vb.net 中的示例。

ps:对不起我的英语。

 Try

        Dim UserTokenHandle As IntPtr = IntPtr.Zero
        Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
        Dim StartInfo As New WindowsApi.STARTUPINFOW

        'obtain an access token(handle) for the session that the user logged in is using.
        WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)

        'widows specification for the process that will be created
        StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))

        'create a new process to run on the user session represented by UserTokenHandle that was obtained in WTSQueryUserToken
        WindowsApi.CreateProcessAsUser(UserTokenHandle,"C:\FILE_TO_RUN.EXE", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)

        'checks whether the UserTokenHandle is nonzero
        If Not UserTokenHandle = IntPtr.Zero Then
            WindowsApi.CloseHandle(UserTokenHandle)
        End If

    Catch ex As Exception
       throw
    End Try

参考资料: https://www.2brightsparks.com/resources/articles/understanding-windows-sessions.pdf

http://blogs.technet.com/b/askperf/archive/2007/04/27/application-compatibility-session-0-isolation.aspx

【讨论】:

没有理由对错误翻译的单词做出否定的回答。相反,它可能会建议更好的翻译。为什么不建议修复代码?等等,代码有效,但你知道这一点。再说一次,对不起我的英语。 对不起。我以为你试图解释为什么批处理文件没有运行,我没有意识到你误解了这个问题。不幸的是,您的代码不会执行 OP 想要的操作 - 批处理文件必须以特定用户身份运行,您的代码将以交互方式登录的任何用户身份运行它。 (如果没有用户登录,则根本无法工作。)

以上是关于如何启动一个进程以从 Windows 服务运行 bat 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Windows 服务启动进程到当前登录的用户会话

Windows ssh - 如何在断开连接后保持进程运行

如何以与 Windows 服务不同的用户身份运行进程

如何获取 PHP 脚本以从已运行的进程发送和接收数据?

以 Windows 登录用户身份从服务启动进程

如何传递运行时参数以从批处理文件启动 exe