# encoding: ascii
# api: csharp
# title: Get-Link
# description: Sorry, but for now this is an all-in-one link creating/editing function: GET-Link and then call methods on it … feel free to polish it up and paste back. All credit goes to Ian Clegg for writing 90% of this code.
# version: 0.1
# type: class
# license: CC0
# x-poshcode-id: 2493
# x-archived: 2011-02-09T06:00:45
#
#
param([Parameter(ValueFromPipelineByPropertyName=$true)][Alias("PSPath")][string]$Path)
begin {
Add-Type -TypeDef @"
using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Huddled.Interop
{
[Flags()] // SHELL_LINK_DATA_FLAGS
public enum ShellLinkFlags : uint {
Default = 0x00000000,
HasIdList = 0x00000001,
HasLinkInfo = 0x00000002,
HasName = 0x00000004,
HasRelpath = 0x00000008,
HasWorkingdir = 0x00000010,
HasArgs = 0x00000020,
HasIconLocation = 0x00000040,
Unicode = 0x00000080,
ForceNoLinkInfo = 0x00000100,
HasExpSz = 0x00000200,
RunInSeparate = 0x00000400,
HasLogo3Id = 0x00000800,
HasDarwinId = 0x00001000,
RunasUser = 0x00002000,
HasExpIconSz = 0x00004000,
NoPidlAlias = 0x00008000,
ForceUncname = 0x00010000,
RunWithShimlayer = 0x00020000,
ForceNoLinktrack = 0x00040000,
EnableTargetMetadata = 0x00080000,
DisableLinkPathTracking = 0x00100000,
DisableKnownfolderRelativeTracking = 0x00200000,
NoKFAlias = 0x00400000,
AllowLinkToLink = 0x00800000,
UnaliasOnSave = 0x01000000,
PreferEnvironmentPath = 0x02000000,
KeepLocalIdListForUncTarget = 0x04000000,
Valid = 0x07fff7ff,
Reserved = (uint)0x80000000
}
// IShellLink.ShowCmd fFlags
[Flags()]
public enum ShowCmd
{
Normal = 1,
Maximized = 3,
Minnoactive = 7
}
// IShellLink.Resolve fFlags SLR_FLAGS
[Flags()]
public enum ResolveFlags
{
NoUI = 0x1,
AnyMatch = 0x2,
Update = 0x4,
NoUpdate = 0x8,
NoSearch = 0x10,
NoTrack = 0x20,
NoLinkInfo = 0x40,
InvokeMsi = 0x80
}
// IShellLink.GetPath fFlags SLGP_FLAGS
[Flags()]
public enum GetPathFlags
{
ShortPath = 0x1,
UncPriority = 0x2,
RawPath = 0x4
}
// Win32 COORD
[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
public short X;
public short Y;
}
// IShellDataLink NT_CONSOLE_PROPS
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct NT_CONSOLE_PROPS
{
public int cbSize; // Size of this extra data block
public uint dwSignature; // signature of this extra data block
public ushort wFillAttribute; // fill attribute for console
public ushort wPopupFillAttribute; // fill attribute for console popups
public COORD dwScreenBufferSize; // screen buffer size for console
public COORD dwWindowSize; // window size for console
public COORD dwWindowOrigin; // window origin for console
public int nFont;
public int nInputBufferSize;
public COORD dwFontSize;
public uint uFontFamily;
public uint uFontWeight;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string FaceName;
public uint uCursorSize;
public bool bFullScreen;
public bool bQuickEdit;
public bool bInsertMode;
public bool bAutoPosition;
public uint uHistoryBufferSize;
public uint uNumberOfHistoryBuffers;
public bool bHistoryNoDup;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public uint[] ColorTable;
}
// The CharSet must match the CharSet of the corresponding PInvoke signature
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct WIN32_FIND_DATA
{
public uint dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=14)]
public string cAlternateFileName;
}
[ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("0000010B-0000-0000-C000-000000000046")]
public interface IPersistFile
{
#region Methods inherited from IPersist
void GetClassID(
out Guid pClassID);
#endregion
[PreserveSig()]
int IsDirty();
void Load(
[MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
int dwMode);
void Save(
[MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
[MarshalAs(UnmanagedType.Bool)] bool fRemember);
void SaveCompleted(
[MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
void GetCurFile(
out IntPtr ppszFileName);
}
[ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("000214F9-0000-0000-C000-000000000046")]
public interface IShellLinkW
{
void GetPath(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
int cchMaxPath,
out WIN32_FIND_DATA pfd,
GetPathFlags fFlags);
void GetIDList(
out IntPtr ppidl);
void SetIDList(
IntPtr pidl);
void GetDescription(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
int cchMaxName);
void SetDescription(
[MarshalAs(UnmanagedType.LPWStr)] string pszName);
void GetWorkingDirectory(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
int cchMaxPath);
void SetWorkingDirectory(
[MarshalAs(UnmanagedType.LPWStr)] string pszDir);
void GetArguments(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
int cchMaxPath);
void SetArguments(
[MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
void GetHotkey(
out short pwHotkey);
void SetHotkey(
short wHotkey);
void GetShowCmd(
out int piShowCmd);
void SetShowCmd(
int iShowCmd);
void GetIconLocation(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
int cchIconPath,
out int piIcon);
void SetIconLocation(
[MarshalAs(UnmanagedType.LPWStr)] string pszIconPath,
int iIcon);
void SetRelativePath(
[MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
int dwReserved);
void Resolve(
IntPtr hwnd,
ResolveFlags fFlags);
void SetPath(
[MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
[ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("45E2b4AE-B1C3-11D0-B92F-00A0C90312E1")]
public interface IShellLinkDataList
{
void AddDataBlock(IntPtr pDataBlock);
void CopyDataBlock(uint dwSig, out IntPtr ppDataBlock);
void RemoveDataBlock(uint dwSig);
void GetFlags(out uint dwFlags);
void SetFlags(uint dwFlags);
}
public class ShellLink
{
private IShellLinkW _ShellLink;
private NT_CONSOLE_PROPS _ConsoleProperties;
private ushort _ScreenFill;
private ushort _PopUpFill;
public Color[] ConsoleColors = new Color[16];
public ShellLink(string Path) {
_ShellLink = Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("00021401-0000-0000-C000-000000000046"))) as IShellLinkW;
if (File.Exists(Path))
{
IntPtr pConsoleProperties = IntPtr.Zero;
((IPersistFile)_ShellLink).Load(Path, 0);
try
{
// TODO: Fix memory leak here
((IShellLinkDataList)_ShellLink).CopyDataBlock(0xA0000002, out pConsoleProperties);
_ConsoleProperties = (NT_CONSOLE_PROPS)Marshal.PtrToStructure(pConsoleProperties, typeof(NT_CONSOLE_PROPS));
_ScreenFill = _ConsoleProperties.wFillAttribute;
_PopUpFill = _ConsoleProperties.wPopupFillAttribute;
for (int i = 0; i < 16; i++)
{
ConsoleColors[i] = ColorTranslator.FromWin32((int)_ConsoleProperties.ColorTable[i]);
}
}
catch (Exception)
{
}
}
else
{
((IPersistFile)_ShellLink).Save(Path, true);
}
// Initialize default Console Properties (TODO: Fix this bug too)
if (_ConsoleProperties.dwSignature != 0xA0000002)
{
_ConsoleProperties = new NT_CONSOLE_PROPS();
_ConsoleProperties.cbSize = Marshal.SizeOf(_ConsoleProperties);
_ConsoleProperties.dwSignature = 0xA0000002;
_ConsoleProperties.ColorTable = new uint[16];
for (int i = 0; i < 16; i++)
{
_ConsoleProperties.ColorTable[i] = 0xffffffff;
}
}
}
public ShellLinkFlags Flags {
get {
uint flags;
((IShellLinkDataList)_ShellLink).GetFlags( out flags );
return (ShellLinkFlags)flags;
}
set {
((IShellLinkDataList)_ShellLink).SetFlags( (uint)value );
}
}
public void Save(string Path)
{
SetConsoleColors();
((IPersistFile)_ShellLink).Save(Path, true);
}
public void Save()
{
SetConsoleColors();
((IPersistFile)_ShellLink).Save(null, true);
}
public IShellLinkW GetShellLink()
{
return _ShellLink;
}
public string Path
{
get
{
StringBuilder sb = new StringBuilder(260);
WIN32_FIND_DATA pfd = new WIN32_FIND_DATA();
_ShellLink.GetPath(sb, 259, out pfd, GetPathFlags.RawPath);
return sb.ToString();
}
set
{
_ShellLink.SetPath(value);
}
}
public string Description
{
get
{
StringBuilder sb = new StringBuilder(2048);
_ShellLink.GetDescription(sb, 2048);
return sb.ToString();
}
set { _ShellLink.SetDescription(value); }
}
public string WorkingDirectory
{
get
{
StringBuilder sb = new StringBuilder(260);
_ShellLink.GetWorkingDirectory(sb, 260);
return sb.ToString();
}
set { _ShellLink.SetWorkingDirectory(value); }
}
public ShowCmd ShowCmd
{
get
{
int nShowCmd;
_ShellLink.GetShowCmd(out nShowCmd);
return (ShowCmd)Enum.ToObject(typeof(ShowCmd), nShowCmd);
}
set
{
_ShellLink.SetShowCmd((int)value);
}
}
public bool QuickEditMode
{
get { return _ConsoleProperties.bQuickEdit; }
set { _ConsoleProperties.bQuickEdit = value; }
}
public bool InsertMode
{
get { return _ConsoleProperties.bInsertMode; }
set { _ConsoleProperties.bInsertMode = value; }
}
public bool AutoPosition
{
get { return _ConsoleProperties.bAutoPosition; }
set { _ConsoleProperties.bAutoPosition = value; }
}
public void SetScreenBufferSize(short x, short y)
{
COORD c = new COORD();
c.X = x;
c.Y = y;
_ConsoleProperties.dwScreenBufferSize = c;
}
public void SetWindowSize(short x, short y)
{
COORD c = new COORD();
c.X = x;
c.Y = y;
_ConsoleProperties.dwWindowSize = c;
}
public uint CommandHistoryBufferSize
{
get { return _ConsoleProperties.uHistoryBufferSize; }
set { _ConsoleProperties.uHistoryBufferSize = value; }
}
public uint CommandHistoryBufferCount
{
get { return _ConsoleProperties.uNumberOfHistoryBuffers; }
set { _ConsoleProperties.uNumberOfHistoryBuffers = value; }
}
public byte ScreenBackgroundColor
{
set
{
_ScreenFill &= 0x00ff;
_ScreenFill += (ushort)(value << 4);
}
}
public byte ScreenTextColor
{
set
{
_ScreenFill &= 0xff00;
_ScreenFill += value;
}
}
public byte PopUpBackgroundColor
{
set
{
_PopUpFill &= 0x00ff;
_PopUpFill += (ushort)(value << 4);
}
}
public byte PopUpTextColor
{
set
{
_PopUpFill &= 0xff00;
_PopUpFill += value;
}
}
// This does more than console colors
private void SetConsoleColors()
{
for (int i = 0; i < 16; i++)
{
_ConsoleProperties.ColorTable[i] = (uint)ColorTranslator.ToWin32(ConsoleColors[i]);
}
_ConsoleProperties.wFillAttribute = _ScreenFill;
_ConsoleProperties.wPopupFillAttribute = _PopUpFill; ;
IntPtr pConsoleProperties = Marshal.AllocCoTaskMem(_ConsoleProperties.cbSize);
Marshal.StructureToPtr(_ConsoleProperties, pConsoleProperties, true);
((IShellLinkDataList)_ShellLink).RemoveDataBlock(0xA0000002);
((IShellLinkDataList)_ShellLink).AddDataBlock(pConsoleProperties);
}
}
}
"@ -ReferencedAssemblies System.Drawing
function global:Get-Link {
param([Parameter(ValueFromPipelineByPropertyName=$true)][Alias("PSPath")][string]$Path)
process {
New-Object Huddled.Interop.ShellLink (Convert-Path $Path)
}
}
}
process {
Get-Link $Path
}