I have a proprietary software that I use to download some confidential data from the internet, this software is the only way to access that data.
The software opens up with a screen and then I have to click on "download" and the download commences. I would like to download this data late-night (say 0200 Hrs) every night. The downside was that I had to sit in front of the laptop to "click" on the download button.
So, I wrote an AutoIt script to open the software, wait for 30 seconds so that the software finishes the initialisation routine and then "go to" a certain location (co-ordinates) on the screen and execute a "mouseclick()". I then created a "scheduled task" using windows task scheduler to run this autoit executable at 0200 Hrs. Every thing works fine, as expected.
Autoit executable runs well when the user is "active". But if the user is "locked" (i.e. lock screen) then it is stuck in "WinActivate()" waiting for the user to become "Active" and resumes from there on after the user becomes "active". This means the laptop has to be in unlocked mode overnight which is not advisable for security reasons. I then found out that I could use "ControlClick()" to do the same when the screen is locked.
My problem now is that when I use AutoIt Window Info tool, it does not show the CLASS or any info related to download button when I hover over the download button. So, may be the screen is a flash screen or something else that was intentionally made to make sure that button CLASS was not seen!
An option would be to take a screenshot, find the location and then send the coords to Mouseclick() but that could easily get way more complicated considering different screen resolution on different machines (in case this gets ported to another machine etc etc)
Any suggestions and solutions?
WinActivate() will wait until the user is activated to activate the window and then return and it is a blocking function in this case so avoid it. Keep your VB application in the background, not minimized and remove WinActivate() function. ControlClick doesn't need the window to be active.
This should work with the right handle name and class name:
HotKeySet("!{s}", "_exit")
Local $count = 0
Local $handle
While $count < 3
Sleep(5000)
$handle = ControlGetHandle("name", "", "[CLASS:ThunderRT6FormDC]") ;add name as well if there is one
If $handle Then ;check if handle exists
ConsoleWrite("Handle exists" & #LF)
ControlClick($handle, "", "[CLASS:Classhere]", "left", 1, 191, 115) ;add a class if exists
EndIf
ConsoleWrite("Try: " & $count & " times" & #LF)
$count += 1
WEnd
Func _exit()
ConsoleWrite("Exiting!" & #LF & "Tried: " & $count & #LF)
Exit
EndFunc
The informations you gave me from the autoit info tool arent enough. Use some other tool to get more information.
Spy++ is a great tool. Try it out and come back with more information about the windows handle name and classes.
And again you are giving a few informations about your code. This example should performe a control click but you may have other function besides winactivate that will block your script again
Edit: Added Tesseract OCR UDF: http://www.autoitscript.com/forum/topic/89542-tesseract-screen-ocr-udf/
Related
I'm trying to switch between virtual desktops on win10 using the XButton1 and XButton2 of my mouse.
So far this is working quite alright, except the fact that when I have for example Firefox as my active scope, obviously those buttons are used to go forward/backward (problem appears in every window using these buttons for something).
This seems to prevent AHK from either noticing that I used the configured trigger or not executing the script (which I believe is less likely).
For Firefox I found a workaround by disabling the use of these buttons in the [about: config](about config) page by setting mousbutton.4th.enable and mouse button.5th.enable to false but this won't work for everything since there isn't always a way to disable these buttons.
I have tried to use the mouse-wheel tilting buttons as well but the default usage oh them is even more common in the programs I'm working with.
Here is the script I am using.
# NoEnv; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
XButton1::Send ^#{Left}
XButton2::Send ^#{Right}
return
If someone has a workaround or a completely different idea (for example a totally obvious Win10 feature/setting I'm missing) I would be absolutely happy.
You can define custom combinations for those two keys in your script
e.g.
XButton1 & LButton::return ; do nothing
; or another action:
; XButton1 & LButton:: Run notepad
XButton1::Send ^#{Left}
XButton2 & a::return
XButton2::Send ^#{Right}
This way the keys lose their native function in the programs.
For details, see Custom Combinations.
EDIT:
If a program is running with admin privileges, then AHK won't intercept the key presses, and that could very well be the reason behind this problem.
If that is the case, try to run the AHK script as administrator by adding this to the auto-execute section (top of the script):
; If the script is not elevated, relaunch as administrator and kill current instance:
full_command_line := DllCall("GetCommandLine", "str")
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
try ; leads to having the script re-launching itself as administrator
{
if A_IsCompiled
Run *RunAs "%A_ScriptFullPath%" /restart
else
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
}
ExitApp
}
https://autohotkey.com/docs/commands/Run.htm#RunAs.
When in need to use AHK the solution from user3419297 works perfekt.
Another way to accomplish the same result is to use X-Mouse Button Control.
Simply set Mouse Button 4/5 to Simulated Keys: with {CTRL}{LWIN}{RIGHT} and {CTRL}{LWIN}{LEFT}.
I'm automating some reports using visual basic. I've recorded some scripts that worked fine by seem to have stopped working for reasons unknown. I record the following (comments added) and the script fails at a file dialog box.
session.findById("wnd[0]").resizeWorkingPane 95,22,false
session.findById("wnd[0]/tbar[0]/okcd").text = "se16"
session.findById("wnd[0]").sendVKey 0
' Run AGR_TCODES
session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").caretPosition = 10
session.findById("wnd[0]").sendVKey 0
'Select Extended Name, Multiple selection
session.findById("wnd[0]/usr/btn%_I3_%_APP_%-VALU_PUSH").press
session.findById("wnd[1]").sendVKey 23
' select file
session.findById("wnd[2]/usr/ctxtDY_PATH").text = "c:\my_directory\"
session.findById("wnd[2]/usr/ctxtDY_FILENAME").text = "myfile"
session.findById("wnd[2]").sendVKey 0
Its at this point in script playback that the script just stops with the file select text inputs blank. I can type the information in, but that kinda defeats the purpose. I can't find the reasons or a cause, but lots of various upgrades have occurred, including my laptop and a reinstall of the os to WIN10. I don't really care why - but I do need to find a way around it.
There are 2 scenarios I've identified:
It appears that SAP occasionally loses the focus of dialog boxed. Use gratuitous .setfocus commands on the window to compensate
It appears that uploads via scripts may be blocked by security settings. You can do it manually, but not via script. A telltale sign is that when you record the script, your inputs are not recorded. So the DY_FILENAME.text line will be completely missing from the recording. I'm not sure how to fix this, but at least you know where to look!
Good luck with your scripts.
I have an issue with an auto start of Outlook 2016 at boot/log on which is intended to start Outlook minimised to the Windows system tray, such that once invoked at Windows 10 launch mail will be collected by the mail account(s) (NB. All POP in this case.) whilst the program resides in the system tray remaining invisible until required by the user.
The .vbs script below does function as required but much of the time it introduces two unwelcome issues.
The Outlook icon in the System Tray displays a 'cog' overlay with the message "Another program is using Outlook. To disconnect programs and exit Outlook, click the Outlook icon and then click Exit Now".
Attempts to open Outlook from the 'Open Outlook' context menu (right click Outlook icon in the tray) item causes a dialogue box to appear reporting "No active explorer object found". Clicking the "OK" option in response launches Outlook (though issue 1 - cog overlay) remains.
Neither issue is present when Outlook is started normally from the desktop so it would appear that the .vbs script is in someway responsible. I have used this script successfully (see also below: https://superuser.com/questions/467809/start-outlook-automatically-in-tray) in the past both as a startup menu shortcut and a hkcu 'run' registry entry.
Can anyone suggest the cause or alternately a suitable code revision to achieve correct function? In case it is significant, Windows 10 is 64 bit Pro and the version of Office (including Outlook) installed is also 64 bit.
This is the code invoked by the .vbs script:
OPTION EXPLICIT
OPTION EXPLICIT
CONST PATH_TO_OUTLOOK = """C:\Program Files\Microsoft Office\Office16\OUTLOOK.EXE"""
CONST SHOW_MAXIMIZED = 3
CONST MINIMIZE = 1
DIM shell, outlook
SET shell = WScript.CreateObject("WScript.Shell")
' Open Outlook
shell.Run PATH_TO_OUTLOOK, SHOW_MAXIMIZED, FALSE
ON ERROR RESUME NEXT
' Grab a handle to the Outlook Application and minimize
SET outlook = WScript.CreateObject("Outlook.Application")
WScript.Sleep(100)
outlook.ActiveExplorer.WindowState = SHOW_MAXIMIZED
' Loop on error to account for slow startup in which case the
' process and/or the main Outlook window is not available
WHILE Err.Number <> 0
Err.Clear
WScript.Sleep(100)
SET outlook = NOTHING
SET outlook = WScript.CreateObject("Outlook.Application")
outlook.ActiveExplorer.WindowState = MINIMIZE
WEND
ON ERROR GOTO 0
SET outlook = NOTHING
SET shell = NOTHING
Having spent a number of hours on this issue over the weekend I thought that I had resolved the issues and got everything functioning as intended.
Working from similar samples of code I compiled a new script (see below) which I applied both as a shortcut in the Startup folder and also as an entry into the 'run' branch of the HKCU registry.
Now for the issue! Testing the script on two separate Windows 10 Pro (both 64 Bit architecture) systems both with Outlook 2016 64 Bit installed as part of a 64 Bit Office suite I found that whereas on one system the script runs flawlessly on the other I receive the following runtime error:
Script: D:\Neil's Files\Neil's Filing Cabinet\Neil's Emails\Start Outlook Minimised to Tray\Start Outlook 2016 Minimised To Tray.vbs
Line: 11
Char: 5
Error: ActiveX component can't create object: 'GetObject'
Code: 800A01AD
Source: Microsoft VBScript runtime error
This has me perplexed as the script file and it's related shortcut are both physical copies of each other given that the revised script below contains no path references (as these are handled directly by the code in respect of Outlook.exe) which are identified by the placement of either the shortcut or as the data element of the registry string whichever format is used.
The Systems do have some differences however and for comparative purposes I will summarise those I feel to be relevant here:
System 1: (The problem system) is an X58 Asus P6T7, Intel i720 mature PC with many programs installed and specifically the Outlook 2016 has the same 12 addins installed but in addition has two related programs which launch at boot, the enterprise editions of 4team's Sync2 for Microsoft Outlook and Safe PST Backup. The boot times are quite lengthy (but acceptable) as is the Outlook Startup with it's various addins.
System 2: Is a current generation Asus X99-Deluxe, i7 5930 new build pc with little installed as yet save MS Office, Adobe CC and some utilities.
In the case of System 1, Outlook auto-starts as intended however during it's loading splash screen (whilst it is loading up the addins) the runtime error is displayed although Outlook continues to open fully but fails to minimise.....
This suggests to me that the faulting code is the section which activates the window however the above error message refers to "ActiveX component can't create object: 'GetObject'" which suggests instead an issue with the code line "Set OLObj = GetObject("","Outlook.Application")"??
Hopefully somebody can test the code on a similar setup and report back? Or alternately, give me a pointer as to what is going on and how I might resolve it. I would of course also welcome any suggested improvements to the code!
** Quick Update ** Now tested on HP Elitebook 8440P Laptop - Windows 10 Pro 64 Bit with Office 64 Bit + same 12 Outlook Addons - Functions as intended.....
** Further Update ** Tested on a second HP Elitebook 8440P Laptop - Windows 10 Pro 64 Bit with Office 64 Bit + same 12 Outlook Addons - Above RunTime error experienced once again.......struggling to comprehend why these results are occurring?? Any thoughts anybody???
The code below is offered "as is" for the benefit of anyone else seeking the same Outlook auto start criteria. The testing with System 2 indicates that it works so I hope others enjoy similar success until the outstanding issues are sorted.
NB: To adjust the Outlook Launch Window Size (during its 10 second pause prior to automated minimising) to reflect personal preferences change the numeric value in the following line of code:
WshShell.Run "OUTLOOK.EXE" , 3, false
For a maximised window size change the value to 3 For a restored window size change the value to 2
OPTION EXPLICIT
Dim WshShell
Dim OLObj
Set WshShell = WScript. CreateObject ( "Wscript.Shell" )
'Open Outlook: Note that inspite of the launch options, it will open the program in a normal window.
'The file location path is not necessary as Windows 10 correctly identifies Outlook's location.
WshShell.Run "OUTLOOK.EXE" , 3, false
'This will mimimise it to the system tray after a 10 second pause to allow for mail collection on Outlook launch.
WScript.Sleep (10000)
Set OLObj = GetObject("","Outlook.Application")
'Activates the window
OLObj.ActiveExplorer.Activate
'Sends the command to minimise
OLObj.ActiveExplorer.WindowState = 1
'Outlook does not immediately minimise to the system tray so that 'Send/Receive' can initiate mail collection.
Thanks to jrv from Microsoft's "The Scripting Guys" forum who kindly offered a revised (simplified) code which is below. I can report that as with the original code it works flawlessly on the same 2 systems as before, whilst faulting once more on the other two......very much perplexed!!
The Runtime Error:
Script: D:\Neil's Files\Neil's Filing Cabinet\Neil's Emails\Start Outlook Minimised to Tray\Start Outlook 2016 Minimised To Tray.vbs
Line: 3
Char: 5
Error: ActiveX component can't create object: 'Outlook.Application'
Code: 800A01AD
Source: Microsoft VBScript runtime error
The revised code:
Set WshShell = CreateObject ( "Wscript.Shell" )
WshShell.Run "OUTLOOK.EXE" , 3, False
Set ol = CreateObject("Outlook.Application")
ol.ActiveExplorer.Activate
ol.ActiveExplorer.WindowState = 1
You can use like file *.reg:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"Outlook"="C:\\Windows\\system32\\cmd.exe /c \"start \"\" /min \"C:\\Program Files\\Microsoft Office\\Office16\\OUTLOOK.EXE\"\""
[HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Preferences]
"MinToTray"=dword:00000001
I have an answer that works well with Office 2013 on Windows 7, and I hope it works for you too.
Essentially, this solution bypasses the issue with trying to force Outlook to minimize after loading. Instead, it relies on using a shortcut that's already configured to load the program in a minimized state.
Copy a shortcut to Outlook into the directory containing your script.
Right click the shortcut and open Properties.
In the Shortcut tab, change the Run mode to Minimized. Press OK.
Then, all you need to do in your VBScript file is to execute the shortcut like so:
Dim sh : Set sh = CreateObject("WScript.Shell")
sh.run "Outlook.lnk"
Note that because this solution uses a shortcut, you could potentially remove the VBScript part entirely by putting the shortcut into the All Users Startup folder.
It's me again! I have an answer that should bypass any issues with VBScript by using third-party software, DisplayFusion. I don't know how you'll feel about that, but I tested it and it works over here. I use this at home and at work to manage multiple monitors and various other things. It may even help solve problems with other programs you use and render various VBS hacks redundant.
In your case, there is a feature called 'Triggers'. Note that while there is a free version of DF, you'll have to activate a 30 day trial for the Pro version to use Triggers, and after that, it's up to you to decide if it's worth your while.
Firstly, after installing DF, you'll want to open up its settings window (right-click desktop and go to DisplayFusion > Settings).
Go to the Triggers tab and click Add.
Set up the trigger for when a window is created. Tell the trigger to activate only once per process ID so it won't also try to minimize subsequent windows, such as when composing a new email. Find the path to your outlook.exe. Then, add an action on the right-hand side to minimize the window.
Click OK twice and then see if it works by loading Outlook. For me, the splash screen appears as normal, then the main window is minimized as soon as it appears.
DF runs as a system service with admin privileges and has been tested with tonnes of software packages, so if this method also fails for you, it could indicate bigger issues with your system/Office configuration.
I'm trying to run some automation tests in my application but the UFT Hidden-mode notification tooltip is coming in front of the objects in the screen, preventing my tests to run.
I know I can un-check the option "Display hidden-mode notification tooltip" in Remote Agent Settings to fix this issue and it works fine on my machine after I do this, but these tests are executed in other machines, by other users in my company, and it would be a real effort to tell each and everyone of them to change this setting on their machine.
Is it a way to disable this checkbox programmaticaly instead?
EDIT:
Here is a little more detail on where this is affecting me:
I'm testing a Web application and in some of my test cases I need to download a file from this application. I do that by clicking on "Save As" in the context menu which is displayed on a notification bar at the bottom of the browser.
Following is the portion of code to perform such operation:
Dim brwBottom
Set brwBottom = Browser("brw_Bottom_Save_As")
If brwBottom.WinObject("wo_Notification").WinButton("wb_Selector").Exist Then
brwBottom.WinObject("wo_Notification").WinButton("wb_Selector").Click
brwBottom.WinMenu("wm_Selector").Select "Save As"
End If
This works fine on my machine because UFT notification is not being displayed, but in other machines where the UFT Notification is displayed, it overlaps the menu and my script is unable to select the "Save As" option. So, in case it is not possible to programmatically close this notification at runtime, is there any alternative solution to click on the "Save As" button, even with this notification overlapping it?
I managed to identify the UFT Notification tooltip and close it. With this, there is no more objects in front of the button I need to click and my script can be executed successfully.
Following is the code used. I'm not marking this as the acceptable answer yet because I am still waiting for my team to accept the solution, but this works.
Dim brwBottom
Set brwBottom = Browser("brw_Bottom_Save_As")
' To close UFT Notification Tooltip, if exists
If Window("regexpwndtitle:=NotificationWindow").Exist(2) Then
If InStr(Window("regexpwndtitle:=NotificationWindow").GetROProperty("nativeclass"),"UFTRemoteAgent") > 0 Then
Window("regexpwndtitle:=NotificationWindow").Close
End If
End If
If brwBottom.WinObject("wo_Notification").WinButton("wb_Selector").Exist Then
brwBottom.WinObject("wo_Notification").WinButton("wb_Selector").Click
brwBottom.WinMenu("wm_Selector").Select "Save As"
End If
Create UFT GUI test and include these three lines:
extern.Declare micLong, "WritePrivateProfileString", "kernel32.dll", "WritePrivateProfileString", micString, micString, micString, micString
extern.WritePrivateProfileString "RemoteAgent", "ShowBallon", "0", Environment("ProductDir") + "\bin\mic.ini"
systemutil.CloseProcessByName "UFTRemoteAgent.exe"
From ALM, run it on all your UFT machines.
Notes:
This will switch the flag that controls such tooltip to be off, so next time Remote Agent launches will read it and won't display the tooltip anymore.
The third line will kill UFT's remote agent for GUI testing which is in charge of the communication between UFT and ALM Client and this will cause an error in ALM's Automatic Runner (The RPC server is unavailable)... just ignore it. We need to kill it so it is re-launched next time we try to run a test from ALM (as mentioned above, new value for tooltip will be read)
EDIT:
I just found something interesting: this flag is actually saved in two locations:
mic.ini
RemoteAgentGUISettings.xml
but the one that actually makes the change effective is RemoteAgentGUISettings.xml (it seems they're switching from .ini files to .xml... which makes sense). In this case, the code will change a little, but the idea is the same:
filePath = CreateObject("WScript.Shell").ExpandEnvironmentStrings("%appdata%") + "\Hewlett-Packard\UFT\Persistence\Dialogs\RemoteAgentGUISettings.xml"
Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.load filePath
Set nNode = xmlDoc.selectsinglenode ("//SettingsViewModel/IsShowBalloon")
nNode.text = "false"
strResult = xmldoc.save(filePath)
systemutil.CloseProcessByName "UFTRemoteAgent.exe"
This time I made sure it works ;)
I totally understand your pain because my projects also need to interact with IE download bar. Usually, I use SendKeys to handle download activity in different projects.
When download bar comes out, you can send ALT+N first to set focus on download bar, then send some tab keys to select on Save, and some Down Arrow key to select SaveAs.
In this way, you don't need to bother handle UFT notifications...
Sample SendKeys codes can be easily Googled.
Can you activate the desired browser with the following, and then try to do Save as
hwnd = Browser("title:=.*").GetROProperty("hwnd")
Window("hwnd:=" & hwnd).Activate
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):
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.
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?
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.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.
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.