none
[分享]一個用於 Active Direcotory 中返回 Windows 內核大版本和是否爲服務器的腳本 blueghost.bat RRS feed

  • 常规讨论

  • 先將腳本 blueghost.bat 的代碼貼出來,
    然後依據代碼進行一下說明.

    以下爲代碼

    @echo off
    
    setlocal enabledelayedexpansion
    for /f "tokens=* skip=1" %%n in ('ver') do @set batou=%%n
    
    set /a san=0
    echo "!batou!" | find /i "windows xp" 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=51
    )
    
    echo "!batou!" | find /i "5.2" 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=520
    )
    
    echo "!batou!" | find /i "6.0" 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=60
    )
    
    echo "!batou!" | find /i "6.1" 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=61
    )
    
    echo "!batou!" | find /i "6.2" 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=62
    )
    
    echo "!batou!" | find /i "6.3" 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=63
    )
    
    echo "!batou!" | find /i "10." 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=100
    )
    
    if !san! lss 60 (
      diskpart -? 1> nul 2> nul
      if !errorlevel! neq 0 (
        exit /b 9
      ) else (
        exit /b !san!
      )
    )
    
    whoami -groups | find "S-1-16-12288" 1> nul 2> nul
    if !errorlevel! neq 0 (
      exit /b 9
    )
    
    dir !WINDIR!\winsxs\*datacenter* /ad/b 1> nul 2> nul
    if !errorlevel! equ 0 (
      set /a san=!san!*10
    )
    
    exit /b !san!
    



    以上爲代碼

    這個批處理腳本通過一定的規則, 將 NT 內核的大版本號和是否爲服務器系統, 以自定義系統錯誤碼(ERRORLEVEL)方式返回.
    因爲考慮到其主要是作爲 Active Directory 客戶端的開機/關機腳本運行, 所以強制要求執行用戶至少具有管理員權限.

    此腳本沒有針對代碼中所列出的系統, 進行逐一測試, 如果遇到問題, 需要自行更改.
    在生產環境使用, 請自擔風險.

    處理規則是:

    1. 這個腳本首先通過內部命令 ver 獲取 NT 內核的大版本號, 比如 5.1 .
        並將該結果存放在一個變量中.
    2. 對於 Windows Server 2003, 這裏做簡化處理, 直接設置爲 520.
        對於 Windows 10 系統, 將其基準值設置 100, 以保證該數值的遞增.
        當然如果希望區分 Windows 10 的 RS 版本, 可自行修改.
    3. 因爲這個腳本, 主要是用在 Active Directory 開機腳本中,
        而系統運行開機腳本的帳戶, 是模仿爲 "Authenticated Users" 組的 SYSTEM 帳戶.
        如果腳本不能以高權限運行, 則沒有意義, 所以這裏先判斷, 運行腳本是否爲至少是管理員權限.
        對於 NT 5.x 系統. 使用執行命令

       diskpart -?

       來判斷. 對於 diskpart 命令, 哪怕是給出幫助, 也要管理員權限.
       如果執行命令的帳戶是普通用戶, 則返回值不爲零, 所以據此來作爲 NT 5.x 系統下的判斷依據.
    4. 對於 NT 6.x 或者更高版本的系統, 則直接執行命令

       whoami -groups | find "S-1-16-12288" 1> nul 2> nul

       查看執行命令的用戶, 是否存在 SID 爲 S-1-16-12288 的 "高強制級別".
       該命令不會觸發 UAC.
       如果確認是普通用戶在執行, 則直接返回 9.
    5. 最後判斷 NT 6.x 系統是否爲服務器, 有多個方法. 比如調用 wmic 命令, 或者用 reg 命令讀取特定註冊表項.
        但 wmic 命令可能因爲服務沒有啓動, 或者其他原因導致執行失敗, 而讀取註冊表項, 可能因爲值被修改, 而導致
        返回錯誤的結果.
        雖然可以用命令

        dism -online -get-currentedition

        來確認. 但實踐表明, 執行該命令, 返回結果時間相對太慢, 可能需要等待好幾秒.
        所以經過一番思考, 首先想到的是通過 

        dir %WINDIR%\system32\*server*.msc

        但這個方法, 可能會因爲客戶端安裝了 RSAT 而返回錯誤的結果.

        通過查找 winsxs 目錄是否存在 datacenter 字樣的子目錄, 來確認.
        一般來說, 不會有人會在這裏建立自定義目錄, 所以用這個方法可以快速確認.
        也可以進一步用 

        icacls 

        命令確認其權限是否存在特定帳戶, 即 winsxs 目錄中默認的權限設置.
        當然這些都是有限確認, 但對於企業環境一般足夠了.
    6. 上面的腳本代碼中, find 命令後帶 /i 參數, 屬於輸入習慣, 雖然某些字符沒有大小之分.
    7. 雖然這個代碼的功能, 可以通過 PowerShell 腳本來解決, 但是就實際情況來說,
        PowerShell 所需資源確實要比批處理大.

    Folding@Home

    2017年4月28日 8:50

全部回复

  • 這些命令需要更換

    whoami -groups | find "S-1-16-12288" 1> nul 2> nul
    if !errorlevel! neq 0 (
      exit /b 9
    )
    



    由於之前並沒有確實以域的啓動腳本進行測試, 而忽略了系統帳戶 SYSTEM 的強制訪問級別是

    System Mandatory Level(S-1-16-16384)

    與一般經過提權的管理員用戶強制訪問級別不同.
    雖然也可以判斷系統內建 Administrators 組的 SID (S-1-5-32-544)

    但如果運行腳本的用戶是內建 Administrator, 同時該用戶啓用安全選項 "批准模式",
    那麼該 S-1-5-32-544,  僅作爲被拒絕項列出.

    所以將命令更換爲如下形式, 直接取 SID 進行比較.
    同時也演示了如何在批處理中使用 if elseif.

    for /f "tokens=6" %%s in ('whoami -groups ^| find /i "Mandatory Level"') do set sid="%%s"
    if !sid! equ "S-1-16-16384" (
      REM sys
    ) else if !sid! equ "S-1-16-12288" (
      REM adm
    ) else (
      exit /b 9
    )


    比較 SID 也繞過了 S-1-5-32-544 是否爲拒絕項時, 可能由於編碼問題而導致執行失敗.
    當然上述 for 命令也可能存在因編碼問題, 而導致列索引改變.


    Folding@Home

    2017年5月8日 8:10