How to set "Run as administrator" flag on shortcut created by MSI installer

bernhof picture bernhof · Jul 11, 2011 · Viewed 35.7k times · Source

I have a Setup and Deployment project in Visual Studio 2010.

I would like the installer to create two shortcuts to the executable of another project in my solution. One normal shortcut that simply runs the application using current credentials and another which has the Run as administrator flag set, thereby ensuring that the user is asked for credentials with administrative rights when clicking the shortcut.

Set "Run as administrator flag" on shortcut

Running the application with administrative rights enables certain features that are otherwise not available.

Setting this flag doesn't seem to be possible at first glance. Can this be done directly in Visual Studio? If not, are there any other options?

Edit: If not, is it possible to modify the shortcut programmatically using a custom installer class?

Answer

Daz picture Daz · Sep 3, 2012

I know this is quite an old question, but I needed to find an answer and I thought I could help other searchers. I wrote a small function to perform this task in VBScript (pasted below). It is easily adapted to VB.net / VB6.

Return codes from function:
0 - success, changed the shortcut.
99 - shortcut flag already set to run as administrator.
114017 - file not found
114038 - Data file format not valid (specifically the file is way too small)
All other non-zero = unexpected errors.


As mentioned by Chada in a later post, this script will not work on msi Advertised shortcuts. If you use this method to manipulate the bits in the shortcut, it must be a standard, non-advertised shortcut.

References: MS Shortcut LNK format: http://msdn.microsoft.com/en-us/library/dd871305
Some inspiration: Read and write binary file in VBscript

Please note that the function does not check for a valid LNK shortcut. In fact you can feed it ANY file and it will alter Hex byte 15h in the file to set bit 32 to on.

If copies the original shortcut to %TEMP% before amending it.

Daz.

'# D.Collins - 12:58 03/09/2012
'# Sets a shortcut to have the RunAs flag set.  Drag an LNK file onto this script to test

Option Explicit

Dim oArgs, ret

Set oArgs = WScript.Arguments

If oArgs.Count > 0 Then
    ret = fSetRunAsOnLNK(oArgs(0))
    MsgBox "Done, return = " & ret
Else
    MsgBox "No Args"
End If

Function fSetRunAsOnLNK(sInputLNK)
    Dim fso, wshShell, oFile, iSize, aInput(), ts, i
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set wshShell = CreateObject("WScript.Shell")
    If Not fso.FileExists(sInputLNK) Then fSetRunAsOnLNK = 114017 : Exit Function
    Set oFile = fso.GetFile(sInputLNK)
    iSize = oFile.Size
    ReDim aInput(iSize)
    Set ts = oFile.OpenAsTextStream()
    i = 0
    Do While Not ts.AtEndOfStream
        aInput(i) = ts.Read(1)
        i = i + 1
    Loop
    ts.Close
    If UBound(aInput) < 50 Then fSetRunAsOnLNK = 114038 : Exit Function
    If (Asc(aInput(21)) And 32) = 0 Then 
        aInput(21) = Chr(Asc(aInput(21)) + 32)
    Else
        fSetRunAsOnLNK = 99 : Exit Function
    End If
    fso.CopyFile sInputLNK, wshShell.ExpandEnvironmentStrings("%temp%\" & oFile.Name & "." & Hour(Now()) & "-" & Minute(Now()) & "-" & Second(Now()))
    On Error Resume Next
    Set ts = fso.CreateTextFile(sInputLNK, True)
    If Err.Number <> 0 Then fSetRunAsOnLNK = Err.number : Exit Function
    ts.Write(Join(aInput, ""))
    If Err.Number <> 0 Then fSetRunAsOnLNK = Err.number : Exit Function
    ts.Close
    fSetRunAsOnLNK = 0
End Function