Powershell: Uninstall Software that has prompts for user input - powershell

Does anybody know if it is possible to uninstall software through PowerShell if it prompts for user input? I have multiple scripts that can uninstall just about anything, except for the one software that I need it to uninstall. I'm specifically trying to uninstall PDFForge toolbar which is installed when downloading PDFCreator.
None of the scripts that I've written fail, they just hang when run, I believe because the uninstall process is asking for user input to proceed.

PowerShell isn't going to interact with the prompts... you can't just tell it to click "Next" in an executable because it can't see it.
You can send keys to it though. You're really just using COM objects.
So, first, get your process ID by setting a variable that contains an array, the data for which is defined by the name of your process. Let's say your process is called, "Uninstall" and the process is ALREADY RUNNING:
$a = Get-Process | ?{$_.Name -eq "Uninstall"}
Start the COM:
$wshell = New-Object -ComObject wscript.shell;
Bring the uninstallation program with this process ID to the front so we can send it keystrokes:
$wshell.AppActivate($a.id)
Give it a few seconds to bring that window forward. I chose 5, but if your machine isn't stressed, 2 is probably enough:
Start-Sleep 5
Now start telling it what keys you want to send. The syntax here is this: whatever is in the () is what will be sent. The position in the single-quote is the keystroke to send, after the comma is how long you want it to wait before proceeding. Assuming the first screen is "Next" you can send your first command by telling PowerShell to send the ENTER key and wait 5 seconds:
$wshell.SendKeys('~',5)
The wait function is optional, but for your purposes, you're definitely going to want it. (If you don't want it $wshell.SendKeys('~') would send the ENTER key and immediately move to the next command.)
Walk through the uninstallation yourself manually, using all keystrokes, and for any keystroke you send, pay attention to how long it takes before the next part of uninstallation is loaded, and wait longer than that with your script (e.g. if it processes your ENTER key instantaneously, I'd have it wait 3 or 5 seconds before it sends the next command. If it takes 5 seconds to load, I'd tell it to wait 10 seconds before sending the next command).
Letters are letters, and numbers are numbers. Most non-commands are just assigned to their keys (meaning if you want to type "K" your command would just be $wshell.SendKeys('K')) You can get the rundown for the specific keys here: https://msdn.microsoft.com/en-us/library/office/aa202943(v=office.10).aspx.

Related

ReadKey() doesn't track keystrokes in other windows or instances

I wrote a simple script to track keys being pressed and released as shown below:
$j = 0
while($j -lt 10000){
$PressedKey = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,IncludeKeyUp")
$PressedKey
continue
}
When I run it and start pressing keys, it works. However when I switch to a different Instance or Window and start pressing keys, it stops giving an output. I assume this is because it stops tracking the keystrokes, can't produce an output, or both. Does anyone know any good alternatives to ReadKey() to how to make it track keystrokes on other Windows and/or Instances
I believe this is PowerShell 7
thx.
The object $Host refers to the current PowerShell console host. Therefore, connecting to the ReadKey() method will only return the current PowerShell host keystrokes, and that is the point of the ReadKey() method, return the current host's keystrokes so that other functions (e.g. PSReadline) can act on them.
If you want to globally respond to keystrokes across applications, I personally recommend AutoHotKey. It is fairly easy to create a script that will detect a key combination and perform an action. It is fast and easy to use and I have dozens of key combinations that I have scripted and use every day.
It is possible to create PowerShell scripts that globally hook into keyboard keystrokes and respond to events, but this is beyond the scope of a SO post.

How do I wait for a process OR if a certain window becomes the active one in AutoHotKey?

I have a loop that waits for a process to exist before continuing. However, I want to make it so that the loop will proceed if EITHER the process exists or a window with some certain class is present. Right now I have the following:
Loop {
Process, Wait, ProcessName.exe
; Do stuff
Sleep, 50
}
I want to be clear that I specifically used Process, Wait because I didn't want the loop to constantly running.
Instead of "ProcessName.exe" you can use "ahk_exe Process Name/Path" to identify the process.
Use "DetectHiddenWindows, On" if there's no visible window of this process.
This way you can create a window group with GroupAdd that contains both the process and the window.
Replace "Process, Wait, ProcessName.exe" with "WinWait, ahk_group GroupName" in the loop.

Cannot press any key to continue with command pause

I wrote a script to remote execute test.cmd file by PsExec.exe.
PsExec.exe \\IP -u administrator -p password "C:\\Users\Administrator\Desktop\test.cmd"
Although I can run the script successfully, I cannot press any key to continue the process when it runs into command pause.
Press any key to continue . . . aaaaaa
The only way to keep going is press Enter.
Besides, if there are many lines of Pause or set /p which waits users to input, once user press Enter, it will affect couple lines of Pause or set /p. It really confuses me.
Best is that you use different logic in accordance with your limitations.
Try exchanging the Pause with a different suitable solution.
Other suggestion would be that you share your code, inputs and expectations (output is already given - the script doesn’t continue). Then someone can review the code and suggest for further steps.
Alternatively, it is also possible that you can fix it by using Console.ReadKey()

AutoHotkey to use clipboard info to open files in Word works in Win8 but not in Win7

I created an AHK macro for a colleague. I have Windows 8; she has Windows 7. She has two "pending work" folders, one for documents and the other for audio files. The (text) file names in the documents folder correspond to the file names in the audio folder. So, for example, if there is an audio file called abc123.mp3 in the audio folder, there will be a file named abc123.txt in the documents folder.
As she opens the audio file in her transcription (media player) app, as part of that process, I want to have an AHK macro automatically open the matching text file (in Word).
I created an AHK macro that picks up from the point of her selecting the file to open from her transcription app. At the point where she selects the file, she invokes the AHK shortcut, which then toggles the rename feature (F2), copies the text to the clipboard (Ctrl+C), opens the file (Alt+O), and then uses the clipboard info (along with path info) to open the appropriate text file in Word.
It's working PERFECTLY on my system. However, when I logged into her system earlier today to demo the macros, the macro would not work. It works to a point - it will rename the file, copy the name of the file, and open the audio file, and file name is in the clipboard. But that's where it dies, with no error message. During troubleshooting, I tried isolating the macro down to one command - to simply open (fixed name) file in WinWord.exe, but that doesn't work, either.
I have been unable to find any research related to this issue. I know there are numerous ways to accomplish this task, but my AHK scripting skills and my free time are limited, so I went with what I knew I could accomplish quickly. I am open to suggestions for how to troubleshoot or tweak this macro to get it working on her system. It's hard to troubleshoot when it works on mine!
NumpadEnter::
Send {F2}{Sleep 100}
Clipboard=
Send ^c
Send {Sleep 100}!o{Sleep 100}
Run, WinWord.exe "C:\DocFiles\"%Clipboard%.txt
Return
Just a guess, but I believe you wanted Sleep command and not a Sleep Key? Be sure that you are using the Latest Version of AutoHotkey you can download it from www.ahkscript.org
NumpadEnter::
Send {F2}
Sleep, 100
Clipboard=
Send, ^c
Run, WinWord.exe "C:\DocFiles\"%Clipboard%.txt
Sleep 100
Send, ^o
Sleep 100
Send, ^v
Sleep 100
Send, !o
Return
Edit:
In the script you posted, you are telling the computer to Send a Sleep Key by placing brackets around the word Sleep. Like so {Sleep}
Furthermore, you are also telling your script to not just Send one key... you are telling it to Send the Sleep Key 100 times by placing the number 100 in the brackets, separated by a space, with the named key. Like so: {Sleep 100}
I fail to see how you would want to have your script simulate 100 Sleep key presses?
What I posted above uses the Sleep Command which delays the script in milliseconds. I believe this is truly what you want.

programmatically press an enter key after starting .exe file in Matlab

In Matlab I can start external .exe files that sometime have a pop up that requires an enter key pressed. For example:
system('C:\Program Files (x86)\WinZip\WINZIP32.EXE')
will start Winzip, and then in order to use it you need to pass the "buy now" pop up window by pressing enter.
Now my problem is not with winzip, I only gave it as an example (i use winrar anyway :).
How can I programmatically press an enter key in Matlab in such cases ? (I use win 7)
Can an event listener be used to solve that?
EDIT: The java.awt.Robot class indeed works on explorer, but not on any software that has a pop up window with an OK button that needs to be pressed. I don't know why it doesn't work for that. I gave the winzip example because I assume everybody has winzip/winrar installed in their machine. The actual software I have is different and irrelevant for the question.
There is a way using Java from Matlab, specifically the java.awt.Robot class. See here.
Apparently there are two types of programs, regarding the way they work when called from Matlab with system('...'):
For some programs, Matlab waits until the program has finished before running the next statement. This happens for example with WinRAR (at least in my Windows 7 machine).
For other programs this doesn't happen, and Matlab proceeds with the next statement right after the external program has been started. An example of this type is explorer (the standard Windows file explorer).
Now, it is possible to return execution to Matlab immediately even for type 1 programs: just add & at the end of the string passed to system. This is standard in Linux Bash shell, and it also works in Windows, as discussed here.
So, you would proceed as follows:
robot = java.awt.Robot;
command = '"C:\Program Files (x86)\WinRAR\WinRAR"'; %// external program; full path
system([command ' &']); %// note: ' &' at the end
pause(5) %// allow some time for the external program to start
robot.keyPress (java.awt.event.KeyEvent.VK_ENTER); %// press "enter" key
robot.keyRelease (java.awt.event.KeyEvent.VK_ENTER); %// release "enter" key
If your applications are only on Windows platform, you can try using .net objects.
The SendWait method of the SendKeys objects allows to send virtually any key, or key combination, to the application which has the focus, including the "modifier" keys like Alt, Shift, Ctrl etc ...
The first thing to do is to import the .net library, then the full syntax to send the ENTER key would be:
NET.addAssembly('System.Windows.Forms');
System.Windows.Forms.SendKeys.SendWait('{ENTER}'); %// send the key "ENTER"
If you only do it once the full syntax is OK. If you plan to make extensive use of the command, you can help yourself with an anonymous helper function.
A little example with notepad
%% // import the .NET assembly and define helper function
NET.addAssembly('System.Windows.Forms');
sendkey = #(strkey) System.Windows.Forms.SendKeys.SendWait(strkey) ;
%% // prepare a few things to send to the notepad
str1 = 'Hello World' ;
str2 = 'OMG ... my notepad is alive' ;
file2save = [pwd '\SelfSaveTest.txt'] ;
if exist(file2save,'file')==2 ; delete(file2save) ; end %// this is just in case you run the test multiple times.
%% // go for it
%// write a few things, save the file then close it.
system('notepad &') ; %// Start notepad, without matlab waiting for the return value
sendkey(str1) %// send a full string to the notepad
sendkey('{ENTER}'); %// send the {ENTER} key
sendkey(str2) %// send another full string to the notepad
sendkey('{! 3}'); %// note how you can REPEAT a key send instruction
sendkey('%(FA)'); %// Send key combination to open the "save as..." dialog
pause(1) %// little pause to make sure your hard drive is ready before continuing
sendkey(file2save); %// Send the name (full path) of the file to save to the dialog
sendkey('{ENTER}'); %// validate
pause(3) %// just wait a bit so you can see you file is now saved (check the titlebar of the notepad)
sendkey('%(FX)'); %// Bye bye ... close the Notepad
As explained in the Microsoft documentation the SendKeys class may have some timing issues sometimes so if you want to do complex manipulations (like Tab multiple times to change the button you actually want to press), you may have to introduce a pause in your Matlab calls to SendKeys.
Try without first, but don't forget you are managing a process from another without any synchronization between them, so timing all that can require a bit of trial and error before you get it right, at least for complex sequences (simple one should be straightforward).
In my case above for example I am running all my data from an external hard drive with an ECO function which puts it into standby, so when I called the "save as..." dialog, it takes time for it to display because the HDD has to wake up. If I didn't introduce the pause(1), sometimes the file path would be imcomplete (the first part of the path was send before the dialog had the focus).
Also, do not forget the & character when you execute the external program. All credit to Luis Mendo for highlighting it. (I tend to forget how important it is because I use it by default. I only omit it if I have to specifically wait for a return value from the program, otherwise I let it run on its own)
The special characters have a special code. Here are a few:
Shift +
Control (Ctrl) ^
Alt %
Tab {TAB}
Backspace {BACKSPACE}, {BS}, or {BKSP}
Validation {ENTER} or ~ (a tilde)
Ins Or Insert {INSERT} or {INS}
Delete {DELETE} or {DEL}
Text Navigation {HOME} {END} {PGDN} {PGUP}
Arrow Keys {UP} {RIGHT} {DOWN} {LEFT}
Escape {ESC}
Function Keys {F1} ... {F16}
Print Screen {PRTSC}
Break {BREAK}
The full list from Microsoft can be found here
There is a small javascript utility that simulates keystrokes like this on the Windows javascript interpreter.
Just create a js file with following code:
var WshShell = WScript.CreateObject("WScript.Shell");
WshShell.SendKeys(WScript.Arguments(0));
then call it from Matlab after the necessary timeout like this:
system('c:\my\js\file\script.js {Enter}');
Can't test here now, but I think this should work...
If you need to run a console-only program in a context that permits full DOS redirection, you can create a file called, say, CR.txt containing a carriage return and use the '<' notation to pipe the value into the program.
This only works if you can provide all the keyboard input can be recorded in the file. It fails dismally if the input has to vary based on responses.
An alternative is to duplicate the input (and possibly output) stream(s) for the program and then pipe data into and out of the program. This is more robust and can permit dynamic responses to the data, but will also likely require substantial effort to implement a robot user to the application.
Rog-O-Matic is an example of a large application completely controlled by a program that monitors screen output and simulates keyboard input to play an early (1980s) ASCII graphic adventure game.
The other responses will be required for GUI-based applications.
Python package pywinauto can wait any dialog and click buttons automatically. But it's capable for native and some .NET applications only. You may have problems with pressing WPF button (maybe QT button is clickable - not checked), but in such case code like app.DialogTitle.wait('ready').set_focus(); app.DialogTitle.type_keys('{ENTER}') may help. Your case is quite simple and probably some tricks with pywinauto are enough. Is your "app with popup" 64-bit or 32-bit?
wait and wait_not functions have timeout parameter. But if you need precisely listener with potentially infinite loop awaiting popups, good direction is global Windows hooks (pyHook can listen mouse and keybd events, but cannot listen dialog opening). I'll try to find my prototype that can detect new windows. It uses UI Automation API event handlers... and... ops... it requires IronPython. I still don't know how to set UI Automation handler with COM interface from standard CPython.
EDIT (2019, January): new module win32hooks was implemented in pywinauto a while ago. Example of usage is here: examples/hook_and_listen.py.