Question about ISE vs Console with SystemEvents - powershell

When I run the following in PowerShell ISE, it works perfectly, gives me the reason "AccountLock" or "AccountUnlock" exactly as it's supposed to. However, when I run this exact command in an elevated powershell console, it does not return the sessionswitch reason at all in console. It returns nothing after an unlock.
I checked Get-EventSubscriber as well as Get-Job and both look successfully created.
Screenshot of Subscriber & Job:
Register-ObjectEvent -InputObject $([microsoft.win32.systemevents]) -EventName "SessionSwitch" -Action {write-host $event.SourceEventArgs.Reason}
One thing I would like to do is have windows detect when the session is unlocked (after a user syncs their password with the domain) and open a program.
OS: Windows 10
Version: 5.1 Build 17134 R 590

After a lot of looking around, i couldn't find a good way to use [windows.win32.systemevents], so i reached out to Lee Holmes. He said it is because the powershell console host runs by default in the Single Thread Apartment (STA) model. If you run it in MTA, it works fine.
Simplest workaround is to use code similar to this at the beginning of your script to ensure you are in MTA mode, and if start a new powershell process if you are not and reload the script.
if ([System.Threading.Thread]::CurrentThread.ApartmentState -ne [System.Threading.ApartmentState]::MTA)
{
powershell.exe -MTA -File $MyInvocation.MyCommand.Path
return
}

Have a look to Microsoft documentation : SystemEvents.SessionSwitch Event, the explanation seems to be that this message is sent to message pump which is the part of code that process graphic messages. You perhaps can try to use an hidden form in your code to force creation of a message pump.
Note :
This event is only raised if the message pump is running. In a Windows service, unless a hidden form is used or the message pump has been started manually, this event will not be raised. For a code example that shows how to handle system events by using a hidden form in a Windows service, see the SystemEvents class.

Related

Powershell - Changing X-button behavior of console

I am working with a script that uses Excel as a COM application, so whenever I close my scipt using the X-button, it will leave an Excel task open in the background.
So I have a function that will close the Exceltask whenever I give "exit" as an user input, but I want to be able to close the console and excel with the X-button in the console. Is there any way that I can change the behavior from the X-button so it will first trigger a function, maybe? To give an idea about the function:
function Close(){
if($workbook){$workbook.close($false)}
if($excel){[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$excel)}
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
Remove-Variable excel -ErrorAction SilentlyContinue
exit
}
EDIT
It seems that exiting via the x-button will remain an issue for me as this thread (github) suggests.
So the reason for whom it interests is that:
"The event never kicks in if PowerShell is not in control of its own termination: Thus, closing the window / quitting the terminal emulator will not run the event handler."
which is just what so happens by pressing the x-button. So this issue is being considered in PS 7.0. Furthermore this thread, which discusses the same problem, also helped me find the thread on github.
You can carry out events when the form closes:
$form.Add_FormClosing({
# Actions to carry out when form closed.
})
Edit:
$Null supresses output - you can remove it to see whats going on.
The following code works on my PC:
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -SupportEvent -Action { New-Item -Path c:\temp -Name text.txt }
File created when PS window shut

Powershell script triggers process only when invoked manually. Timing out when triggered via Scheduled Task

On a Windows 2012 R2 server there is a Powershell script that I can manually invoke to start a process on some EXE, this works just fine.
But when trying to trigger it via a scheduled task (invoking the same script) the start-process within the script just doesn't trigger or finish. Causing the task scheduler to terminate the task due to exceeding the timeout threshold.
Here's the core section of the script:
$exe = "c:\some\app.exe"
$arguments = "-user me -pwd secret"
$process = Start-Process $exe -ArgumentList $arguments -PassThru -Wait
return $process
Is there some way I can get some insights into what start-process is doing or why the same script works when invoked manually but not programmatically?
I want to emphasize that the way the script is invoked from the scheduled task is not a problem! The script triggers because the corresponding log file populates.
Any insights or help on this is greatly appreciated!
quick update on this since I found the problem. It turns out, it had nothing to do with either the powershell script or the scheduled task itself...
On the machine the script is running on, there is a network share that is mapped as the z:\ drive. I use it to save logs to. Now apparently that mapping/mounting is handled differently depending on whether the script is invoked interactively or programatically, because in the latter case it appears that the resoultion of the network path \\network\share\folder1 does not succeed, however there is nothing complaining about it, the process just silently does not start. If however, I point the logs to a physical local path or the explicit full network path itself, there is no problem running the script.
Lesson learned, never trust OS' drive mapping of network paths :D
Cheers

Powershell Ambiguous Code Running on Windows Machine

Out of sudden, a colleague of mine found a script that runs during the startup of the Windows on his machine, which is found to be a powershell script.
The code is below, what I understood that it only minimizes all windows opened.
powershell -command "& { $x = New-Object -ComObject Shell.Application; $x.minimizeall() }"
I need to know if there is an impact from this code on his machine as to isolate from the network.
It doesn't seem to present a threat in and of itself. If someone is doing something unwanted, it would probably be that they're starting some other program that does something not nice, and this PowerShell command minimizes its window (possibly to the taskbar notification area where it can be hidden) so that you don't see what's going on. But the command itself appears harmless.
It only minimizes all the windows. Except that nothing else. I don't think it is harmful. If someone has kept it in the startup, I believe the reason being some other App is opening window in the startup , so it is trying to avoid that.

How to perform logging of forcefully exiting a running script?

I have a powershell script that registers certain events and logs them to a file.
I want to be able to also log to that file the moment that the script was forcefully stopped. For example, by closing the window via X button.
How could I perform this?
We can include in the ecuation the following languages: Powershell via ConEmu console, Perl via ConEmu console, AutoIT.
This does the trick.
Register-EngineEvent PowerShell.Exiting -SupportEvent -Action `
{
#action
}

PowerShell ISE and PowerShell.Exiting event

I'm using the PowerShell.Exiting engine event to save my command history and do some other tidying up when I close a PowerShell session, registering it in my profile thus:
# Set up automatic functionality on engine exit.
Register-EngineEvent PowerShell.Exiting -SupportEvent -Action `
{
#stuff
...
}
This works perfectly when I use PowerShell in a console window, but when I'm running PowerShell in ISE, it appears that the PowerShell.Exiting event somehow never fires, since nothing I put in there, be it the usual stuff or test code, ever runs.
Is this a known problem, and if so, is there a known workaround or alternative?
Well, this is weird as hell.
After cutting down the profile completely outside the Register-EngineEvent call only to find that it still didn't work, I started to cut down the contents of that, too, and restored the rest of the profile to its original state. Here are my findings:
If you have a write-host, or other output to the PowerShell host, in the scriptblock for Register-EngineEvent PowerShell.Exited, it doesn't run when you exit ISE (even though it works fine when you exit the console).
In fact, none of the scriptblocks you have registered against the PowerShell.Exited event appear to run, even ones that don't contain any statements outputting to the host. (Which is why when I tested other people's working examples up above, they didn't work for me unless I started PowerShell without running the profile that added the existing event handler.)
Expunge all statements that cause host output from the scriptblocks you use with Register-EngineEvent PowerShell.Exited , or redirect the output somewhere else, and they all start working.
(Take this with appropriate quantities of salt, since I have not yet had time to go chasing it with a debugger, but I have a sneaking suspicion ISE is closing down its tab before the engine is done with it...)