1

我有一个 Windows 服务应用程序。目前所有的管理任务都是通过配置编辑完成的。

我想添加某种命令行界面 - 我希望它通过 powershell 来完成。

而且我不知道我应该从哪里开始 - 在这种情况下我该如何创建应用程序界面。powershell 应该如何与服务通信?在这种情况下还需要远程功能。

(在该功能中可能还有其他管理工具 - 使用 GUI 或通过浏览器。)

4

2 回答 2

2

稍微扩展一下 LB 的简短评论:让特权服务与用户桌面交互并不是最好的想法,因为这样做可能会打开特权提升的途径。例如,粉碎攻击就是这样工作的。

处理与用户交互的更好方法是在 localhost(例如127.0.0.1:5555)上有一个非特权侦听器,它将显示通过该端口提交的消息,并让特权服务连接到侦听器以向用户发送消息。

下面的代码片段 - 虽然留有很大的改进空间 - 应该让您大致了解这样的侦听器的外观:

$addr = "127.0.0.1"
$port = 5555

[byte[]]$byte = @(0)
$enc = [System.Text.Encoding]::ASCII
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$socket = New-Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Parse($addr), $port)
$socket.Start()
while ( $true ) {
  $client = $socket.AcceptTcpClient()
  $stream = $client.GetStream()
  [byte[]]$input = @()
  while ( ($i = $stream.Read($byte, 0, 1)) -ne 0 ) { $input += $byte }
  $client.Close()
  [System.Windows.Forms.MessageBox]::Show($enc.GetString($input), "Title")
}
于 2012-09-25T21:55:27.053 回答
2

Windows 服务最初看起来像这样:

using System.ServiceProcess;
internal partial class MyService : ServiceBase
{
    static void Main()
    {
        ServiceBase[] ServicesToRun = new ServiceBase[] { new MyService() };
        ServiceBase.Run( ServicesToRun );
    }
}

我所做的是修改Main(),以便我可以使用它来启动服务和处理命令行内容,如下所示:

using System;
using System.Runtime.InteropServices;
using System.ServiceProcess;
internal partial class MyService : ServiceBase
{
    const int ATTACH_PARENT_PROCESS = -1;

    [DllImport( "kernel32.dll" )]
    static extern bool AttachConsole( int dwProcessId );
    [DllImport( "kernel32.dll" )]
    static extern bool FreeConsole();

    static void Main()
    {
        if ( Environment.UserInteractive ) {
            try {
                // Redirect console output to the parent process.
                AttachConsole( ATTACH_PARENT_PROCESS );

                // Process command line arguments here...
            } catch {
                // Handle exceptions here...
            } finally {
                // Detach from the console.
                FreeConsole();
            }
        } else {
            ServiceBase[] ServicesToRun = new ServiceBase[] { new MyService() };
            ServiceBase.Run( ServicesToRun );
        }
    }
}

构建可执行文件后,我像往常一样在操作系统中注册它(实际上,我使用 -install 命令行选项来执行此操作)。服务启动时,UserInteractive标志为false,因此服务照常启动。但是,在命令提示符下,UserInteractive标志为true,因此命令行处理会接管。

此时您需要的只是让可执行文件的命令行实例通过某种 IPC(套接字、管道、共享内存、WCF 等)与可执行文件的服务实例进行通信。

于 2012-09-26T04:34:37.123 回答