Contains helper methods for user impersonation.
        /// <summary>
        /// Impersonates the specified user.
        /// </summary>
        /// <param name="domainUser">The domain user.</param>
        /// <param name="processFilter">Predicate to find the process suitable for impersonation. If it's <see langword="null"/>, the first <paramref name="domainUser"/>'s process will be used.</param>
        /// <returns>
        /// Impersonated context.
        /// </returns>
        /// <exception cref="ArgumentNullException"><paramref name="domainUser"/> is <see langword="null"/> or empty.</exception>
        /// <exception cref="ArgumentException"><paramref name="domainUser"/> is not in the <c>DOMAIN\username</c> format.</exception>
        /// <exception cref="InvalidOperationException">
        /// No processes are running for the <paramref name="domainUser"/>.
        ///     <para>-or-</para>
        /// Process handle cannot be duplicated.
        /// </exception>
        /// <remarks>
        /// This method looks for the existing <paramref name="domainUser"/> process running in the system, obtains and duplicates
        /// its token, and uses it to impersonate the caller. So it won't work, if the user is logged out or has no processes running.
        /// </remarks>
        public static WindowsImpersonationContext Impersonate(string domainUser, Predicate <Process> processFilter)
        {
            if (string.IsNullOrEmpty(domainUser))
            {
                throw new ArgumentNullException(nameof(domainUser));
            }

            // Process returned by the ProcessHelper.FindUserProcesses may already be closed, so we want to retry.
            return(RetryHelper.Retry(
                       () =>
            {
                using (Process process = ProcessHelper.FindUserProcesses(domainUser).FirstOrDefault(p => processFilter == null || processFilter(p)))
                {
                    if (process == null)
                    {
                        throw new InvalidOperationException("No suitable user processes found.");
                    }

                    return WindowsIdentity.Impersonate(Impersonator.DuplicateProcessHandle(process));
                }
            },
                       Impersonator.DefaultRetryCount,
                       Impersonator.DefaultRetryDelay,
                       new[] { typeof(InvalidOperationException) }));
        }
        /// <summary>
        /// Impersonates the currently logged on user in the current thread context.
        /// </summary>
        /// <returns>Impersonation context.</returns>
        public static WindowsImpersonationContext ImpersonateCurrentUser()
        {
            try
            {
                return(Impersonator.Impersonate(UserHelper.LoggedOnUser));
            }
            catch
            {
                // Exception might occur, if we have outdated username information.
                // Maybe, that user has logged out. So, try to find a new username.
                string previousUserName = UserHelper.LoggedOnUser;
                string newUserName      = UserHelper.GetCurrentUser();

                // If username is the same, don't retry.
                if (string.Equals(previousUserName, newUserName, StringComparison.OrdinalIgnoreCase))
                {
                    throw;
                }

                UserHelper.LoggedOnUser = newUserName;
            }

            return(Impersonator.Impersonate(UserHelper.LoggedOnUser));
        }
 /// <summary>
 /// Impersonates the specified user within the <c>Explorer</c> process context.<br/>
 /// <c>Explorer</c> process is vital for the system and should always be there, if the user is logged in.
 /// </summary>
 /// <param name="domainUser">The domain user.</param>
 /// <returns>
 /// Impersonated context.
 /// </returns>
 /// <exception cref="ArgumentNullException"><paramref name="domainUser"/> is <see langword="null"/> or empty.</exception>
 /// <exception cref="ArgumentException"><paramref name="domainUser"/> is not in the <c>DOMAIN\username</c> format.</exception>
 /// <exception cref="InvalidOperationException">
 /// No processes are running for the <paramref name="domainUser"/>.
 ///     <para>-or-</para>
 /// Process handle cannot be duplicated.
 /// </exception>
 /// <seealso cref="Impersonate(string,Predicate{Process})"/>
 public static WindowsImpersonationContext Impersonate(string domainUser)
 {
     return(Impersonator.Impersonate(domainUser, p => p.ProcessName.Equals("explorer", StringComparison.OrdinalIgnoreCase)));
 }