English 中文(简体)
Run a batch file on Windows 7 shutdown before closing programs (preferably on power button press)
原标题:

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	oVMWare VIXvmrun.exe" -T player stop "C:path	omachine.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.

最佳回答

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.dllSetProcessShutdownParameters", 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.

问题回答

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.

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.





相关问题
Chrome OS Development on a Mac

Google just announced the open source release of their Chromium/Chrome OS product: Hello, open source developers. Would you like to help build an operating system for web users? I m working on a ...

VMware Fusion and MacbookPro keyboard

I m running Windows 7 Ultimate (retail) under VMware Fusion on a Macbook Pro. I ve created a keyboard layout for the mac using Microsoft keyboard Layout Creator MSKLC. My problem is that when I type ...

热门标签