8

How do you pin to start special folders using powershell? Like "ThisPC", iexplorer

This will pin to start exe's fine, but what about windows explorer and myComputer? How to pin those items since they have no target?

Given this

 <start:DesktopApplicationTile Size="2x2" Column="0" Row="0" DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows System\This PC.lnk" />

It seems to have issues with .lnk's for "This PC", "File Explorer", etc

Function PinLnk
{
    Param
    (
        [Parameter(Mandatory,Position=0)]
        [Alias('p')]
        [String[]]$Path
    )
    $Shell = New-Object -ComObject Shell.Application
    $Desktop = $Shell.NameSpace(0X0)
    $WshShell = New-Object -comObject WScript.Shell
    $Flag=0
    Foreach($itemPath in $Path)
    {
        $itemName = Split-Path -Path $itemPath -Leaf
        #pin application to windows Start menu
        $ItemLnk = $Desktop.ParseName($itemPath)
        $ItemVerbs = $ItemLnk.Verbs()
        Foreach($ItemVerb in $ItemVerbs)
        {
            If($ItemVerb.Name.Replace("&","") -match "Pin to Start")
            {
                $ItemVerb.DoIt()
                $Flag=1
            }
        }
    }
}
PinLnk "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe"

I tried this approach as well still not pinning mycomputer to start

PS C:\WINDOWS\system32> Function PinLnk14
>> {
>>
>> $shell = new-object -com Shell.Application
>> $folder = $shell.NameSpace("shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}") # ssfDRIVES
>> $ItemVerbs=$folder.Self.Verbs()
>>         Foreach($ItemVerb in $ItemVerbs)
>>         {
>>             Write-Output $ItemVerb.Name
>>             If($ItemVerb.Name.Replace("&","") -match "Pin to Start")
>>             {
>> Write-Output "TRYING TO PIN"
>>                 $ItemVerb.DoIt()
>>             }
>>         }
>>     }
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> Pinlnk14
&Open
Pin to Quick access
Mana&ge
&Pin to Start
TRYING TO PIN
Map &network drive...
Dis&connect network drive...
Create &shortcut
&Delete
Rena&me
P&roperties
nlstack01
  • 789
  • 2
  • 7
  • 30
  • I read once that those special folders are accessed through GUIDs: see https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx – Dennis Kuypers Aug 14 '17 at 20:25
  • *"This will pin to start exe's fine"*... which is exactly what 'My Computer' (explorer) and Internet Explorer (iexplore.exe) are. What __exactly__ are you trying to do that did not work? – gravity Aug 14 '17 at 20:30
  • @gravity if I am given SomePath\ThisPC.lnk. How do I find the target to this path to give to the function above? – nlstack01 Aug 14 '17 at 20:33
  • When you replace `PinLnk (location)` with your `.lnk` file, _what happened?_ Why are you not referencing the *source program/file* as opposed to a `.lnk` file which just points to the file directly anyway? Why the redundancy? – gravity Aug 14 '17 at 20:35
  • @gravity for these types of .lnk it says $ItemVerbs = $ItemLnk.Verbs() is null – nlstack01 Aug 14 '17 at 21:00
  • You need to debug your input and figure out why one of your many `$item` variables is returning nothing. – gravity Aug 14 '17 at 21:30

1 Answers1

7

Most special folders are accessible using special values, documented here: ShellSpecialFolderConstants enumeration

So, if you want to get the My Computer (a.k.a. "This PC") folder, you can do this:

$shell = new-object -com Shell.Application
$folder = $shell.NameSpace(17) # "ssfDRIVES" constant

And this will get you a Folder object.

There is another way wich uses the folder CLSID (a guid). It will allow you to get to any folder in what's called the shell namespace, even the ones that may not be defined in the enumeration above (3rd party shell namespace extensions for example). The syntax is this:

$shell = new-object -com Shell.Application
$folder = $shell.Namespace("shell:::{CLSID}")

In fact, this funny syntax combines the 'shell:' URI moniker with the shell namespace parsing syntax ::{CLSID}.

So for example to get the My Computer folder, you would do use the constant known as CLSID_MyComputer like this:

$shell = new-object -com Shell.Application
$folder = $shell.Namespace("shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")

This will also work:

$shell = new-object -com Shell.Application
$folder = $shell.Namespace("shell:MyComputerFolder") # direct shell: syntax

And it should bring you back the same object as in the previous call. They're all equivalent.

Once you have a Folder object, there is a last trick to get the associated verbs, because the Verbs() method is only defined on the FolderItem object. To get the FolderItem from the Folder (as a Folder is also an "item" in the namespace, so it has also a FolderItem facade), you can use the Self property, like this:

$shell = new-object -com Shell.Application
$folder = $shell.NameSpace("shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}") # ssfDRIVES
$folder.Self.Verbs()

Ok, that was to get verbs for a FolderItem. To pin an item to start however, the "Pin to Start" verb invocation does not always work (for My Computer for example), or the verb isn't even available (for a standard folder for example). In general, it doesn't really work well for folders for some reason.

So, one solution for folders is to first create a shortcut file (.lnk) somewhere to that folder (including My Computer or other special locations), and pin that shortcut file to start. Note: the standard (non language localized) verb for Pin to Start is "PinToStartScreen", it's better to use that than to scan various verbs (all verbs have a canonical name). So the code would look like this to pin My Computer to start:

$wshell = new-object -com WScript.Shell
$shortcut = $wshell.CreateShortcut("c:\temp\mypc.lnk")
$shortcut.TargetPath = "shell:MyComputerFolder" # use the same syntax as described above
$shortcut.Save()

$shell = new-object -com Shell.Application
$folder = $shell.NameSpace("c:\temp")
$lnk = $folder.ParseName("mypc.lnk") # get the shortcut file
$lnk.InvokeVerb("PinToStartScreen") # invoke "Pin To Start" on the shortcut file

The fact is that's exactly what Windows does when we do "Pin to Start" on My Computer, it creates a shortcut in C:\Users\<my user>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • thanks for the response. I updated the post. Finding the verb is now working fine, but pinning is not happening using .DoIt(). Nothing happens – nlstack01 Aug 18 '17 at 01:43
  • Unfortunately still cant get it to Pin. It creates the shortcut fine, but no pinning takes place. I tried creating the shortcut in C:\Users\\AppData\Roaming\Microsoft\Windows\Start Menu\Programs as well – nlstack01 Aug 18 '17 at 14:08
  • 1
    @nlstack01 - Mhhh... it works for me (Windows 10 - 64b). Make sure your powershell app runs with the same bitness as Windows. You can check that using `[Environment]::Is64BitProcess` in powershell. You can also try the original approach with verbs scanning and DoIt() call. – Simon Mourier Aug 18 '17 at 14:59