Pathing in Powershell - powershell

My corrent Code is this
Add-Type #"
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Wallpaper
{
public enum Style : int
{
Tile, Center, Stretch, NoChange
}
public class Setter {
public const int SetDesktopWallpaper = 20;
public const int UpdateIniFile = 0x01;
public const int SendWinIniChange = 0x02;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo (int uAction, int uParam, string lpvParam, int fuWinIni);
public static void SetWallpaper ( string path, Wallpaper.Style style ) {
SystemParametersInfo( SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange );
RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", true);
switch( style )
{
case Style.Stretch :
key.SetValue(#"WallpaperStyle", "2") ;
key.SetValue(#"TileWallpaper", "0") ;
break;
case Style.Center :
key.SetValue(#"WallpaperStyle", "1") ;
key.SetValue(#"TileWallpaper", "0") ;
break;
case Style.Tile :
key.SetValue(#"WallpaperStyle", "1") ;
key.SetValue(#"TileWallpaper", "1") ;
break;
case Style.NoChange :
break;
}
key.Close();
}
}
}
"#
[Wallpaper.Setter]::SetWallpaper( 'C:\Users\God\Desktop\Test\God.bmp' , 0 )
Ok, the Script comes with the God.bmp, which are ALWAYS in the same
directory (Folder Test on Desktop right now), I tried to replace the Path "C:\Users\God\Desktop\Test\God.bmp" With ".\God.bmp" which should work but it doesent seem to work I tried "./God.bmp" aswell but the Background turns black and not into the God picture. So how can I make it work because normally .\ makes it use the current Path as far as i know

Probably Windows doesn't handle relative paths to wallpaper in registry. If you'd like to use relative paths in your code, you have to expand them to full paths before writing to the registry:
$FullPath = Join-Path -Path (Get-Location -PSProvider FileSystem).Path -ChildPath 'God.bmp'
[Wallpaper.Setter]::SetWallpaper($FullPath , 0)

PowerShell will try to find .\God.bmp relative to where the caller is, not where the executing script exists in the filesystem.
Try this simple example:
# C:\scripts\relativepath.ps1
[System.IO.Path]::GetFullPath(".\god.bmp")
If you open a prompt and cd to C:\scripts, it works as expected:
PS C:\scripts> .\relativepath.ps1
C:\scripts\god.bmp
But if you change to another directory:
PS C:\somewhere\else> C:\scripts\relativepath.ps1
C:\somewhere\else\god.bmp
If you want the full path relative to where the executing script is located, use the $PSScriptRoot automatic variable:
$WallPaperPath = Join-Path -Path $PSScriptRoot -ChildPath "god.bmp"

Related

Disable SHIFT Stickykey shortcut

I'm trying to disable the popout that appears when pressing shift 5 times. Despite setting the HKCU\Control Panel\Accessibility\StickyKeys\Flags key to the 506 value in the registry, the change is not automatically applied.
I tried the code below in powershell, but to no avail:
$SKHA = Add-Type -MemberDefinition '[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint vParam, uint init);' -Name 'Test' -PassThru;
$SKHA::SystemParametersInfo(0x003B, 0, 4, 0)
The documents I used were:
SystemParametersInfoA function (winuser.h)
STICKYKEYS structure (winuser.h)
Is there any way to disable this popout without the user having to manually disable or log off/restart the system after changing the registry?
Thank you in advance.
As explained by mklement0 you need to use the STICKYKEYS structure. Here is a working snippet based on following answer which first, read the current data then apply the parameter
$MethodDefinition = #'
[StructLayout(LayoutKind.Sequential)]
public struct STICKYKEYS
{
public uint cbSize;
public int dwFlags;
}
[DllImport("user32.dll")]
public static extern int SystemParametersInfo(int uiAction, int uiParam, out STICKYKEYS pvParam, int fWinIni);
'#
$get = 0x003A
$set = 0x003B
$WinApiVariable = Add-Type -MemberDefinition $MethodDefinition -Name 'Win32' -NameSpace '' -PassThru
$startupStickyKeys = New-Object -TypeName 'Win32+STICKYKEYS'
$startupStickyKeys.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($startupStickyKeys)
[Win32]::SystemParametersInfo($get, [System.Runtime.InteropServices.Marshal]::SizeOf($startupStickyKeys), [ref]$startupStickyKeys, 0)
Write-Host "Current:"
$startupStickyKeys.dwFlags
Write-host "Set current flag to disabled (506)"
$startupStickyKeys.dwFlags = 506
[Win32]::SystemParametersInfo($set, [System.Runtime.InteropServices.Marshal]::SizeOf($startupStickyKeys), [ref]$startupStickyKeys, 0)
To complement Brice's helpful and effective solution (his answer deserves the accepted status):
Below is a more fully featured, PowerShell-friendly way to access and manage the sticky-keys feature: The code at the bottom defines type [demo.StickyKeys] with static members that allow you do to do the following:
# Get the active flags as a combination of friendly enum values; e.g.:
# AVAILABLE, HOTKEYACTIVE, CONFIRMHOTKEY, HOTKEYSOUND, INDICATOR, AUDIBLEFEEDBACK, TRISTATE, TWOKEYSOFF
[demo.StickyKeys]::ActiveFlags
# Query if the hotkey is currently enabled.
[demo.StickyKeys]::IsHotKeyEnabled
# Disable the hotkey *for the current session*
# Afterwards, [demo.StickyKeys]::ActiveFlags output no longer contains HOTKEYACTIVE
[demo.StickyKeys]::IsHotKeyEnabled = $false
# Disable the hotkey *persistently*.
[demo.StickyKeys]::EnableHotKey($false, $true)
# Show the flags in effect by default, on a pristine system.
[demo.StickyKeys]::DefaultFlags
Add-Member-based definition of [demo.StickyKeys]:
Add-Type -Namespace demo -Name StickyKeys -MemberDefinition '
// The WinAPI P/Invoke declaration for SystemParametersInfo()
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref STICKYKEYS pvParam, uint fWinIni);
// The data structure used by SystemParametersInfo() to get and set StickyKey-related flags.
[StructLayout(LayoutKind.Sequential)]
struct STICKYKEYS {
public uint cbSize;
public UInt32 dwFlags;
}
// A helper enum that represents a given combination of flags as a list of friendly symbolic identifiers.
[Flags]
public enum StickyKeyFlags : uint { // Prefix SKF_ omitted from the value names.
AUDIBLEFEEDBACK = 0x00000040,
AVAILABLE = 0x00000002,
CONFIRMHOTKEY = 0x00000008,
HOTKEYACTIVE = 0x00000004,
HOTKEYSOUND = 0x00000010,
INDICATOR = 0x00000020,
STICKYKEYSON = 0x00000001,
TRISTATE = 0x00000080,
TWOKEYSOFF = 0x00000100,
LALTLATCHED = 0x10000000,
LCTLLATCHED = 0x04000000,
LSHIFTLATCHED = 0x01000000,
RALTLATCHED = 0x20000000,
RCTLLATCHED = 0x08000000,
RSHIFTLATCHED = 0x02000000,
LALTLOCKED = 0x00100000,
LCTLLOCKED = 0x00040000,
LSHIFTLOCKED = 0x00010000,
RALTLOCKED = 0x00200000,
RCTLLOCKED = 0x00080000,
RSHIFTLOCKED = 0x00020000,
LWINLATCHED = 0x40000000,
RWINLATCHED = 0x80000000,
LWINLOCKED = 0x00400000,
RWINLOCKED = 0x00800000
}
// Gets or set the enabled status of the sticky-keys hotkey.
// Note: Setting is invariably *non-persistent*.
// Use the .EnableHotKey() method for optional persistence.
public static bool IsHotKeyEnabled {
get { return (GetFlags() & StickyKeyFlags.HOTKEYACTIVE) != 0u; }
set { EnableHotKey(value, false); }
}
// Gets or set the active sticky-keys flags.
// Note: Setting is invariably *non-persistent*.
// Use the .SetFlags() method for optional persistence.
public static StickyKeyFlags ActiveFlags {
get { return GetFlags(); }
set { SetFlags(value, false); }
}
// The flags in effect on a pristine system.
public static StickyKeyFlags DefaultFlags {
get { return StickyKeyFlags.AVAILABLE | StickyKeyFlags.HOTKEYACTIVE | StickyKeyFlags.CONFIRMHOTKEY | StickyKeyFlags.HOTKEYSOUND | StickyKeyFlags.INDICATOR | StickyKeyFlags.AUDIBLEFEEDBACK | StickyKeyFlags.TRISTATE | StickyKeyFlags.TWOKEYSOFF; } // 510u
}
// Enable or disable the stick-keys hotkey, optionally persistently.
public static void EnableHotKey(bool enable = true, bool persist = false) {
var skInfo = new STICKYKEYS();
skInfo.cbSize = (uint)Marshal.SizeOf(skInfo);
var flags = GetFlags();
SetFlags((enable ? flags | StickyKeyFlags.HOTKEYACTIVE : flags & ~StickyKeyFlags.HOTKEYACTIVE), persist);
}
// Get the currently active flags; exposed via the static .ActiveFlags property only.
private static StickyKeyFlags GetFlags() {
var skInfo = new STICKYKEYS();
skInfo.cbSize = (uint)Marshal.SizeOf(skInfo);
if (!SystemParametersInfo(0x003a /* SPI_GETSTICKYKEYS */, 0, ref skInfo, 0))
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
return (StickyKeyFlags)skInfo.dwFlags;
}
// Set the active flags *in full*, i.e. the value must combine all flags that should be set.
// Best to start from the current combination of flags reported by .ActiveFlags.
public static void SetFlags(StickyKeyFlags flags, bool persist = false) {
var skInfo = new STICKYKEYS();
skInfo.cbSize = (uint)Marshal.SizeOf(skInfo);
skInfo.dwFlags = (UInt32)flags;
if (!SystemParametersInfo(0x003b /* SPI_SETSTICKYKEYS */, 0, ref skInfo, persist ? 1u : 0u))
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
'

Installing 'printer forms' using powershell without prnadmin.dll?

Due to the fact that the latest security updates coming from Microsoft have turned the Jet OLEDB Provider unusable I have to rewrite several elder VBScripts.
Is there a better way to install printer forms on Windows Server 2008 R2 and 2012 R2 then calling the outdated prnadmin.dll via regsvr32/COM/VBscript?
prnadmin.dll was first introduced with Windows Server 2000 Resource Kit and I would like to migrate the whole script to PowerShell.
Unfortunately I can't find any usefull PowerShell cmdlet within the module PrintManagement. So how can I add custom forms to the Printer Server using PSH?
The programmatic way to add a system form definition is to call AddForm. There is not a good wrapper for this call that I am aware of, but P/Invoking to AddForm works. I wrote a quick wrapper and posted it on GitHub.
Example using the wrapper:
Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.
PS C:\Drop> Import-Module .\PowershellPrinterFormsModule.dll
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 1' -Units Inches -Size '4,5'
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 2' -Units Inches -Size '4,5' -Margin '0.25,0.5'
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 3' -Units Millimeters -Size '80,50' -Margin '10,10,0,0'
Actual P/Invoke call to AddForm:
SafePrinterHandle hServer;
if (!OpenPrinter(null, out hServer, IntPtr.Zero))
{
throw new Win32Exception();
}
using (hServer)
{
var form = new FORM_INFO_1()
{
Flags = 0,
Name = this.Name,
Size = (SIZEL)pageSize,
ImageableArea = (RECTL)imageableArea
};
if (!AddForm(hServer, 1, ref form))
{
throw new Win32Exception();
}
}
internal static class NativeMethods
{
#region Constants
internal const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
#endregion
#region winspool.drv
private const string Winspool = "winspool.drv";
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool OpenPrinter(string szPrinter, out SafePrinterHandle hPrinter, IntPtr pd);
public static SafePrinterHandle OpenPrinter(string szPrinter)
{
SafePrinterHandle hServer;
if (!OpenPrinter(null, out hServer, IntPtr.Zero))
{
throw new Win32Exception();
}
return hServer;
}
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool EnumForms(SafePrinterHandle hPrinter, int level, IntPtr pBuf, int cbBuf, out int pcbNeeded, out int pcReturned);
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool AddForm(SafePrinterHandle hPrinter, int level, [In] ref FORM_INFO_1 form);
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool DeleteForm(SafePrinterHandle hPrinter, string formName);
#endregion
#region Structs
[StructLayout(LayoutKind.Sequential)]
internal struct FORM_INFO_1
{
public int Flags;
[MarshalAs(UnmanagedType.LPWStr)]
public string Name;
public SIZEL Size;
public RECTL ImageableArea;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SIZEL
{
public int cx;
public int cy;
public static explicit operator SIZEL(Size r)
=> new SIZEL { cx = (int)r.Width, cy = (int)r.Height };
public static explicit operator Size(SIZEL r)
=> new Size(r.cx, r.cy);
}
[StructLayout(LayoutKind.Sequential)]
internal struct RECTL
{
public int left;
public int top;
public int right;
public int bottom;
public static explicit operator RECTL(Rect r)
=> new RECTL { left = (int)r.Left, top = (int)r.Top, right = (int)r.Right, bottom = (int)r.Bottom };
public static explicit operator Rect(RECTL r)
=> new Rect(new Point(r.left, r.top), new Point(r.right, r.bottom));
}
#endregion
}
internal sealed class SafePrinterHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafePrinterHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return NativeMethods.ClosePrinter(handle);
}
}

How to properly call static methods of types added with Add-Type from within Powershell classes?

I am adding this type and calling it. It works fine in script/function. As soon as I am trying to call it from powershell class - it gives error "type is not defined".
I have managed to call it using some ugly hacks. Add-Type is called with -PassThru and result is saved in $global:myType. Then I am doing indirect call using $global:myType.GetMethod('GetSymbolicLinkTarget').invoke($null,$dir).
Is there any better solution around?
PS: runspace is reset before each run (Ctrl-T in ISE, automatic in PowerGUI and Powershell Studio).
PS2: Working sample (simplified) below.
#works - returns 2
$Source = ' public class BasicTest { public static int Test(int a) { return (a + 1); } } '
Add-Type -TypeDefinition $Source
[BasicTest]::Test(1)
#gives error: Unable to find type [BasicTest]
$Source = ' public class BasicTest { public static int Test(int a) { return (a + 1); } } '
Add-Type -TypeDefinition $Source
class foo { Static [int]bar() { return [BasicTest]::Test(1) } }
[foo]::bar()
#workaround 1 - indirect call with GetMethod(...).Invoke(...)
# returns 4
$Source = ' public class BasicTest1 { public static int Test(int a) { return (a + 1); } } '
$global:BasicTestType1 = (Add-Type -TypeDefinition $Source -PassThru)
class foo {
static $BasicTestType2 = (Add-Type -TypeDefinition ' public class BasicTest2 { public static int Test(int a) { return (a + 1); } } ' -PassThru)
Static [int]bar() {
$ret = $global:BasicTestType1.GetMethod('Test').Invoke($null, [int]1)
$ret += [foo]::BasicTestType2.GetMethod('Test').Invoke($null, [int]1)
return $ret
}
}
[foo]::bar()
#workaround 2 - invoke-expression; has problems passing parameters
# returns 2
$Source = ' public class BasicTest { public static int Test(int a) { return (a + 1); } } '
Add-Type -TypeDefinition $Source
class foo { Static [int]bar() { return invoke-expression '[BasicTest]::Test(1)' } }
[foo]::bar()
PS3: Two other workarounds are provided here by PetSerAl.
The issue is that the class is parsed at compile time and the reference to the type you added doesn't get added until runtime. So, the reference cannot be resolved.
The best solution I see is to force the order that they are compiled in.
# Add the type
$Source = ' public class BasicTest { public static int Test(int a) { return (a + 1); } } '
Add-Type -TypeDefinition $Source
$scriptBlockText = #"
class foo {
Static foo() {
}
Static [int]bar() { return [BasicTest]::Test(1) }
}
"#
# Create a script block from the text
# the class will be compiled at this point
# but is not in scope yet
$scriptBlock = [scriptblock]::Create($scriptBlockText)
# dot source the class
# this brings the class into scope
.([scriptblock]::Create($scriptBlock))
# it would be better if the class was in a separate file
# but I'm using a string to simplify the sample.
# for a file the syntax would be `. .\myClass.ps1`
# this would replace both creating the script block and
# the dot sourcing statement
# Now you can use the class and the type you addded earlier
[foo]::bar()
Two other workarounds:
#workaround 3 - type variable
# returns 4
$Source = ' public class BasicTest1 { public static int Test(int a) { return (a + 1); } } '
$global:BasicTestType1 = (Add-Type -TypeDefinition $Source -PassThru)
class foo {
static $BasicTestType2 = (Add-Type -TypeDefinition ' public class BasicTest2 { public static int Test(int a) { return (a + 1); } } ' -PassThru)
Static [int]bar() {
$ret = ($global:BasicTestType1)::Test(1)
$ret += ([foo]::BasicTestType2)::Test(1)
return $ret
}
}
[foo]::bar()
#workaround 4 - most elegant so far
# returns 2
class foo {
static foo() {
$Source = ' namespace foo { public class BasicTest1 { public static int Test(int a) { return (a + 1); } } } '
Add-Type -TypeDefinition $Source
}
Static [int]bar() {
$ret = ([type]'foo.BasicTest1')::Test(1)
return $ret
}
}
[foo]::bar()
Workaround 4 is the shortest and cleanest.
It is also possible to play with type accelerators.

How to mute an application with PowerShell

I'm new to PowerShell and have been playing around with it lately.
My question is, how do you mute an specific application with PowerShell? For example, if I am watching a youtube video in chrome, I can mute chrome only by going into the volume mixer and muting chrome out of the list of apps. Is there a way to do this in PowerShell?
I found an article concerning how to mute everything but not a specific app.
Change audio level from powershell?
I wrapped the example-application posted here in a small powershell-script, so it can be used easily from Powershell, using the static methods. This should be what you are looking for, as long as you specify the correct app-name.
E.g:
[SetAppVolume.AppMuter]::Mute("Mozilla Firefox");
Sample code:
$def = #"
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace SetAppVolume
{
public class AppMuter
{
public static void Mute(string app)
{
foreach (string name in EnumerateApplications())
{
Console.WriteLine("name:" + name);
if (name == app)
{
// display mute state & volume level (% of master)
Console.WriteLine("Mute:" + GetApplicationMute(app));
Console.WriteLine("Volume:" + GetApplicationVolume(app));
// mute the application
SetApplicationMute(app, true);
// set the volume to half of master volume (50%)
SetApplicationVolume(app, 50);
}
}
}
public static float? GetApplicationVolume(string name)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return null;
float level;
volume.GetMasterVolume(out level);
return level * 100;
}
public static bool? GetApplicationMute(string name)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return null;
bool mute;
volume.GetMute(out mute);
return mute;
}
public static void SetApplicationVolume(string name, float level)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return;
Guid guid = Guid.Empty;
volume.SetMasterVolume(level / 100, ref guid);
}
public static void SetApplicationMute(string name, bool mute)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return;
Guid guid = Guid.Empty;
volume.SetMute(mute, ref guid);
}
public static IEnumerable<string> EnumerateApplications()
{
// get the speakers (1st render + multimedia) device
IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
IMMDevice speakers;
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);
// activate the session manager. we need the enumerator
Guid IID_IAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
object o;
speakers.Activate(ref IID_IAudioSessionManager2, 0, IntPtr.Zero, out o);
IAudioSessionManager2 mgr = (IAudioSessionManager2)o;
// enumerate sessions for on this device
IAudioSessionEnumerator sessionEnumerator;
mgr.GetSessionEnumerator(out sessionEnumerator);
int count;
sessionEnumerator.GetCount(out count);
for (int i = 0; i < count; i++)
{
IAudioSessionControl ctl;
sessionEnumerator.GetSession(i, out ctl);
string dn;
ctl.GetDisplayName(out dn);
yield return dn;
Marshal.ReleaseComObject(ctl);
}
Marshal.ReleaseComObject(sessionEnumerator);
Marshal.ReleaseComObject(mgr);
Marshal.ReleaseComObject(speakers);
Marshal.ReleaseComObject(deviceEnumerator);
}
private static ISimpleAudioVolume GetVolumeObject(string name)
{
// get the speakers (1st render + multimedia) device
IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
IMMDevice speakers;
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);
// activate the session manager. we need the enumerator
Guid IID_IAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
object o;
speakers.Activate(ref IID_IAudioSessionManager2, 0, IntPtr.Zero, out o);
IAudioSessionManager2 mgr = (IAudioSessionManager2)o;
// enumerate sessions for on this device
IAudioSessionEnumerator sessionEnumerator;
mgr.GetSessionEnumerator(out sessionEnumerator);
int count;
sessionEnumerator.GetCount(out count);
// search for an audio session with the required name
// NOTE: we could also use the process id instead of the app name (with IAudioSessionControl2)
ISimpleAudioVolume volumeControl = null;
for (int i = 0; i < count; i++)
{
IAudioSessionControl ctl;
sessionEnumerator.GetSession(i, out ctl);
string dn;
ctl.GetDisplayName(out dn);
if (string.Compare(name, dn, StringComparison.OrdinalIgnoreCase) == 0)
{
volumeControl = ctl as ISimpleAudioVolume;
break;
}
Marshal.ReleaseComObject(ctl);
}
Marshal.ReleaseComObject(sessionEnumerator);
Marshal.ReleaseComObject(mgr);
Marshal.ReleaseComObject(speakers);
Marshal.ReleaseComObject(deviceEnumerator);
return volumeControl;
}
}
[ComImport]
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
internal class MMDeviceEnumerator
{
}
internal enum EDataFlow
{
eRender,
eCapture,
eAll,
EDataFlow_enum_count
}
internal enum ERole
{
eConsole,
eMultimedia,
eCommunications,
ERole_enum_count
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMMDeviceEnumerator
{
int NotImpl1();
[PreserveSig]
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice);
// the rest is not implemented
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMMDevice
{
[PreserveSig]
int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
// the rest is not implemented
}
[Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAudioSessionManager2
{
int NotImpl1();
int NotImpl2();
[PreserveSig]
int GetSessionEnumerator(out IAudioSessionEnumerator SessionEnum);
// the rest is not implemented
}
[Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAudioSessionEnumerator
{
[PreserveSig]
int GetCount(out int SessionCount);
[PreserveSig]
int GetSession(int SessionCount, out IAudioSessionControl Session);
}
[Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAudioSessionControl
{
int NotImpl1();
[PreserveSig]
int GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal);
// the rest is not implemented
}
[Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ISimpleAudioVolume
{
[PreserveSig]
int SetMasterVolume(float fLevel, ref Guid EventContext);
[PreserveSig]
int GetMasterVolume(out float pfLevel);
[PreserveSig]
int SetMute(bool bMute, ref Guid EventContext);
[PreserveSig]
int GetMute(out bool pbMute);
}
}
"#;
Add-Type -TypeDefinition $def -Language CSharpVersion3
# Example usage
[SetAppVolume.AppMuter]::Mute("Mozilla Firefox");
I have recently enjoyed reading Feature Flags as a Service: The Only Way You Want Feature Flags that expresses my opinion neetly (I have no connection whatsoever to the team of rollout.io)
One of the great debates in the software world is that of build vs. buy. Anyone with a background in software development will tell you that the temptation to reinvent wheels is strong. Sure, any language’s standard libraries have optimized list sort functionality. But what’s the fun in that? Writing your own would be interesting and fun, and you wouldn’t have to rely on some other guy’s approach...When you build software for a living, you tend to react to obstacles by, well, building software. You do what you’re good at. This applies to individuals, and it applies to groups as a whole. But it’s important to overcome this tendency and make business decisions rather than emotional ones.
I would therefore suggest to use NirCmd's muteappvolume feature and build a small Powershell wrapper around it to suit your purposes. In my case, I have a long rain.mp3 playing with VLC without UI as a soundscape of my focus-hours — but I need to toggle mute/unmute for just this process for zooms or just listening to Annie Mac when doing mundane stuff. I toggle the mute/unmute just by pressing r in the terminal with this piece of code living in PowerShell's $profile. Again, it's not just muting, but toggling mute/unmute so I unmute doing exactly the same. No need to reinvent the wheel when such a cool tool as nircmd is readily available.
function toggleRain {
$commandLineProperty = '"C:\Program Files\VideoLAN\VLC\vlc.exe" --intf dummy c:\Users\Admin\Music\rain.mp3'
$rainPid = (Get-Process vlc | Where-Object {$_.CommandLine -eq $commandLineProperty}).Id
nircmd muteappvolume /$rainPid 2
}
Set-Alias r toggleRain

Hide title bar in powershell

In a Powershell environment, is it possible to hide the title bar or at least remove the close button?
I have some scripts that I'd prefer the user not "poke" at while they're running. I've considered running the script as hidden, but then the system will look like it's stuck for a minute or completely done when things are actually still going on under the covers.
You can disable the close button of the Windows console with this script at poshcode.org. However, the user can still close the console from the taskbar, and it doesn't work on console replacements such as ConEmu.
$code = #'
using System;
using System.Runtime.InteropServices;
namespace CloseButtonToggle {
internal static class WinAPI {
[DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteMenu(IntPtr hMenu,
uint uPosition, uint uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DrawMenuBar(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern IntPtr GetSystemMenu(IntPtr hWnd,
[MarshalAs(UnmanagedType.Bool)]bool bRevert);
const uint SC_CLOSE = 0xf060;
const uint MF_BYCOMMAND = 0;
internal static void ChangeCurrentState(bool state) {
IntPtr hMenu = GetSystemMenu(GetConsoleWindow(), state);
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
DrawMenuBar(GetConsoleWindow());
}
}
public static class Status {
public static void Disable() {
WinAPI.ChangeCurrentState(false); //its 'true' if need to enable
}
}
}
'#
Add-Type $code
[CloseButtonToggle.Status]::Disable()
The only option that comes to mind is to hide the window that's running the script, then add this to your script:
start-process powershell.exe -ArgumentList '-noprofile -command "&{get-content c:\temp\log.txt -Wait}"'
and re-direct your script output to that file. They'll be able to see the script ouput in that window, but nothing they do in that window will have any effect on the script. At the end of the script, delete the log file and the log window will close.
You could use a Windows Form in PowerShell, and hide the control box:
[Void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form = New-Object Windows.Forms.Form
$form.ControlBox = $false
$form.Text = "Test Form"
$Button = New-Object Windows.Forms.Button
Would look like: