执行批处理文件
call
参考链接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/call
从一个批处理程序调用另一个批处理程序,而不停止父批处理程序,需要注意的是该指令在命令提示符中执行无效
call [drive:][path]<filename> [<batchparameters>] [:<label> [<arguments>]]
[<drive>:][<path>]<filename>
需要指定的bat
的路径和名称,需要指明批处理文件的文件后缀,name.bat
或name.cmd
<batchparameters>
指定批处理程序所需的任何命令行信息
示例:
创建一个child.bat
,内容如下:
echo helloworld~
同目录下,再创建一个parent.bat
,调用child.bat
@echo off CHCP 65001 echo 开始调用子批量处理文件 call child.bat echo %errorlevel% echo 完成子批量处理文件 pause
执行parent.bat
>parent.bat Active code page: 65001 开始调用子批量处理文件 helloworld~ 完成子批量处理文件 Press any key to continue . . .
:<label>
指定批处理跳转的标签名称
<arguments>
指定要传递给批处理程序的新实例(从开始)的命令行信息 :<label>
批处理参数
%~1 展开 %1 并删除周围的引号 %~f1 将 %1 扩展到完全限定的路径
示例:
创建文件callself.bat
,文件内容如下,以执行方式跳转标签并传递参数
@echo off CHCP 65001 call :labelname "参数01" echo 1 echo 2 if %errorlevel%==1 ( exit /b ) :labelname echo 3 echo 4 exit /b 1
输出结果
>callself.bat Active code page: 65001 3 参数01 4 1 2
定向跳转
goto
将cmd.exe
定向到批处理程序中带标签的行
参考链接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/goto
goto <label>
<label>
指定一个文本字符串,该字符串用作批处理程序中的标签
更改当前工作路径
获取当前bat
所在路径,切换该路径为工作目录
cd /d %~dp0
实现逻辑
将脚本文件作为一个简单的指令入口,将指令依据实际的操作标识字符串进行访问到对应的子批量处理文件,例如输入install
就开始执行安装服务的安装引导,其他操作同理,由于脚本是由多个批处理文件组成,所有批处理结构如下:
判定服务是否存在
查询服务
>sc query servicename
当服务不存在时,输出如下:
>sc query sct [SC] EnumQueryServicesStatus:OpenService FAILED 1060: The specified service does not exist as an installed service.
若只是需要获取错误码,则设置输出为nul
>sc query sct >nul > >echo %errorlevel% 1060
因此可以采用上述方式对服务是否安装进行判定sc query servicename >nul
创建isexist.bat
作为判定服务脚本
@echo off ::CHCP 65001 ::判定服务是否存在 set name=%~1 ::echo %name% sc query %name% >nul exit /b
输入判定
@echo off ::CHCP 65001 ::接收外部参数 set option=%~1 :setname ::输入服务名称 set /p servicename=请输入需要%option%的服务名称: ::判定服务名称是否为空 if "%servicename%"=="" ( echo 服务名称不能为空 goto setname ) call isexist.bat %servicename% if %errorlevel%==1060 ( echo 服务名称不存在或服务未安装 goto setname )
安装
创建一个install.bat
文件,具体内容如下:
@echo off CHCP 65001 ::添加跳转标签 :path set /p startup=请输入服务目标程序路径: if not exist %startup% ( echo %startup%路径不存在,请重新输入 goto :path ) ::通过跳转传递路径参数 call :filename %startup% ::判定执行是否合理 if %errorlevel%==1 ( exit /b ) :filename ::默认服务名 set file_name=%~n1 ::echo %file_name% :setname ::配置服务名称 set /p servicename=请输入服务名称(默认%file_name%): ::配置服务显示名称 if "%servicename%"=="" ( set servicename=%file_name% ) ::判定服务名称是否已存在 call isexist.bat %servicename% if %errorlevel%==1060 ( goto setname ) ::配置服务描述 set /p discription=请输入服务描述(默认%file_name%): if "%discription%"=="" ( set discription=%file_name% ) ::配置服务启动模式 set mode=demand ::配置服务启动模式 set /p servicemode=请输入服务启动模式(默认%mode%手动): if "%servicemode%"=="" ( set servicemode=%mode% ) ::安装服务 sc create %servicename% binPath= %startup% start= %servicemode% DisplayName= %servicename% ::修改描述 sc description %servicename% %discription% exit /b 1
需要注意的是,if条件语句执行体如果包含多条执行语句时,需要用使用()
进行包裹,同时,与条件语句之间需要用空格进行分隔,同时必须是同行中添加(
,否则将出现异常The syntax of the command is incorrect.
这个常规异常
启动
@echo off ::CHCP 65001 set option="启动" :::setname ::::输入服务名称 ::set /p servicename=请输入需要%option%的服务名称: ::::判定服务名称是否为空 ::if "%servicename%"=="" ( ::echo 服务名称不能为空 ::goto setname ::) call input.bat %option% sc start %servicename% exit /b 0
停止
@echo off ::CHCP 65001 set option="停止" call input.bat %option% sc stop %servicename% exit /b 0
卸载
@echo off ::CHCP 65001 set option="卸载" call input.bat %option% ::执行服务删除操作 sc delete %servicename% exit /b 0
组合
@echo off CHCP 65001 ::获取参数 set cmd=%1 ::判定指令 if "%cmd%"=="" ( echo 输入%cmd%无效 goto help ) ::安装服务 if "%cmd%"=="install" ( call install.bat goto finish ) ::卸载服务 if "%cmd%"=="uninstall" ( call uninstall.bat goto finish ) ::启动服务 if "%cmd%"=="start" ( call start.bat goto finish ) ::停止服务 if "%cmd%"=="stop" ( call stop.bat goto finish ) else ( ::帮助指令 echo 输入%cmd%无效 :help echo 输入help查看对应指令 echo scutil [command] echo [command]如下: echo install 安装服务 echo uninstall 卸载服务 echo start 启动服务 echo stop 停止服务 ) ::退出执行 :finish exit /b 0
测试运行
管理员启动cmd
,切换目录到scutil.bat
对应的目录,执行安装指令,当前服务测试路径为E:\Study\Servers\sctest\sctest.exe
,sctest.exe
为上一个章节的服务程序,完全符合windows服务化要求
>scutil install Active code page: 65001 请输入服务目标程序路径:"E:\Study\Servers\sctest\sctest.exe" 请输入服务名称(默认sctest): 请输入服务描述(默认sctest): 请输入服务启动模式(默认demand手动): [SC] CreateService SUCCESS [SC] ChangeServiceConfig2 SUCCESS
查看本地服务sc query sctest
>sc query sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 1 STOPPED WIN32_EXIT_CODE : 1077 (0x435) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0
运行程序
>scutil start Active code page: 65001 请输入需要启动的服务名称:sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 2 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x7d0 PID : 14244 FLAGS :
对应目录下,生成一个当前日期的内容输出文件,内容为不断追加的时间值
当前时间:Service Start 当前时间:22:03:56 当前时间:22:03:57 当前时间:22:03:58 当前时间:22:03:59 当前时间:22:04:00 当前时间:22:04:01 当前时间:22:04:02 当前时间:22:04:03 当前时间:22:04:04 当前时间:22:04:05
停止程序
>scutil stop Active code page: 65001 请输入需要停止的服务名称:sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 3 STOP_PENDING (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 >sc query sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 1 STOPPED WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0
卸载程序
>scutil uninstall Active code page: 65001 请输入需要卸载的服务名称:sctest [SC] DeleteService SUCCESS >sc query sctest [SC] EnumQueryServicesStatus:OpenService FAILED 1060: The specified service does not exist as an installed service
以上就是本章对于将sc.exe
实现脚本化,进而实现程序服务化的交互式操作
总结
这些脚本虽然看似鸡肋,只是将指令进行了二次封装,实际上,这是笔者第一个比较系统化的对脚本的实践和应用,能够将这些指令以类似简单编程的方式进行处理也是一种经验的积累,后续将继续讲解笔者接触到的Windows
服务化的其他工具的使用和思考
instsrv
与srvany
Winsw
Nssm
获取上述内容中的服务测试源码项目,可关注私信或直接评论回复【sc.bat
】