65.9K
CodeProject 正在变化。 阅读更多。
Home

将脚本作为服务运行 - Exsead Service Manager

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.75/5 (4投票s)

2007 年 2 月 6 日

CPOL

5分钟阅读

viewsIcon

64000

downloadIcon

548

Exsead Service Manager 是一个开源(BSD 风格许可)的 Windows 服务,它通过使用脚本来启动任何内容。它刚刚被发布为开源,更多关于它的信息如下。

引言

Exsead Service Manager 是一个开源(BSD 风格许可)的 Windows 服务,它通过使用脚本来启动任何内容

在 Unix 世界中,服务的等价物是通过脚本启动的。这使得工作非常简单。如果想添加一个后台活动,只需将它的启动程序添加到这些脚本之一中即可。不需要特殊编译的可执行文件。在 Windows 世界中,我们选择直接从 Windows 服务系统运行可执行文件。这些可执行文件必须编译进一个特殊的接口。虽然这种方法在许多情况下都有其优点,但它缺乏灵活性,并导致了糟糕的实现,例如使用“运行”级别的注册表指令,而服务将是更可取的。

Exsead Service Manager 的目标是成为整个 Exsead 概念的一部分:EXtreme Script Enterprise Application Development(极致脚本企业应用开发)。在这种情况下,具体目标是将脚本作为服务启动。一旦服务被脚本化,您就可以轻松地做任何事情!

请帮忙!ExseadServiceManager 现在是一个 Source Forge 项目。我正在积极开发,但需要帮助设置 Source Forge SSH、CVS 和网站。

如果您有兴趣帮助这个项目,请随时通过 ajt(at)nerds-central.com 与我联系。目前,当前版本和源代码可以在此处找到。随着我产品的开发,我将在那里发布新版本。请关注 Nerds-Central 获取新闻。我目前正在持续使用此版本,并且我认为核心功能对于 XP/SP2 来说是 beta 版。对于其他操作系统的一些功能,我将认为是 alpha 版。

ExseadServiceManager 实际上是如何工作的?

服务管理器本身只是一个可执行文件。这个可执行文件负责安装、配置、卸载运行服务。它通过运行方式和命令行参数的性质来区分需要执行的操作。

安装和使用服务管理器的步骤如下:

命名服务

ExseadServiceManager 的所有设计都力求简单。我的意思是,我们花了很多心思来让这个应用程序的使用变得简单。这里是第一个例子。它管理的服务的名称由可执行文件的名称控制。如果您想创建一个名为“FlyingPigsNeedNappies”(纸尿裤)的服务,那么您只需复制一份 ExseadServiceManager.exe 并将其重命名为 FlyingPigsNeedNappies.exe。就这么简单——真的。

它将在哪里运行?

当您使用 ExseadServiceManager 安装服务时,它会将服务的工作目录设置为执行安装的目录。所以,如果您创建一个目录 c:\FlyingPigs\Service 并打开一个 CMD 框,然后更改目录到 c:\FlyingPigs\Service 并运行 FlyingPigsNeedNappies.exe -I,那么该服务将在 c:\FlyingPigs\Service 中运行。同样——简单。

安装服务

如上所述,您只需运行可执行文件并带上 -I 选项。这将使其以本地管理员身份运行。如果您使用 -i 选项,它将以不同的帐户运行。

配置服务

可以通过可执行文件的命令行选项来配置、启动、停止和卸载服务。

将服务连接到某个东西

设置好这个服务是很有用的,但它必须要做点什么。这是通过与可执行文件同名但扩展名为 vbs 的脚本来实现的。对于此版本,初始脚本仅支持 VBScript,但后续版本应解决此问题。所以,在 flying pigs 的例子中,初始脚本的名称将是 FlyingPigsNeedNappies.vbs。稍后我将在本文中讨论初始脚本的结构。

日志去哪里了?

当服务管理器作为服务运行时,其日志会发送到其运行帐户的默认临时目录。例如,如果它以本地管理员身份运行,它会将日志发送到 Windows\Temp 目录下的名称.log 文件。对于 flying pigs 的例子,它将是 Windows\FlyingPigsNeedNappies.log。请注意,发送到日志的信息量很少,因为运行服务的大部分工作是由初始脚本完成的,而不是服务管理器。以下是一个日志输出示例:

Service Main Called
Service Handler Acquired
Opening Service: 'TAGService'
Changing working dir to 'C:\CodeRepo\InfraStructure\InstallationAids'
About to run 'start'
Acquiring script object: TAGService.vbs
Acquired script object.
Loaded Script OK.

这是通过运行可执行文件并带上 -? 选项生成的命令行选项的完整列表:

Exsead Service Manager: Command Line Args

  -? Print this message
  -r run start method directly avoiding service
  -e print out current env block
  -i 'user' 'pass' install service
  -I install service as local admin
  -u uninstall service
  -v print version info
  -s start service
  -k stop service
  -K first kill all descendants of the service process then stop service
  -Z  first kill all descendants of the process then kill it.
  -M set to manual start
  -A set to auto start
  -D set to disabled
  -S set to system start
  -B set to boot start

Notes: -K suspends the processes as it traverses the tree, but even with this
   level of checking, it might not get them all or it might kill a process
   that has just received the same pid as one that used to be a descendent.
   Please use this function with caution. This also applies to -Z.

创建和初始化服务脚本

至少,初始脚本必须包含两个子例程:StartService StopService。这两个例程都不接受任何参数。

StartService 在服务本身启动时由服务管理器调用。这个子例程必须启动服务所做的任何事情。当这个子例程退出时,服务将停止。这意味着如果您希望服务保持运行,您必须不要让这个子例程退出,直到服务被强制停止。这可以通过一个无限循环来实现,请参见下面的示例。

StopService 在 Windows 请求停止服务时由服务管理器调用。这可以通过运行可执行文件并带上 -k 选项或使用其他实用程序来启动。StopService 是在与启动服务不同的活动线程中调用的,因此 StartService 没有退出并不重要。在 StopService 中,您必须执行任何必要的进程关闭和清理工作,然后返回。

这是一个实际的初始化脚本,用于运行 TAG Web 应用程序网关的 TAGService

Option Explicit

' Constants and identifiers
' =========================
CONST SERVICE_NAME = "TAGService"
CONST ForReading = 1, ForWriting = 2, ForAppending = 3

' Globals
' =======
Dim objWSHShell
Dim objWSHNetwork
Dim objFSO
Dim objLogger
Dim is_init

' This method ensures the globals are up
' but only creates the object (expensive)
' once.
sub init()
    if not is_init then
        Set objWSHShell   = CreateObject("WScript.Shell")
        Set objWSHNetwork = CreateObject("WScript.Network")
        Set objFSO        = CreateObject("Scripting.FileSystemObject")
        Set objLogger     = new Logger
        is_init=true
    end if
end sub      
    
class Logger

    private logFile 

    Private Sub Class_Initialize()
        set logFile=objFSO.openTextFile(SERVICE_NAME+"_script.log",ForWriting,true)
    End Sub

    public sub WriteLog(what)
        logFile.writeLine(what)
    end sub
    
    Private Sub Class_Terminate()
        logFile.close
    End Sub    

end class

sub StartService()
    init
    'objWSHShell.run SERVICE_NAME + ".exe -K"
    Dim curdir 
    dim tagFile
    curdir = objWSHShell.CurrentDirectory
    tagFile = curdir & "\..\CRI\bin\TAG_Runner.exe"
    If not objFSO.FileExists(tagFile) then
        SilentReport "Could not find " & tagFile, 0
        exit sub
    end if
    objWSHShell.CurrentDirectory=curdir +"\..\CRI\bin"
    while 1=1
        objWSHShell.run "TAG_Runner.exe",0,true
    wend
end sub

sub StopService()
    init
    ' Simply kill any running child processes of the script
    objWSHShell.run SERVICE_NAME + ".exe -K"
end sub

Sub SilentReport(sString, iErr)
    init
    objLogger.WriteLog(now & ": " & sString & " , " & iErr)    
End Sub

有关此主题和其他主题的更多信息,请参阅 Nerds-Central

© . All rights reserved.