running every shortcut in the start menu

What do you think of this? As a test I’m trying to run every shortcut in the start menu for 5 seconds. But the targetpath from CreateShortcut() doesn’t give what I want for certain shortcuts, like Adobe Reader, Microsoft Office, or TightVNC. (Some windows don’t close, and you have to cancel any elevation prompts.)

Adobe Reader XI.lnk C:\Windows\Installer{AC76BA86-7AD7-1033-7B44-AB0000000001}\SC_Reader.ico
Word 2016.lnk C:\Windows\Installer{90160000-0011-0000-1000-0000000FF1CE}\wordicon.exe
Excel 2016.lnk C:\Windows\Installer{90160000-0011-0000-1000-0000000FF1CE}\xlicons.exe
TightVNC Viewer.lnk C:\Windows\Installer{D2372F87-7DA2-47F7-A102-AF2181B8EAA2}\viewer.ico

# https://gist.github.com/DBremen/54403d02c24e303cb5f1

$sh = New-Object -ComObject WScript.Shell


# ls *.lnk | foreach { runshort $_ }
# $args | 

ls -r 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\*.lnk' |

foreach { 
  $lnk = $_
  # must be full path, or wrong subdir
  $shortcut = $sh.CreateShortcut($lnk)
  $targetpath = $shortcut.TargetPath
  $arguments = $shortcut.Arguments
    
  "lnk $lnk targetpath $targetpath arguments $arguments"
  
  if ($targetpath -notmatch 'pdf$|html?$|url$|txt$'){     
    $prog = [Diagnostics.Process]::Start($targetpath,$arguments)
    $end = (get-date) + '0:0:15' # timeout 15 seconds
      while ($prog.MainWindowHandle -eq 0 -and (get-date) -lt $end){ # wait for window
      sleep -Milliseconds 100
    }
    sleep 5
    $prog.kill()
  }

}

not sure if this will help from http://www.computerperformance.co.uk/powershell/powershell_function_shortcut.htm

Function Get-StartMenu{
Begin{
Clear-Host
$Path = “$Env:ProgramData\Microsoft\Windows\Start Menu\Programs”
$x=0
} # End of Begin
Process {
$StartMenu = Get-ChildItem $Path -Recurse -Include *.lnk
ForEach($ShortCut in $StartMenu) {
$Shell = New-Object -ComObject WScript.Shell
$Properties = @{
ShortcutName = $Shortcut.Name
LinkTarget = $Shell.CreateShortcut($Shortcut).targetpath
}
New-Object PSObject -Property $Properties
$x ++
} #End of ForEach
[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
} # End of Process
End{
"`nStart Menu items = $x "
}
}
#Example of function in action:

Get-StartMenu | Sort ShortcutName | Ft LinkTarget -Auto

Thanks, but that’s basically the same thing.

yes but when I ran it I got the correct shortcut link returned. Don’t as me why :slight_smile:

It works most of the time, just not with those shortcuts that you can’t see the properties for with the mouse, like Adobe Reader or Microsoft Word.

Mmm I just has a look at my adobe in the start menu and it looks like a shortcut in explorer

Right click the shortcut for adobe reader and look at the target. Mine just says “Adobe Reader XI (11.0.20)”, and it’s greyed out, instead of being a path to the real .exe file, “C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe”.

Search for “MSI advertised shortcuts”. These links point to the installation msi. Once clicked the system will check if everything is like it is supposed to, repair it if it’s not and then start the application.

What’s the actual purpose of this script?

Just to test that everything launches without error.

I can get the target of an msi shortcut in vbscript:

set msi = CreateObject("WindowsInstaller.Installer")
Set MSITarget = msi.ShortcutTarget('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2016\Word 2016.lnk')
MsgBox msi.ComponentPath(MSITarget.StringData(1), MSITarget.StringData(3))

But somehow it doesn’t translate easily to powershell.

$Msi = New-Object -ComObject WindowsInstaller.Installer
$MSITarget = $Msi.ShortcutTarget('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2016\Word 2016.lnk')
$Msi.ComponentPath($MSITarget.StringData[1], $MSITarget.StringData[3])

Cannot index into a null array.
At line:1 char:1
+ $Msi.ComponentPath($MSITarget.StringData[1], $MSITarget.StringData[3] ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

I tried this too:

$Msi = New-Object -ComObject WindowsInstaller.Installer
$Msi.GetType().InvokeMember('ShortcutTarget', 'InvokeMethod', $Null, $Msi, @('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2016\Word 2016.lnk'))

Exception calling "InvokeMember" with "5" argument(s): "Member not found. (Exception from HRESULT: 0x80020003
(DISP_E_MEMBERNOTFOUND))"
At line:1 char:78
+ ... ll, $Msi, @('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Mic ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : COMException

I dont have the windows installer module install atm but the bottom answer to this link may help so not tested.

https://superuser.com/questions/263505/how-do-i-find-the-target-of-an-advertised-shortcut

https://github.com/heaths/psmsi

Here’s my kludge solution:

# fix msi shortcuts
if ($targetpath -match 'c:\\windows\\installer') {
    $targetpath = cscript /nologo $PSScriptRoot\getrealtarget.vbs $lnk
}