I am Jakoby
I am Jakoby

Reputation: 617

How to get path of shortcut's icon file?

Is there a way to get the path of an .ico of a short cut? I know how to change the shortcuts icon, but how do I find the path of the shortcut's icon file?

Upvotes: 1

Views: 3940

Answers (2)

not2qubit
not2qubit

Reputation: 17027

I couldn't get Theo's code to work, for some reason. I think it was the RegEx. So I modified it for clarity and more info. However, it only works for links. In addition we didn't really address OP question to actually extract and get the icon file, that is embedded.

Put the following in your $PROFILE (or load as external *.ps1 function.).

function Get-ShortcutIcon {
    $private:Path = $args[0]

    $ws = New-Object -ComObject WScript.Shell
    $sc = $ws.CreateShortcut($Path)

    $scInd = 0                              # Default to 0
    $scLoc = $sc.IconLocation               # C:\Windows\System32\shell32.dll,164
    $scTar = $sc.TargetPath                 # "C:\Windows\System32\control.exe"
    $scArg = $sc.Arguments                  # "ncpa.cpl"

    if ($scLoc -match '^(.+),(\d+)') {
        # C:\Windows\System32\shell32.dll,164
        $scLoc  = [string]$matches[1]       # C:\Windows\System32\shell32.dll
        $scInd  = [int]$matches[2]          # 164
    }

    $Tar    = "  {0,-20} : " -f "Shortcut Target"           # $scTar
    $Arg    = "  {0,-20} : " -f "Shortcut Arguments"        # $scArg
    $Loc    = "  {0,-20} : " -f "Icon Location"             # $scLoc
    $Ind    = "  {0,-20} : " -f "Icon Location Index"       # $scInd

    Write-Host -f Yellow "`nFile Icon info:`n"
    Write-Host -f DarkGray "$Tar" -Non;     Write-Host -f White "$scTar"    # 
    Write-Host -f DarkGray "$Arg" -Non;     Write-Host -f Gray "$scArg" # 
    Write-Host -f DarkGray "$Loc" -Non;     Write-Host -f DarkYellow "$scLoc"   # 
    Write-Host -f DarkGray "$Ind" -Non;     Write-Host -f DarkYellow "$scInd"   # 
    
    # Clean up
    $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sc)
    $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ws)
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
    Write-Host
}

Set-Alias -Name GetIcon -Value Get-ShortcutIcon -Description 'lnk icon' -Scope Local -Option ReadOnly, Private

The output for a shortcut looks like this:

Icon Location Index

Drawback / Issues

  • Can't be used for *.exe files
  • Doesn't actually extract or find the embedded icon file.

Upvotes: 1

Theo
Theo

Reputation: 61188

You could use below function.
It handles both 'regular' shrotcut files (.lnk) as well as Internet shortcut files (.url)

function Get-ShortcutIcon {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [Alias('FullName')]
        [string]$Path  # needs to be an absulute path
    )
    switch ([System.IO.Path]::GetExtension($Path)) {
        '.lnk'  {
            $WshShell = New-Object -ComObject WScript.Shell
            $shortcut = $WshShell.CreateShortcut($Path)
            $iconPath = $shortcut.IconLocation
            $iconInfo = if ($iconPath -match '^,(\d+)') {
                [PsCustomObject]@{ IconPath = $shortcut.TargetPath; IconIndex = [int]$matches[1] }
            }
            else {
                [PsCustomObject]@{ IconPath = $iconPath; IconIndex = 0 }
            }

            # clean up
            $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shortcut)
            $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WshShell)
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()

            # return the icon information
            $iconInfo
        }
        '.url' {
            $content = Get-Content -Path $Path -Raw
            $iconPath  = [regex]::Match($content, '(?im)^\s*IconFile\s*=\s*(.*)').Groups[1].Value
            $iconIndex = [regex]::Match($content, '(?im)^\s*IconIndex\s*=\s*(\d+)').Groups[1].Value
            [PsCustomObject]@{ IconPath = $iconPath; IconIndex = [int]$iconIndex }
        }
        default { Write-Warning "'$Path' does not point to a '.lnk' or '.url' shortcut file.." }
    }
}

Upvotes: 4

Related Questions