所有我的伺服器都是在 VMware Worstation 虛擬機器上運行。虛擬機器的優點是管理簡單及容易恢復到先前的快照,這些對開發中的系統相當有用。

部份我的虛擬機器必須在實體電腦開機中隨時一起運行。VMware Workstation 提供了一個 AutoStart 功能,它允許共享的虛擬機器在實體主機啟動時,自動被啟動。然而,那內建的 AutoStart 功能本身有些限制,對我的狀況一點用也沒有。

AutoStart 有何毛病?

VMware Workstation 所製作的 AutoStart 功能有兩個重大問題,讓我必須找尋另外的解決方案:

  1. 只有共享的虛擬機器能被自動啟動。這本身並不構成問題。你只需先將你的虛擬機器設為共享,再設定 AutoStart 即可。但是共享虛擬機器受到一些限制,其中一個是你不能在共享虛擬機器上使用實體磁碟。因為我有一個虛擬機用到實體磁碟,它不能被設成共享,也就不能 AutoStart。
  2. 當我注意到每次在 實體主機重新起到後,一個 AutoStart 虛擬機器上的 MySQL 就需要修復資料庫,我發現到另一個問題。我本以為 AutoStart 功能也會在實體主機關機或重新啟動時,自動將虛擬機器關機/暫停。很明顯地,我想錯了。該功能只做它名稱所宣稱的,也就是自動啟動虛擬機器而已。對我來說,允許可能的資料損失是無法接受的。

一個自動啟動/停止虛擬機器的替代方式

在此我將提出一份腳本程式與步驟,來讓含有實體磁碟的虛擬機器,在實體主機啟動時跟著自動啟動,在實體主機關機時也暫停/關機。並且,所有需要的軟體均已經和 VMware Workstation 一同安裝,或已經存在於 Windows 7 Home Premium 系統中。

我是用 PowerShell 來撰寫這腳本程式。使用 PowerShell 並無特殊原因,只是好玩才用它,我也並非很會 PowerShell。歡迎你修改它,讓它更好。至於控制虛擬機器,我用的是VMware Workstation 中的 'vmrun.exe' 程式。

一旦有了可用的腳本程式,我需要能夠在實體主機啟動與關機時執行它。於 Windows 7 系統上,大概有三種方式可達成它。然而,我發覺使用 Task Scheduler 也許是最簡易也是普及的方法。

接著,我設定好虛擬機器來讓我的自動啟動/停止繳本程式來處理,並在實體主機上測試。最後我有了令人滿意的方式來讓我的虛擬機器自動啟動和暫停。


自動啟動/停止腳本程式

以下的 PowerShell 腳本程式是用以啟動和停止虛擬機器,它會在特定事件發生時被 Task Scheduler 叫用。位於程式開頭的一些變數必須先根據你的實體主機系統設定好。

  • $vmrun_path:VMrun.exe 程式的完整路徑。
  • $auto_vms_path:含有你的虛擬機器之完整路徑。
  • $start_delay:啟動兩個虛擬機器之間的延遲秒數。
  • $stop_delay:停止或暫停兩個虛擬機器之間的延遲秒數。

函式 Get-AutoVMs 是此腳本程式裡的一個工作主力。它找出位於 $auto_vms_path 中,必須被控制的虛擬機器,根據每個虛擬機器檔案夾裡的 +autovm.nn (nn 是啟動順序號碼) 檔案名稱排序好,再將它們送回。

例如,若一個虛擬機器的檔案夾中,有一個檔案 +autovm.03,則它會在有檔案 +autovm.05 的虛擬機器之前被啟動。停止/暫停的順序是啟動順序的相反。要停用一個虛擬機器的自動啟動/停止,你只需要刪除檔案 +autovm.nn 或改名為像是 -autovm.nn

腳本程式內真正控制虛擬機器的部分是兩個 foreach 迴路,一個用來啟動它們,另一個用來停止/暫停它們。那兩個迴路使用 VMrun.exe 程式。啟動一虛擬機器,程式碼

& "$vmrun_path" -T ws start "$vm" nogui

被用到,nogui 指定它會在背景執行且沒有 GUI。停止和暫停一虛擬機器,程式使用

& "$vmrun_path" -T ws $command "$vm" $option

其中 $command 可以是 'stop' 或 'suspend',$option 可以是 'hard' 或 'soft'。當使用選項 'soft',VMware 會要求客戶系統先執行對應的腳本程式。當使用選項 'hard',客戶系統將不會有機會執行它的腳本程式。

# Get script arguments
# $command: start, stop or suspend
# $option: hard or soft when $command is stop or suspend
param ([string] $command, [string] $option = "soft")

## defaults
# location of vmrun.exe
$vmrun_path = "${Env:ProgramFiles(x86)}\VMware\VMware VIX\VMrun.exe"
# location of virtual machine directory
$auto_vms_path = "E:\Virtual Machines"
# delay interval (in seconds) for starting up and stopping VMs
$start_delay = 90
$stop_delay = 30

## functions
# Get VMs to be auto-started at $path sorted by +autovms.xx name.
function Get-AutoVMs($path) {
    Get-ChildItem "$path\*\+autovm.*" | Sort-Object Name `
    | ForEach-Object {$_.DirectoryName+"\*.vmx"} | Get-ChildItem `
    | ForEach-Object {$_.FullName}
}

# Get running VMs
# NOTE: this only works this VMs started in the same session, so we can't use it here.
function Get-RunningVMs() {
    & "$vmrun_path" -T ws list | Where-Object {$_.EndsWith(".vmx")} `
    | Sort-Object -Descending
}

## main program
if ($command.ToLower() -eq "start") {
    # Retrieve VMs to be auto-start
    $auto_vms = @(Get-AutoVMs $auto_vms_path)

    # Start each VM in the list
    foreach ($vm in $auto_vms) {
        & "$vmrun_path" -T ws start "$vm" nogui
        # Delay a little while.
        if ($vm -ne $auto_vms[-1])
            { Start-Sleep -Seconds $start_delay }
    }
    
    exit 10

} elseif ((("stop", "suspend") -contains $command.ToLower()) `
         -and (("soft", "hard") -contains $option.ToLower())) {
    # Retrieve VMs, and reverse its order.
    #$auto_vms = @(Get-RunningVMs)
    $auto_vms = @(Get-AutoVMs $auto_vms_path)
    [Array]::Reverse($auto_vms)

    # Suspend each VM in the running list.
    foreach ($vm in $auto_vms) {
        & "$vmrun_path" -T ws $command "$vm" $option
        # Delay a little while.
        if ($vm -ne $auto_vms[-1]) 
            { Start-Sleep -Seconds $stop_delay }
    }
    
    exit 20
}

exit 1

允許腳本程式執行

當你儲存了腳本程式到你的電腦上並試著執行它,會發現你不被允許執行它。那是因為在 Windows 7 上,預設的 ExecutionPolicy 是限制所有 PowerShell 腳本程式的執行。你必須改變 ExecutionPolicy 來允許一個管理員帳戶執行本地的 PowerShell 腳本程式。那個管理員帳戶將也是用來執行 Task Scheduler 動作。

首先,找到 Windows Powershell 於 Start Menu -> All Programs -> Accessories -> Windows Powershell。用右鍵點按它,並選用 'Run as administrator' 如果你不是以管理員帳戶登入。在指令提示輸入此指令

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

(如 PIC-1)。那將使該管理員帳戶能夠執行本地與簽屬過的遠端 PowerShell 腳本程式。

PIC-1 Set-ExecutionPolicy


於 Task Scheduler 中排定工作

在自動啟動/停止腳本程式備妥後,現在該於 Task Scheduler 設定 2 個工作來在實體主機啟動時啟動虛擬機器,在主機關機時停止它們。有其它可用的方法存在,但使用 Task Scheduler 可能是在 Windows 7 Home Premium 上最簡單的方法。

Task Scheduler 可於 Start Menu -> All Programs -> Accessories -> System Tools 找到。用右鍵點按它,在選用 'Run as administrator' 來用執行腳本程式的管理原帳戶。在 Task Scheduler 視窗的左邊,選擇 'Task Scheduler Library' 並用右鍵點按它。選用 'New Folder...' 來建立一個工作資料夾,例如 VMware。將有兩個工作被放入該工作資料夾。(見 PIC-2.)

PIC-2. New Folder

要建立一則工作來啟動虛擬機器,用右鍵按點新的工作資料夾,並選 'Create Basic Task...'。給它一個名稱及描敘。於 Trigger 選擇 'When the computer starts',而於 Action 選擇 'Start a program'。當被問到Program/script, 輸入 'C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe' 到欄位裡。(請根據你的 PowerShell 位置來調整。) 在 Add arguments (optional) 欄位,輸入 '-File "E:\Scripts\Auto-VMs.ps1" start'。(腳本程式路徑與名稱須以你自己的來取代。) (見 PIC-3.)

PIC-3. Start a Program

於 Summary 步驟,在點按 Finish 按鈕之前,請勾選 'Open the Properties dialog for this task when I click Finish'。該工作的 Properties 視窗會顯示來繼續設定。於 Properties 視窗,請檢查用以執行腳本程式的使用者帳戶是正確的,然後選定 'Run whether user is logged on or not' 並勾選 'Run with highest privileges'。並且確定 Configure for 選項是 'Windows 7, Windows Server 2008 R2'。在你按下 OK 按鈕後,必須輸入用來執行腳本程式的管理員帳戶之密碼。(見 PIC-4.)

PIC-4. Properties

重復相同的過程來建立停止/暫停虛擬機器的工作。但在這次,當問到 Trigger 時,選 'When a specific event is logged'。接著,在 Log 及 Source 拉下選單,分別選擇 'System' 與 'USER32'。於 Event ID 欄位,須入 '1074' ,那是當關機被發起時所記錄的事件。(見 PIC-5.)

PIC-5. When-an-Event-Is-Logged

再一次,在 Action 選擇 'Start a program',當被問到 Program/script 時,輸入 'C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe' 到欄位裡 (根據你的 PowerShell 位置來調整)。於 Add arguments (optional) 欄位中,輸入 '-File "E:\Scripts\Auto-VMs.ps1" suspend soft'。(用你自己的程式路徑和名稱來取代。) 你也可以用 'suspend hard'、'stop soft' 或 'stop hard' 做腳本程式的參數。(見 PIC-6.)

PIC-6. Start a Program: suspend soft

最後在 Summary 頁面和之後的 Properties 視窗做魚之前相同的選擇。現在你有 2 工作設定好,於實體主機啟動及關機時,來自動啟動與停止/暫停虛擬機器。


設置虛擬機器並測試

我們現在必須建立 +autovm.nn 檔案,給那些必須被排定工作控制的虛擬機器。你只要在虛擬機器的檔案夾內,放一個空白檔案 +autovm.nn,其中 nn 是兩位數字用以決定虛擬機器的啟動順序。例如,第一個被啟動的虛擬機器可有檔案 +autovm.01 存在它的檔案夾裡。請記得停止/暫停的順序是啟動順序的相反。

要測試那兩個工作,請再次開啟 Task Scheduler 並進入之前建立的工作資料夾。首先,選擇啟動虛擬機器的工作,在右側選單點選 Run。以之前指定的管理員帳戶來執行 VMware Workstation,檢查是否那些虛擬機器的確被啟動。如果它們如同計畫的啟動,你可選擇停止虛擬機器的工作,在右側選用 Run 來停止/暫停它們。以 VMware Workstation 來檢視它們是否真的停止/暫停。

若一切按照預期的作業,你應該重新啟動實體主機兩次,以確認那些排程好的工作,能夠在實體主機啟動與關機時,啟動/停止虛擬機器。如果有什麼沒按照計畫作業,請檢查整個程序。

 

FaLang translation system by Faboba