在 Windows 10 中使用 PS 将程序(带参数)固定到任务栏

2024-03-28

我可以使用下面的代码将程序固定到 Windows 10 任务栏(感谢this https://stackoverflow.com/questions/31720595/pin-program-to-taskbar-using-ps-in-windows-10/34182076#34182076StackOverflow 问题)。但是,如果我尝试向程序添加命令行参数(如下例所示),它将不起作用。代码似乎假定目标可执行文件没有任何参数。

$Target = "`"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe`" --proxy-server=192.168.1.2:8080"
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)
}

2021年编辑:

从本质上讲,我的函数所做的就是使用从 shell.application ComObject 调用的“pin”动词。这在 2020 年我写答案时曾经有效,但现在似乎已经过时了。

    $Shell = New-Object -ComObject "Shell.Application"
    $Folder = $Shell.Namespace((Get-Item $ShortcutPath).DirectoryName)
    $Item = $Folder.ParseName((Get-Item $ShortcutPath).Name)
    $Item.InvokeVerb("pin")

几年前有一个官方的 Windows API 可以做到这一点,但它也被删除了。

原答案

这是一个将执行以下操作的函数:

  • 使用提供的完整路径创建临时快捷方式。
  • 添加参数/图标/热键和描述(如果有)
  • 调用临时快捷方式上的固定动词来创建固定项目。

固定的项目将引用您的应用程序,而不是临时快捷方式(无论如何,该快捷方式已被删除)

使用时只需填写参数即可(仅Path为必填项)

使用所有参数和泼溅的示例

$PinParams = @{
    Path         = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
    Arguments    = '-incognito'
    Name         = 'Chrome Incognito'
    Description  = 'Launch Chrome (Incognito)'
    Hotkey       = 'ALT+CTRL+K'
    IconLocation = 'C:\Windows\system32\shell32.dll,22'
    RunAsAdmin   =  $true
}
New-PinnedItem @PinParams 

简单的例子

New-PinnedItem -Arguments '-incognito' -Path 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'

仅支持所有项目的名称$env:Path/ 安装的应用程序

New-PinnedItem -Path 'notepad.exe' # Works because c:\windows\system32 is in $env:path
New-PinnedItem -Path 'chrome.exe' # Works because install path in installed appliation
New-PinnedItem -Path 'chrome' # Automatically assume *.exe if no extension provided

支持启动Powershell命令

# Internet options CPL
$inetcpl = @{
  Command      = { Start-Process inetcpl.cpl }
  Name         = 'inetcpl'
  IconLocation = 'C:\Windows\system32\shell32.dll,99'
}

# Win + R
New-PinnedItem @inetcpl

$runcmd = @{
  Command      = { $obj = New-Object -ComObject Shell.Application; $obj.FileRun() }
  Name         = 'Run'
  IconLocation = 'C:\Windows\system32\shell32.dll,25'
}
New-PinnedItem @runcmd 

#Multiline will automatically be converted to single line behind the scene.
New-PinnedItem -name 'test' -Command {
  Write-Host 'test'
  pause
} -WindowStyle Normal

--

功能定义

Function New-PinnedItem {
    [CmdletBinding()]
    param (
        [ValidateScript( { $_.IndexOfAny([System.IO.Path]::GetInvalidFileNameChars()) -eq -1 })]
        [Parameter(ParameterSetName = 'Path')]
        [Parameter(Mandatory, ParameterSetName = 'Command')]
        [String]$Name,
        [Parameter(Mandatory, ParameterSetName = 'Path')]
        [ValidateNotNullOrEmpty()]
        [String]$Path,
        [Parameter(Mandatory, ParameterSetName = 'Command')]
        [scriptblock]$Command,
        [ValidateSet('Normal', 'Minimized', 'Maximized')]
        [String]$WindowStyle = 'Normal',
        [String]$Arguments,
        [String]$Description,
        [String]$Hotkey,
        [String]$IconLocation,
        [Switch]$RunAsAdmin,
        [String]$WorkingDirectory,
        [String]$RelativePath
    )

    $pinHandler = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\Windows.taskbarpin" -Name "ExplorerCommandHandler"
    New-Item -Path "HKCU:Software\Classes\*\shell\pin" -Force | Out-Null
    Set-ItemProperty -LiteralPath "HKCU:Software\Classes\*\shell\pin" -Name "ExplorerCommandHandler" -Type String -Value $pinHandler

    if ($PSCmdlet.ParameterSetName -eq 'Command') {
        #$Path = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
        $Path = "powershell.exe"
        $Arguments = ('-NoProfile -Command "&{{{0}}}"' -f ($Command.ToString().Trim("`r`n") -replace "`r`n", ';'))
        if (!$PsBoundParameters.ContainsKey('WindowStyle')) {
            $WindowStyle = 'Minimized'
        }
    }
    $NoExtension = [System.IO.Path]::GetExtension($path) -eq ""    
    if (!(Test-Path -Path $Path)) {
        if ($NoExtension) {
            $Path = "$Path.exe"
            
        }
        $Found = $False
        $ShortName = [System.IO.Path]::GetFileNameWithoutExtension($path)
        # testing against installed programs (Registry)
        $loc = Get-ChildItem HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
        $names = ($loc | foreach-object { Get-ItemProperty $_.PsPath }).Where( { ![String]::IsNullOrWhiteSpace($_.InstallLocation) })
        $InstallLocations1, $InstallLocations2 = $names.Where( { $_.DisplayName -Like "*$ShortName*" }, 'split') 
        $InstallLocations1 = $InstallLocations1 | Select -ExpandProperty InstallLocation
        $InstallLocations2 = $InstallLocations2 | Select -ExpandProperty InstallLocation
        Foreach ($InsLoc in $InstallLocations1) {
            if (Test-Path -Path "$Insloc\$path") {
                $Path = "$Insloc\$path"
                $Found = $true
                break
            }
        }
        if (! $found) {
            $Result = $env:Path.split(';').where( { Test-Path -Path "$_\$Path" }, 'first') 
            if ($Result.count -eq 1) { $Found = $true }
        }

        # Processing remaining install location (less probable outcome)
        if (! $found) {
            Foreach ($InsLoc in $InstallLocations2) {
                if (Test-Path -Path "$Insloc\$path") {
                    $Path = "$Insloc\$path"
                    $Found = $true
                    exit for
                }
            }
        }

        if (!$found) {
            Write-Error -Message "The path $Path does not exist"
            return 
        }

    }


    if ($PSBoundParameters.ContainsKey('Name') -eq $false) {
        $Name = [System.IO.Path]::GetFileNameWithoutExtension($Path)
    }

    $TempFolderName = "tmp$((48..57 + 97..122| get-random -Count 4 |% {[char][byte]$_}) -join '')"
    $TempFolderPath = "$env:temp\$TempFolderName"
    $ShortcutPath = "$TempFolderPath\$Name.lnk"
    [Void](New-Item -ItemType Directory -Path $TempfolderPath)


    if ($Path.EndsWith(".lnk")) {
        Copy-Item -Path $Path -Destination $ShortcutPath
        $obj = New-Object -ComObject WScript.Shell 
        $link = $obj.CreateShortcut($ShortcutPath) 
    }
    else {
        $obj = New-Object -ComObject WScript.Shell 
        $link = $obj.CreateShortcut($ShortcutPath) 
        $link.TargetPath = $Path
    }

    switch ($WindowStyle) {
        'Minimized' { $WindowstyleID = 7 }
        'Maximized' { $WindowstyleID = 3 }
        'Normal' { $WindowstyleID = 1 }
    }

    $link.Arguments = $Arguments
    $Link.Description = $Description
    if ($PSBoundParameters.ContainsKey('IconLocation')) { $link.IconLocation = $IconLocation }
    $link.Hotkey = "$Hotkey"
    $link.WindowStyle = $WindowstyleID
    if ($PSBoundParameters.ContainsKey('WorkingDirectory')) { $link.WorkingDirectory = $WorkingDirectory }
    if ($PSBoundParameters.ContainsKey('RelativePath')) { $link.RelativePath = $RelativePath }
    $link.Save()

    if ($RunAsAdmin) {
        $bytes = [System.IO.File]::ReadAllBytes($ShortcutPath)
        $bytes[0x15] = $bytes[0x15] -bor 0x20 #set byte 21 (0x15) bit 6 (0x20) ON
        [System.IO.File]::WriteAllBytes($ShortcutPath, $bytes)
    }

    $Shell = New-Object -ComObject "Shell.Application"
    $Folder = $Shell.Namespace((Get-Item $ShortcutPath).DirectoryName)
    $Item = $Folder.ParseName((Get-Item $ShortcutPath).Name)
    $Item.InvokeVerb("pin")

    Remove-Item -LiteralPath  "HKCU:Software\Classes\*\shell\pin\" -Recurse   
    Remove-item -path $ShortcutPath
    Remove-Item -Path $TempFolderPath 
    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$shell)
    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$obj)
}

总之,根据您的需要,您可以这样称呼它:

New-PinnedItem -Path 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' -Arguments '--proxy-server=192.168.1.2:8080'

其他注意事项

看起来固定某些东西时需要考虑两件事。

  • 应用程序的完整路径
  • 流传下来的论据

其他参数对于 PIN 操作无关紧要。 使用同一组完整路径和参数调用的任何 PIN 操作都将与其他引脚以及引脚(如果未找到)或取消固定(如果找到)进行比较,而不考虑名称/图标位置/热键/等...

请注意,如果您使用该函数来固定已打开的项目(例如:Chrome),如果路径/参数匹配,则将在当前实例上执行固定/取消固定操作,这意味着它可能看起来好像不起作用但如果您查看打开的应用程序的固定状态(或关闭它),您应该会看到行为从取消固定更改为固定或固定更改为取消固定(如果已固定)

补充笔记

引脚数据存储在 2 个位置

  • HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband
  • $env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar

您可以通过使用它们轻松交换 2 个或更多引脚的任务栏。

这是一段代码,用于以十六进制/字符串形式查看最喜欢的数据

$Bytes = Get-ItemPropertyValue -LiteralPath  "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband\" -name  'Favorites'
# Data as Hex
[System.BitConverter]::ToString($bytes) 

# A look at the data
[System.Text.Encoding]::UTF8.GetString($Bytes)

参考

[MS-SHLLINK]:Shell 链接 (.LNK) 二进制文件格式 https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943?redirectedfrom=MSDN

创建以管理员身份运行快捷方式 https://stackoverflow.com/a/29002207/934946

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Windows 10 中使用 PS 将程序(带参数)固定到任务栏 的相关文章

随机推荐

  • requestAnimationFrame 仅被调用一次

    我正在尝试在 Ionic 2 应用程序中使用 ThreeJS 实现非常基本的动画 基本上是尝试旋转一个立方体 但立方体没有旋转 因为 requestAnimationFrame 仅在渲染循环内执行一次 I m able to see onl
  • 如何设置 Eclipse CDT 使用 GCC-4 而不是 GCC?

    如何设置 Eclipse CDT 使用 GCC 4 而不是 GCC 我问这个问题是因为我使用 Windows 64 位和 Cygwin 而 gcc exe 不起作用 我需要配置 Eclipse CDT 以使用 gcc 4 exe 但我不知道
  • 将 CSV 文件或 Excel 电子表格转换为 RESX 文件

    我正在寻找针对我遇到的问题的解决方案或建议 我有一堆需要本地化的 ASPX 页面 还有一堆需要支持 6 种语言的文本 进行翻译的人员无法访问 Visual Studio 最简单的工具可能是 Excel 如果我们使用 Excel 甚至导出到
  • 带有 firebase crashlytics 的 Hermes 包的反应本机源图

    我想从react native应用程序中读取crashlytics报告 但它在firebase控制台中根本不可读 Android 的崩溃示例如下所示 Non fatal Exception io invertase firebase cra
  • 使用 AST 解析器提取类实现的接口

    我正在使用 AST 解析器编译项目源代码 我可以通过什么方式提取类层次结构信息 即它是否正在实现任何接口或从另一个类扩展 您可以访问TypeDeclaration节点并从中获取类型绑定 ITypeBinding typeBind typDe
  • Scala,让我的循环更加实用

    我正在尝试减少像 Java 一样编写 Scala 2 8 的程度 这是我遇到的问题的简化 您能否对我的解决方案提出 更实用 的改进建议 变换地图 val inputMap mutable LinkedHashMap 1 gt a 2 gt
  • 在 Bash 中执行时间戳比较的最佳方法是什么

    我有一个警报脚本 我试图阻止它向我发送垃圾邮件 因此我想设置一个条件 如果在过去一小时内发送了警报 则不再发送警报 现在我有一个 cron 作业 每分钟检查一次条件 因为我需要在满足条件时快速收到警报 但我不需要每分钟都收到电子邮件 直到问
  • Spark - 是否可以控制分区到节点的放置?

    在 Spark 中 自定义Partitioner可以为 RDD 提供 通常 生成的分区会随机分配给一组工作人员 例如 如果我们有 20 个分区和 4 个工作线程 则每个工作线程将 大约 获得 5 个分区 然而 放置分区到工作节点 节点 看起
  • 将 ChartPanel 添加到 JPanel

    我这里有一些不起作用的代码 XYSeriesCollection dataset new XYSeriesCollection dataset addSeries series JFreeChart chart ChartFactory c
  • Angularjs:理解递归指令

    我在这里找到了一个很棒的树指令 原来的 http jsfiddle net n8dPm http jsfiddle net n8dPm 我一直试图通过其他几个问题来理解它的功能 1 https stackoverflow com quest
  • 如何在表单应用程序中获取参数?

    我可以找到许多有关如何在控制台应用程序中获取参数的示例 但我似乎找不到如何在 Windows 窗体应用程序中获取参数的示例 我想关注以下事情 每当我打开 jpg 文件时 Windows 都会启动我的应用程序 我想知道我的应用程序中 jpg
  • AWS Lambda 和 AWS API Gateway:如何发送二进制文件?

    我有一个 lambda 函数 它使用事件中的输入键从 s3 获取文件 并需要将其发送到客户端 我正在使用以下函数从 s3 获取文件 function getObject key var params Bucket my bucket Key
  • PouchDb.get(id,{attachments: true}) 在 Android 上不返回数据

    我正在使用 PouchDb 无复制 开发一个 Ionic 应用程序 我能够成功地存储带有附件的数据 为了检索数据 我使用下面的控制器片段来调用 angularjs 工厂中的 get 函数 pouchDbManager getData cur
  • 春云流兔的退避设置

    我仍在使用rabbitmq和spring云消息传递设置示例消息传递系统 但遇到了错误 或者我误解了文档 使用spring boot版本2 0 3 RELEASE 为了这个例子 我想要以下设置 spring cloud stream rabb
  • 如何将具有多个依赖项的 C 库编译到 Python 包中? Cmake?

    我在 python3 x 中有一个 Python 包 我一直在编写它 它与 C 库中的两个 C 函数交互 目前 我一直在使用ctypes我直接链接到共享库 so 然后使用 python 脚本与之交互 https docs python or
  • 为协作者使用 git 存储库的最佳方式是什么?

    一般来说 为协作者使用存储库的最佳方式是什么 我们应该只从主存储库中推送和拉取 还是为每个协作者创建一个分支 然后在适当的时候进行合并 如果这是一个愚蠢 基本的问题 我深表歉意 git noob 在这里 谢谢 Git 支持许多不同的工作流程
  • 无法将搜索栏拖动到滚动视图内

    如果这个问题在其他地方得到了回答 我深表歉意 我找不到任何有同样问题的人 我将 SeekBar 添加到位于嵌套 ScrollView 内的relativelayout 但是 我无法拖动搜索栏的拇指 我可以沿着其路径单击来更改其值 但无法拖动
  • 模板类的模板成员函数的类外定义的语法

    template
  • 无法计算表达式,因为代码已优化或本机框架位于调用堆栈顶部

    我正在开发一个网站 用户可以在该网站上提交一些信息 提交信息后 我尝试同时发送两封邮件 一封发送给我的销售团队 一封发送给我网站上的访问者 在发送邮件时 我在使用重定向到另一个页面时收到以下错误Response Redirect http
  • 在 Windows 10 中使用 PS 将程序(带参数)固定到任务栏

    我可以使用下面的代码将程序固定到 Windows 10 任务栏 感谢this https stackoverflow com questions 31720595 pin program to taskbar using ps in win