在Windows 10中使用PowerShell将程序固定到任务栏

52

我正在尝试使用以下代码将程序固定到Windows 10(RTM)任务栏:

$shell = new-object -com "Shell.Application"  
$folder = $shell.Namespace((Join-Path $env:SystemRoot System32\WindowsPowerShell\v1.0))
$item = $folder.Parsename('powershell_ise.exe')
$item.invokeverb('taskbarpin');

这在Windows 8.1上可以运行,但在Windows 10上不再起作用。

如果我执行$item.Verbs(),我会得到以下结果:

Application Parent Name
----------- ------ ----
                   &Open
                   Run as &administrator
                   &Pin to Start

                   Restore previous &versions

                   Cu&t
                   &Copy
                   Create &shortcut
                   &Delete
                   Rena&me
                   P&roperties

正如您所看到的,没有将其固定到任务栏的动词。但是,如果我右键单击该特定文件,则会出现该选项:
Available verbs in UI 问题:
我有什么遗漏吗?
在Windows 10中,是否有一种新的方法可以将程序固定到任务栏?

1
也许这是一个向微软连接的案例?似乎缺少动词!但在注册表中查找似乎存在! - CB.
3
@CB。好主意。这是报告链接:https://connect.microsoft.com/PowerShell/feedbackdetail/view/1609288/pin-to-taskbar-no-longer-working-in-windows-10 虽然我有一种感觉,这可能是故意的,为了防止程序“污染”任务栏? - Daniel Hilgarth
3
可以,但无论如何微软都必须开始记录这种变化!我会在Connect上投赞成票。 - CB.
1
呃...如果这个问题在我们组织迁移到Win10之前没有解决,我将不得不更改几个登录脚本。 - ATek
1
由于ParseName是COM对象而不是PowerShell方法,因此您需要使用小写字母N来调用它,这可能会有所区别。如果我右键单击一个文件夹,我会看到“固定到开始菜单”,但没有“固定到任务栏”。 - Eris
显示剩余7条评论
9个回答

17

非常好!我对该PowerShell示例进行了一些微小的调整,希望你不介意:)

param (
    [parameter(Mandatory=$True, HelpMessage="Target item to pin")]
    [ValidateNotNullOrEmpty()]
    [string] $Target
)
if (!(Test-Path $Target)) {
    Write-Warning "$Target does not exist"
    break
}

$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)
}

1
首先,这太棒了!我有一段时间没有回来看这个帖子了,所以看到有一个PS解决方案我非常高兴。 @Skatterbrainz(或任何人),我对两个细节很好奇。 1:最后,有一个测试,看看在删除动词键之后,shell键是否有任何内容。但是这两个键都是早期创建的。为什么要测试而不是只使用Remove-Item在shell键上使用-recurse? - Gordon
1
如果我使用这段代码,而快捷方式已经被固定在任务栏上,它会被取消固定。我有点希望它能够保持不变,即动词PinToTaskbar的最终结果是当前状态,因此不需要做任何事情。 - Gordon
1
关于#2,我搜索了在HKLM中找到的GUID,并且在HKCR中有一个引用,其中ImplementsVerbs = taskbarpin; taskbarunpin,这解释了切换行为。 - Gordon
1
但它又引出了另一个问题。GUID是固定的吗,还是在不同版本的Win10、不同语言等方面会有所不同?如果它总是相同的,难道不可以直接将其硬编码,而不必先在HKLM中查找吗? - Gordon
3
Windows 10专业版20H2版本出现问题,但没有错误提示,也没有任何变化。我在想是否不小心以未知的方式编辑了注册表。 - Eric Hansen
显示剩余6条评论

9

以下是 Humberto 的 VBScript 解决方案移植到 PowerShell:

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)
}

你好,我正在尝试将您的PowerShell代码放入一个函数中,但是我无法让它正常工作: - WubiUbuntu980 Unity7 Refugee
@WubiUbuntu980Unity7Refugee 有几个需要删除的杂散反引号。我会尝试编辑评论来修复它们。 - fourwhey

9
我有同样的问题,我仍然不知道如何处理它,但是这个小的命令行工具可以解决:http://www.technosys.net/products/utils/pintotaskbar。您可以在命令行中像这样使用它:
syspin "path/file.exe" c:5386

如何将程序固定到任务栏

syspin "path/file.exe" c:5387

要取消它的钉住,请执行以下操作。这对我来说效果很好。

3
考虑到 Technosys EXE 的存在,很可能可以使用一些内联的 C# 代码来编写 PowerShell 脚本。我的情况是商业用途,我正在管理一个会议实验室,我们将会话软件的快捷方式放在任务栏上,并使用 PowerShell 在会话之间进行刷新。如有需要,希望获得一些授权建议。 - Gordon
1
就此而言,许可证的需求源于Technosys EXE未经签名,我宁愿支付签名代码的费用,也不愿要求人们信任未经签名的代码。 - Gordon
1
顶一下。有人找到了在C#中实现这个的方法吗?Technosys想要2000美元来许可这个微小的功能,这似乎过于昂贵了。 - Gordon
请查看此链接(第一个解决方案不太好,但可以使用):https://connect.microsoft.com/PowerShell/feedback/details/1609288/pin-to-taskbar-no-longer-working-in-windows-10 - deru
@Gordon 看看这个答案,了解如何在C#中实现它:https://dev59.com/ylwZ5IYBdhLWcg3wM9_Z#38880235 - AlexDev
显示剩余3条评论

8
在Windows 10中,微软增加了一个简单的检查来显示操作。可执行文件的名称必须是explorer.exe。它可以在任何文件夹中,只需检查名称即可。因此,在C#或任何编译程序中,简单的方法就是将您的程序重命名。
如果无法重命名,您可以欺骗shell对象以认为您的程序被称为explorer.exe。我在这里写了一篇文章(链接),说明如何通过更改PEB中的Image Path在C#中实现这一点。

1
我不是PS专家,但你不能下载链接中的C#代码,编译它并从PS中调用它吗? - AlexDev
1
我可以选择编译路线,但我一直试图保持我的代码可见,并希望它有教育意义。但是在PowerShell中内联C#似乎有些危险,所以我们将看看它的表现如何。谢谢! - Gordon
1
你的项目有任何类型的许可证吗? - Humberto Freitas
1
@HumbertoFreitas MIT许可证 - AlexDev
2
不幸的是,在Windows 10 1903五月更新中,这个技巧停止起作用了。 - GeekUser
显示剩余3条评论

6

很抱歉再次提及旧事。

我不知道如何在PowerShell中实现此操作,但在VBScript中,您可以使用我开发的该方法。它适用于任何系统语言。

适用于Windows 8.x和10。

脚本

If WScript.Arguments.Count < 1 Then WScript.Quit
'----------------------------------------------------------------------
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFile    = WScript.Arguments.Item(0)
sKey1      = "HKCU\Software\Classes\*\shell\{:}\\"
sKey2      = Replace(sKey1, "\\", "\ExplorerCommandHandler")
'----------------------------------------------------------------------
With WScript.CreateObject("WScript.Shell")
    KeyValue = .RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" & _
        "\CommandStore\shell\Windows.taskbarpin\ExplorerCommandHandler")

    .RegWrite sKey2, KeyValue, "REG_SZ"

    With WScript.CreateObject("Shell.Application")
        With .Namespace(objFSO.GetParentFolderName(objFile))
            With .ParseName(objFSO.GetFileName(objFile))
                .InvokeVerb("{:}")
            End With
        End With
    End With

    .Run("Reg.exe delete """ & Replace(sKey1, "\\", "") & """ /F"), 0, True
End With
'----------------------------------------------------------------------

命令行:

pin and unpin: taskbarpin.vbs [fullpath]

Example: taskbarpin.vbs "C:\Windows\notepad.exe"

2
我已经尝试过所有这些建议(ps1,vbs),在Win 10版本1903上均无效。有人对此有最新的消息吗? - julesverne
显然,微软通过这种方式停用了该引脚。我有另一个使用此解决方案方法的脚本,它仍然有效,因此似乎她认为这个引脚形状是一个安全漏洞。此解决方案仍然有效:https://dev59.com/ylwZ5IYBdhLWcg3wM9_Z#34182076 - Humberto Freitas
@julesverne,确实,现在是2022年10月,在Win 10 21H2和Windows 11上,这里的PowerShell或VBScript答案都不起作用(你指出这个问题后已经过去了2年)。请这里提供这些伟大答案的一些天才更新它们以解决Microsoft的问题。提示:此页面上唯一有效的答案是使用syspin.exe,并且该答案上有如何在C#中执行此操作的链接。如果可以将其翻译为PowerShell,则此页面将具有可行的答案(当前此整个页面都是一个陷阱,人们只是浪费时间,因为这里没有任何PowerShell可用)。 - YorSubs

6

警告:此页面上的PowerShell / VBScript答案在Windows 10 21H2或Windows 11上均不适用(自2019年以来,该功能就已经失效)。

我将这一点加粗,以便人们不要在这里浪费时间。希望有人可以更新上面的内容(因为它们是很好的答案,但由于微软进行了更改,所以不再起作用,因此希望对这里的答案进行一些调整以使其再次工作)。由于目前没有已知的方法可以使用PowerShell将应用程序固定到任务栏(因为此页面上的解决方案都不起作用),我所知道的唯一可行解决方案是使用syspin.exe应用程序。请更新PowerShell答案,因为这比使用syspin要好得多。目前(令人遗憾的是),这个页面大多只是一个“诱饵”,人们来到这里,希望找到一个答案,结果却浪费了时间尝试所有都失效的解决方案。


3

参考@Humberto Freitas的回答,我对其进行了修改以达到我的目的,您可以尝试使用此Vbscript在Windows 10中固定程序到任务栏。

Vbscript: TaskBarPin.vbs

Option Explicit
REM Question Asked here ==> 
REM https://dev59.com/ylwZ5IYBdhLWcg3wM9_Z#34182076
Dim Title,objFSO,ws,objFile,sKey1,sKey2,KeyValue
Title = "Pin a program to taskbar using Vbscript in Windows 10"
'----------------------------------------------------------------------
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set Ws     = CreateObject("WScript.Shell")
objFile    = DeQuote(InputBox("Type the whole path of the program to be pinned or unpinned !",Title,_
"%ProgramFiles%\windows nt\accessories\wordpad.exe"))
REM Examples
REM "%ProgramFiles%\Mozilla Firefox\firefox.exe"
REM "%ProgramFiles%\Google\Chrome\Application\chrome.exe"
REM "%ProgramFiles%\windows nt\accessories\wordpad.exe"
REM "%Windir%\Notepad.exe"
ObjFile = ws.ExpandEnvironmentStrings(ObjFile)
If ObjFile = "" Then Wscript.Quit()
sKey1      = "HKCU\Software\Classes\*\shell\{:}\\"
sKey2      = Replace(sKey1, "\\", "\ExplorerCommandHandler")
'----------------------------------------------------------------------
With CreateObject("WScript.Shell")
    KeyValue = .RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" & _
    "\CommandStore\shell\Windows.taskbarpin\ExplorerCommandHandler")
    .RegWrite sKey2, KeyValue, "REG_SZ"
    
    With CreateObject("Shell.Application")
        With .Namespace(objFSO.GetParentFolderName(objFile))
            With .ParseName(objFSO.GetFileName(objFile))
                .InvokeVerb("{:}")
            End With
            
        End With
    End With
    .Run("Reg.exe delete """ & Replace(sKey1, "\\", "") & """ /F"), 0, True
End With
'----------------------------------------------------------------------
Function DeQuote(S)
    If Left(S,1) = """" And Right(S, 1) = """" Then 
        DeQuote = Trim(Mid(S, 2, Len(S) - 2))
    Else 
        DeQuote = Trim(S)
    End If
End Function
'----------------------------------------------------------------------

编辑:2020年12月24日

参考: Windows 10中的Microsoft Edge位于哪里?我该如何启动它?

Microsoft Edge应该在任务栏中,它是蓝色的“e”图标。

Taskbar

如果您没有或取消了固定,您只需要重新固定它。不幸的是,MicrosoftEdge.exe不能通过双击运行,创建普通快捷方式也无法工作。您可能在此位置找到它。

Location

您需要做的就是在开始菜单或搜索栏中搜索Edge。一旦看到Microsoft Edge,请右键单击并固定到任务栏

Search


您可以使用此vbscript运行Microsoft Edge:Run-Micro-Edge.vbs

CreateObject("wscript.shell").Run "%windir%\explorer.exe shell:Appsfolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge"

0
我根据上述答案的启发编写了一个 Powershell 类。我将其放入一个模块中,然后导入到我的其他脚本中。
using module "C:\Users\dlambert\Desktop\Devin PC Setup\PinToTaskbar.psm1"

[PinToTaskBar_Verb] $pin = [PinToTaskBar_Verb]::new();

$pin.Pin("C:\Windows\explorer.exe") 
$pin.Pin("$env:windir\system32\SnippingTool.exe") 
$pin.Pin("C:\Windows\explorer.exe") 
$pin.Pin("C:\Program Files (x86)\Google\Chrome\Application\chrome.exe") 
$pin.Pin("C:\Program Files\Notepad++\notepad++.exe") 
$pin.Pin("$env:windir\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe") 

以下是模块

class PinToTaskBar_Verb 
{
    [string]$KeyPath1  = "HKCU:\SOFTWARE\Classes"
    [string]$KeyPath2  = "*"
    [string]$KeyPath3  = "shell"
    [string]$KeyPath4  = "{:}"
    
    [Microsoft.Win32.RegistryKey]$Key2 
    [Microsoft.Win32.RegistryKey]$Key3
    [Microsoft.Win32.RegistryKey]$Key4

    PinToTaskBar_Verb()
    {
        $this.Key2 = (Get-Item $this.KeyPath1).OpenSubKey($this.KeyPath2, $true)
    }
    

    [void] InvokePinVerb([string]$target)
    {
        Write-Host "Pinning $target to taskbar"
        $Shell = New-Object -ComObject "Shell.Application"
        $Folder = $Shell.Namespace((Get-Item $Target).DirectoryName)
        $Item = $Folder.ParseName((Get-Item $Target).Name)
        $Item.InvokeVerb("{:}")
    }



    [bool] CreatePinRegistryKeys()
    {
        $TASKBARPIN_PATH = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\Windows.taskbarpin";
        $ValueName = "ExplorerCommandHandler"
        $ValueData = (Get-ItemProperty $TASKBARPIN_PATH).ExplorerCommandHandler
        
        Write-Host "Creating Registry Key: $($this.Key2.Name)\$($this.KeyPath3)"
        $this.Key3 = $this.Key2.CreateSubKey($this.KeyPath3, $true)

        Write-Host "Creating Registry Key: $($this.Key3.Name)\$($this.KeyPath4)"
        $this.Key4 = $this.Key3.CreateSubKey($this.KeyPath4, $true)

        Write-Host "Creating Registry Key: $($this.Key4.Name)\$($valueName)"
        $this.Key4.SetValue($ValueName, $ValueData)

        return $true
    }

    [bool] DeletePinRegistryKeys()
    {
        Write-Host "Deleting Registry Key: $($this.Key4.Name)"
        $this.Key3.DeleteSubKey($this.KeyPath4)
        if ($this.Key3.SubKeyCount -eq 0 -and $this.Key3.ValueCount -eq 0) 
        {
            Write-Host "Deleting Registry Key: $($this.Key3.Name)"
            $this.Key2.DeleteSubKey($this.KeyPath3)
        }
        return $true
    }

    [bool] Pin([string]$target)
    {
        try
        {
            $this.CreatePinRegistryKeys()
            $this.InvokePinVerb($target)
        }
        finally
        {
            $this.DeletePinRegistryKeys()
        }
        return $true
    }

}

2
这是否也会从任务栏和Windows 10 20H2版本中取消固定?我尝试过这里所有答案和其他帖子,但无法通过编程方式从Windows 10 20H2取消固定任何内容。想知道您是否了解此事,并且是否有任何已确认可用于使用PS或任何可以从PS运行的C#代码进行编程方式取消固定任务栏的内容。如果没有别的,我想问一下您是否有什么建议。据我所知(并测试),微软更改了某些内容,以便您不能再使用人们编写的方法取消固定。 - Bitcoin Murderous Maniac
1
看起来很酷,但在Win10 Pro 20H2上对我没用。 - Baxorr

-1

我建议使用这个Windows 10功能。它允许人们通过XML文件指定固定程序(和其他内容)。


似乎这个方法行不通:请参见https://superuser.com/a/1117140 - andjelx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接