太陽當空照-Windows服務化方式腳本封裝sc指令


前言

接過上一章節,sc.exe進行Windows中,進行系統程序服務化的操作方式不難發現,直接進行基礎工具服務化操作,一個是人狠話不多,出錯不好說,一個就是不太優雅,每回都需要自己手動去輸入配置信息,例如:sc [Service name] 程序路徑,服務方式等內容,啥也別說,改成腳本引導,交互式輸入,以下是腳本的幾個需求:

  • 啟動腳本出現輸入引導信息

  • 輸入相關服務配置

  • 完成對目標程序服務操作(注冊、啟動、停止和刪除)

ggcy-blog-service-bat-header

准備作業

腳本是啥?在系統中又叫批處理腳本,用於實現系統使用過程中,通過系統Dos指令實現部分功能需求的可執行文件,相關交互指令被稱之為批處理腳本,此處簡稱腳本,在Windows系統中,腳本文件常見以.bat.cmd作為文件后綴

要寫當然啥不會肯定不行,先簡單學一學指令,筆者整理了相關的基本語法,如下:

變量

變量的主要目的是為了接受在批處理文件外部接受輸入值和處理文件內部對變量的設置和使用

blog-jrz-bat-var

系統變量

%CD% 獲取當前路徑
%PATH% 獲取命令搜索路徑/全局環境變量中的PATH
%DATE% 獲取當前日期
%TIME% 獲取當前時間
%ERRORLEVEL% 獲取上一個命令的執行結果碼

輸出內容echo

>echo %DATE%
2021/07/16 周五

設置變量(局部)set

set 變量名稱=變量值
>set test=12
>echo %test%
12

基本指令

以下介紹僅僅包含當前需要實現的批處理文件需要用到的指令,並不是完整指令細化,具體參考可以閱讀對應的微軟文檔參考鏈接

blog-jrz-bat-cmd

注釋

::注釋內容

輸入

參考鏈接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/set_1

set

顯示、設置或刪除 cmd.exe 環境變量。 如果不使用參數,則 set 將 顯示當前環境變量設置

set [<variable>=[<string>]]
set [/p] <variable>=[<promptString>]
set /a <variable>=<expression>

<variable>指定要修改或設置的環境變量名稱

<string>實際需要給變量設置的變量值

>set test=aaa
>echo %test%
aaa

/p將用戶輸入行作為對應需要設置的變量的值

創建一個setcase.batCHCP 65001目的是為了設置當前cmd窗口的當前代碼頁設置為utf-8,同時把bat腳本編碼設置為utf-8內容如下:

@echo off
CHCP 65001
set /p uname=請輸入用戶名稱:
echo 用戶名:%uname%

執行sctest.bat

>sctest.bat
Active code page: 65001
請輸入用戶名稱:張珊
用戶名:張珊

需要注意的是,如果執行后輸出內容為中文亂碼,那么極為可能是,當前bat的文件編碼和cmd窗口編碼不一致造成,可通過CHCP 編碼進行編碼統一,上述案例設置的是65001表示輸出腳本當前窗口編碼為utf-8,和bat的編碼保持一致

輸出

echo

參考鏈接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/echo

顯示消息或打開或關閉命令回顯功能。 如果不使用參數, echo 將顯示當前的回顯設置,默認為on

echo [<message>]
echo [on | off]

顯示信息(輸出信息)

>echo Hello World
echo Hello World

控制是否顯示命令提示符,在dos環境下直接執行該指令有效,為防止在bat文件中顯示

echo [on | off]

執行echo用於顯示當前回顯狀態

>echo 
ECHO 處於打開狀態。

創建一個echo.bat文件內容如下:

echo hellw world
pause 

保存后,雙擊執行,輸出結果如下:

bat文件路徑>echo hellw world
hellw world
bat文件路徑>pause

關閉回顯,防止批處理文件中的所有命令 (包括 echo off 命令) 在屏幕上顯示在批處理文件類型的第一行,echo.bat修改如下:

@echo off
echo hellw world
pause

保存后,直接雙擊bat執行效果如下:

hellw world
請按任意鍵繼續. . .

暫停

pause

參考鏈接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/pause

暫停批處理程序的執行,並顯示提示, Press any key to continue . . .,按任意鍵繼續執行后續的執行

>pause
請按任意鍵繼續. . .

退出

exit

參考鏈接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/exit

退出命令解釋器或當前批處理腳本

exit [/b] [<exitcode>]

/b為退出當前批處理腳本,而不是退出cmd.exe,如果從批處理腳本外部執行或直接執行批處理腳本,則退出 cmd.exe

<exitcode>指定數值, 如果指定了 /b ,則 ERRORLEVEL 環境變量設置為該數字; 如果要退出命令解釋器,則進程退出代碼將設置為該數字

批處理腳本exit.bat內容如下:

@echo off
echo hellw world
exit /b  

直接雙擊運行bat,看似無反應,實際是腳本執行結束后,退出了了

通過命令提示符切換到改exit.bat所在目錄下,執行exit.bat,結果輸出如下:

>sctest.bat
hellw world
>

命令提示符cmd.exe並未退出

判定

if

參考鏈接:https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/if

在批處理程序中執行條件處理

if [not] ERRORLEVEL <number> <command> [else <expression>]
if [not] <string1>==<string2> <command> [else <expression>]
if [not] exist <filename> <command> [else <expression>]

啟用了命令擴展,語法如下:

if [/i] <string1> <compareop> <string2> <command> [else <expression>]
if cmdextversion <number> <command> [else <expression>]
if defined <variable> <command> [else <expression>]

not當條件為false,對應判定語句才能夠執行內部的相關操作

>if not false==true echo the condition is false
the condition is false

errorlevel 表示cmd.exe上一個執行程序的返回的退出代碼對應的數字

>echo %errorlevel%
0
>if not %errorlevel%==1 echo the condition is false
the condition is false

exist判定特定路徑文件是否存在,存在則返回true,命令提示符工作目錄下存在文件sctest.bat

>if exist sctest.bat  echo the condition is true
the condition is true

else <express>不符合if條件判定時的其他情況,執行對應的相關操作語句,執行語句需要用()進行囊括在一個塊中,否則else將執行無效

>if exist echo.bat  (echo the condition is true) else (echo the condition is false)
the condition is false

執行批處理文件

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.batname.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就開始執行安裝服務的安裝引導,其他操作同理,由於腳本是由多個批處理文件組成,所有批處理結構如下:

blog-jrz-bat-group

判定服務是否存在

查詢服務

>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.exesctest.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              :

對應目錄下,生成一個當前日期的內容輸出文件,內容為不斷追加的時間值

blog-jrz-bat-run

當前時間: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服務化的其他工具的使用和思考

  • instsrvsrvany
  • Winsw
  • Nssm

獲取上述內容中的服務測試源碼項目,可關注私信或直接評論回復【sc.bat


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM