WScript/VBScript命令行参数使用srvany.exe创建自定义服务
提醒:本页面将不再更新、维护或者支持,文章、评论所叙述内容存在时效性,涉及技术细节或者软件使用方面不保证能够完全有效可操作,请谨慎参考!
之前写过一篇文章
介绍srvany.exe
这个小工具的,今天有网友反映能否使用命令行方式创建基于srvany.exe的Windows服务,我想到之前编写的
SrvanyUI软件
没有命令参数直接调用的功能,本来想完善一下SrvanyUI这个软件的,苦于最近较忙,于是先用VBScript凑合写着一个命令行控制的脚本
srvany.vbs
,其中用到了
RestartService
子过程来自
Rob van der Woude
,在此表示感谢!
基本的思路很简单,就是先创建srvany.exe为可执行映像的NT系统服务,然后在利用注册表修改其间的配置参数,最后再启动服务。
先把
srvany.vbs
的代码贴在这儿,具体的使用方法稍后附上。
'
' 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测试了一下算是通过了,代码供大家参考吧。
请问 WScript srvany.vbs -name 服务名称 -srvany "C:\Windows\srvany.exe" -file "C:\Windows\notepad.exe" 支持Windows7 x86 和windows7 x64吗?? 是否测试过? 谢谢
你好,我这个脚本是在64位Windows 7系统下编写并测试通过的,手边暂时没有32位Win7,所以没做测试,不过应该也是可以通过的。