antony@notes:~/virtualization$ cat "2023-Windows-VMware-IaC-開發及使用手冊.md"
2023 Windows & VMware IaC 開發及使用手冊
2023 Windows & VMware IaC 開發及使用手冊
緣由
要手動部屬多台虛擬主機時,有高機率造成 Human Error ,會產生大量時間成本
虛擬化技術中,一個資料夾代表一台電腦,要設定每一台虛擬主機的 hostname, IP 位址, 名稱解析檔…等,此時容易發生 Human Error。
當每一台虛擬主機手動做好以上設定時,要將每一台虛擬主機先壓縮,此時必須坐在電腦前面,手動將每一台虛擬主機都壓縮,壓縮完後,再手動將每一個壓縮檔,派送到對應的實體 Windows 電腦,再手動將每一台虛擬主機的壓縮檔解壓縮,最後再進到每一台虛擬主機的目錄,將虛擬主機啟動。
以上動作,如果沒有事先規劃好,壓縮檔的檔名,要放在哪個目錄,哪一台虛擬機要派送到哪一台實體 Windows 電腦,要解壓縮到哪一個目錄,當叢集需要用到的 虛擬主機數量越大時,會造成管理上的不方便。
當以上動作完成,將已派送到對應 Windows 主機裡的虛擬主機都啟動後,又發現與當初規劃的規格不符,此時又要跳回第一步,會耗用大量時間成本。
認識 IaC
伺服器環境的手動配置給 IT 專業人員帶來了一些挑戰,例如,由於不斷增加的複雜性和對 IT 基礎架構的相關需求。
Infrastructure as Code,中文翻為 “基礎架構程式碼” ,提供了一種替代方法,將基礎架構的提供、配置與管理方式自動化。
Infrastructure 以實體比喻的話,就是機房裡的 Server
Iac 分為兩種方法,分別是 Declarative (聲明式) 和 Imperative (宣告式)
- 聲明式主要說明基礎系統架構要完成甚麼目標、需要的資源或任何狀態
- 宣告式定義了實現基礎系統架構所需的特定命令,並以正確的順序執行這些命令。
執行它的好處不僅可以降低 Human Error 、縮短建置系統的時間,還可以確保每次都建立出一模一樣的基礎架構。
舉例,在 CNT.2023.v4.6 的套件包裡面的 docker.bat, k8s.bat, dt.bat …等批次檔案,都能快速建立起,對應的基礎架構。
註解:IaC 技術幫我們從落地雲主機自動產生以及複製虛擬主機,並派送至多台不同的實體 Windows 10 主機
參考文章連結 :
- Understanding Infrastructure as Code (IaC) in less than 10 minutes
- 何謂基礎架構程式碼 (IaC)?
- What is Infrastructure as Code (IaC)?
Windows & VMware IaC 平台設計
平台目標
自動化建置與管理分散型叢集系統基礎架構
以 Kubernetes 架構範例 :
- 一台 Master 主機
- 三台 Worker 主機
以 Hadoop 架構範例 :
- 一台 Admin 機器
- 兩台 Master 機器
- M1 跑 Name Node, Secondary Name Node
- M2 跑 Resource Manager, Jobhistory Server
- 三台 Worker 機器
- 每一台機器都會跑 Data Node, Node Manager
重要操作步驟
- 設計叢集架構 (
mactohost) - 產生虛擬電腦資料夾
- 壓縮虛擬電腦資料夾
- 派送虛擬電腦資料夾
- 解壓縮所有虛擬主機壓縮檔
- 啟動與檢視所有虛擬主機
- 關閉所有虛擬主機
- 備份與還原所有虛擬主機
- 清除所有虛擬主機
實體電腦硬體規格
- 多台實體 Windows 10 電腦
- 記憶體至少 24 G
- CPU: 4 C / 2 HT 以上
- 須為靜態 IPv4 的 IP 位址
- 每台實體 Windows 10 電腦會分別跑一台或多台不同的虛擬電腦
虛擬電腦硬體規格
- Linux 作業系統
- 記憶體 : 依建置叢集需求設定
- CPU : 依建置叢集需求設定
- 網路模式 : bridge
虛擬電腦網路設定
根據叢集的大小來規劃 IP 位址、 Subnetmask 以及 Default Gateway
開始建置 C1 Cluster (1M3W)
建置叢集系統前準備
關閉防火牆 :::spoiler 步驟一 : 打開"檔案總管",滑鼠右鍵點選"網路",選擇 “內容”
:::
:::spoiler 步驟二 : 點選 “Windows Defender 防火牆”
:::
:::spoiler 步驟三 : 點選 “開啟或關閉 Windows Defender 防火牆”
:::
:::spoiler 步驟四 : 在私人網路 和 公用網路 下,兩個都點選 “關閉 Windows Defender 防火牆(不建議)",再按確定
:::確認實體 Windows 10 主機之間可用
SSH連接 測試命令 :> ssh bigred@<要派送的實體 Windows 10 電腦 的 IP 位址>無法連線,請用滑鼠右鍵點選 Windows Powershell 圖示,選擇"以系統管理員身分執行”,並執行以下命令
- 檢查 OpenSSH 目前的狀態如果 OpenSSH Server 沒有安裝,命令應返回以下輸出 :
PS > Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'Name : OpenSSH.Client~~~~0.0.1.0 State : Installed Name : OpenSSH.Server~~~~0.0.1.0 State : NotPresent - 安裝 OpenSSH Server 命令 :螢幕輸出 :
PS > Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0Path : Online : True RestartNeeded : False - 啟動 sshd 服務命令
PS > Start-Service sshd - 將 sshd 服務設為開機自動啟動
PS > Set-Service -Name sshd -StartupType 'Automatic' - 連線要派送虛擬主機壓縮檔的實體 Windows 10 電腦 的 IP 位址 測試
> ssh bigred@<要派送的實體 Windows 10 電腦 的 IP 位址>
- 檢查 OpenSSH 目前的狀態
將連接 Windows 實體主機 使用者的密碼存入
passwd檔案> notepad %USERPROFILE%\CNT.2023.v4.6\C1-1M3W\passwd將連接 模板 虛擬主機 使用者的密碼存入
passwd_vm檔案> notepad %USERPROFILE%\CNT.2023.v4.6\C1-1M3W\passwd_vm請執行 VMware Player 這軟體以下設定 步驟一 :
Player>File>Preferences...步驟二 : In the “Software updates” group > uncheck the “Check for software components as needed” option.確認被遠端控制的實體 Windows 主機,開放讓 psexec 遠端連接權限 用系統管理員身份打開 CMD,並執行以下命令
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f[註] 1. 機碼修改後,需重啟電腦 2. 如有安裝 F-Secure,請關閉 F-Secure 防火牆 參考文章連結 : PsTools 於 Windows 10 的環境設定
確認 Windows 主機上當前的使用者家目錄下 ssh 的私鑰
%USERPROFILE%\.ssh\id_rsa權限是否太開放, :::spoiler 示意圖
::: 如果在群組或其他使用者這個欄位下,有其他人,那麼請執行以下命令 :> cd %USERPROFILE%\CNT.2023.v4.6\C1-1M3W && sshsetup.bat螢幕輸出 :
SSH key Setup ok !:::spoiler 示意圖
:::
1. 設計 c1 叢集架構
設定 c1 叢集架構檔 - mactohost
mactohost在 Windows 中,打開 CMD ,執行以下命令
切換至工作目錄
> cd CNT.2023.v4.6\C1-3M3W編輯 c1mactohost
> notepad c1mactohost檔案內容 :
# Default Cluster
00:00 x1 none
00:01 x2 VMware
00:02 x3 VMware
00:03 a1 admin
00:04 m1 master
00:05 m2 master
00:06 m3 master
00:07 w1 worker
00:08 w2 worker
00:09 w3 worker
# K8S c1 Cluster ALP.K8S
10:f0 c1a1 admin
10:f1 c1m1 master c1m1.241.zip c1/alp.c1m1 120.96.143.170
10:f2 c1m2 master
10:f3 c1m3 master
10:f4 c1e1 etcd
10:f5 c1w1 worker c1w1.245.zip c1/alp.c1w1 120.96.143.170
10:f6 c1w2 worker c1w2.246.zip c1/alp.c1w2 120.96.143.171
10:f7 c1w3 worker c1w3.247.zip c1/alp.c1w3 120.96.143.171
10:f8 c1w4 worker
10:f9 c1w5 worker欄位說明 (用 空格 做切割) :
- 先單獨看第 12 行內容,
# K8S c1 Cluster ALP.K8S
- 第三欄
c1會與CNT.2023.V4.6\C1-1A3M\c1mactohost這個檔案的前兩個字c1比較,所以不能亂設定 - 第五欄
ALP.K8S設定 模板機的目錄名稱- 模板機必須放在
%USERPROFILE%\CNT.2023.v4.6\目錄下
- 模板機必須放在
- 第三欄
- 第一欄為 設定 VM 主機 的 Mac Address 最後兩個位元 (byte)
- 用冒號分隔的格式 : 前半部是 c1 = 10, c2 = 20… 依此類推 後半部是 VM 的 IP 位址尾數換算為 16 進位
- 舉例 :
假設現在要設定的是 c1 叢集裡面 IP 位址尾數
.210的 VM, 依照上述規則,得到的答案 :10:d2:::danger Note: 1. 16 進位中的英文需設為小寫 2. 不能設為 :10:xx,會導致虛擬機器的/etc/hosts無法正常解析 ! 3. 在此檔案中的任何一台 VM 的 Mac Address 不可重複
:::
- 第二欄為 設定 VM 主機名稱
- 格式 : 叢集名稱 + mactohost 第三欄位的第一個字 + 序號(從 1 開始)
- 第三欄為 各 VM 的角色扮演
- 第四欄為 VM 目錄壓縮檔名
- 格式 : VM 主機名稱 + VM IP 位址的尾數 + 壓縮檔的附檔名 (.zip)
- 第五欄為 VM 存放的目錄名稱
- 格式 :
叢集名稱/us.主機名稱(us = Ubuntu Server 的縮寫) - 格式 :
叢集名稱/alp.主機名稱(alp = Alpine Linux 的縮寫)
- 格式 :
- 第六欄為 VM 要分配到哪一台實體電腦的 IP 位址
2. 建立 c1 叢集所有虛擬主機
create.bat 程式概述 : 在落地雲主機的 C:\Users\bigred\CNT.2023.v4.6\C1-1M3W 目錄下,做出 c1 的資料夾,並在 c1 目錄下建立 4 台虛擬機
[重要] 根據實體電腦的記憶體來修改 vmcreate.bat 中 RSMMAX 變數直的大小
:::spoiler 完整程式內容
@echo off
REM 設定 Cluster Name
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set mactohost=%%y
)
for /f "tokens=3 delims= " %%z in ('type %mactohost% ^| more +11 ^| findstr "#"') do (
set CN=%%z
)
REM 判斷 Cluster Name 有沒有設定錯誤
if NOT %mactohost:~0,2% == %CN% (
echo "Cluster Name Error !"
GOTO:eof
)
if exist %CN%\ (
echo "%CN% Folder existed !"
GOTO:eof
)
REM 設定 模板機所在目錄名稱 和 模板機的 vmx 檔案位置 變數
for /f "skip=1 tokens=5 delims= " %%a in ('type %mactohost% ^| findstr Cluster') do (
set vmfolder=%%a
for /f "tokens=1" %%g in ('dir /S /B ..\%%a\ ^| findstr vmx$') do (
set vmx=%%g
)
)
REM 將 c*mactohost 中 實體 Windows 主機的 IP 匯入 ip.txt 檔案中
if exist ip.txt (del ip.txt)
for /f "skip=12 tokens=6 delims= " %%y in (%mactohost%) do (
echo %%y >> ip.txt
)
REM 判斷要派送的主機 22 port 有沒有開, psexec 功能是否正常
setlocal EnableDelayedExpansion
for /f "tokens=1 delims= " %%h in ('type ip.txt ^| sort.exe /unique') do (
for /f "tokens=1" %%p in ('powershell -command "& {(New-Object System.Net.Sockets.TcpClient).ConnectAsync('%%h', 22).Wait(100)}"') do (
if %%p == False echo "%%h SSH Error" && GOTO:eof
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%e
)
if not defined HostIP "echo !HostIP! should manual configuration in %~nx0"
if not !HostIP! == %%h (
psexec -accepteula -nobanner \\%%h -s "hostname" > nul 2> nul
)
if !ERRORLEVEL! NEQ 0 (
echo "%%h psexec Error" && GOTO:eof
)
)
del ip.txt 2> nul > nul
REM 判斷 VM 使用的 IP 目前有無被占用
for /f "skip=12 tokens=4,6 delims= " %%a in (%mactohost%) do (
for /f "tokens=1-3 delims=." %%x in ('echo %%b') do (
for /f "tokens=2 delims=." %%i in ('echo %%a') do (
ping -n 1 %%x.%%y.%%z.%%i | find "TTL" 2> nul >nul
if !ERRORLEVEL! EQU 0 echo "%%x.%%y.%%z.%%i is already being used." && GOTO:eof
)
)
)
)
REM 判斷 10 進位轉 16 進位有沒有算錯
for /f "tokens=1,2 delims=." %%k in ('type %mactohost% ^| findstr zip') do (
for /f "tokens=2 delims=:" %%s in ("%%k") do (
for /f "tokens=1" %%o in ("%%s") do (
set "h=%%o"
set "DEC=%%l"
cmd /C exit !DEC!
set "HEX=!=ExitCode!"
for /F "tokens=* delims=0" %%Z in ("!HEX!") do (
if /I !DEC! LSS 16 (
set "HEX=0%%Z"
for /F "delims=" %%r in ('powershell -command " '!HEX!'.ToLower() "') do (
set "SHEX=%%r"
if NOT "!h!" EQU "!SHEX!" echo The hexadecimal representation of !DEC! is !SHEX!, not !h!. && GOTO:eof
)
) else (
set "HEX=%%Z"
for /F "delims=" %%r in ('powershell -command " '!HEX!'.ToLower() "') do (
set "SHEX=%%r"
if NOT "!h!" EQU "!SHEX!" echo The hexadecimal representation of !DEC! is !SHEX!, not !h!. && GOTO:eof
)
)
)
)
)
)
REM 設定 VM 可用記憶體範圍
powershell -Command "(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /8Mb" > max.txt
powershell -Command "(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /8Mb" > min.txt
set /P MAX=<max.txt
set /P MIN=<min.txt
for /f "tokens=2 delims==" %%a in ('type %vmx% ^| findstr memsize') do (
set mem=%%a
)
set RSMMAX='memsize = \"%mem:~2,-1%\"', 'memsize = \"%MAX%\"'
set RSMMIN='memsize = \"%mem:~2,-1%\"', 'memsize = \"%MIN%\"'
set RSADR1='ethernet0.generatedAddressOffset = \"0\"'
set RSADR2='ethernet0.addressType = \"generated\"' , 'ethernet0.addressType = \"static\"'
set RSTYPE='ethernet0.connectionType = \"nat\"' , 'ethernet0.connectionType = \"bridge\"'
for %%i in (vmfolder vmx mem) do (
if not defined %%i (
echo %%i not defined && GOTO:eof
)
)
REM 上載 mactohosts 至 模板 虛擬主機
"C:\Program Files (x86)\VMware\VMware Player\vmrun" start "%vmx%" > nul
timeout /t 60 > nul
"C:\Program Files (x86)\VMware\VMware Player\vmrun" getGuestIPAddress "%vmx%" > admip.txt
set /P admip=<admip.txt
echo y | pscp -pwfile "passwd_vm" ".\%CN%mactohost" bigred@%admip%:/home/bigred/bin/mactohost 2> nul > nul
if %ERRORLEVEL% EQU 0 echo "%CN%mactohost scp ok"
echo y | pscp -pwfile "passwd_vm" bigred@%admip%:/home/bigred/.ssh/* %USERPROFILE%\.ssh\ 2> nul > nul
if %ERRORLEVEL% EQU 0 echo "%admip% .ssh/* scp ok"
del %USERPROFILE%\.ssh\known_hosts 2> nul
del %USERPROFILE%\.ssh\known_hosts.old 2> nul
type %vmx% | findstr Ubuntu > nul 2> nul
if %ERRORLEVEL% NEQ 0 (
ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@%admip% "sudo apk update; sudo apk upgrade" > nul 2>nul
if !ERRORLEVEL! EQU 0 echo "System upgrade ok"
) else (
ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@%admip% "sudo apt update; sudo apt -y upgrade; sudo apt -y autoremove" > nul 2>nul
if !ERRORLEVEL! EQU 0 echo "System upgrade ok"
)
"C:\Program Files (x86)\VMware\VMware Player\vmrun" stop "%vmx%" > nul
timeout /t 60 > nul
REM 設定模板機 displayName 變數
for /f "tokens=2 delims==" %%a in ('type %vmx% ^| findstr displayName') do (
set odn=%%a
)
REM 設定模板機 mac address 變數
for /f "tokens=2 delims==" %%a in ('type %vmx% ^| findstr "ethernet0.generatedAddress" ^| findstr ":"') do (
set vmac=%%a
)
for %%j in (odn vmac) do (
if not defined %%j (
echo %%j not defined && GOTO:eof
)
)
REM 建立 Cluster 的所有 VM
if exist %mactohost% (
if not exist %CN%\ (
mkdir %CN% > nul
if %ERRORLEVEL% EQU 0 (
for /f "tokens=1-6 delims= " %%a in ('findstr zip %mactohost%') do (
set x=%%~nxe
set RS='displayName = \"%odn:~2,-1%\"', 'displayName = \"!x!\"'
set y=%%a
set RSMAC='ethernet0.generatedAddress = \"%vmac:~2,-1%\"' , 'ethernet0.address = \"00:50:56:ab:!y!\"'
mkdir %CN%\!x! > nul
xcopy /E /Y ..\%vmfolder% %CN%\!x!\ > nul
for /f "tokens=1" %%p in ('dir %CN%\!x! /B /S ^| findstr vmx$') do set nvmx=%%p
powershell -Command "(gc !nvmx!) -replace "!RS!" -replace "!RSMAC!" -replace "%RSMMAX%" -replace "%RSTYPE%" -replace "%RSADR1%" -replace "%RSADR2%" | Out-File -Encoding "UTF8" vm.temp"
del /Q !nvmx!
copy /Y vm.temp !nvmx! > nul
if !ERRORLEVEL! EQU 0 echo "%CN%\!x!\ (%MAX%) ok"
)
del *.txt > nul
del vm.temp > nul
)
)
):::
執行建立 c1 叢集命令
在執行命令前,請先確定是否已完成 叢集系統準備
在 Windows 工作目錄 CNT.2023.v4.6\c1-1M3W 下,執行程式
> vmcreate.bat螢幕輸出
"c1mactohost scp ok"
"192.168.61.131 .ssh/* scp ok"
"System upgrade ok"
"c1\alp.c1m1\ (4096) ok"
"c1\alp.c1w1\ (4096) ok"
"c1\alp.c1w2\ (4096) ok"
"c1\alp.c1w3\ (4096) ok"[註] 如遇到需要輸入密碼,請參考以下連結 : Windows SSH: Permissions for ‘private-key’ are too open
3. 壓縮 c1 叢集所有虛擬主機
zip.bat 程式概述 : 此程式使用 7z 作為虛擬主機目錄的壓縮命令
:::spoiler 完整程式內容
@echo off
REM 設定 Cluster Name
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 在 mactohost 中抓取壓縮時需要的字串
if exist %CN:~0,2%zip.txt (del %CN:~0,2%zip.txt > nul)
for /f "tokens=3,* delims= " %%a in (%CN:~0,2%mactohost) do echo %%b | findstr zip >> %CN:~0,2%zip.txt
REM 透過 For 迴圈,逐行代變數壓縮 VM 所在的資料夾
setlocal EnableDelayedExpansion
for /f "tokens=1,2 delims= " %%a in (%CN:~0,2%zip.txt) do (
7z\7z -mx1 a %CN:~0,2%\%%a %%b > nul
if !ERRORLEVEL! EQU 0 (echo "%%a ok")
)
del %CN:~0,2%zip.txt > nul:::
執行壓縮程式
> vmzip.bat螢幕輸出
"c1m1.141.zip ok"
"c1w1.145.zip ok"
"c1w2.146.zip ok"
"c1w3.147.zip ok"4. 派送 c1 叢集所有虛擬主機
scp.bat 概述 : 使用 pscp.exe 命令,將 c1 叢集每一台虛擬主機的壓縮檔派送到 mactohost 中設定對應的各台實體 Windows 主機
:::spoiler 完整程式內容
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%e
)
REM 抓取在 d*mactohost 中,每一台虛擬主機的相關資訊,並將資料逐行匯入 d*scp.txt
if exist %CN:~0,2%scp.txt (del %CN:~0,2%scp.txt > nul)
for /f "tokens=1* delims= " %%a in (%CN:~0,2%mactohost) do echo %%b | findstr zip >> %CN:~0,2%scp.txt
REM 將每一台虛擬主機的壓縮檔透過 pscp 命令,派送至對應的實體 Windows 主機的使用者家目錄
setlocal EnableDelayedExpansion
for /f "tokens=3,5 delims= " %%a in (%CN:~0,2%scp.txt) do (
if %%b == %HostIP% (
xcopy /Y %CN:~0,2%\%%a %USERPROFILE%\ > nul
if !ERRORLEVEL! EQU 0 (
echo "%%a to %%b ok"
) else (
echo "%%a to %%b failed"
)
) else (
echo y | pscp -scp -q -pwfile passwd "%CN:~0,2%\%%a" %USERNAME%@%%b:"%%a" 2> nul > nul
if !ERRORLEVEL! EQU 0 (
echo "%%a to %%b ok"
) else (
echo "%%a to %%b failed"
)
)
)
del %CN:~0,2%scp.txt > nul:::
執行程式
> vmscp.bat螢幕輸出
"c1m1.141.zip to 120.96.143.152 ok"
"c1w1.145.zip to 120.96.143.152 ok"
"c1w2.146.zip to 120.96.143.153 ok"
"c1w3.147.zip to 120.96.143.153 ok"5. 解壓縮所有虛擬主機壓縮檔至落地雲主機
unzip.bat 程式概述 : 本程式在本機使用 7z 將 虛擬主機的壓縮檔解壓縮,遠端的主機使用 Windows Powershell 的 Expand-Archive 命令
:::spoiler 完整程式內容
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%a in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%a
)
REM 解壓縮在本地或遠端的虛擬主機壓縮檔
for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do (
if %%c == %HostIP% (
setlocal EnableDelayedExpansion
"%ProgramFiles%\7-Zip\7z" "x" "C:\Users\%USERNAME%\%%a" "-oC:\Users\%USERNAME%" > nul 2> nul
if !ERRORLEVEL! EQU 0 (
echo "%%c %CN:~0,2%\%%~nxb unzip ok !"
) else (
echo "%%c %CN:~0,2%\%%~nxb unzip Failed !"
)
setlocal DisableDelayedExpansion
) else (
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do (
if %%i == True (
psexec -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" "-Recurse" 2> nul
psexec -accepteula -nobanner \\%%c -s "powershell" "-Command" "Expand-Archive" "-LiteralPath" "C:\Users\%USERNAME%\%%a" "-DestinationPath" "C:\Users\%USERNAME%" 2> nul
) else (
psexec -accepteula -nobanner \\%%c -s "powershell" "-Command" "Expand-Archive" "-LiteralPath" "C:\Users\%USERNAME%\%%a" "-DestinationPath" "C:\Users\%USERNAME%" 2> nul
)
)
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do (
if %%i == True (
echo "%%c %CN:~0,2%\%%~nxb unzip ok !"
) else (
echo "%%c %CN:~0,2%\%%~nxb unzip Failed !"
)
)
)
):::
[註] %%~nxb,在範例中 %%b 為包含目錄的檔案名稱 : c1/alp.c1w1,
%%~nb - 顯示 alp (%%b 的 檔名)
%%~xb - 顯示 .c1w1 ( %%b 的副檔名,包含 .)
執行解壓縮程式
> vmunzip.bat螢幕輸出
"120.96.143.152 c1\alp.c1m1 unzip ok !"
"120.96.143.152 c1\alp.c1w1 unzip ok !"
"120.96.143.153 c1\alp.c1w2 unzip ok !"
"120.96.143.153 c1\alp.c1w3 unzip ok !"6. 啟動與檢視 c1 叢集所有虛擬主機
start.bat 程式概述 : 使用 VMware 的 vmrun 命令,配合 psexec 命令將 遠端 Windows 實體主機中的 虛擬主機啟動
:::spoiler 完整程式內容
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%a in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%a
)
setlocal EnableDelayedExpansion
for /f "tokens=6 delims= " %%a in (%CN:~0,2%mactohost) do (
for /f "tokens=1" %%k in ('dir %USERPROFILE%\%CN:~0,2% /S /B ^| findstr vmx$') do (
for /f "tokens=5,* delims=\" %%l in ("%%k") do (
set hostvmx=%%m
)
)
for /f "tokens=1" %%x in ('PsExec.exe -accepteula -nobanner \\%%a -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Get-ChildItem" "-Path" "%USERPROFILE%\%CN:~0,2%" "-Name" "-Recurse" "-Force" ^2^>nul ^| findstr vmx$') do (
for /f "tokens=1,* delims=\" %%y in ("%%x") do (
set remotevmx=%%z
)
)
)
REM 啟動每一台虛擬主機
for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do (
if %%c == %HostIP% (
"C:\Program Files (x86)\VMware\VMware Player\vmrun" start "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb\%hostvmx%" nogui 2> nul > nul
if !ERRORLEVEL! EQU 0 (
echo "%CN:~0,2%\%%~nxb started"
) else (
echo "%CN:~0,2%\%%~nxb failed"
)
timeout /t 5 > nul
) else (
psexec \\%%c -accepteula -nobanner -s "C:\Program Files (x86)\VMware\VMware Player\vmrun" "start" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb\%remotevmx%" "nogui" 2> nul > nul
if !ERRORLEVEL! EQU 0 (
echo "%CN:~0,2%\%%~nxb started"
) else (
echo "%CN:~0,2%\%%~nxb failed"
)
timeout /t 5 > nul
)
):::
1. 執行啟動 c1 叢集所有虛擬主機命令
> vmstart.bat螢幕輸出
"c1\alp.c1m1 started"
"c1\alp.c1w1 started"
"c1\alp.c1w2 started"
"c1\alp.c1w3 started"2. 在 Windows 檢視已開啟的虛擬電腦
list.bat 程式概述 : 透過 ssh 遠端對虛擬主機執行命令,並檢視 虛擬主機的狀態
:::spoiler 完整程式 :
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 先用 ping 命令,檢測每一台虛擬主機網路,有回應則用 ssh 命令遠端對虛擬主機執行命令
for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do (
for /f "tokens=1-3 delims=." %%x in ('echo %%b') do (
for /f "tokens=2 delims=." %%i in ('echo %%a') do (
ping -n 2 "%%x.%%y.%%z.%%i" | find "TTL" 2> nul > nul
if errorlevel 1 (
echo "%%x.%%y.%%z.%%i not running"
) else (
ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@"%%x.%%y.%%z.%%i" "n=$(hostname;hostname -i); echo $n running" 2> nul
)
)
)
):::
執行檢測命令
> vmlist.bat螢幕輸出 :
c1m1 120.96.143.141 running
c1w1 120.96.143.145 running
c1w2 120.96.143.146 running
c1w3 120.96.143.147 running[註] 如將 VM 開機後,遇到類似以下錯誤訊息
`8f: value too great for base (error token is "8f")`請將 /home/bigred/bin/chnameip 程式中原本的 51 行命令 ip=$((16#$v)) ,修改為 ip=$(printf "%d\n" 0x"$v")
7. 關閉 c1 叢集所有虛擬主機
stop.bat 程式概述 : 利用 ssh 遠端對虛擬主機執行 sudo poweroff 的命令,將虛擬主機關閉
:::spoiler 完整程式內容
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 利用 ssh 遠端對每一台虛擬主機執行關機命令
setlocal EnableDelayedExpansion
for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do (
for /f "tokens=1-3 delims=." %%x in ('echo %%b') do (
for /f "tokens=2 delims=." %%i in ('echo %%a') do (
ping -n 2 "%%x.%%y.%%z.%%i" | find "TTL" 2> nul > nul
if errorlevel 1 (
echo "%%x.%%y.%%z.%%i not running"
) else (
ssh -o "ConnectTimeout=5" -o "StrictHostKeyChecking=no" bigred@"%%x.%%y.%%z.%%i" "sudo poweroff; exit" 2> nul > nul
if !ERRORLEVEL! EQU 0 (
echo "%%x.%%y.%%z.%%i stoped"
) else (
if !ERRORLEVEL! EQU -1 echo "%%x.%%y.%%z.%%i stoped"
)
)
)
)
):::
執行關機 c1 叢集所有虛擬主機 命令
> vmstop.bat螢幕輸出
"120.96.143.141 stoped"
"120.96.143.145 stoped"
"120.96.143.146 stoped"
"120.96.143.147 stoped"8. 備份與還原 c1 叢集所有虛擬主機
backup.bat 程式概述 : 如果虛擬主機在本機,會透過 7z 壓縮,如果在遠端,會配合 psexec 命令,壓縮遠端的虛擬主機
:::spoiler 完整程式內容
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%e
)
REM 先用 ping 命令,檢測每一台虛擬主機是否已關機
setlocal EnableDelayedExpansion
for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do (
for /f "tokens=1-3 delims=." %%x in ('echo %%b') do (
for /f "tokens=1,2 delims=." %%i in ('echo %%a') do (
ping -n 2 "%%x.%%y.%%z.%%j" | find "TTL" 2> nul > nul
if !ERRORLEVEL! == 0 (
echo "Please Execute vmstop.bat" && GOTO:eof
)
)
)
)
for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do (
if %%c == %HostIP% (
if not exist "%USERPROFILE%\7-Zip" (
xcopy /E /Y ".\7z" "%USERPROFILE%\7-Zip\" > nul
)
"%USERPROFILE%\7-Zip\7z" -mx1 a "C:\Users\%USERNAME%\%%a.bak" "C:\Users\%USERNAME%\%%b" 2> nul > nul
if !ERRORLEVEL! EQU 0 (
echo "%%c %%a.bak backup ok !"
) else (
echo "%%c %%a.bak backup failed !"
)
) else (
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "%USERPROFILE%\7-Zip" ^2^>nul') do (
if %%i == False (
echo y | pscp -scp -pwfile passwd -q -r ".\7z" %USERNAME%@%%c:"%USERPROFILE%\7-Zip\"
)
)
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do (
if %%i == True (
psexec -accepteula -nobanner \\%%c -s "%USERPROFILE%\7-Zip\7z" "-mx1" "a" "C:\Users\%USERNAME%\%%a.bak" "C:\Users\%USERNAME%\%%b" 2> nul > nul
if !ERRORLEVEL! EQU 0 (
echo "%%c %%a.bak backup ok !"
) else (
echo "%%c %%a.bak backup failed !"
)
) else (
echo "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb VM folder not found !"
GOTO:eof
)
)
)
):::
執行備份 c1 叢集所有虛擬主機 命令
> vmbackup.bat螢幕輸出 :
"120.96.143.152 c1m1.141.zip.bak backup ok "
"120.96.143.152 c1w1.145.zip.bak backup ok "
"120.96.143.153 c1w2.146.zip.bak backup ok "
"120.96.143.153 c1w3.147.zip.bak backup ok "執行失敗的螢幕輸出
"Please Execute vmstop.bat" 可能原因 : 只要有一台 c1 cluster VM 沒關,就會噴出此錯誤訊息
[註] 新的備份檔會直接覆蓋掉舊的備份檔
執行還原 c1 叢集所有虛擬主機命令
restore.bat 程式概述 : 如果虛擬主機在本機,會透過 7z 解壓縮,如果在遠端,會配合 psexec 命令,解壓縮遠端的虛擬主機
:::spoiler 完整程式內容
@echo off
REM 判斷叢集名稱
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%e in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%e
)
REM 先用 ping 命令,檢測每一台虛擬主機是否已關機
setlocal EnableDelayedExpansion
for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do (
for /f "tokens=1-3 delims=." %%x in ('echo %%b') do (
for /f "tokens=1,2 delims=." %%i in ('echo %%a') do (
ping -n 2 "%%x.%%y.%%z.%%j" | find "TTL" 2> nul > nul
if !ERRORLEVEL! == 0 (
echo "Please Execute vmstop.bat" && GOTO:eof
)
)
)
)
for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do (
if %%c == %HostIP% (
if exist "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" (
RD /S /Q "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" > nul 2> nul
"%USERPROFILE%\7-Zip\7z" x "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul
) else (
"%USERPROFILE%\7-Zip\7z" x "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul
)
if exist "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" (
echo "%%c %CN:~0,2%\%%~nxb restore ok !"
) else (
echo "%%c %CN:~0,2%\%%~nxb restore Failed !"
)
) else (
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do (
if %%i == True (
psexec -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" "-Recurse" 2> nul
psexec -accepteula -nobanner \\%%c -s "%USERPROFILE%\7-Zip\7z" "x" "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul
) else (
psexec -accepteula -nobanner \\%%c -s "%USERPROFILE%\7-Zip\7z" "x" "C:\Users\%USERNAME%\%%a.bak" "-oC:\Users\%USERNAME%\%CN:~0,2%" > nul 2> nul
)
)
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%CN:~0,2%\%%~nxb" ^2^>nul') do (
if %%i == True (
echo "%%c %CN:~0,2%\%%~nxb restore ok !"
) else (
echo "%%c %CN:~0,2%\%%~nxb restore Failed !"
)
)
)
):::
> vmrestore.bat螢幕輸出 :
"120.96.143.152 c1\alp.c1m1 restore ok "
"120.96.143.152 c1\alp.c1w1 restore ok "
"120.96.143.153 c1\alp.c1w2 restore ok "
"120.96.143.153 c1\alp.c1w3 restore ok "執行失敗的螢幕輸出
"Please Execute vmstop.bat" 可能原因 : 只要有一台 c1 cluster VM 沒關,就會噴出此錯誤訊息
9. 清除 c1 叢集所有虛擬主機
del.bat 程式概述 : 如果虛擬主機在本地,會利用 Windows Powershell 的 Remove-Item 命令,刪除 c1 叢集所有虛擬主機、壓縮檔、本地的 c1 目錄,如果虛擬主機在遠端,會利用 Remove-Item 命令 配合 psexec 命令刪除
:::spoiler 完整程式內容 :
@echo off
REM 設定 Cluster Name
for /f "tokens=1" %%y in ('dir /B ^| findstr "mactohost"') do (
set CN=%%y
)
REM 設定本機 IP 變數
for /f "delims=[] tokens=2" %%a in ('ping -4 -n 1 %ComputerName% ^| findstr [') do (
set HostIP=%%a
)
REM 判斷是否已備份
for /f "tokens=4-6 delims= " %%a in ('type %CN:~0,2%mactohost ^| findstr zip') do (
if %%c == %HostIP% (
if not exist %HOMEPATH%\%%a.bak (
echo "Please Execute vmbackup.bat first" && GOTO:eof
)
) else (
for /f "tokens=1 delims= " %%i in ('PsExec.exe -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Test-Path" "-Path" "C:\Users\%USERNAME%\%%a.bak" ^2^>nul') do (
if %%i == False (
echo "Please Execute vmbackup.bat first" && GOTO:eof
)
)
)
)
REM 先用 ping 命令,檢測每一台虛擬主機是否已關機
setlocal EnableDelayedExpansion
for /f "skip=12 tokens=4,6 delims= " %%a in (%CN:~0,2%mactohost) do (
for /f "tokens=1-3 delims=." %%x in ('echo %%b') do (
for /f "tokens=1,2 delims=." %%i in ('echo %%a') do (
ping -n 2 "%%x.%%y.%%z.%%j" | find "TTL" 2> nul > nul
if !ERRORLEVEL! == 0 (
echo "Please Execute vmstop.bat" && GOTO:eof
)
)
)
)
REM 將 d*mactohost 中 實體 Windows 主機的 IP 匯入 ip.txt 檔案中
if exist ip.txt (del ip.txt)
for /f "skip=12 tokens=6 delims= " %%y in (%CN:~0,2%mactohost) do echo %%y >> ip.txt
REM 刪除 ip.txt 檔案中每一台實體 Windows 電腦 使用者家目錄中以叢集為名稱的目錄
setlocal EnableDelayedExpansion
for /f "tokens=1 delims= " %%x in ('type ip.txt ^| sort.exe /unique') do (
if %%x == %HostIP% (
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Command Remove-Item C:\Users\%USERNAME%\%CN:~0,2% -Recurse 2> nul
if !ERRORLEVEL! EQU 0 (
echo "%%x %CN:~0,2% folder deleted !"
) else (
echo "%%x %CN:~0,2% folder does not exist !"
)
) else (
psexec -accepteula -nobanner \\%%x -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%CN:~0,2%" "-Recurse" 2> nul
if !ERRORLEVEL! EQU 0 (
echo "%%x %CN:~0,2% folder deleted !"
) else (
echo "%%x %CN:~0,2% folder does not exist !"
)
)
)
REM 刪除在本地或遠端的虛擬主機壓縮檔
for /f "skip=12 tokens=4-6 delims= " %%a in (%CN:~0,2%mactohost) do (
if %%c == %HostIP% (
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Command Remove-Item C:\Users\%USERNAME%\%%a 2> nul
if !ERRORLEVEL! EQU 0 (
echo "%%c %%a deleted !"
) else (
echo "%%c %%a does not exist !"
)
) else (
psexec -accepteula -nobanner \\%%c -s "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "Remove-Item" "C:\Users\%USERNAME%\%%a" 2> nul
if !ERRORLEVEL! EQU 0 (
echo "%%c %%a deleted !"
) else (
echo "%%c %%a does not exist !"
)
)
)
del ip.txt 2> nul > nul
REM 刪除執行程式所在的目錄 (例如 : %USERPROFILE%\CNT.2023.v4.6\D9-1A2M3W\) 中的 d9 目錄
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Command Remove-Item %CN:~0,2% -Recurse 2> nul
if %ERRORLEVEL% == 0 (
echo "%HostIP% %CD%\%CN:~0,2% folder deleted !"
) else (
echo "%HostIP% %CD%\%CN:~0,2% folder does not exist !"
):::
執行清除 c1 叢集所有虛擬主機命令
> vmdel.bat螢幕輸出 :
"120.96.143.152 c1 folder deleted "
"120.96.143.153 c1 folder deleted "
"120.96.143.152 c1m1.141.zip deleted "
"120.96.143.152 c1w1.145.zip deleted "
"120.96.143.153 c1w2.146.zip deleted "
"120.96.143.153 c1w3.147.zip deleted "
"120.96.143.170 C:\Users\bigred\CNT.2023.v4.6\C1-1M3W\c1 folder deleted "執行失敗的螢幕輸出
"Please Execute vmbackup.bat first" 可能原因 : 程式一開始會檢查每一台 VM 對應的實體 Windows 主機的使用者家目錄,有無 *.bak 的備份檔,只要少一個備份檔,此程式就會噴出此錯誤訊息
[註] 會保留在本地或遠端實體主機的虛擬主機備份 (*.bak) 檔
IaC 平臺 開發關鍵技術
技術重點 1 - Windows batch script - 透過 FOR 命令可以將文字檔中的欄位資料取出
:star: 首先要注意 ! 如果要在批次程式中使用 FOR 命令,請指定 %%variable,而不要指定%variable。變數名稱有大小寫的區分,所以 %i 不同於 %I。
逐行讀取文字檔的 for /F 迴圈
/f ,可以對 for 迴圈傳入的檔案、字串或命令,進行解析,以下為讀取檔案的範例 :
for /f "tokens=3,* delims= " %%a in (c1mactohost) do echo %%b- 概述:逐行讀取
k1mactohost檔案的內容,然後依照分隔符號 (空格) 將檔案內容的值分別設為指定的變數,再將指定的變數內容輸出在螢幕上。 tokens=x,y,m-n用來決定一次要取出幾個欄位,第一個欄位會存放在第一個自動變數,第二個欄位會存放在第二個自動變數裡,依此類推。在範例中為tokens=3,*,代表將第三個欄位的值存放在變數a,其他剩餘欄位的值會放在變數b註:x, x, m, n都為數字,只是m-n是一種特別的表示法,代表一個解析欄位的範圍。例如tokens=2-4就代表取得第2、第 3 與第 4 個欄位的值並分別塞指定的變數裡delims=xxx用來決定欄位的分隔符號,預設為空格與 TAB 符號,並可自訂多個符號。在範例中,將欄位的分隔符號設為空格 註:xxx代表多個字元,如果要同時設定小數點.與逗號,就要輸入delims=.,
練習
啟動一個文字檔 tip.txt
> notepad tip.txt 內容是
10:6e d8a5 120.96.143.22
10:6f d8a6 120.96.143.22寫一隻程式 (tip.bat)用冒號分割顯示以下的結果:
6e
6f答案:
先編輯一個批次檔
$ notepad tip.bat內容是
@echo off
for /f "tokens=1 delims= " %%a in (tip.txt) do echo %%a 將 a 變數匯入一個檔案
@echo off
for /f "tokens=1 delims= " %%a in (tip.txt) do echo %%a >> t1.txt
for /f "tokens=2 delims=:" %%b in (t1.txt) do echo %%b執行批次檔
$ tip.bat螢幕輸出
6e
6f另一種答案,雙迴圈
@echo off
for /f "tokens=1 delims= " %%a in (tip.txt) do (
for /f "tokens=1,2 delims=:" %%b in ('echo %%a') do echo %%b %%c
) 甚麼是 @echo off ?
認識 echo on
在 Windows batch script 中,預設是 echo on,當 Windows 電腦在執行批次程式中的每一行命令時,會先顯示其解析後的結果,才會再顯示執行後的結果
範例 :
編輯一個 test.bat 批次檔
> notepad test.bat檔案內容
set a=b
echo %a%執行程式
> test.bat 螢幕輸出
>set a=b
>echo b
b可以看到它在執行程式中的每一行命令時,會先顯示其解析後的結果,才會再顯示執行後的結果
認識 @echo off
@echo off 可以分為兩個部分,最前面的 @ 和 後面的echo off
@是針對特定命令,讓它不要顯示被解析後的結果,直接顯示命令執行後的結果echo off通常會被加在 Windows 批次檔的最上面,它的作用是,程式在執行時,只顯示命令執行結果。
所以 @echo off ,它會不顯示自己被解析後的結果,且程式的每一行命令在執行時,只顯示命令執行結果。
延續上一個範例 :
編輯 test.bat 批次檔
> notepad test.bat檔案內容的最上面新增 @echo off
@echo off
set a=b
echo %a%執行程式
> test.bat 螢幕輸出
b甚麼是 setlocal EnableDelayedExpansion ?
在了解 甚麼是 setlocal EnableDelayedExpansion 之前,先來看看以下一段批次程式的內容
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" @echo "If you see this, it worked"
)看完以後您覺得執行這隻程式的結果會顯示 "If you see this, it worked" 這段字串嗎?
來看看程式執行結果
> set VAR=before
> if "before" == "before" (
set VAR=after
if "before" == "after"
)在預設情況下,每行命令被執行之前,變數擴展成值,只會發生一次,即使你在 if 的括號之中,把它分成兩行。
通過 SETLOCAL EnableDelayedExpansion 命令打開 延遲擴展可以讓批次檔中的變數,在執行時擴展變成值,而不是在命令被解析的時後。
使用 FOR 迴圈 或是 if 括號表達式等循環命令,延遲擴展將允許您始終讀取變數的當前值。
現在我們在程式的最上面加上 SETLOCAL EnableDelayedExpansion
> notepad test.bat檔案內容
SETLOCAL EnableDelayedExpansion
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" @echo "If you see this, it worked"
)執行程式
> test.bat螢幕輸出
>test.bat
>SETLOCAL EnableDelayedExpansion
>set VAR=before
>if "before" == "before" (
set VAR=after
if "before" == "after"
)奇怪 ??? 為甚麼還是沒有在螢幕上輸出 “If you see this, it worked” 這段字串 ?
答案是因為 :
要讓延遲擴展生效,必須使用!variable_name!,在變數的前後都加驚嘆號,來立即讀取變數的值。
修改程式
> notepad test.bat編輯程式內容,將 第二個 %VAR% 改成 !VAR!
@echo off
SETLOCAL EnableDelayedExpansion
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "!VAR!" == "after" @echo "If you see this, it worked"
)執行程式
> test.bat 螢幕輸出
"If you see this, it worked"成功 ~
參考文章
技術重點 2 - Windows 遠端啟動 VMware 虛擬電腦
1. 使用 psexec 必須使用此設定
開放遠端連線權限,用系統管理員身份打開 CMD,並執行以下命令
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f[註] 1. 機碼修改後,需重啟電腦 2. 如有安裝 F-Secure,請關閉 F-Secure 防火牆 參考文章連結 : PsTools 於 Windows 10 的環境設定
2. 執行 psexec 簡易命令
打開 CMD ,切換到 CNT.2023.v4.5\D9-1A2M3W工作目錄,執行以下測試命令
psexec \\192.168.39.55 -s "hostname"螢幕輸出
PsExec v2.4 - Execute processes remotely
Copyright (C) 2001-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
DESKTOP-VNDI6BN
hostname exited on 192.168.39.55 with error code 0.3. 啟動虛擬機器
$ psexec \\120.96.143.3 -s -d "C:\Program Files (x86)\VMware\VMware Player\vmrun" "start" "C:\Users\bigred\alp.k1a1\alpine64.vmwarevm\alpine64.vmx" "nogui"參數解釋 :
-s,遠端執行的命令將會由 System account 執行-d,我們連線的實體主機即使斷線,所執行的命令不會因此中斷。您無法獲得任何退出代碼或輸出,因為遠程 PsExec 服務只是啟動程序,將新程序 ID 告知原始 PsExec 程序,而不再關心新程序的作用。
[stackoverflow 參考文章] What does psexec -s do?
4. 如何知道執行 psexec 成功
打開工作管理員,確認有沒有以下的顯示

5. 關閉虛擬機器
方法一 : 直接下命令
psexec \\120.96.143.5 -s -d "C:\Program Files (x86)\VMware\VMware Player\vmrun" "stop" "C:\Users\bigred\alp.k1w3\alpine64.vmwarevm\alpine64.vmx"方法二 : 使用工作管理員在 vmware-vmx.exe 按右鍵結束工作
:::spoiler 參考圖片
:::
將 *.lck檔和類型是 VMEM檔案 的三個檔案刪掉
:::spoiler 參考圖片
:::