Create shortcuts with PowerShell: New-Shortcut

Discussion in 'Scripting' started by GodHand, Jan 5, 2019.

  1. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    417
    465
    10
    New-Shortcut is an advanced PowerShell function that allows one to easily create shortcuts from any application. These shortcuts can be elevated (Run as Administrator) or not. Once created, the function outputs a custom object detailing the newly created shortcut with its set parameters.

    Elevation can be added to any created shortcut by using the -Elevated switch. Elevation is enabled by using the .NET classes ReadAllBytes and WriteAllBytes to change the appropriate offset bit and not the terribly inefficient (and extremely slow) FileStream and BinaryWriter which use internal buffers.

    All parameters, other than -TargetApplication, are optional and can be customized to whatever suits your needs. You can change the default name of the shortcut, add a comment description, set any arguments for the shortcut to pass to the target application, set a hotkey, etc:

    [​IMG]
    [​IMG]
    [​IMG]

    Or you can quickly create a shortcut using the pipeline:
    [​IMG]
    [​IMG]
    Code:
    Function New-Shortcut
    {
        <#
        .SYNOPSIS
            Easily create shortcuts from any application.
        
        .DESCRIPTION
            Creates shorcuts that can be elevated or not from any application, outputting a custom PowerShell object detailing the newly created shortcut and any parameters set to it.
        
        .PARAMETER TargetApplication
            The full path to the target application the shortcut will point to.
        
        .PARAMETER OutputDirectory
            The full path to the directory where the shortcut will be created. If no output directory is supplied, the shortcut will be created in the same location as the target application.
        
        .PARAMETER Name
            The name of the shortcut. By default the target application name is used for the shortcut name.
        
        .PARAMETER Description
            A comment describing the details of the shortcut.
        
        .PARAMETER Arguments
            Any special arguments the shortcut will pass to the target application.
        
        .PARAMETER WorkingDirectory
            The full path of the directory the target application uses during execution.
        
        .PARAMETER HotKey
            A hotkey combination that can be used to execute the shortcut.
        
        .PARAMETER WindowStyle
            The windows style of the target application - Normal, Maximized or Minimized.
        
        .PARAMETER IconPath
            The full path and optional integer value of the icon file to use for the shortcut. Example: 'imageres.dll,-1023'
        
        .PARAMETER Elevated
            Sets the shortcut to run with administrative privileges.
        
        .EXAMPLE
            PS C:\> New-Shortcut -TargetApplication "C:\Tools and Utilities\Registry Workshop\RegWorkshop64.exe" -OutputDirectory "$HOME\Desktop" -Name "Registry Workshop" -Description "An advanced registry editor." -Elevated
            PS C:\> New-Shortcut -TargetApplication "C:\Tools and Utilities\Notepad++\notepad++.exe" -HotKey Ctrl+Alt+N
            PS C:\> "D:\Imaging Tools\Deployment\imagex.exe | New-Shortcut
        
        .OUTPUTS
            PSCustomObject
        #>
        [CmdletBinding()]
        [OutputType([PSCustomObject])]
        Param
        (
            [Parameter(Mandatory = $true,
                ValueFromPipeline = $true,
                ValueFromPipelineByPropertyName = $true,
                HelpMessage = 'The full path to the target application the shortcut will point to.')]
            [ValidateScript( { Test-Path (Resolve-Path -Path $_).Path })]
            [ValidateNotNullOrEmpty()]
            [string]$TargetApplication,
            [Parameter(HelpMessage = 'The full path to the directory where the shortcut will be created.')]
            [string]$OutputDirectory,
            [Parameter(HelpMessage = 'The name of the shortcut. By default the target application name is used for the shortcut name.')]
            [string]$Name,
            [Parameter(HelpMessage = 'A comment describing the details of the shortcut.')]
            [string]$Description,
            [Parameter(HelpMessage = 'Any special arguments the shortcut will pass to the target application.')]
            [string]$Arguments,
            [Parameter(HelpMessage = 'The full path of the directory the target application uses during execution.')]
            [string]$WorkingDirectory,
            [Parameter(HelpMessage = 'A hotkey combination that can be used to execute the shortcut.')]
            [string]$HotKey,
            [Parameter(HelpMessage = 'The windows style of the target application.')]
            [ValidateSet('Normal', 'Maximized', 'Minimized')]
            [string]$WindowStyle = 'Normal',
            [Parameter(HelpMessage = 'The full path and integer value to the icon file to use for the shortcut.')]
            [string]$IconPath,
            [Parameter(HelpMessage = 'Sets the shortcut to run with administrative privileges.')]
            [switch]$Elevated
        )
        
        Begin
        {
            $Offset = 0x15
        }
        Process
        {
            If ($Name)
            {
                $ShortcutName = [System.IO.Path]::ChangeExtension($Name, '.lnk')
            }
            Else
            {
                $ShortcutName = [System.IO.Path]::ChangeExtension($(Split-Path -Path $TargetApplication -Leaf), '.lnk')
            }
            If (!$OutputDirectory)
            {
                $ShortcutPath = Join-Path -Path (Split-Path -Path $TargetApplication -Parent) -ChildPath $ShortcutName
            }
            Else
            {
                $ShortcutPath = Join-Path -Path $OutputDirectory -ChildPath $ShortcutName
            }
            Switch ($WindowStyle)
            {
                'Normal' { [int]$WindowStyle = 1 }
                'Maximized' { [int]$WindowStyle = 3 }
                'Minimized' { [int]$WindowStyle = 7 }
            }
            Try
            {
                $ObjShell = New-Object -ComObject WScript.Shell
                $Shortcut = $ObjShell.CreateShortcut($ShortcutPath)
                $Shortcut.TargetPath = $TargetApplication
                $Shortcut.WorkingDirectory = $WorkingDirectory
                $Shortcut.Description = $Description
                $Shortcut.Arguments = $Arguments
                $Shortcut.WindowStyle = $WindowStyle
                $Shortcut.HotKey = $HotKey
                If ($IconPath)
                {
                    $Shortcut.IconLocation = $IconPath
                }
                $Shortcut.Save()
                If ($Elevated)
                {
                    $Bytes = [System.IO.File]::ReadAllBytes($ShortcutPath)
                    $Bytes[$Offset] = $Bytes[$Offset] -bor 0x20
                    [System.IO.File]::WriteAllBytes($ShortcutPath, $Bytes)
                    [bool]$Elevated = $true
                }
                Else
                {
                    [bool]$Elevated = $false
                }
                $Result = [PSCustomObject]@{
                    Name        = $ShortcutName
                    Directory   = (Split-Path -Path $ShortcutPath -Parent)
                    Application = (Split-Path -Path $TargetApplication -Leaf)
                    Description = $Description
                    Arguments   = $Arguments
                    HotKey      = $HotKey
                    Elevated    = $Elevated
                } | Format-List
            }
            Catch
            {
                $PSCmdlet.ThrowTerminatingError($_)
            }
            Finally
            {
                [void][Runtime.InteropServices.Marshal]::ReleaseComObject($ObjShell)
            }
        }
        End
        {
            If ($Result)
            {
                Return $Result
            }
        }
    }