3

我对windows services. 我WCF service在一台机器(机器 1)上运行,而 Windows 服务在另一台机器(机器 2)上运行。

我需要powershell使用 WCF 服务在机器 2 上运行脚本。我不知道从哪里开始以及如何完成。此外,我需要将消息从 WCF Web 服务传递到 Windows 服务

请给我建议或提供一些好的例子或教程。

编辑
我想在机器 2 上运行一个 powershell 脚本。这个 powershell 脚本只知道 WCF 服务。
只是想做的是,将那个powershell传递给机器2。怎么做?

4

1 回答 1

4

首先,我假设您正在接管一个现有项目,因为您的问题有点矛盾:您是 Windows 服务的新手,但您声明您的系统中有一个。我还将考虑您必须维护现有的软件模型,同时您可以控制两台机器。所以:

  • 机器 1上的 WCF 服务提供 PS 脚本
  • 机器 2上的 Windows 服务应在这些脚本可用并由机器 1上的 WCF 服务传递时立即执行这些脚本

为了解决这个问题,您可以考虑在机器 2上托管另一个 WCF 服务How to: Host a WCF Service in a Managed Windows Service

这将如何运作?每次有新的 PS 脚本可用时,您都可以从机器 1上的 WCF 服务调用机器 2上的第二个 WCF 服务。随后,机器 2上的 WCF 服务可能会将脚本保存到某个存储库(文件、数据库、内存中)并调用Windows 服务上的ServiceController.ExecuteCommand 方法。此时,Windows 服务将从其保存位置获取脚本并执行它。虽然我觉得这是一个不必要的过于复杂的软件项目,但这里有一个针对您的情况的实现,只是为了回答您的问题,是的,这是可能的

机器 2上,安装包含 WCF 服务的 Windows 服务:

using System;
using System.Linq;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration.Install;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace Sample.Services
{
    [ServiceContract(Namespace = "http://Sample.Services")]
    public interface IScriptExecutor
    {
        [OperationContract]
        void ExecuteScript(string script);
    }

    /// <summary>
    /// The WCF service class which will pass the script to the Windows
    /// service
    /// </summary>
    public class ScriptExecutorService : IScriptExecutor
    {
        const string PATH = @"C:\test\queue.txt";
        public void ExecuteScript(string script)
        {
            File.WriteAllText(PATH, script);
            ServiceController myService = 
                new ServiceController("WCFScriptWindowsService");
            myService.ExecuteCommand((int)MyCustomCommands.ExecuteScript);

        }
    }

    public class ScriptWindowsService : ServiceBase
    {
        const string PATH = @"C:\test\queue.txt";
        const string PATH_OUT = @"C:\test\out.txt";

        public ServiceHost serviceHost = null;
        public ScriptWindowsService()
        {
            ServiceName = "WCFScriptWindowsService";
        }

        protected override void OnCustomCommand(int command)
        {
            switch (command)
            {
                case (int)MyCustomCommands.ExecuteScript:
                    // Execute the PS script
                    var ps = PowerShell.Create();
                    var runspace = RunspaceFactory.CreateRunspace();
                    ps.Runspace = runspace;
                    // read the command from a repository, 
                    // could also be a database
                    ps.AddCommand(File.ReadAllText(PATH));
                    runspace.Open();
                    var results = ps.Invoke().ToList();
                    runspace.Close();
                    foreach (var result in results)
                    {
                        // writing the results to a file
                        File.AppendAllText(PATH_OUT, 
                            String.Format("{0}\r\n", 
                                result.BaseObject.GetType()));
                    }
                    break;
                default:
                    break;
            }
        }

        public static void Main()
        {
            ServiceBase.Run(new ScriptWindowsService());
        }

        protected override void OnStart(string[] args)
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }
            serviceHost = 
                new ServiceHost(typeof(ScriptExecutorService));
            serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
                serviceHost = null;
            }
        }
    }

    // Provide the ProjectInstaller class which allows 
    // the service to be installed by the Installutil.exe tool
    [RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceProcessInstaller process;
        private ServiceInstaller service;

        public ProjectInstaller()
        {
            process = new ServiceProcessInstaller();
            process.Account = ServiceAccount.LocalSystem;
            service = new ServiceInstaller();
            service.ServiceName = "WCFScriptWindowsService";
            Installers.Add(process);
            Installers.Add(service);
        }
    }

    /// <summary>
    /// Holds the custom commands (only one, in our case)
    /// </summary>
    public enum MyCustomCommands { ExecuteScript = 128 };
}

机器 1上,修改 WCF 服务,使其调用机器 2上的 WCF 服务:

using System.ServiceModel;

namespace Sample.Services
{
    [ServiceContract(Namespace = "http://Sample.Services")]
    public interface IScriptProvider
    {
        [OperationContract]
        string GetScript();
    }
    public class ScriptProviderService : IScriptProvider
    {
        public string GetScript()
        {
            // do some processing ...
            // let's say we end up with the "Get-Service" script
            var script = "Get-Service";
            // make sure you add a reference to the ExecutorServiceReference
            // WCF service on machine 2
            var client = new WcfService1.ExecutorServiceReference
                .ScriptExecutorClient();
            client.ExecuteScript(script);
            return script;
        }
    }
}

我再次强调:您不必从 Windows 服务本身执行 PS 脚本。通过在 Windows 服务中托管新的 WCF 服务,您可以轻松调用它的方法并将逻辑从OnCustomCommand方法的覆盖移动到ScriptExecutorService'sExecuteScript方法。

如果我的模型假设错误,我会更新我的答案。

于 2013-07-01T13:47:25.543 回答