Is there a way to command-line emulate the "kind of sleep" that Windows 11 enters when one picks "Sleep" from the power menu? - windows

I want to make my computer sleep from the command line (DOS, PS, or WSL) in a way so that it wakes up when I click the mouse or press a key - exactly how it works when one clicks "Start -< Power -> Sleep"
The following DO NOT WORK - all of the below put the machine into some other kind of deeper sleep, which ignores keyboard/mouse input (it's a laptop plugged into a monitor - I have to open its lid and press the power button to wake it, which messes up my desktop...)
psshutdown -d -t 0
C:\Windows\System32\rundll32.exe powrprof.dll,SetSuspendState 0,1,0
C:\Windows\System32\rundll32.exe powrprof.dll,SetSuspendState 1,1,0
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") ; $PowerState = [System.Windows.Forms.PowerState]::Suspend; [System.Windows.Forms.Application]::SetSuspendState($PowerState, $false, $false);
(aka)
powershell -Command "[Void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') ; $PowerState = [System.Windows.Forms.PowerState]::Suspend;echo Zzzz;[System.Windows.Forms.Application]::SetSuspendState($PowerState, $false, $false);"
Is there maybe some way to inject key-presses into the windows buffer? This would probably do the trick, if it's possible?:-
Ctrl-Esc, Up-Arrow, Right-Arrow, Right-Arrow, Right-Arrow, Right-Arrow, Enter, Enter
Does the Accessibility subsystem have any easy way to find desktop UI elements (the start menu) and trigger actions on them maybe ? (A click on the "Sleep").
Obviously - the best answer would be if anyone knows exactly what system call windows itself is making when that sleep button is pressed!

I guess this literally answers my question, although it's not ideal (takes a long time, is prone to probably going wrong if keys are pressed in the middle).
powershell - Command "$wshell = New-Object -ComObject wscript.shell;
$explorerpid = Get - Process | Select MainWindowTitle, ProcessName, Id | where {
$_.ProcessNAme - eq 'explorer'
} | foreach {
$_.Id
};
$wshell.AppActivate($explorerpid);
sleep 1;
$wshell.SendKeys('^{ESC}');
sleep 1;
$wshell.SendKeys('{UP}');
sleep 1;
$wshell.SendKeys('{RIGHT}');
sleep 1;
$wshell.SendKeys('{RIGHT}');
sleep 1;
$wshell.SendKeys('{RIGHT}');
sleep 1;
$wshell.SendKeys('{RIGHT}');
sleep 1;
$wshell.SendKeys('{ENTER}');
sleep 1;
$wshell.SendKeys('{ENTER}');
True
The above can be put into a .bat file, or made into a shortcut to make it easier to get to as well.
If anyone knows the correct way to invoke whatever underlying call the explorer.exeprocess is using to trigger a sleep directly, do please let us know!

This is another method which doesn't work for me - might work for others though?
(powershell):-
$PowrProf = Add-Type -MemberDefinition "[DllImport(`"PowrProf.dll`", CharSet = CharSet.Unicode)]`npublic static extern bool SetSuspendState(bool bHibernate, bool bForce, bool bWakeupEventsDisabled);" -Name Kernel32 -Namespace Win32 -PassThru
$PowrProf::SetSuspendState($False, $True, $False) ;echo bForce is not used
From: https://learn.microsoft.com/en-us/windows/win32/api/powrprof/nf-powrprof-setsuspendstate
p.s. The above also shows you how to call arbitrary windows API functions from the command line. Note that the weird things with backticks ` in front of them are powershell escapes for newline `n and quotes `"
Here also is yet-another, which simply does nothing whatsoever for me:-
$Kernel32 = Add-Type -MemberDefinition "[DllImport(`"kernel32.dll`", CharSet = CharSet.Unicode)]`npublic static extern bool SetSystemPowerState(bool fSuspend, bool fForce);" -Name Kernel32 -Namespace Win32 -PassThru
$Kernel32::SetSystemPowerState($True, $False)
Whatever explorer.exe is doing with their "sleep" button is clearly not using any of the above documented APIs - grrr!!

Related

How to programmatically eject locked HDD eSATA drive with PowerShell?

I am trying to eject eSATA HDD drive via "USB tray icon of windows" for safe remove, but it is not possible because "another program using the drive" error (I already tired of this stup## Windows error).
I tried this code on PowerShell:
$vol = get-wmiobject -Class Win32_Volume | where{$_.Name -eq 'F:\'}
$vol.DriveLetter = $null
$vol.Put()
$vol.Dismount($false, $false)
And this other:
$Eject = New-Object -comObject Shell.Application
$Eject.NameSpace(17).ParseName($usbDrvLetter+“:”).InvokeVerb(“Eject”)
And nothing happens.
Any method valid to get this to work?
Not sure but the overload definitions for the .Dismount() method are:
OverloadDefinitions
-------------------
System.Management.ManagementBaseObject Dismount(System.Boolean Force, System.Boolean Permanent)
So maybe change to: $Vol.Dismount($true, $true) effectively force the dismount.
I've tried testing this, except in general I think you should use the CIM cmdlets instead of -WMI. Get-WMIObject is deprecated in Windows PowerShell and has been removed from PowerShell Core.
It's also important to consider the potential return codes (documented here) from the Dismount method.
RETURN VALUE Return code Description
------------ ------------------------
0 Success
1 Access Denied
2 Volume Has Mount Points
3 Volume Does Not Support The No-Autoremount State
4 Force Option Required
To get the volume instance:
$Vol = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'E:'"
That's obviously similar enough to the older approach. However, invoking methods is done a little differently:
$Vol | Invoke-CimMethod -MethodName Dismount -Arguments #{ Force = $true; Permanent = $true }
ReturnValue PSComputerName
----------- --------------
2
And, it doesn't appear to dismount the drive. However, if I change the arguments:
$Vol | Invoke-CimMethod -MethodName Dismount -Arguments #{ Force = $true; Permanent = $false }
ReturnValue PSComputerName
----------- --------------
0
This does appear to dismount the drive, as Explorer shifted focus. However, the drive is still visible and when clicked can be accessed. I never saw the Safely eject message. It seems that Dismounting the drive is not equivalent to safely ejecting it.

why [CONSOLE]::NumberLock is not working in remote destop system [duplicate]

I have tried the following command but I only get a value of False:
Invoke-Command -ComputerName Server01 -ScriptBlock {[console]::CapsLock}
When I run [console]::CapsLock locally the command works.
Using[Console]::CapsLock
The [Console]::CapsLock property can be read to get whether CapsLock is On or Off ($true or $false):
[Console]::CapsLock
You can also check the state of NumLock with [Console]::NumberLock as well.
Using MS Word
Seems that the remote session doesn't reflect whether CapsLock is on or off based on whether the physical keyboard has it on or off.
I was able to find another method but don't have a way to test it myself, and it requires Microsoft Word to be installed:
$word = New-Object -ComObject "Word.Application"
# Check CapsLock
$word.CapsLock
# Check NumLock
$word.NumLock
Using the System.Windows.Forms Namespace
A third method that might work for your needs would be to use the System.Windows.Forms namespace to read the caps lock setting.
# Make System.Windows.Forms available in Powershell
Add-Type -AssemblyName System.Windows.Forms
# Check CapsLock
[System.Windows.Forms.Control]::IsKeyLocked( 'CapsLock' )
# Check NumLock
[System.Windows.Forms.Control]::IsKeyLocked( 'NumLock' )
Using the Win32 API
You can also check the state using the Win32 API:
# Compile some quick C# so we can `P/Invoke` to the native library
$signature = #"
[DllImport("USER32.dll")]
public static extern short GetKeyState(int nVirtKey);
"#
$Kernel32 = Add-Type -MemberDefinition $signature -Name Kernel32 -Namespace Win32 -Passthru
# Check CapsLock
[bool]( $Kernel32::GetKeyState(0x14) )
# Check NumLock
[bool]( $Kernel32::GetKeyState(0x90) )
0x14 is the key id for CapsLock and 0x90 is the key id for NumLock. See this page for more information on making use of this API from .NET, and this page for the documentation of GetKeyState itself.
Doing it remotely
I could not find any reliable methods of doing this remotely, which makes sense, as CapsLock is a per session setting - not a system wide one. Even assuming there is a way to get the CapsLock status for a given active session, you could have several user sessions on one remote system at once, and it becomes difficult to know which session to look at for its CapsLock status.

Unpin the Microsoft Edge and store taskbar shortcuts programmatically

I setup computers daily and I need to remove the Microsoft Edge and Store taskbar shortcuts.
I am having trouble creating a script and I have searched for other stackoverflow posts but they were not helpful to me.
Does anyone have a script that can unpin the MS Edge and Store taskbar shortcuts?
You can unpin taskbar items by running the following PowerShell commands.
function Unpin-App([string]$appname) {
((New-Object -Com Shell.Application).NameSpace('shell:::{4234d49b-0245-4df3-b780-3893943456e1}').Items() |
?{$_.Name -eq $appname}).Verbs() | ?{$_.Name.replace('&','') -match 'Unpin from taskbar'} | %{$_.DoIt()}
}
Unpin-App("Microsoft Edge")
Unpin-App("Microsoft Store")
This should work for any application on the taskbar. If the application isn't found, the error InvokeMethodOnNull will be thrown.
What this does:
Enumerates the Shell/taskbar COM object namespace
Matches the item with the name $appname (in this case, Edge and Store)
Gets the verb Unpin from taskbar of that com object
Executes the verb to remove it from the taskbar (without having to kill explorer.exe)
Very nice solution from Judge2020, +1
With a RegEx and -match instead of -eq you can unpin several Apps in one run
The unpin verbs are localized, in German it's Von "Start" lösen
$appnames = "^Microsoft Edge$|^Store$"
((New-Object -Com Shell.Application).NameSpace('shell:::{4234d49b-0245-4df3-b780-3893943456e1}').Items() |
Where-Object{$_.Name -match $appnames}).Verbs() |
Where-Object{$_.Name.replace('&','') -match 'Unpin from taskbar|Von "Start" lösen'} |
ForEach-Object{$_.DoIt(); $exec = $true}

batch file open windows and resize them

I am currently trying to open two windows through a batch file and then resize and move them (to be splitscreen). Opening the separate windows is easy:
#echo off
cd "C:\Program Files (x86)\Internet Explorer"
start iexplore.exe
cd "C:\Program Files (x86)\Mozilla Firefox"
start firefox.exe
exit
but I can't find a way to resize and move the windows I am opening. I would prefer not having to use any third party programs. I tried looking through the start /? help menu and don't believe any of the options are of use to me.
Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.
C:\WINDOWS\system32>start /?
Starts a separate window to run a specified program or command.
START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED]
[/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL]
[/NODE <NUMA node>] [/AFFINITY <hex affinity mask>] [/WAIT] [/B]
[command/program] [parameters]
"title" Title to display in window title bar.
path Starting directory.
B Start application without creating a new window. The
application has ^C handling ignored. Unless the application
enables ^C processing, ^Break is the only way to interrupt
the application.
I The new environment will be the original environment passed
to the cmd.exe and not the current environment.
MIN Start window minimized.
MAX Start window maximized.
SEPARATE Start 16-bit Windows program in separate memory space.
SHARED Start 16-bit Windows program in shared memory space.
LOW Start application in the IDLE priority class.
NORMAL Start application in the NORMAL priority class.
HIGH Start application in the HIGH priority class.
REALTIME Start application in the REALTIME priority class.
Press any key to continue . . .
If you have PowerShell installed (and you likely do), you can use user32.dll to move and adjust windows. Once upon a time, I needed a script for work that does exactly what you need and I found this and adjusted it to suit my needs. I then used this to convert it to a batch/powershell hybrid so that I only had to double-click the file to get the PowerShell script to run.
<# :
:: Based on https://gist.github.com/coldnebo/1148334
:: Converted to a batch/powershell hybrid via http://www.dostips.com/forum/viewtopic.php?p=37780#p37780
#echo off
setlocal
cls
set "POWERSHELL_BAT_ARGS=%*"
if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%"
endlocal & powershell -NoLogo -NoProfile -Command "$_ = $input; Invoke-Expression $( '$input = $_; $_ = \"\"; $args = #( &{ $args } %POWERSHELL_BAT_ARGS% );' + [String]::Join( [char]10, $( Get-Content \"%~f0\" ) ) )"
goto :EOF
#>
# Add the relevant section of the Win32 API to the PowerShell session
# Allows windows to be moved and resized
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
"#
################################################################################
# Moves and resizes the window based the broswer
#
# Arguments: $browser - the browser being moved and resized
# Returns: None
################################################################################
Function MoveAndResize ($browser)
{
# $browser_path is the full path to the browser
# $screen_x is the horizontal location of the window on the screen
# $screen_y is the vertical location of the window on the screen
# $win_x is the width of the target window
# $win_y is the height of the target window
Switch($browser){
InternetExplorer{
$browser_path="C:\Program Files\Internet Explorer\IEXPLORE.EXE"
$screen_x = 0
$screen_y = 0
$win_x = 960
$win_y = 1080
break
}
Firefox{
$browser_path="C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
$screen_x = 960
$screen_y = 0
$win_x = 960
$win_y = 1080
break
}
default {continue}
}
# Start the desired browser
Start-Process $browser_path
# Wait one second until the browser is fully loaded
Start-Sleep -S 1
# Find the running process where the application path matches $browser_path
$browser = (Get-Process | where {$_.Path -eq $browser_path}).MainWindowHandle
[Win32]::MoveWindow($browser, $screen_x, $screen_y, $win_x, $win_y, $true)
}
MoveAndResize "InternetExplorer"
MoveAndResize "Firefox"
Note that I'm using the Program Files version of iexplore instead of the Program Files (x86) version because that one wouldn't move or resize for some reason.

Not able to spawn off email message from windows search in powershell

I have a powershell script that is searching the Windows Search index directly for emails and files. I have the following code:
$searchme="my thing to find"
$sql="SELECT System.FileName, System.ItemPathDisplay, System.DateCreated, System.DateModified, system.itemurl, system.itemtypetext FROM SYSTEMINDEX WHERE Contains(System.FileName, '"+$searchme+"') OR Contains('"+$searchme+"')"
$adapter = new-object system.data.oledb.oleDBDataadapter -argumentlist $sql, "Provider=Search.CollatorDSO;Extended Properties=’Application=Windows’;"
$ds = new-object system.data.dataset
$adapter.Fill($ds)
foreach ($record in $ds.Tables[0].Rows)
{
$exeparams = $record[4]
write-host $exeparams
write-host $exeparams.split(":")[0]
if ($exeparams.split(":")[0] -eq "mapi15")
{
$exeparams2="mapi://" + $exeparams.substring(8)
}
write-host $exeparams
write-host "start"
$exe="start"
$exe+" "+$exeparams | Out-File 'file.txt' -encoding Unicode
write-host "start-process"
Start-Process $exeparams
Start-Process $exeparams2
write-host "andpersand process"
&$exe $exeparams
&$exe $exeparams2
write-host "dotnet"
$proc = [Diagnostics.Process]::Start($exeparams)
$proc.WaitForExit()
$proc = [Diagnostics.Process]::Start($exeparams2)
$proc.WaitForExit()
}
There are several "shell" calls because I was trying to figure out if it was a process spawning issue. Files work with no issue. Emails however fail with either No such interface if i leave mapi15, or Unspecified error if i change mapi15 to mapi. I believe that Open mails in outlook from java using the protocol "mapi://" may be the solution, but if it is I am not sure how to apply this in powershell. Thank you for your help.
Ok, that took more work than I expected, and I blame Office 2013 for it. Here's the short answer:
$exeparams2 = $exeparams -replace "^mapi15", "mapi"
& start $exeparams2
That is the code that now opens an email for me. That code did not do that yesterday, all it did is tell me:
Either there is no default mail client or the current mail client cannot fulfill the messaging request. Please run Microsoft Outlook and set it as the default mail client.
Infuriating is what this was, because I did have Outlook, in fact it was running, and was the default mail application for everything email related. This annoyed me, and sent me on a quest to figure out WTF was wrong, and if I could fix it. The answers to that are "I'm not real sure WTF was wrong, except maybe a naming change on MS's part", and "yes, yes I can fix it".
I finally found the fix that worked for me (and I believe that this is probably Office 2013/Office 365 specific) was found at the bottom of this thread:
https://social.technet.microsoft.com/Forums/office/en-US/64c0bedf-2bcd-40aa-bb9c-ad5de20c84be/cannot-send-email-with-microsoft-outlook-2010-64-bit-from-adobe-outlook-not-recognised-as?forum=outlook
The process is simple. Change 2 Registry Entries, then re-set your default mail application. Registry entries:
HKLM:\Software\Clients\Mail(default)
HKLM:\Software\Clients\Mail\Microsoft Outlook(default)
Change the value of (Default) from "Microsoft Outlook" to simply "Outlook".
After that I set Outlook to be the default for everything it could be ( in Win8 that's Control Panel > All Control Panel Items > Default Programs > Set Default Programs then select Outlook, and choose the first option to make it default for all extensions that it is registered for). Once that was done I was able to run the modified code above to launch an email that I had search the index for.

Resources