How to bring GUI window to front after an event? - powershell

As the title says, how can I bring a Powershell GUI window in front of another window after an event has happened, if it is at all possible? As in, I have, for example, Firefox opened and the Powershell GUI is running behind it, after certain event happens inside of the Powershell it pops in front of the Firefox?

On Windows, you can use [Microsoft.VisualBasic.Interaction]::AppActivate() to reactivate your own process' main window via the process ID, as reflected in the automatic $PID variable:
# Enable cross-process window activation (see below).
(Add-Type -ErrorAction Stop -PassThru -Namespace "Random.Ns$PID.AllowWindowActivation" -Name WinApiHelper -MemberDefinition #'
[DllImport("user32.dll", EntryPoint="SystemParametersInfo")]
static extern bool SystemParametersInfo_Set_UInt32(uint uiAction, uint uiParam, UInt32 pvParam, uint fWinIni);
public static void AllowWindowActivation()
{
if (! SystemParametersInfo_Set_UInt32(0x2001 /* SPI_SETFOREGROUNDLOCKTIMEOUT */, 0, 0 /* timeout in secs */, 0 /* non-persistent change */)) {
throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error(), "Unexpected failure calling SystemParametersInfo() with SPI_SETFOREGROUNDLOCKTIMEOUT");
}
}
'#)::AllowWindowActivation()
# Load the required assembly.
Add-Type -AssemblyName Microsoft.VisualBasic
# Launch a sample GUI application that will steal the focus
# (will become the foreground application).
Start-Process notepad.exe
# Wait a little.
Start-Sleep 3
# Now reactivate the main window of the current process.
[Microsoft.VisualBasic.Interaction]::AppActivate($PID)
Note:
Programmatic activation of arbitrary windows across process boundaries is prevented by default:
Instead of the targeted window getting activated, its taskbar button flashes, so as to signal to the user the intent to make the window active.
The Add-Type -MemberDefinition call above overrides this for the current session using a P/Invoke call to the SystemParametersInfo WinAPI function, via setting its SPI_SETFOREGROUNDLOCKTIMEOUT parameter to 0.
This will incur a one-time compilation performance penalty per session.
Cross-process window activation will be enabled for the remainder of the session, for all processes.

Related

Bring a specific window to the front before save automation [duplicate]

As the title says, how can I bring a Powershell GUI window in front of another window after an event has happened, if it is at all possible? As in, I have, for example, Firefox opened and the Powershell GUI is running behind it, after certain event happens inside of the Powershell it pops in front of the Firefox?
On Windows, you can use [Microsoft.VisualBasic.Interaction]::AppActivate() to reactivate your own process' main window via the process ID, as reflected in the automatic $PID variable:
# Enable cross-process window activation (see below).
(Add-Type -ErrorAction Stop -PassThru -Namespace "Random.Ns$PID.AllowWindowActivation" -Name WinApiHelper -MemberDefinition #'
[DllImport("user32.dll", EntryPoint="SystemParametersInfo")]
static extern bool SystemParametersInfo_Set_UInt32(uint uiAction, uint uiParam, UInt32 pvParam, uint fWinIni);
public static void AllowWindowActivation()
{
if (! SystemParametersInfo_Set_UInt32(0x2001 /* SPI_SETFOREGROUNDLOCKTIMEOUT */, 0, 0 /* timeout in secs */, 0 /* non-persistent change */)) {
throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error(), "Unexpected failure calling SystemParametersInfo() with SPI_SETFOREGROUNDLOCKTIMEOUT");
}
}
'#)::AllowWindowActivation()
# Load the required assembly.
Add-Type -AssemblyName Microsoft.VisualBasic
# Launch a sample GUI application that will steal the focus
# (will become the foreground application).
Start-Process notepad.exe
# Wait a little.
Start-Sleep 3
# Now reactivate the main window of the current process.
[Microsoft.VisualBasic.Interaction]::AppActivate($PID)
Note:
Programmatic activation of arbitrary windows across process boundaries is prevented by default:
Instead of the targeted window getting activated, its taskbar button flashes, so as to signal to the user the intent to make the window active.
The Add-Type -MemberDefinition call above overrides this for the current session using a P/Invoke call to the SystemParametersInfo WinAPI function, via setting its SPI_SETFOREGROUNDLOCKTIMEOUT parameter to 0.
This will incur a one-time compilation performance penalty per session.
Cross-process window activation will be enabled for the remainder of the session, for all processes.

Change numa group in running process via PowerShell

I would like to change numa group in running process via PS
all the time is take group 1 :( and cpu work 50%
this - I can do by hand but I don`t know how via PS
my problem is that I have processes that always get assigned to the same group, resulting in 50% of the cpu
Mathias when I add 2 I get this (in the powershell instruction the bitmask controlls number of cpus to in a processor group only - so if the process get's assigned to a group 0, the instruction only changes the number of cpus in this group)
This is not what I call an answer actually (I am not a C++ dev), however, here is a part of the way to probably achieve this :
$MethodDefinition = #'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool SetThreadGroupAffinity(......);
'#
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name "Kernel32" -PassThru
#Retrieve the Thread handle first
#Call by $Kernel32::SetThreadGroupAffinity(......)
MS docs SetThreadGroupAffinity,
MS docs GoupAfffinity Structure
May be this one be useful too MS docs SetThreadAffinityMask
You need to set the ProcessorAffinity property on the corresponding process:
Get-Process vmmem |ForEach-Object {
$_.ProcessorAffinity = [IntPtr]::new([long]-1) # -1 corresponds to all 64 bits set
}

PowerBuilder restart function

We are using Restart function in an application to close the application and re-open the same when the application is left idle for the specified period of time.
The fucntion works fine when we call the function from SDI application but when we call the function from MDI, the application closes off after couple of restarts.
In MDI frame, when the function is trigger is first time, the application restart works fine. When we leave the application for another idle time and the restart function is triggered again, the applicaiton just closes off. It does not crash or anything but just closes. Any idea on how to troubleshoot and solve the issue. Thanks.
One approach is after the idle event triggers, open a new instance of the application then close self.
This simple example is not designed to function in the IDE.
[PB external function declaration]
FUNCTION int GetModuleFileNameA(&
ulong hinstModule, &
REF string lpszPath, &
ulong cchPath) LIBRARY "kernel32" alias for "GetModuleFileNameA;ansi"
[in the application open event]
if commandline = "RESTARTED" then
messagebox( "Welcome Back!", "Click to Continue" )
end if
idle(300) // Restart the application if there is no activity for 5 minutes
Open ( w_main )
[in application IDLE event]
string ls_ExePathFileName
unsignedlong lul_handle
ls_ExePathFileName = space(1024)
lul_handle = Handle(GetApplication())
GetModuleFilenameA(lul_handle, ls_ExePathFileName, 1024)
run( ls_ExePathFileName + " RESTARTED" )
HALT CLOSE

Hide progress of Invoke-WebRequest

How can I hide the progress display of Invoke-WebRequest? I do a lot of successive requests and have my own Write-Progress display that I use, so I don't need the built-in one popping up underneath it every time.
I use the mshtml results (the IE COM object) that are created from the result of Invoke-WebRequest automatically, so I can't switch to a WebClient or something like that, unless someone provides instructions on how to get an mshtml object from a WebClient request.
Use the $progressPreference variable. It should have a value of 'Continue' by default unless you've edited it elsewhere, which tells Powershell to display the progress bar. Since you mentioned that you have your own custom progress displays, I would reset it immediately after the cmdlet is executed. For example:
$ProgressPreference = 'SilentlyContinue' # Subsequent calls do not display UI.
Invoke-WebRequest ...
$ProgressPreference = 'Continue' # Subsequent calls do display UI.
Write-Progress ...
More info on preference variables at about_preference_variables. Here's the entry for $ProgressPreference:
$ProgressPreference
-------------------
Determines how Windows PowerShell responds to progress updates
generated by a script, cmdlet or provider, such as the progress bars
generated by the Write-Progress cmdlet. The Write-Progress cmdlet
creates progress bars that depict the status of a command.
Valid values:
Stop: Does not display the progress bar. Instead,
it displays an error message and stops executing.
Inquire: Does not display the progress bar. Prompts
for permission to continue. If you reply
with Y or A, it displays the progress bar.
Continue: Displays the progress bar and continues with
(Default) execution.
SilentlyContinue: Executes the command, but does not display
the progress bar.
Here is a reusable function to temporarily hide the progress of any script block and automatically restore the progress preference when the script block ends, even if an exception (script-terminating error) is thrown by the script block.
# Create an in-memory module so $ScriptBlock doesn't run in new scope
$null = New-Module {
function Invoke-WithoutProgress {
[CmdletBinding()]
param (
[Parameter(Mandatory)] [scriptblock] $ScriptBlock
)
# Save current progress preference and hide the progress
$prevProgressPreference = $global:ProgressPreference
$global:ProgressPreference = 'SilentlyContinue'
try {
# Run the script block in the scope of the caller of this module function
. $ScriptBlock
}
finally {
# Restore the original behavior
$global:ProgressPreference = $prevProgressPreference
}
}
}
Usage example:
Invoke-WithoutProgress {
# Here $ProgressPreference is set to 'SilentlyContinue'
Invoke-WebRequest ...
}
# Now $ProgressPreference is restored
Write-Progress ...
Notes:
The New-Module call is there so the script block passed to Invoke-WithoutProgress doesn't run in a new scope (allowing it to directly modify surrounding variables, similar to ForEach-Object's script block). See this answer for more information.

Properly displaying a tray balloon tooltip in PowerShell

Short version: I think I need help with properly using events in PowerShell that are invoked as a result of a Windows Message to get rid of a balloon tooltip's icon.
Long Version:
I have a long-running PowerShell command (a build) that I would like to be notified when it completes via a balloon tooltip in the system tray/notification area.
I was able to create a Write-BalloonTip script (below) that does roughly what I want. The only problem is that, as sometimes happens with tray icons, the tray icon doesn't disappear until I mouse over it. By re-using the same global variable to represent the NotifyIcon, I'm able to re-use this script and keep it so that only one system tray icon remains (until I mouse over it). This still feels like a hack. I tried to add an event handler so that it'd be notified on the BalloonTipClosed event and then dispose of it there. In the event handler, I tried all three techniques I've seen suggested for getting rid of the lingering icon to no avail.
The annoying part is that a simple .Dispose seems to work on subsequent calls of the script, leading me to think that the event script block isn't being called at all.
I've verified that BalloonTipClosed gets called after the tip fades away in a separate WinForms app.
Am I missing something basic? Any help is much appreciated. Thanks!
Here's the code for "Write-BalloonTip.ps1":
param
(
$text,
$title = "",
$icon = "Info",
$timeout=15000
)
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null
if ($global:writeBalloonTipIcon)
{
# This gets rid of the previous one
$global:writeBalloonTipIcon.Dispose()
}
$global:writeBalloonTipIcon = new-object System.Windows.Forms.NotifyIcon
$global:writeBalloonTipIcon.Icon = [System.Drawing.SystemIcons]::Information
# FIXME: This *should* cleanup the icon after it's done, but it doesn't seem to work
$global:writeBalloonTipIcon.add_BalloonTipClosed(
{
# this *should* work, but it's not. What am I missing?
$global:writeBalloonTipIcon.Icon = $null;
$global:writeBalloonTipIcon.Visible = $false;
$global:writeBalloonTipIcon.Dispose();
});
$global:writeBalloonTipIcon.Visible = $true;
$global:writeBalloonTipIcon.ShowBalloonTip($timeout, $title, $text, $icon);
I think you need to execute this code in an STA thread. PowerShell (v2 shown here) executes in an MTA thread by default:
PS U:\> [System.Threading.Thread]::CurrentThread
ManagedThreadId : 5
ExecutionContext : System.Threading.ExecutionContext
Priority : Normal
IsAlive : True
IsThreadPoolThread : False
IsBackground : False
ThreadState : Running
ApartmentState : MTA
CurrentUICulture : en-US
CurrentCulture : en-US
Name : Pipeline Execution Thread
I would recommend using the Register-ObjectEvent to subscribe to the BalloonTipClosed event. This came up recently in another SO post. Check it out.