I've ran into this problem when there was a requirement to call a UI enabled program from a NT service. Usually the NT service runs under the Session 0 which means NO UI. So if you tried to invoke a program with a UI then it'll also start under Session 0. While to appear a program on the logged in desktop it has to have the same session as a win logon process is having. So I did a work around and fixed the problem by getting the win logon session ID and launching the process with that session Id. This solution will work on windows Vista, 7 and 8. 

Here is the complete solution class that was used:

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
  
namespace Shared.ApplicationLoaderUtil
{
    /// <summary>
    /// Class that allows running applications with full admin rights. In
    /// addition the application launched will bypass the Vista UAC prompt.
    /// Windows 8 have two OS modes for running application Windows 8 and Windows Vista mode.
    /// </summary>
    public class ApplicationLoader
    {
        /// <summary>
        /// The token duplicate.
        /// </summary>
        private const int TokenDuplicate = 0x0002;
  
        /// <summary>
        /// The maximum allowed.
        /// </summary>
        private const uint MaximumAllowed = 0x2000000;
  
        /// <summary>
        /// The create new console.
        /// </summary>
        private const int CreateNewConsole = 0x00000010;
  
        /// <summary>
        /// The idle priority class.
        /// </summary>
        private const int IdlePriorityClass = 0x40;
  
        /// <summary>
        /// The normal priority class.
        /// </summary>
        private const int NormalPriorityClass = 0x20;
  
        /// <summary>
        /// The high priority class.
        /// </summary>
        private const int HighPriorityClass = 0x80;
  
        /// <summary>
        /// The real time priority class.
        /// </summary>
        private const int RealtimePriorityClass = 0x100;
  
        /// <summary>
        /// The win logon process name.
        /// </summary>
        private const string WinLogonProcessName = "winlogon";
  
        /// <summary>
        /// The toke n_ type.
        /// </summary>
        private enum TokenType
        {
            /// <summary>
            /// The token primary.
            /// </summary>
            TokenPrimary = 1,
  
            /// <summary>
            /// The token impersonation.
            /// </summary>
            TokenImpersonation = 2
        }
  
        /// <summary>
        /// The security impersonation level.
        /// </summary>
        private enum SecurityImpersonationLevel
        {
            /// <summary>
            /// The security anonymous.
            /// </summary>
            SecurityAnonymous = 0,
  
            /// <summary>
            /// The security identification.
            /// </summary>
            SecurityIdentification = 1,
  
            /// <summary>
            /// The security impersonation.
            /// </summary>
            SecurityImpersonation = 2,
  
            /// <summary>
            /// The security delegation.
            /// </summary>
            SecurityDelegation = 3,
        }
  
        /// <summary>
        /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
        /// </summary>
        /// <param name="applicationName">The name of the application to launch</param>
        /// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param>
        /// <returns>true or false</returns>
        public static bool StartProcessAndBypassUAC(string applicationName, out ProcessInformation procInfo)
        {
            uint winlogonPid = 0;
            IntPtr userTokenDup = IntPtr.Zero;
            IntPtr processPtr = IntPtr.Zero;
            IntPtr ptoken = IntPtr.Zero;
            procInfo = new ProcessInformation();
  
            // obtain the currently active session id; every logged on user in the system has a unique session id
            uint sessionId = WTSGetActiveConsoleSessionId();
  
            // obtain the process id of the winlogon process that is running within the currently active session
            Process[] processes = Process.GetProcessesByName(WinLogonProcessName);
            foreach (Process p in processes)
            {
                if ((uint)p.SessionId == sessionId)
                {
                    winlogonPid = (uint)p.Id;
                }
            }
  
            // obtain a handle to the winlogon process
            processPtr = OpenProcess(MaximumAllowed, false, winlogonPid);
  
            // obtain a handle to the access token of the winlogon process
            if (!OpenProcessToken(processPtr, TokenDuplicate, ref ptoken))
            {
                CloseHandle(processPtr);
                return false;
            }
  
            // Security attribute structure used in DuplicateTokenEx and CreateProcessAsUser
            // I would prefer to not have to use a security attribute variable and to just
            // simply pass null and inherit (by default) the security attributes
            // of the existing token. However, in C# structures are value types and therefore
            // cannot be assigned the null value.
            SecurityAttributes sa = new SecurityAttributes();
            sa.Length = Marshal.SizeOf(sa);
  
            // copy the access token of the winlogon process; the newly created token will be a primary token
            if (!DuplicateTokenEx(ptoken, MaximumAllowed, ref sa, (int)SecurityImpersonationLevel.SecurityIdentification, (int)TokenType.TokenPrimary, ref userTokenDup))
            {
                CloseHandle(processPtr);
                CloseHandle(ptoken);
                return false;
            }
  
            // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
            // the window station has a desktop that is invisible and the process is incapable of receiving
            // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
            // interaction with the new process.
            Startupinfo si = new Startupinfo();
            si.Cb = (int)Marshal.SizeOf(si);
            si.Desktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
  
            // flags that specify the priority and creation method of the process
            const int CreationFlags = NormalPriorityClass | CreateNewConsole;
  
            var path = Path.GetFullPath(applicationName);
            var dir = Path.GetDirectoryName(path);
  
            // create a new process in the current user's logon session
            bool result = CreateProcessAsUser(
                userTokenDup,           // client's access token
                path,                   // file to execute
                string.Format("\"{0}\" {1}", applicationName.Replace("\"", "\"\""), string.Empty),        // command line
                ref sa,                 // pointer to process SECURITY_ATTRIBUTES
                ref sa,                 // pointer to thread SECURITY_ATTRIBUTES
                false,                  // handles are not inheritable
                CreationFlags,        // creation flags
                IntPtr.Zero,            // pointer to new environment block
                dir,                    // name of current directory
                ref si,                 // pointer to STARTUPINFO structure
                out procInfo);          // receives information about new process
                 
            if (!result)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
  
            // invalidate the handles
            CloseHandle(processPtr);
            CloseHandle(ptoken);
            CloseHandle(userTokenDup);
  
            return result; // return the result
        }
  
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr snapshot);
  
        /// <summary>
        /// Creates the process as user.
        /// </summary>
        /// <param name="token">The token.</param>
        /// <param name="applicationName">Name of the application.</param>
        /// <param name="commandLine">The command line.</param>
        /// <param name="processAttributes">The process attributes.</param>
        /// <param name="threadAttributes">The thread attributes.</param>
        /// <param name="inheritHandle">if set to <c>true</c> [inherit handle].</param>
        /// <param name="creationFlags">The creation flags.</param>
        /// <param name="environment">The environment.</param>
        /// <param name="currentDirectory">The current directory.</param>
        /// <param name="startupInfo">The startup info.</param>
        /// <param name="processInformation">The process information.</param>
        /// <returns>
        /// true or false
        /// </returns>
        [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern bool CreateProcessAsUser(
            IntPtr token,
            string applicationName,
            string commandLine,
            ref SecurityAttributes processAttributes,
            ref SecurityAttributes threadAttributes,
            bool inheritHandle,
            int creationFlags,
            IntPtr environment,
            string currentDirectory,
            ref Startupinfo startupInfo,
            out ProcessInformation processInformation);
  
        /// <summary>
        /// Duplicates the token ex.
        /// </summary>
        /// <param name="existingTokenHandle">The existing token handle.</param>
        /// <param name="desiredAccess">The dw desired access.</param>
        /// <param name="threadAttributes">The lp thread attributes.</param>
        /// <param name="tokenType">Type of the token.</param>
        /// <param name="impersonationLevel">The impersonation level.</param>
        /// <param name="duplicateTokenHandle">The duplicate token handle.</param>
        /// <returns>true or false</returns>
        [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
        private static extern bool DuplicateTokenEx(
            IntPtr existingTokenHandle,
            uint desiredAccess,
            ref SecurityAttributes threadAttributes,
            int tokenType,
            int impersonationLevel,
            ref IntPtr duplicateTokenHandle);
  
        [DllImport("kernel32.dll")]
        private static extern uint WTSGetActiveConsoleSessionId();
  
        /// <summary>
        /// Opens the process.
        /// </summary>
        /// <param name="desiredAccess">The dw desired access.</param>
        /// <param name="inheritHandle">if set to <c>true</c> [b inherit handle].</param>
        /// <param name="processId">The dw process id.</param>
        /// <returns>integer pointer</returns>
        [DllImport("kernel32.dll")]
        private static extern IntPtr OpenProcess(uint desiredAccess, bool inheritHandle, uint processId);
  
        /// <summary>
        /// Opens the process token.
        /// </summary>
        /// <param name="processHandle">The process handle.</param>
        /// <param name="desiredAccess">The desired access.</param>
        /// <param name="tokenHandle">The token handle.</param>
        /// <returns>true or false</returns>
        [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity]
        private static extern bool OpenProcessToken(IntPtr processHandle, int desiredAccess, ref IntPtr tokenHandle);
  
        /// <summary>
        /// The process information.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct ProcessInformation
        {
            /// <summary>
            /// The process.
            /// </summary>
            public IntPtr Process;
  
            /// <summary>
            /// The thread.
            /// </summary>
            public IntPtr Thread;
  
            /// <summary>
            /// The process id.
            /// </summary>
            public uint ProcessId;
  
            /// <summary>
            /// The thread id.
            /// </summary>
            public uint ThreadId;
        }
  
        /// <summary>
        /// The security attributes.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct SecurityAttributes
        {
            /// <summary>
            /// The length.
            /// </summary>
            public int Length;
  
            /// <summary>
            /// The lp security descriptor.
            /// </summary>
            public IntPtr SecurityDescriptor;
  
            /// <summary>
            /// The b inherit handle.
            /// </summary>
            public bool InheritHandle;
        }
  
        /// <summary>
        /// The startupinfo.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct Startupinfo
        {
            /// <summary>
            /// The cb.
            /// </summary>
            public int Cb;
  
            /// <summary>
            /// The lp reserved.
            /// </summary>
            public string Reserved;
  
            /// <summary>
            /// The desktop.
            /// </summary>
            public string Desktop;
  
            /// <summary>
            /// The title.
            /// </summary>
            public string Title;
  
            /// <summary>
            /// The dw x.
            /// </summary>
            public uint X;
  
            /// <summary>
            /// The y.
            /// </summary>
            public uint Y;
  
            /// <summary>
            /// The x size.
            /// </summary>
            public uint XSize;
  
            /// <summary>
            /// The y size.
            /// </summary>
            public uint YSize;
  
            /// <summary>
            /// The x count chars.
            /// </summary>
            public uint XCountChars;
  
            /// <summary>
            /// The y count chars.
            /// </summary>
            public uint YCountChars;
  
            /// <summary>
            /// The fill attribute.
            /// </summary>
            public uint FillAttribute;
  
            /// <summary>
            /// The flags.
            /// </summary>
            public uint Flags;
  
            /// <summary>
            /// The show window.
            /// </summary>
            public short ShowWindow;
  
            /// <summary>
            /// The reserved 2.
            /// </summary>
            public short Reserved2;
  
            /// <summary>
            /// The lp reserved 2.
            /// </summary>
            public IntPtr LpReserved2;
  
            /// <summary>
            /// The std input.
            /// </summary>
            public IntPtr StdInput;
  
            /// <summary>
            /// The std output.
            /// </summary>
            public IntPtr StdOutput;
  
            /// <summary>
            /// The std error.
            /// </summary>
            public IntPtr StdError;
        }
    }
}

Hope this will help someone with the similar requirement.