Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@warthurton
Forked from Beej126/README.md
Last active October 23, 2018 15:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save warthurton/007a7ff2ef8966abc941d7b8011fd8b6 to your computer and use it in GitHub Desktop.
Save warthurton/007a7ff2ef8966abc941d7b8011fd8b6 to your computer and use it in GitHub Desktop.
Scripted Windows 10 "Win+X" Menu (aka "Power User Menu")

Scripted Win+X shortcuts

Using this in tandem with ListShortcuts.csx becomes a simple scripted backup/restore mechanism for porting your favorite WinX shortcuts to other machines, etc.

sample usage:

  • scriptcs ListShortCuts.csx -- "%LOCALAPPDATA%\Microsoft\Windows\WinX\Group3" > FaveLinks.md
  • scriptcs WinXCreate.csx -- FaveLinks.md

handy nuggets:

Sample Screenshot

image

# Created by https://www.gitignore.io/api/visualstudiocode,vim
### Vim ###
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# End of https://www.gitignore.io/api/visualstudiocode,vim
rmdir /s /q "%LOCALAPPDATA%\Microsoft\Windows\WinX\Group3"
rmdir /s /q "%LOCALAPPDATA%\Microsoft\Windows\WinX\Group4"
Display Name Target Working Dir Elevated Arguments
CMD C:\Utils\hstart\hstart.exe False /NOELEVATE "C:\Users\warthurton\scoop\apps\cmder\current\Cmder.exe /START %userprofile%\Downloads""
Process Explorer C:\Utils\hstart\hstart.exe False /NOUAC "C:\ProgramData\scoop\apps\sysinternals\current\procexp.exe"
Certs C:\Utils\hstart\hstart.exe False /NOUAC /SHELL "C:\Windows\System32\certlm.msc"
Environment Variables C:\Utils\hstart\hstart.exe False /NOUAC "C:\Windows\System32\rundll32.exe sysdm.cpl,EditEnvironmentVariables"
Uninstall Apps C:\Utils\hstart\hstart.exe False /NOUAC "C:\Windows\explorer.exe shell:::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}"
Device Manager C:\Utils\hstart\hstart.exe False /NOUAC "C:\Windows\System32\control.exe /name Microsoft.DeviceManager"
Event Viewer C:\Utils\hstart\hstart.exe False /NOUAC "C:\Windows\System32\eventvwr.exe"
Disk Management C:\Utils\hstart\hstart.exe False /NOUAC /SHELL "C:\Windows\System32\diskmgmt.msc"
Services C:\Utils\hstart\hstart.exe False /NOUAC /SHELL "C:\Windows\System32\services.msc"
Local Security Policy C:\Utils\hstart\hstart.exe False /NOUAC /SHELL "C:\Windows\System32\secpol.msc /s"
Local Users C:\Utils\hstart\hstart.exe False /NOUAC /SHELL "C:\Windows\System32\lusrmgr.msc"
Power C:\Utils\hstart\hstart.exe False /NOUAC "C:\Windows\System32\rundll32.exe shell32.dll,Control_RunDLL PowerCfg.cpl @0,/editplan:381b4222-f694-41f0-9685-ff5bb260df2e"
System C:\Utils\hstart\hstart.exe False /NOUAC "C:\Windows\System32\control.exe /name Microsoft.System"
PowerShell ISE C:\Windows\System32\WindowsPowerShell\v1.0\powershell_ise.exe False
Task Scheduler C:\Utils\hstart\hstart.exe False /NOUAC /SHELL "C:\Windows\System32\taskschd.msc /s"
WinXEditor C:\Utils\hstart\hstart.exe False /NOUAC "C:\Utils\app\WinXMenuEditor\WinXEditor.exe"
Display Name Target Working Dir Elevated Arguments
WARTHURTON-W540 C:\Utils\hstart\hstart.exe False /NOELEVATE /D="C:" "C:\Windows\System32\explorer.exe"
#r "Interop.IWshRuntimeLibrary.dll"
//generated by referencing "Windows Script Host Object Model" in Visual Studio project
//from here: http://stackoverflow.com/a/4909475/813599
using IWshRuntimeLibrary;
using System.Text.RegularExpressions;
private bool IsElevated(string lnkFile)
{
using (FileStream fs = new FileStream(lnkFile, FileMode.Open, FileAccess.Read))
{
fs.Seek(21, SeekOrigin.Begin);
return (fs.ReadByte() == 0x22);
}
}
private void Main() {
if (Env.ScriptArgs.Count < 1) {Console.WriteLine("must provide path"); return;}
var wsh = new WshShell();
var shortcutFileNames = System.IO.Directory.EnumerateFiles(Env.ScriptArgs[0], "*.lnk").ToArray();
Console.WriteLine("Display Name | Target | Working Dir | Elevated | Arguments");
Console.WriteLine("--- | --- | --- | --- | ---");
for (var i=shortcutFileNames.Length-1; i>-1; i--) //Win+X menu is structured in reverse order
{
var fn = shortcutFileNames[i];
var title = Regex.Match(fn, ".*?- (.*?).lnk").Groups[1].Value;
var sc = (IWshShortcut)wsh.CreateShortcut(fn);
Console.WriteLine($"{title} | {sc.TargetPath} | {sc.WorkingDirectory} | {IsElevated(fn)} | {sc.Arguments}");
}
}
Main();
call ClearGroup3
scriptcs WinXCreate.csx -- FaveLinks3.md
scriptcs WinXCreate.csx -- FaveLinks4.md
tk explorer
taskkill /im %1.exe /f
if "%1" == "explorer" start explorer
#r "Microsoft.WindowsAPICodePack.Shell.dll"
#r "Microsoft.WindowsAPICodePack.dll"
#r "Interop.IWshRuntimeLibrary.dll"
using IWshRuntimeLibrary;
using Microsoft.WindowsAPICodePack.Shell;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
internal class ReverseSorter : System.Collections.IComparer
{
int System.Collections.IComparer.Compare(object x, object y)
{
return new System.Collections.CaseInsensitiveComparer().Compare(y, x);
}
}
private static readonly KeyValuePair<string, string>[] SystemFolderMapping = new[]
{
new KeyValuePair<string, string>(Environment.ExpandEnvironmentVariables("%programfiles%").ToLower(), "{905E63B6-C1BF-494E-B29C-65B732D3D21A}"),
new KeyValuePair<string, string>(Environment.ExpandEnvironmentVariables("%windir%\\system32").ToLower(), "{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}"),
new KeyValuePair<string, string>(Environment.ExpandEnvironmentVariables("%windir%").ToLower(), "{F38BF404-1D43-42F2-9305-67DE0B28FC23}"),
new KeyValuePair<string, string>(Environment.ExpandEnvironmentVariables("%systemroot%").ToLower(), "{F38BF404-1D43-42F2-9305-67DE0B28FC23}")
};
private static readonly WshShell wsh = new WshShell();
private static readonly string WinXFolder = Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Microsoft\Windows\WinX");
private static readonly System.Collections.IComparer ReverseSort = new ReverseSorter();
public static class WinXHasher
{
[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError=true)]
internal static extern int HashData([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 1)] [In] byte[] pbData, int cbData, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 3)] [Out] byte[] piet, int outputLen);
private static bool _isFileList = false;
private static string _groupFolderPath;
public static void HashLnk(string lnkFile)
{
if (Path.GetExtension(lnkFile)?.ToLower() != ".lnk")
{
if (_isFileList) return;
_isFileList = true;
if (_groupFolderPath == null) {
_groupFolderPath = Path.Combine(WinXFolder, "Group"+GetNextMaxGroup());
Directory.CreateDirectory(_groupFolderPath);
}
var lines = System.IO.File.ReadAllLines(lnkFile);
for (var lineNum=0; lineNum < lines.Length-2; lineNum++) //skip first 2 header lines
{
var line = lines[lineNum+2]; //skip first 2 header lines
var chunks = line.Split('|');
if (chunks.Length != 5) {
Console.WriteLine("Listing file needs to be lines in following bar separated format (no quotes):");
Console.WriteLine("Display Name | exe path | Elevated (True/False) | Arguments");
return;
}
var title = chunks[0].Trim();
var lnkPath = Path.Combine(_groupFolderPath,
//the menu structure works in reverse of the top to bottom order in the shortcuts listing file
(lines.Length - lineNum).ToString().PadLeft(2, '0') + " - " + title + ".lnk");
var wshShortcut = (IWshShortcut)wsh.CreateShortcut(lnkPath);
wshShortcut.Description = title;
wshShortcut.TargetPath = chunks[1].Trim();
wshShortcut.WorkingDirectory = chunks[2].Trim();
bool isElevated; bool.TryParse(chunks[3].Trim(), out isElevated);
wshShortcut.Arguments = chunks[4].Trim();
Console.WriteLine($"lnk: {lnkPath}, target: {wshShortcut.TargetPath}, args: {wshShortcut.Arguments}");
wshShortcut.Save();
if (isElevated) ElevateLnk(lnkPath);
HashLnk(lnkPath);
}
return;
}
var lnk = (IWshShortcut)wsh.CreateShortcut(lnkFile);
var text = lnk.TargetPath;
// ReSharper disable once LoopCanBeConvertedToQuery
foreach(var kv in SystemFolderMapping) text = text.ToLower().Replace(kv.Key, kv.Value);
//this is the magic kicker that makes the shortcuts special and show up in the start menu
//lifted following hash algorithm from: http://winaero.com/download.php?view.21
if (lnk.Arguments.Length > 0) text += lnk.Arguments;
//this magic string appears to be necessary for the hash to be accepted by Windows
text += "do not prehash links. this should only be done by the user.";
text = text.ToLower();
var inBytes = Encoding.GetEncoding(1200).GetBytes(text);
var byteCount = inBytes.Length;
var outBytes = new byte[byteCount];
var hashResult = HashData(inBytes, byteCount, outBytes, byteCount);
if (hashResult != 0) throw new Exception("Shlwapi::HashData failed: {Marshal.GetLastWin32Error()}");
using (var propertyWriter = ShellFile.FromFilePath(lnkFile).Properties.GetPropertyWriter())
{
propertyWriter.WriteProperty("System.Winx.Hash", BitConverter.ToUInt32(outBytes, 0));
}
}
private static int GetNextMaxGroup()
{
var directories = Directory.GetDirectories(WinXFolder, "Group*", SearchOption.TopDirectoryOnly);
Array.Sort(directories, ReverseSort);
foreach (var path in directories)
{
var s = Path.GetFileName(path)?.Substring(5).Trim();
if (s == null) continue;
int result;
if (int.TryParse(s, out result)) return result+1;
}
return 0;
}
//from: http://blog.coretech.dk/hra/create-shortcut-with-elevated-rights/
private static void ElevateLnk(string lnkFile)
{
using (FileStream fs = new FileStream(lnkFile, FileMode.Open, FileAccess.ReadWrite))
{
fs.Seek(21, SeekOrigin.Begin);
fs.WriteByte(0x22);
}
}
}
WinXHasher.HashLnk(Env.ScriptArgs[0]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment