所有我的伺服器都是在 VMware Worstation 虚拟机器上运行。虚拟机器的优点是管理简单及容易恢复到先前的快照,这些对开发中的系统相当有用。
部份我的虚拟机器必须在实体电脑开机中随时一起运行。VMware Workstation 提供了一个 AutoStart 功能,它允许共享的虚拟机器在实体主机启动时,自动被启动。然而,那内建的 AutoStart 功能本身有些限制,对我的状况一点用也没有。
AutoStart 有何毛病?
VMware Workstation 所制作的 AutoStart 功能有两个重大问题,让我必须找寻另外的解决方案:
- 只有共享的虚拟机器能被自动启动。这本身并不构成问题。你只需先将你的虚拟机器设为共享,再设定 AutoStart 即可。但是共享虚拟机器受到一些限制,其中一个是你不能在共享虚拟机器上使用实体磁碟。因为我有一个虚拟机用到实体磁碟,它不能被设成共享,也就不能 AutoStart。
- 当我注意到每次在 实体主机重新起到后,一个 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 脚本程式。
于 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.)
要建立一则工作来启动虚拟机器,用右键按点新的工作资料夹,并选 '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.)
于 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.)
重复相同的过程来建立停止/暂停虚拟机器的工作。但在这次,当问到 Trigger 时,选 'When a specific event is logged'。接着,在 Log 及 Source 拉下选单,分别选择 'System' 与 'USER32'。于 Event ID 栏位,须入 '1074' ,那是当关机被发起时所记录的事件。(见 PIC-5.)
再一次,在 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.)
最后在 Summary 页面和之后的 Properties 视窗做鱼之前相同的选择。现在你有 2 工作设定好,于实体主机启动及关机时,来自动启动与停止/暂停虚拟机器。
设置虚拟机器并测试
我们现在必须建立 +autovm.nn 档案,给那些必须被排定工作控制的虚拟机器。你只要在虚拟机器的档案夹内,放一个空白档案 +autovm.nn,其中 nn 是两位数字用以决定虚拟机器的启动顺序。例如,第一个被启动的虚拟机器可有档案 +autovm.01 存在它的档案夹里。请记得停止/暂停的顺序是启动顺序的相反。
要测试那两个工作,请再次开启 Task Scheduler 并进入之前建立的工作资料夹。首先,选择启动虚拟机器的工作,在右侧选单点选 Run。以之前指定的管理员帐户来执行 VMware Workstation,检查是否那些虚拟机器的确被启动。如果它们如同计划的启动,你可选择停止虚拟机器的工作,在右侧选用 Run 来停止/暂停它们。以 VMware Workstation 来检视它们是否真的停止/暂停。
若一切按照预期的作业,你应该重新启动实体主机两次,以确认那些排程好的工作,能够在实体主机启动与关机时,启动/停止虚拟机器。如果有什么没按照计划作业,请检查整个程序。