在 Windows 10 中使用 PS 将程序(带参数)固定到任务栏 [英] Pin program (with parameters) to Taskbar using PS in Windows 10

查看:59
本文介绍了在 Windows 10 中使用 PS 将程序(带参数)固定到任务栏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以使用以下代码将程序固定到 Windows 10 任务栏(感谢 这个 StackOverflow 问题).但是,如果我尝试向程序添加命令行参数,如下例所示,它不起作用.代码似乎假定目标可执行文件没有任何参数.

I am able to pin programs to the Windows 10 Taskbar using the below code (thanks to this StackOverflow question). However, if I try to add a command-line parameter to the program, like the example below, it doesn't work. It seems like the code presumes the target executable doesn't have any parameters.

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

推荐答案

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

Here's a function that will do the following:

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

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

The pinned item will reference your application and not the temporary shortcut (which has been deleted by then anyway)

使用时填写参数即可(Only Path为必填项)

To use, just fill out the parameters (Only Path is mandatory)

使用所有参数的示例喷溅

$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/已安装应用程序中的所有项目的名称

Support for name only for all items in $env:Path / installed application

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
    )
    $NoExtension = [System.IO.Path]::GetExtension($path) -eq ""
    $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'
        }
    }

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

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

To conclude, for your needs, you'd call it like this:

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

其他注意事项

看起来固定某些东西时需要考虑两件重要的事情.

It looks like there is two things important to consider when pinning something.

  • 应用程序的完整路径
  • 传递的参数

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

Other parameters are inconsequential to the PIN action. Any PIN action called with the same set of full path and arguments will be compared to other pins and either pin (if not found) or unpinned (if found) without consideration for Name / IconLocation / Hotkey / etc...

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

Note that if you use the function to pin an item which is already open (eg: Chrome), the pin / unpin action will be performed on the current instance if the path / arguments match, meaning it could appear as if didn't worked but if you look at the pin status of the opened app (or close it), you should see that the behavior changed from unpinned to pinned or pinned to unpinned (if already pinned)

附加说明

Pin 数据存储在 2 个位置

Pin Data is stored in 2 locations

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

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

You could easily swap 2 taskbars set of pin or more by making use of them.

这是一段代码,用于以十六进制/字符串形式查看收藏夹数据

Here's a snippet on code to view the favorite data as Hex / string

$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 Link (.LNK) 二进制文件格式

创建以管理员身份运行的快捷方式

这篇关于在 Windows 10 中使用 PS 将程序(带参数)固定到任务栏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆