WScript/VBScript命令行参数使用srvany.exe创建自定义服务

!本文可能 超过1年没有更新,今后内容也许不会被维护或者支持,部分内容可能具有时效性,涉及技术细节或者软件使用方面,本人不保证相应的兼容和可操作性。

之前写过一篇文章介绍srvany.exe这个小工具的,今天有网友反映能否使用命令行方式创建基于srvany.exe的Windows服务,我想到之前编写的SrvanyUI软件没有命令参数直接调用的功能,本来想完善一下SrvanyUI这个软件的,苦于最近较忙,于是先用VBScript凑合写着一个命令行控制的脚本srvany.vbs,其中用到了RestartService子过程来自Rob van der Woude,在此表示感谢!

基本的思路很简单,就是先创建srvany.exe为可执行映像的NT系统服务,然后在利用注册表修改其间的配置参数,最后再启动服务。

先把srvany.vbs的代码贴在这儿,具体的使用方法稍后附上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
'
' Usage: 
'    WScript.exe srvany.vbs -name   [ServiceName]
'                           -srvany [SrvAnyFileName]
'                           -file   [ExeFileName]
'                           -dir    [ExeFileDirectory]
'                           -params [ExeFileParameters]
'
' For more information please visit http://wangye.org
'
Option Explicit
 
Const HKLM = &H80000002
 
' Service Type
Const KERNEL_DRIVER        =   1
Const FS_DRIVER            =   2
Const ADAPTER              =   4
Const RECOGNIZER_DRIVER    =   8
Const OWN_PROCESS          =  16
Const SHARE_PROCESS        =  32
Const INTERACTIVE_PROCESS  = 256
 
Const INTERACT_WITH_DESKTOP = FALSE
 
' Error Control
Const NOT_NOTIFIED         = 0
Const USER_NOTIFIED        = 1
Const SYSTEM_RESTARTED     = 2
Const SYSTEM_STARTS        = 3
 
Class CommandLineParser
    ' Written by WangYe
    ' http://wangye.org
    Private parameters
    Private splitargs
 
    Private Sub Class_Initialize()
        Set parameters = WSH.CreateObject("Scripting.Dictionary")
        Set splitargs = WSH.CreateObject("Scripting.Dictionary")
    End Sub
 
    Private Sub Class_Terminate()
        splitargs.RemoveAll
        Set splitargs = Nothing
        parameters.RemoveAll
        Set parameters = Nothing
    End Sub
 
    Public Sub addSplitter(key, value)
        splitargs.Add key, value
    End Sub
 
    Public Sub parse(args)
        Dim i, j, k, token, c, statusChanged
        Dim statusSkipped, tokens
        Dim keys, items
 
        statusChanged = False
        keys = splitargs.Keys
        items = splitargs.Items
 
        For i = 0 To args.Count-1
            If statusChanged Then
                parameters.Add token, args(i)
                statusChanged = False
            End If
            c = Left(Trim(args(i)), 1)
            If c = "-" Then
                statusChanged = True
                statusSkipped = False
                For j=2 To Len(args(i))-1
                    c = MID(args(i), j, 1)
                    statusSkipped = CBool(c = "-")
                    If Not statusSkipped Then Exit For
                Next
                token = Right(args(i), Len(args(i)) - j+1)
 
                For k = 0 To splitargs.Count - 1
                    tokens = Split(token, items(k))
 
                    If UBound(tokens) > 0 Then
                        If keys(k) = tokens(0) Then
                            parameters.Add tokens(0), _
                                        tokens(1)
                            statusChanged = False
                        End If
                    End If
                Next
            End If
 
            If i = args.Count-1 And statusChanged Then
                parameters.Add token, ""
            End If
        Next
    End Sub
 
    Public Sub dump()
        Dim i, Keys, Items
        Keys = parameters.Keys
        Items = parameters.Items
 
        For i = 0 To parameters.Count - 1
            WSH.Echo Keys(i) & "=" & Items(i)
        Next
    End Sub
 
    Public Function hasArgument(name)
        hasArgument = parameters.Exists(name)
    End Function
 
    Public Function getArgument(name)
        getArgument = ""
        If parameters.Exists(name) Then
            getArgument = parameters(name)
        End If
    End Function
 
    Public Default Property Get Item(name)
        Item = getArgument(name)
    End Property
End Class
 
Sub RestartService( myService, blnQuiet )
' This subroutine restarts a service
' Arguments:
' myService     use the service's DisplayName
' blnQuiet      if False, the state of the service is displayed
'               every second during the restart procedure
'
' Written by Rob van der Woude
' http://www.robvanderwoude.com
 
    ' Standard housekeeping
    Dim colServices, colServicesTest, objService
    Dim objServiceTest, objWMIService, strQuery, strTest
 
    ' Create a WMI object
    Set objWMIService = GetObject( "winmgmts:\\.\root\CIMV2" )
 
    ' Query the services for "our" service
    strQuery = "SELECT * FROM Win32_Service WHERE DisplayName='" & myService & "'"
    Set colServices = objWMIService.ExecQuery( strQuery, "WQL", 48 )
 
    ' Loop through the "collection" of returned services
    For Each objService In colServices
        ' See if we need to tell the user we're going to stop the service
        If Not blnQuiet Then
            WScript.Echo "Stopping " & myService
        End If
 
        ' Stop the service
        objService.StopService
 
        ' Wait until the service is stopped
        Do Until strTest = "Stopped"
            ' Create a new object for our service; this work-around is required
            ' since otherwise the service's state information isn't properly updated
            Set colServicesTest = objWMIService.ExecQuery( strQuery, "WQL", 48 )
 
            ' Loop through the "collection" of returned services
            For Each objServiceTest In colServicesTest
                ' Check the service's state
                strTest = objServiceTest.State
                ' See if we need to show the progress
                If Not blnQuiet Then
                    WScript.Echo "State: " & strTest
                End If
                ' Wait 1 second
                WScript.Sleep 1000
            Next
 
            ' Clear the temporary object
            Set colServicesTest = Nothing
        Loop
 
        ' See if we need to tell the user we're going to (re)start the service
        If Not blnQuiet Then
            WScript.Echo "Starting " & myService
        End If
 
        ' Start the service
        objService.StartService
 
        ' Wait until the service is running again
        Do Until strTest = "Running"
            ' Create a new object for our service; this work-around is required
            ' since otherwise the service's state information isn't properly updated
            Set colServicesTest = objWMIService.ExecQuery( strQuery, "WQL", 48 )
 
            ' Loop through the "collection" of returned services
            For Each objServiceTest In colServicesTest
                ' Check the service's state
                strTest = objServiceTest.State
                ' See if we need to show the progress
                If Not blnQuiet Then
                    WScript.Echo "State: " & strTest
                End If
                ' Wait 1 second
                WScript.Sleep 1000
            Next
 
            ' Clear the temporary object
            Set colServicesTest = Nothing
        Loop
    Next
End Sub
 
Const L_Argument_Service_Name    = "name"
Const L_Argument_SrvAnyFile_Name = "srvany"
Const L_Argument_AppFile_Name    = "file"
Const L_Argument_AppParams_Name  = "params"
Const L_Argument_AppDir_Name     = "dir"
 
Function VBMain(argc, args)
 
    VBMain = 0
 
    If argc<1 Then
        VBMain = -1
        WSH.Echo "Usage:  -name   [ServiceName]" & vbCrLf & _
                "        -srvany [SrvAnyFileName]" & vbCrLf & _
                "        -file   [ExeFileName]" & vbCrLf & _
                "        -dir    [ExeFileDirectory]" & vbCrLf & _
                "        -params [ExeFileParameters]"
        Exit Function
    End If
 
    Dim nResult
    Dim strAppFileName, strAppParameters, strAppDirectory
    Dim strComputer, strServiceName, strSrvAnyFileName
    strComputer       = "."
 
    Dim objCommandLineParser
    Set objCommandLineParser = New CommandLineParser
 
    Call objCommandLineParser.parse(args)
    ' objCommandLineParser.dump
 
    strServiceName    = objCommandLineParser(L_Argument_Service_Name)
    strSrvAnyFileName = objCommandLineParser(L_Argument_SrvAnyFile_Name)
    strAppFileName    = objCommandLineParser(L_Argument_AppFile_Name)
    strAppParameters  = objCommandLineParser(L_Argument_AppParams_Name)
    strAppDirectory   = objCommandLineParser(L_Argument_AppDir_Name)
 
    If strServiceName = "" Then
        WSH.Echo "Service Name is invalid (Usage: -name [ServiceName])"
        VBMain = -2
        Exit Function
    End If
 
    Dim objFileSystemObject
    Set objFileSystemObject = WSH.CreateObject("Scripting.FileSystemObject")
 
    If strSrvAnyFileName <> "" Then
        strSrvAnyFileName = objFileSystemObject.GetAbsolutePathName(strSrvAnyFileName)
        If Not objFileSystemObject.FileExists(strSrvAnyFileName) Then
            strSrvAnyFileName = ""
        End If
    End If
 
    If strSrvAnyFileName = "" Then
        WSH.Echo "SrvAny File Name is invalid (Usage: -srvany [SrvAnyFileName])"
        VBMain = -2
        Exit Function
    End If
 
    If strAppFileName <> "" Then
        strAppFileName = objFileSystemObject.GetAbsolutePathName(strAppFileName)
        If Not objFileSystemObject.FileExists(strAppFileName) Then
            strAppFileName = ""
        End If
    End If
 
    If strAppFileName = "" Then
        WSH.Echo "Application File Name is invalid (Usage: -file [SrvAnyFileName])"
        VBMain = -2
        Exit Function
    End If
 
    If strAppDirectory = "" Then
        strAppDirectory = objFileSystemObject.GetParentFolderName(strAppFileName)
    End If
 
    Set objFileSystemObject = Nothing
    Dim objWMI, objService
    Set objWMI = GetObject("winmgmts:\\" & _
                    strComputer & "\root\cimv2")
    Set objService = objWMI.Get("Win32_Service")
    nResult = objService.Create( _
        strServiceName    , _
        strServiceName    , _
        strSrvAnyFileName , _
        OWN_PROCESS       , _
        NOT_NOTIFIED      , _
        "Automatic"       , _
        INTERACT_WITH_DESKTOP, _
        "NT AUTHORITY\LocalService", _
        "" _
        )
 
    Set objService = Nothing
    Set objWMI = Nothing
 
    If nResult > 0 Then
        VBMain = nResult
        Exit Function
    End If
 
    ' Write Registry
    Dim strKeyPath, objReg
    strKeyPath = "SYSTEM\CurrentControlSet\Services\" & _
                strServiceName & "\Parameters"
    Set objReg = GetObject("winmgmts:\\" & _
            strComputer & "\root\default:StdRegProv")
    objReg.CreateKey HKLM,strKeyPath
    objReg.SetStringValue HKLM, strKeyPath, "Application"   , strAppFileName
    objReg.SetStringValue HKLM, strKeyPath, "AppParameters" , strAppParameters
    objReg.SetStringValue HKLM, strKeyPath, "AppDirectory" , strAppDirectory
 
    Set objReg = Nothing
 
    RestartService strServiceName, True
End Function
 
WSH.Quit(VBMain(WScript.Arguments.Count, WScript.Arguments))

调用方法,编写批处理文件(*.bat)或者直接调用命令:

WScript srvany.vbs -name 服务名称 -srvany "C:\Windows\srvany.exe" -file "C:\Windows\notepad.exe"

我这里假设srvany.exe位于C:\Windows路径下,然后希望将notepad.exe作为服务启动,当然上面的调用参数没有写全,省去的参数是-params,如果你不希望你的程序启动时传入启动参数,这个可以省略;还有一个参数就是-dir这个是指程序启动时的目录,如果省去则默认为-file所指派的程序所在目录。

当然这个脚本还略显简陋,我简单的在Windows XP测试了一下算是通过了,代码供大家参考吧。

若无特别说明,本网站文章均为原创,原则上这些文章不允许转载,但是如果阁下是出于研究学习目的可以转载到阁下的个人博客或者主页,转载遵循创作共同性“署名-非商业性使用-相同方式共享”原则,请转载时注明作者出处谢绝商业性、非署名、采集站、垃圾站或者纯粹为了流量的转载。谢谢合作!

  1. 请问
    WScript srvany.vbs -name 服务名称 -srvany “C:\Windows\srvany.exe” -file “C:\Windows\notepad.exe”

    支持Windows7 x86 和windows7 x64吗??

    是否测试过?

    谢谢

    • 你好,我这个脚本是在64位Windows 7系统下编写并测试通过的,手边暂时没有32位Win7,所以没做测试,不过应该也是可以通过的。

请稍后...

发表评论

电子邮件地址不会被公开。 必填项已用*标注