Suplantar usuario en el servicio de Windows

Estoy tratando de suplantar a un usuario de dominio en un servicio de Windows con el servicio conectado como la cuenta del sistema local.

Hasta ahora, solo puedo hacer que esto funcione al iniciar sesión en el servicio y configurar el proceso utilizando las credenciales de usuario, como las siguientes.

        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.FileName = CommandDetails.Command;
        startInfo.WorkingDirectory = Settings.RoboCopyWorkingDirectory;
        startInfo.Arguments = commandLine;

        startInfo.UseShellExecute = false;
        startInfo.CreateNoWindow = true;
        startInfo.RedirectStandardError = true;
        startInfo.RedirectStandardOutput = true;

        // Credentials
        startInfo.Domain = ImperDomain;
        startInfo.UserName = ImperUsername;
        startInfo.Password = ImperPasswordSecure;

        process = Process.Start(startInfo);

Mi objetivo es no tener el registro de servicio en un usuario de dominio, sino más bien como sistema local, ya que las contraseñas de las cuentas de dominio se restablecen.

Cuando uso el sistema local, obtengoAcceso denegado

¿Alguna idea de cómo lograr esto?

StackTace

Access is denied

   at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
   at System.Diagnostics.Process.Start()
   at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
   at Ace.WindowsService.ProcessCmd.ProcessCommand.StartProcess(ProcessStartInfo startInfo) in 

He intentado envolver el código en el código de Suplantación que se detalla a continuación sin éxito.

Código de suplantación

public class Impersonation2 : IDisposable
{
    private WindowsImpersonationContext _impersonatedUserContext;

    // Declare signatures for Win32 LogonUser and CloseHandle APIs
    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LogonUser(
      string principal,
      string authority,
      string password,
      LogonSessionType logonType,
      LogonProvider logonProvider,
      out IntPtr token);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool RevertToSelf();

    // ReSharper disable UnusedMember.Local
    enum LogonSessionType : uint
    {
        Interactive = 2,
        Network,
        Batch,
        Service,
        NetworkCleartext = 8,
        NewCredentials
    }
    // ReSharper disable InconsistentNaming
    enum LogonProvider : uint
    {
        Default = 0, // default for platform (use this!)
        WinNT35,     // sends smoke signals to authority
        WinNT40,     // uses NTLM
        WinNT50      // negotiates Kerb or NTLM
    }
    // ReSharper restore InconsistentNaming
    // ReSharper restore UnusedMember.Local

    /// <summary>
    /// Class to allow running a segment of code under a given user login context
    /// </summary>
    /// <param name="user">domain\user</param>
    /// <param name="password">user's domain password</param>
    public Impersonation2(string domain, string username, string password)
    {
        var token = ValidateParametersAndGetFirstLoginToken(username, domain, password);

        var duplicateToken = IntPtr.Zero;
        try
        {
            if (DuplicateToken(token, 2, ref duplicateToken) == 0)
            {
                throw new Exception("DuplicateToken call to reset permissions for this token failed");
            }

            var identityForLoggedOnUser = new WindowsIdentity(duplicateToken);
            _impersonatedUserContext = identityForLoggedOnUser.Impersonate();
            if (_impersonatedUserContext == null)
            {
                throw new Exception("WindowsIdentity.Impersonate() failed");
            }
        }
        finally
        {
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (duplicateToken != IntPtr.Zero)
                CloseHandle(duplicateToken);
        }
    }

    private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain, string username, string password)
    {


        if (!RevertToSelf())
        {
            throw new Exception("RevertToSelf call to remove any prior impersonations failed");
            ErrorLogger.LogEvent("RevertToSelf call to remove any prior impersonations failed", System.Diagnostics.EventLogEntryType.Error, "");

        }

        IntPtr token;

        var result = LogonUser(domain, username,
                               password,
                               LogonSessionType.Interactive,
                               LogonProvider.Default,
                               out token);
        if (!result)
        {
            var errorCode = Marshal.GetLastWin32Error();
            ErrorLogger.LogEvent(string.Format("Could not impersonate the elevated user.  LogonUser: {2}\\{1} returned error code: {0}.", errorCode, username, domain), System.Diagnostics.EventLogEntryType.Error, "");
            throw new Exception("Logon for user " + username + " failed.");
        }
        return token;
    }

    public void Dispose()
    {
        // Stop impersonation and revert to the process identity
        if (_impersonatedUserContext != null)
        {
            _impersonatedUserContext.Undo();
            _impersonatedUserContext = null;
        }
    }

Actualizar

Esto funciona bien si solo lo estoy ejecutando si solo lo estoy ejecutando. Pero cuando se ejecuta como un servicio, no funcionará

Actualización 2

No obtengo el acceso denegado del Proceso. Comience cuando cambie el inicio de sesión de suplantación a LogonSessionType.NewCredentials y elimine las credenciales del proceso. Pero ahora veo un error al ejecutar el comando robocopy. Cuando tengo las credenciales en el proceso, no produce un archivo de registro del comando robocopy

Error

2016/07/16 09:19:12 ERROR 5 (0x00000005) 
Accessing Source Directory \\[server]\[path]\
Access is denied.

Cambio

var result = LogonUser(domain, username,
   password,
   LogonSessionType.NewCredentials,
   LogonProvider.Default,
   out token);

Actualización 3

Las funciones de copiar y mover están funcionando. Pero crear subproceso no lo es. He estado jugando con CreateProcessAsUser como ha sugerido Hary Johnston.

Respuestas a la pregunta(1)

Su respuesta a la pregunta