Virtualbox Windows在主机关闭时正常关闭来宾


19

我试图找到一种解决方案,以在主机关闭或重新启动时正常关闭在VirtualBox Windows下运行的所有来宾VM。

似乎最安全的选择是在主机开始关闭时触发“保存状态”命令,但尚不清楚主机是否会等待足够长的时间以使VM完成保存状态并关闭电源。

有没有人对此问题(看似基本)有一个可靠的解决方案?


安装来宾添加项?那不提供所需的功能吗?
加拿大卢克REINSTATE MONICA,2015年

@CanadianLuke不是。:)
马特·詹金斯

Answers:


6

我有一个类似的问题,并通过将VirtualBox作为服务运行来解决:

http://vboxvmservice.sourceforge.net/

使用VBoxVMService,您可以选择希望计算机关机(保存状态,关闭电源)和启动方式。由于它作为服务运行,因此Windows将在系统关闭过程中自动等待其关闭。


在Windows 10上,设置过程不是很自动。我必须参考故障排除方法以了解问题所在。但是,经过正确配置后,该软件完全可以满足我的需求。谢谢您的出色工作。
iuradz '17

3

不幸的是,对于通过VirtualBox GUI启动的VM似乎无法实现。即使GUI可能会捕获主机关闭事件并做出反应,VirtualBox服务也会终止:https : //forums.virtualbox.org/viewtopic.php? p = 278668#p278668

如果您不需要图形控制台,则可以使用VBoxHeadlessTray或VBoxVMService。两者都支持在Windows主机关闭和重新启动时自动保存和继续。

VirtualBox 5.0引入了“可分离UI”启动模式。此模式使用单独的UI进程启动无头VM。尽管图形性能有所下降,但尚不支持3D加速。但这也许将来可以与VBoxHeadlessTray结合使用(VBoxHeadlessTray尚不支持5.0。)链接到VBoxHeadlessTray GitHub存储库以及相应的GitHub pull请求,以添加对VirtualBox 5的支持

编辑:VBoxVmService也从5.0版开始不支持新的可分离模式。到目前为止,只有无头。我为此添加了功能请求


因为每个帖子我都不能移植两个以上的链接,所以这里是指向VBoxHeadlessTray和相应的GitHub拉取请求的链接,以添加VirtualBox 5支持。
Leo B

我没有遇到线程中概述的问题。请参阅我对此主题的回答。我可以运行Windows主机关机然后走开。关闭所有关闭的虚拟机,直到关闭所有虚拟机为止,并且我更改了默认操作以执行干净关闭或保存状态。
克里斯·巴恩森

2

我有3个批处理脚本,而不是使用startmenu电源按钮。

do_shutdown.bat(关闭计算机的等待时间为10秒,不是给虚拟机 10秒的保存时间,而是让我在10秒内取消关闭。倒数是在虚拟机关闭后开始的)

"C:\VirtualBox\VBoxManage.exe" controlvm "Ubuntu Server" savestate
"C:\VirtualBox\VBoxManage.exe" controlvm "Ubuntu Minimal" savestate
shutdown /s /t 10

do_reboot.bat(关闭虚拟机后立即重新启动)

"C:\VirtualBox\VBoxManage.exe" controlvm "Ubuntu Server" savestate
"C:\VirtualBox\VBoxManage.exe" controlvm "Ubuntu Minimal" savestate
shutdown /r /t 0

do_cancel.bat(允许我在10秒的等待时间内取消pc-shutdown。由于它们被do_shutdown.bat关闭,因此它会重新启动vm)。

shutdown /a
C:\VirtualBox\VBoxManage.exe startvm "Ubuntu Minimal" --type headless
C:\VirtualBox\VBoxManage.exe startvm "Ubuntu Server" --type headless

代替savestate您也可以使用以下之一

poweroff        - pulls the plug
                  (probably not a good idea...)

acpipowerbutton - presses the power off button for a clean shutdown
                  ("The system is going down for power off NOW!" to all consoles)

acpisleepbutton - tells the os to go to sleep
                  (probably just as bad as poweroff)

1
谢谢,这很有趣。不幸的是,还有其他一些我需要处理的非手动关机/重新启动方案。例如,Windows Update计划的重新启动或电池电量不足的关闭/关闭事件。
马特·詹金斯

1
哦好的。还有一个带有“脚本(启动/关闭)”部分的组策略编辑器lifehacker.com / ...我正在使用该命令执行非常短的关闭命令(一次curl调用),所以我不知道它的行为需要一些时间才能完成的脚本。
Daniel F

2

抱歉,我迟到了。有一个确切的答案,尽管它需要一些命令行-foo。有关更多信息,请参见此线程文章:https : //forums.virtualbox.org/viewtopic.php?f=6&t=53684#p285540

您要查找的命令是:

“ C:\ Program Files \ Oracle \ VirtualBox \ VBoxManage.exe” setextradata“ VM NAME” GUI / DefaultCloseAction关闭

这是我在多个VM上使用的方法,关闭窗口,它会自动启动安全关闭。关闭Windows,并尝试关闭所有内容,它将等待这些过程完成。


1

我有一个类似的问题,并找到了此页面。我不想将VirtualBox作为服务运行,因为我有很多要测试的VM,通常会选择不同的VM在VirtualBox UI中运行。当我关闭计算机时,手动保存每个VM的状态很烦人。在这种情况下,使用脚本保存所有正在运行的VM似乎是一种实用的解决方案。为了使Daniel F的回答更加笼统,我编写了这些脚本,这些脚本自动保存所有正在运行的VM的状态,而无需明确命名它们。

Windows的saveRunningVMs.bat

set VBoxManageEXE="%ProgramFiles%\Oracle\VirtualBox\VBoxManage.exe"
set ListRunningVMS=%VboxManageEXE% list runningvms
for /f tokens^=2^,4^ delims^=^" %%p in ('%ListRunningVMS%') do %VBoxManageEXE% controlvm %%p savestate

echo all vms saved, you can shutdown now.

rem shutdown /s /t 10

用于Linux的saveRunningVMs.sh

#!/bin/bash
vboxmanage list runningvms | while read line; do
  #echo "VBoxManage controlvm $uuid savestate;"
  echo $line
  if [[ $line =~ \{(.*)\} ]]
  then
    vboxmanage controlvm ${BASH_REMATCH[1]} savestate
  fi
done

0

我创建了一个python脚本,该脚本将挂起所有正在运行的VirtualBox VM,然后将系统设置为在注销时作为计划任务运行该脚本。

我不知道这种方法到底有多可靠。正如其他人指出的那样,系统等待Winlogon 7002任务完成的时间是有限的。但是我个人没有任何问题,即使在多个运行中的VM跨越4 GB以上的总VM RAM,它也提供了可用的保存状态。

设置步骤如下:

  1. 从python.org下载并安装Python 2.7.x
  2. 使用记事本或任何其他纯文本编辑器在系统上的某处创建python脚本文件(请参见下文)
  3. 打开任务计划程序
  4. 选择“操作”->“创建基本任务...”,然后使用向导通过以下设置创建任务
    • 您选择的名称
    • 记录特定事件后启动任务
    • 日志:系统
    • 资料来源:Winlogon
    • 事件ID:7002
    • 开始一个程序
    • 在“ 程序/脚本”旁边,输入的完整路径python.exe,例如c:\Python27\python.exe
    • 添加参数旁边,输入放置python脚本文件的完整路径,例如,我将我的放置在我的documents文件夹的子文件夹中,所以这是C:\Users\rakslice\Documents\vboxsuspend\vboxsuspend.py
    • 选择完成。

现在,VirtualBox VM应该在注销/重新启动/关闭时挂起。

下面是执行关闭操作的python脚本:

# A script to suspend all running VirtualBox VMs

import os

import subprocess

import sys


class VM(object):
    def __init__(self, name, uuid):
        self.name = name
        self.uuid = uuid

    def __repr__(self):
        return "VM(%r,%r)" % (self.name, self.uuid)


class VBoxRunner(object):
    def __init__(self):
        program_files = os.environ["ProgramW6432"]
        vbox_dir = os.path.join(program_files, "Oracle", "VirtualBox")
        self.vboxmanage_filename = os.path.join(vbox_dir, "VBoxManage.exe")

    def vbox_run(self, *args):
        subprocess.check_call([self.vboxmanage_filename] + list(args))

    def vbox_run_output(self, *args):
        return subprocess.check_output([self.vboxmanage_filename] + list(args))

    def list(self, running=True):
        if running:
            list_cmd = "runningvms"
        else:
            list_cmd = "vms"

        return [self.parse_vm_list_entry(x) for x in self.vbox_run_output("list", list_cmd).strip().split("\n")]

    def suspend_all(self):
        success = True
        stopped_some_vms = False
        vms = self.list(running=True)
        for vm in vms:
            if vm is None:
                continue
            # noinspection PyBroadException
            try:
                self.suspend_vm(vm)
            except:
                success = False
            else:
                stopped_some_vms = True
        if not stopped_some_vms:
            self.message("No running vms")
        return success

    @staticmethod
    def parse_vm_list_entry(x):
        """:type x: str"""
        if not x.startswith('"'):
            return None
        end_pos = x.find('"', 1)
        if end_pos == -1:
            return None
        name = x[1:end_pos]
        assert x[end_pos + 1: end_pos + 3] == " {"
        assert x.endswith("}")
        uuid = x[end_pos + 2:]

        return VM(name, uuid)

    @staticmethod
    def message(msg):
        print >>sys.stderr, msg

    def suspend_vm(self, vm):
        assert isinstance(vm, VM)
        self.vbox_run("controlvm", vm.uuid, "savestate")


def main():
    vr = VBoxRunner()
    success = vr.suspend_all()
    if not success:
        sys.exit(1)


if __name__ == "__main__":
    main()

1
其他人关于使用批处理脚本的建议是,如果适合您的用例,则可以手动运行并执行savestates,然后执行关闭操作。但是我真正想要的是Windows Update自动重新启动,因为我一直在使用的VM在一夜之间被Windows Update硬关闭了电源,在过去的两天中,Windows Update连续重新启动...
rakslice
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.