在关闭程序之前在 Windows 7 关机时运行批处理文件(最好是在按下电源按钮时)

发布于 2024-10-14 03:43:25 字数 1276 浏览 6 评论 0原文

我有一个 Windows 7 机器,其中包含多台在启动时启动的 VMWare Player 机器。我使用 WMWare VIX 和批处理文件来关闭虚拟机,如下所示:

"C:\path\to\VMWare VIX\vmrun.exe" -T player stop "C:\path\to\machine.vmx" soft

我想要完成的是在主机关闭时运行这些命令,这样我就不需要单独关闭每个虚拟机。部署后,短按 ACPI 电源按钮即可开始关闭,而不是从“开始”菜单。我尝试过的方法不起作用(至少不够好):

  1. 组策略 - 最明显的方法,但在 Windows 7 中,“异步”运行关闭脚本的选项消失了。
    结果是 Windows 首先告诉所有打开的窗口关闭,虚拟机响应它们正在使用,然后您会看到“强制关闭”对话框。只有VMWare Player 和其他所有内容都关闭后,脚本才会运行,没有任何用处。
    你可能会认为这可以改变,但我想我记得看到过一些微软官方的说明,大意是“不,抱歉”。但找不到链接。

  2. 使用一个批处理文件关闭所有虚拟机,然后将主机作为桌面快捷方式关闭,而不是通常的关闭按钮。 - 有效,这就是我现在开发时使用的内容。
    但使用 ACPI 电源按钮会启动正常关机,其结果与之前相同,并且如果每天打开和关闭计算机的最终用户不需要使用显示器和鼠标,那就更好了。< br> 所以我现在正在谷歌搜索的是一种修改按下物理电源按钮时调用的操作的方法。 Windows 允许您在一些不同的操作之间进行选择,例如睡眠、休眠、重新启动等,但是您可以将其更改为“运行此 .bat”吗?或者完全更改关闭命令的行为?

  3. 以编程方式拦截关闭消息、中止关闭、运行批处理文件、重新启动关闭。关于拦截关闭有一些讨论,例如此处此处这里,但除了 Ruby 或 Java 之外,我对所有语言都还很陌生,无法真正理解在这种情况下是否可以以及如何完成。如果有人可以阐明如何实际完成这项工作(不会卡在“强制关闭”屏幕上),那么我很想尝试您提供的任何语言。

I have a Windows 7 box with multiple VMWare Player machines that are started on boot. I use WMWare VIX and a batch file to shutdown the virtual machines like so:

"C:\path\to\VMWare VIX\vmrun.exe" -T player stop "C:\path\to\machine.vmx" soft

What I want to accomplish is to run these commands when the host machine is shut down, so that I don't need to shut down each VM separately. When deployed, shutdowns will likely be started with a short press of the ACPI power button, not from the Start menu. Ways I've tried that don't work (at least not well enough):

  1. Group Policies - The most obvious way to go, but in Windows 7, the option to run shutdown scripts 'asynchronously' is gone.
    The result is that Windows first tells all open windows to close, the VMs respond that they are in use and you get the 'Force close' dialog. Only after VMWare Player and everything else is closed are the scripts run, to no use.
    You'd think this could be changed, but I think I remember seeing some official MS note along the lines of "nope, sorry". Can't find the link though.

  2. Use one batch file that closes all VMs and then shutdowns the host as a desktop shortcut instead of the usual shutdown button. - Works, and that's about what I'm using right now while developing.
    But using the ACPI power button initiates a normal shutdown with the same result as earlier, and it would be better if the end-user who turns the machine on and off on a daily basis wouldn't need to use a monitor and mouse.
    So what I'm googling for at the moment is a way to modify the action called when pressing the physical power button. Windows allows you to choose between some different actions like Sleep, Hibernate, Restart etc, but could you change that into 'Run this .bat'? Or maybe change the behaviour of the shutdown command altogether?

  3. Programmatically intercept the shutdown message, abort shutdown, run batch file, re-initiate shutdown. There has been some discussion on intercepting shutdown e.g. here, here and here, but I'm still too much of a n00b in all languages except maybe Ruby or Java to really understand if and how it could be done in this case. If someone can clarify how to actually make this work (without getting stuck on the 'Force close' screen) then I'm eager to try out any language you offer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

最佳男配角 2024-10-21 03:43:25

好的,所以我找到了一个适合我的解决方案;一个名为 AutoHotkey_L 的工具和一个根据这些 主题

这是我正在使用的代码,我建议阅读文档。当我了解代码的实际用途时,我正在调整代码,但目前这是可行的。 :)

#NoEnv
#Persistent
SendMode Input
SetWorkingDir %A_ScriptDir%
SetTimer, RunBeforeShutdown, Off

Gui,+LastFound
hwnd:=WinExist()
DllCall("ShutdownBlockReasonCreate","Uint",hwnd,"Str","")
DllCall("kernel32.dll\SetProcessShutdownParameters", UInt, 0x4FF, UInt, 0)
;puts us first in line for getting the shutdown call, i guess?
OnMessage(0x11, "WM_QUERYENDSESSION")
Return

WM_QUERYENDSESSION(wParam, lParam)
{
    ENDSESSION_Logoff = 2147483648
    If (lParam == ENDSESSION_Logoff) {
        global EventType = "Logoff"
    } Else {
        global EventType = "Shutdown"
        ;no way to distinguish between shutdown and restart
    }

    SetTimer, RunBeforeShutdown, On
    Return false
}

runBeforeShutdown:
    SetTimer, RunBeforeShutdown, Off
    Sleep, 1000
    SendInput, {ENTER}  ; gets us past the 'Force shudown' screen
    Sleep, 1000
    #SingleInstance, Force
    DllCall("ShutdownBlockReasonDestroy","Uint",hwnd)
    ; **** Your commands go here ****
    RunWait shutdown.bat
    ; ********

    If (EventType == "Logoff") {
        Shutdown, 0
    } Else {
        Shutdown, 1
    }
    Reload
Return

所以现在它只区分注销和关闭,但是这篇文章 有一个简单的 HTML GUI,让用户选择是否要重新启动、休眠等。

在我的情况下,无论 VMware 是否正在运行,都可以中断关闭并运行批处理文件,但您可以设置一个条件例如,像这样:

IfWinExist, ahk_class VMPlayerFrame {
    SetTimer, RunBeforeShutdown, On
    Return false
} Else { 
    Return true
}

我已经遇到了这个脚本的问题,比如当主机速度如此缓慢(内存泄漏)时,“强制关闭”屏幕不会及时出现以便脚本关闭它。它可能会受益于跟踪尝试次数,以便在第一次尝试失败时可以强制关闭。

至少现在足够好了。毕竟我的项目甚至可能不需要虚拟化,但希望它可以帮助其他人。替代解决方案仍然很受欢迎。

Okay, so i found a solution that worked for me; a tool called AutoHotkey_L and a script made according to these threads on the AutoHotkey forums.

This is the code I'm using, and I suggest reading up on AutoHotkey commands in the documentation. I'm tweaking the code as I learn what it's actually doing, but for now this works. :)

#NoEnv
#Persistent
SendMode Input
SetWorkingDir %A_ScriptDir%
SetTimer, RunBeforeShutdown, Off

Gui,+LastFound
hwnd:=WinExist()
DllCall("ShutdownBlockReasonCreate","Uint",hwnd,"Str","")
DllCall("kernel32.dll\SetProcessShutdownParameters", UInt, 0x4FF, UInt, 0)
;puts us first in line for getting the shutdown call, i guess?
OnMessage(0x11, "WM_QUERYENDSESSION")
Return

WM_QUERYENDSESSION(wParam, lParam)
{
    ENDSESSION_Logoff = 2147483648
    If (lParam == ENDSESSION_Logoff) {
        global EventType = "Logoff"
    } Else {
        global EventType = "Shutdown"
        ;no way to distinguish between shutdown and restart
    }

    SetTimer, RunBeforeShutdown, On
    Return false
}

runBeforeShutdown:
    SetTimer, RunBeforeShutdown, Off
    Sleep, 1000
    SendInput, {ENTER}  ; gets us past the 'Force shudown' screen
    Sleep, 1000
    #SingleInstance, Force
    DllCall("ShutdownBlockReasonDestroy","Uint",hwnd)
    ; **** Your commands go here ****
    RunWait shutdown.bat
    ; ********

    If (EventType == "Logoff") {
        Shutdown, 0
    } Else {
        Shutdown, 1
    }
    Reload
Return

So right now it only distinguishes between logoff and shutdown, but this post has a simple GUI in HTML that lets the user choose if they want to restart, hibernate etc.

In my case it's okay to interrupt shutdown and run the batch file regardless of whether VMware is running or not, but you can set a condition for it for example like so:

IfWinExist, ahk_class VMPlayerFrame {
    SetTimer, RunBeforeShutdown, On
    Return false
} Else { 
    Return true
}

I have already run into problems with this script, like when the host is so slowed down (memory leakage) that the "Force shudown" screen won't appear in time for the script to close it. And it would probably benefit from keeping track of the number of tries, so that it could shutdown forcibly if the first try fails.

Good enough for now at least. And I may not even need virtualization for my project after all, but hopefully it can help someone else. Alternative solutions are still very welcome.

爱人如己 2024-10-21 03:43:25

我针对同样的问题提出了这个解决方案:
http://communities.vmware.com/thread/334740

克服“强制”的技巧close”是首先挂起/停止所有虚拟机,然后在同一脚本中重新发出关闭命令。这似乎对我有用。

I have come up with this solution to the same problem:
http://communities.vmware.com/thread/334740

The trick to get past the "force close" is to first suspend/stop all VMs then re-issue the shutdown in the same script. It seems to work for me.

猫九 2024-10-21 03:43:25

Workstation 优先选择“在 Workstation 关闭后保持虚拟机运行”。 VMware播放器有同样的选项吗?

我认为其工作方式:启用上述首选项。窗口关闭,虚拟机继续运行。然后,关闭过程可以继续执行#1 中的脚本,该脚本应在终止之前关闭/挂起虚拟机。

我自己没有任何播放器虚拟机,所以我无法对此进行测试,但我希望它有所帮助。

Workstation has a preference to 'Keep VMs running after Workstation closes'. Does VMware player have the same option?

The way I see this working: Enable the above preference. The window closes, leaving the VMs running. The shutdown process can then continue to your script from #1, which should shutdown/suspend the VMs before terminating.

I don't have any Player VMs myself, so I can't test this out, but I hope it helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文