Powershell: Get specific firefox window - windows

As part of working with the VirtualDesktop module, I need to get the MainWindowHandle of a particular firefox window in order to put it where I want it. It seems like most firefox processes don't have a MainWindowHandle:
PS> (ps firefox)[0].MainWindowHandle
0
PS> (ps firefox)[2].MainWindowHandle
591744
PS> (ps firefox).Length
19
What's interesting about the last bit of this is that I have 19 firefox tabs open across all my virtual desktops. Somewhere in an earlier question it mentioned that firefox perhaps uses win32 Windowless Controls, and so wouldn't necessarily have a window handle.
If I run ps firefox |format-table id, name, mainWindowTitle, mainWindowHandle then I can see that, in fact, only the most recently accessed tab has a mainWindowTitle or mainWindowHandle
I know that firefox pulls a little sneaky on us RE processes for performance/stability reasons. Are there any APIs (Moz or MS) that understand how to tear it into digestible bits?
Working code below for additional context:
# Setup windows on first open
Get-Desktop 1 | Switch-Desktop
Start-Process firefox.exe "-new-window open.spotify.com"
Start-Process firefox.exe "-new-window discord.com/channels/#me"
Start-Process -wait firefox.exe "-new-window gmail.com"
Get-Desktop 0 | Switch-Desktop
Start-Process code

Related

Launch Applications in WIndows using AppID and get the pid

I'm trying to launch Windows applications using their AppID such as Microsoft.WindowsCalculator_8wekyb3d8bbwe!App which I get by calling Get-StartApps
Currently I can launch the applications but can't get the correct PID
cmd = exec.Command("powershell", "start", `shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App`)
err := cmd.Start()
fmt.Println(cmd.Process.Pid)
This returns the PID of powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe start shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
Is there a way to launch the application by the AppID and still get the correct PID?
tl;dr
// Make PowerShell not only launch Calculator, but also
// determine and output its PID, as described in the next section.
out, _ :=
exec.Command(
`powershell.exe`,
`-NoProfile`,
`-Command`,
`Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID`,
).Output()
// Parse stdout output, which contains the PID, into an int
var pid int
fmt.Sscanf(string(out), "%d\n", &pid)
In principle, you can pass -PassThru to PowerShell's Start-Process (start) cmd, which returns a process-info object that has an .Id property containing the launched process' PID, and output the latter.
Unfortunately, with UWP / AppX applications specifically, such as Calculator, this does not work, which is a problem that exists in the underlying .NET APIs, up to at least .NET 6.0 - see GitHub issue #10996.
You can try the following workaround:
Launch the AppX application with Start-Process, which indirectly creates a process whose name is Calculator (Windows 10) / CalculatorApp (Windows 11).
You can identify this name yourself if you run (Get-Process *calc*).Name after launching Calculator. Get-Process *calc* | Select-Object Name, Path would show the executable path too, but note that this executable should be considered an implementation detail and can not be invoked directly.
Return the ID of that Calculator / CalculatorApp process. The fact that Calculator only ever creates one such process in a given user session actually makes identifying that process easy.
Note that this means that the PID of a preexisting Calculator process may be returned, which, however, is the correct one, because the transient process launched by Start-Process simply delegates creation of a new Calculator window to an existing process.
If you wanted to identify the newly created window, more work would be required: You'd have to enumerate the process' windows and identify the one with the highest z-order.
PowerShell code (note: in Windows 11, replace Calculator with CalculatorApp):
# Launch Calculator - which may reuse an existing instance and
# merely create a new *window* - and report the PID.
Start-Process -ErrorAction Stop calculator:
(Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID
Note that I've used the URL scheme calculator: as a simpler way to launch Calculator.
Note:
The Where-Object SessionId -eq (Get-Process -ID $PID).SessionId guards against mistakenly considering potential Calculator processes created by other users in their own sessions (Get-Process returns all processes running on the local machine, across all user sessions). Filtering by .SessionID, i.e. by the active user session (window station), prevents this problem.
As a PowerShell CLI call:
powershell.exe -NoProfile -Command "Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID"

Is a universal script to disable devices under Windows 10 "Device Manager", launch an executable, then enable said devices after app exit possible?

I'm trying to run some old software that refuses to launch (an issue for many users) unless the "HID-compliant consumer control device" devices, under Windows 10's "Device Manager", are disabled. I was able to do so with the simple batch script (using devcon):
devcon.exe /r disable #"PLACEHOLDER*"
however I was wondering if its possible to then run
devcon.exe /r enable #"PLACEHOLDER*"
upon exit of the application.
I attempted a little Power-Shell script to try and make my initial script more universal:
$id = (Get-CimInstance Win32_PnPEntity |
where caption -match 'HID-compliant consumer control device').pnpDeviceID
$ppid = "{0}{1}" -f '#',$id
Set-Location c:\PLACEHOLDER
Devcon status $ppid
Devcon enable $ppid
Devcon status $ppid
However this was met with a multitude of errors such as the script not being signed when attempting to test within "PowerShell ISE".
Any insight or assistance anyone can offer would be greatly appreciated.

How to close other PowerShell windows from script

I have a PowerShell script which has the following steps:
Opens another PowerShell window
Navigates to an angular projects directory
Runs a command to serve the project
Is there a way that I can close all other running PowerShell windows, but keep the currently running script and it's newly created window open? Following the changes, I would like it to behave like this:
Close all other PowerShell windows
Opens another PowerShell window
Navigates to an angular projects directory
Runs a command to serve the project
You could use Get-Process to enumerate all running powershell processes, then filter out the current one by comparing with the value of $PID, before piping the rest to Stop-Process:
Get-Process powershell |? Id -ne $PID |Stop-Process -Force
You can include the child process by ID if necessary:
$childProcess = Start-Process powershell $childProcArgs -PassThru
Get-Process powershell |? Id -notin #($PID;$childProcess.Id) |Stop-Process -Force
... although I would suggest simply killing all other powershell instances first, and then launch the child process after
Is there a way that I can close all other running PowerShell windows,
but keep the currently running script and it's newly created window
open?
$Previous = Get-process -Name *Powershell*;
{YOUR SCRIPT}
Stop-process $previous

Window opened via psexec is blank when using PowerShell Direct, but is OK when psexec starts locally

I am trying to build a simple environment to take screenshots automatically. I have several Hyper-V VMs and I need to use PowerShell Direct to run commands on them in a special sequence. When I run psexec to open notepad.exe via PowerShell Direct, Notepad's window opens, but it is blank. I can blindly click controls on the window (e.g., on the toolbar) and it appears that they work, but nothing is actually displayed besides a blank window.
The only simple option to open Windows in an existing session I see now is to run psexec (any other suggestions would be greatly appreciated because my attempts to stick to PowerShell-only approach hits a roadblock, see Starting a GUI application on a guest VM with PowerShell Direct).
I run psexec on one of the virtual machines to start notepad.exe in session 2. This PowerShell snippet runs on a host VM, it contacts guest VM via PowerShell Direct.
Invoke-Command -VMName 'client1.example.com' -Credential $credential -ScriptBlock {
C:\bin\psexec.exe \\client1.example.com -i 2 "notepad.exe"
}
notepad.exe starts, but the window is blank. Is this a bug in psexec?
Please see the screenshot:
The problem does not occur when I run psexec directly in a guest VM.
C:\bin\psexec.exe \\client1.example.com -i 2 "notepad.exe"
Solved by adding the -s option. I don't understand why the problem occurs in the first place and how running it "in the system account" helps.
-s Run the remote process in the System account.
The problem does not occur when I start explorer.exe, BTW.

How to Kill Process searching for Description with Loop via Powershell

I'm trying to figure out how to create a batch file by searching a text on Description of the Process then killing it. I managed to find one on this stackoverflow. But how do I loop this search before killing it?
This is the batch file I made
:loop
powershell -command "(get-process | ? {$_.Description -like 'Internet*'} if $_.Description -ne "Internet*" ( GOTO LOOP) ELSE (get-process | ? {$_.Description -like 'Internet*'}).kill())"
Well I'm just trying to experiment it but it's not working. I have a super little knowledge about Powershell.
FYI: I'm doing this because I own a Computer shop and there are some people who are trying to use the Internet Download Manager Portable to download big files, I tried limiting the bandwidth of the idman.exe using NetLimiter, but they are just renaming the file to let say 1.exe or 2.exe etc., so that's why I will try using the task scheduler and run this batch file in the background.
I'm not sure killing the process would be a good solution in your case, but if you trying to kill a process with a specific description, you can simply pipe the process to Stop-Process.
Get-Process | where {$_.Description -like "Internet*"} | Stop-Process

Resources