I'm currently building a small application in C# to assist with configuration of our companies computers after staging them. This to automate some tasks that we currently do manually for no real reason.
One of the steps I'd like to automate is to pin items to the taskbar in Windows 10. We currently use the following powershell script, which can perform this task:
Param($Target)
$KeyPath1 = "HKCU:\SOFTWARE\Classes"
$KeyPath2 = "*"
$KeyPath3 = "shell"
$KeyPath4 = "{:}"
$ValueName = "ExplorerCommandHandler"
$ValueData = (Get-ItemProperty("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\" +
"Explorer\CommandStore\shell\Windows.taskbarpin")).ExplorerCommandHandler
$Key2 = (Get-Item $KeyPath1).OpenSubKey($KeyPath2, $true)
$Key3 = $Key2.CreateSubKey($KeyPath3, $true)
$Key4 = $Key3.CreateSubKey($KeyPath4, $true)
$Key4.SetValue($ValueName, $ValueData)
$Shell = New-Object -ComObject "Shell.Application"
$Folder = $Shell.Namespace((Get-Item $Target).DirectoryName)
$Item = $Folder.ParseName((Get-Item $Target).Name)
$Item.InvokeVerb("{:}")
$Key3.DeleteSubKey($KeyPath4)
if ($Key3.SubKeyCount -eq 0 -and $Key3.ValueCount -eq 0) {
$Key2.DeleteSubKey($KeyPath3)
}
I've attempted to import this powershellscript in C#, but can't seem to call it from within a function. When I try, windows throws various errors, and the items are not pinned to taskbar.
I've done the full idiot path and tried to enter it using strings and then using Powershell.Create() with those strings to replicate what the script does, to no avail.
Does anyone see some way to translate what this script does to C#? Or know of an alternative method to pin items to taskbar in windows 10 ?
Note: I'd like for the App to remain standalone - so I can't make calls to a network file. If possible, I'd also like to have this as a portable exe (using Costura.Fody NuGet Package), So I'd like to avoid just putting the script in the same folder and running it from C#, or use an installer.
edit: found a workable, albeit rather idiotic solution. I created a string[] containing the script mentioned above, then used streamwriter to create a .ps1 with the entire script, and executed that with Powershell.create. I then used another powershell.create to delete the file. Clunky, but workeable.
Pintotaskbar.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Management.Automation;
using System.Text;
namespace ConfiguratorLibrary
{
public class PinToTaskBar
{
private string itempath;
public string pinitem
{
get { return itempath; }
set { itempath = value; }
}
public string Pin()
{
string[] psscript = { "$Target = ("+"\u0022" + $"{itempath}" + "\u0022" + ")" , "\n\r" , "$KeyPath1 = " + "\"HKCU:\\SOFTWARE\\Classes\"", "$KeyPath2 = " +"\"*\"", "$KeyPath3 = " + "\"shell\"",
"$KeyPath4 = " + "\"{:}\"", "$ValueName = " + "\"ExplorerCommandHandler\"", "$ValueData = (Get-ItemProperty(" + "\"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\\"" + " + " + "\"Explorer\\CommandStore\\shell\\Windows.taskbarpin\"" + ")).ExplorerCommandHandler",
"\r\n", "$Key2 = (Get-Item $KeyPath1).OpenSubKey($KeyPath2, $true)", "$Key3 = $Key2.CreateSubKey($KeyPath3, $true)","$Key4 = $Key3.CreateSubKey($KeyPath4, $true)","$Key4.SetValue($ValueName, $ValueData)", "\r\n",
"$Shell = New-Object -ComObject " + "\"Shell.Application\"", "$Folder = $Shell.Namespace((Get-Item $Target).DirectoryName)","$Item = $Folder.ParseName((Get-Item $Target).Name)",
"$Item.InvokeVerb("+ "\"{:}\"" + ")", "\r\n", "$Key3.DeleteSubKey($KeyPath4)", "if ($Key3.SubKeyCount -eq 0 -and $Key3.ValueCount -eq 0) {","$Key2.DeleteSubKey($KeyPath3)",
"}"};
StringBuilder psout = new StringBuilder();
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\pinitemstotaskbar.ps1"))
{
foreach (string line in psscript)
{
file.WriteLine(line);
}
}
using (PowerShell ps = PowerShell.Create())
{
ps.AddScript(@"cd C:\");
ps.AddScript("Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force ");
ps.AddScript(@".\pinitemstotaskbar.ps1");
ps.AddScript("rm pinitemstotaskbar.ps1");
Collection<PSObject> scriptoutput = ps.Invoke();
foreach (PSObject psoutp in scriptoutput)
{
if(psoutp != null)
{
psout.Append(psoutp);
}
else
{
psout.Append("Error");
}
}
String output = psout.ToString();
return output;
}
}
}
}
Forgot to mention: This Method takes the full path to the .exe of the application you wish to input as string.
Example, inputting string @"C:\Windows\system32\Notepad.exe" as property Pinitem and then running the method would pin notepad to the taskbar. I'm currently using it to pin default user apps to the taskbar such as Outlook, Word and Excel - as well as some company-specific apps.