webentwicklung-frage-antwort-db.com.de

Verwenden von Process.Start () zum Starten eines Prozesses als anderer Benutzer innerhalb eines Windows-Dienstes

Ich möchte regelmäßig ein beliebiges .NET-Programm unter einem angegebenen Benutzerkonto von einem Windows-Dienst ausführen. 

Bisher habe ich meinen Windows-Dienst mit Logik ausgeführt, um zu entscheiden, was der Zielprozess ist und wann er ausgeführt werden soll. Der Zielprozess wird auf folgende Weise gestartet:

  1. Der Windows-Dienst wird mit "Administrator" -Anmeldeinformationen gestartet.
  2. Wenn die Zeit kommt, wird ein .NET-Zwischenprozess mit Argumenten ausgeführt, die angeben, welcher Prozess gestartet werden soll (Dateiname, Benutzername, Domäne, Kennwort).
  3. Dieser Prozess erstellt ein neues System.Diagnostics.Process, ordnet ein ProcessStartInfo-Objekt zu, das mit den übergebenen Argumenten gefüllt ist, und ruft dann Start () für das Prozessobjekt auf.

Wenn das erste Mal dies geschieht, wird der Zielprozess fehlerfrei ausgeführt und dann normal geschlossen . Jedes Mal, wenn der Zielprozess gestartet wird, wird jedoch der Fehler "Die Anwendung konnte nicht ordnungsgemäß initialisieren (0xc0000142)" ausgelöst werden. Durch einen Neustart des Windows-Dienstes kann der Prozess erneut erfolgreich ausgeführt werden (für die erste Ausführung).

Ziel ist es natürlich, den Zielprozess jedes Mal erfolgreich auszuführen.

Zu Schritt 2 oben: Um einen Prozess als anderen Benutzer auszuführen, ruft .NET die win32-Funktion CreateProcessWithLogonW auf. Diese Funktion erfordert ein Fensterhandle, um den angegebenen Benutzer anzumelden. Da der Windows-Dienst nicht im interaktiven Modus ausgeführt wird, hat er kein Fensterhandle. Dieser Zwischenprozess löst das Problem, da er ein Fensterhandle hat, das an den Zielprozess übergeben werden kann.

Bitte keine Vorschläge zur Verwendung von psexec oder dem Windows-Taskplaner. Ich habe mein Los im Leben angenommen, und dazu gehört auch die Lösung des Problems auf die oben angegebene Weise.

34
Matt Jacobsen

Ich scheine eine funktionierende Implementierung (Works On My Machine (TM)) für die folgenden Szenarien zu haben:

Batch-Datei, .NET Console Assembly, .NET Windows Forms-Anwendung.

Hier ist wie:

Ich habe einen Windows-Dienst, der als Administratorbenutzer ausgeführt wird. Ich füge dem Administratorbenutzer die folgenden Richtlinien hinzu:

  • Melden Sie sich als Dienst an 
  • Handeln Sie als Teil des Betriebssystems
  • Passen Sie die Speicherkontingente für einen Prozess an 
  • Ersetzen Sie ein Token auf Prozessebene

Diese Richtlinien können hinzugefügt werden, indem Sie Systemsteuerung/Verwaltung/Lokale Sicherheitsrichtlinie/Zuweisung von Benutzerrechten öffnen. Sobald sie festgelegt sind, werden die Richtlinien erst beim nächsten Anmelden wirksam. Sie können einen anderen Benutzer anstelle des Administrators verwenden, was die Sache ein bisschen sicherer macht :)

Jetzt verfügt mein Windows-Dienst über die erforderlichen Berechtigungen, um Jobs als andere Benutzer zu starten. Wenn ein Job gestartet werden muss, führt der Dienst eine separate Assembly ("Starter" .NET Console Assembly) aus, die den Prozess für mich initiiert.

Der folgende Code, der sich im Windows-Dienst befindet, führt meine Assembly "Starter" aus:

Process proc = null;
System.Diagnostics.ProcessStartInfo info;
string domain = string.IsNullOrEmpty(row.Domain) ? "." : row.Domain;
info = new ProcessStartInfo("Starter.exe");
info.Arguments = cmd + " " + domain + " " + username + " " + password + " " + args;
info.WorkingDirectory = Path.GetDirectoryName(cmd);
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
proc = System.Diagnostics.Process.Start(info);

Die Konsolenbaugruppe startet dann den Zielprozess über Interop-Aufrufe:

class Program
{
    #region Interop

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
        public UInt32 LowPart;
        public Int32 HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID_AND_ATTRIBUTES
    {
        public LUID Luid;
        public UInt32 Attributes;
    }

    public struct TOKEN_PRIVILEGES
    {
        public UInt32 PrivilegeCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public LUID_AND_ATTRIBUTES[] Privileges;
    }

    enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin,
        TokenElevationType,
        TokenLinkedToken,
        TokenElevation,
        TokenHasRestrictions,
        TokenAccessInformation,
        TokenVirtualizationAllowed,
        TokenVirtualizationEnabled,
        TokenIntegrityLevel,
        TokenUIAccess,
        TokenMandatoryPolicy,
        TokenLogonSid,
        MaxTokenInfoClass
    }

    [Flags]
    enum CreationFlags : uint
    {
        CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
        CREATE_DEFAULT_ERROR_MODE = 0x04000000,
        CREATE_NEW_CONSOLE = 0x00000010,
        CREATE_NEW_PROCESS_GROUP = 0x00000200,
        CREATE_NO_WINDOW = 0x08000000,
        CREATE_PROTECTED_PROCESS = 0x00040000,
        CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
        CREATE_SEPARATE_WOW_VDM = 0x00001000,
        CREATE_SUSPENDED = 0x00000004,
        CREATE_UNICODE_ENVIRONMENT = 0x00000400,
        DEBUG_ONLY_THIS_PROCESS = 0x00000002,
        DEBUG_PROCESS = 0x00000001,
        DETACHED_PROCESS = 0x00000008,
        EXTENDED_STARTUPINFO_PRESENT = 0x00080000
    }

    public enum TOKEN_TYPE
    {
        TokenPrimary = 1,
        TokenImpersonation
    }

    public enum SECURITY_IMPERSONATION_LEVEL
    {
        SecurityAnonymous,
        SecurityIdentification,
        SecurityImpersonation,
        SecurityDelegation
    }

    [Flags]
    enum LogonFlags
    {
        LOGON_NETCREDENTIALS_ONLY = 2,
        LOGON_WITH_PROFILE = 1
    }

    enum LOGON_TYPE
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK,
        LOGON32_LOGON_BATCH,
        LOGON32_LOGON_SERVICE,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT,
        LOGON32_LOGON_NEW_CREDENTIALS
    }

    enum LOGON_PROVIDER
    {
        LOGON32_PROVIDER_DEFAULT,
        LOGON32_PROVIDER_WINNT35,
        LOGON32_PROVIDER_WINNT40,
        LOGON32_PROVIDER_WINNT50
    }

    #region _SECURITY_ATTRIBUTES
    //typedef struct _SECURITY_ATTRIBUTES {  
    //    DWORD nLength;  
    //    LPVOID lpSecurityDescriptor;  
    //    BOOL bInheritHandle;
    //} SECURITY_ATTRIBUTES,  *PSECURITY_ATTRIBUTES,  *LPSECURITY_ATTRIBUTES;
    #endregion
    struct SECURITY_ATTRIBUTES
    {
        public uint Length;
        public IntPtr SecurityDescriptor;
        public bool InheritHandle;
    }

    [Flags] enum SECURITY_INFORMATION : uint
    {
        OWNER_SECURITY_INFORMATION        = 0x00000001,
        GROUP_SECURITY_INFORMATION        = 0x00000002,
        DACL_SECURITY_INFORMATION         = 0x00000004,
        SACL_SECURITY_INFORMATION         = 0x00000008,
        UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
        UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
        PROTECTED_SACL_SECURITY_INFORMATION   = 0x40000000,
        PROTECTED_DACL_SECURITY_INFORMATION   = 0x80000000
    }

    #region _SECURITY_DESCRIPTOR
    //typedef struct _SECURITY_DESCRIPTOR {
    //  UCHAR  Revision;
    //  UCHAR  Sbz1;
    //  SECURITY_DESCRIPTOR_CONTROL  Control;
    //  PSID  Owner;
    //  PSID  Group;
    //  PACL  Sacl;
    //  PACL  Dacl;
    //} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
    #endregion
    [StructLayoutAttribute(LayoutKind.Sequential)]
    struct SECURITY_DESCRIPTOR
    {
        public byte revision;
        public byte size;
        public short control; // public SECURITY_DESCRIPTOR_CONTROL control;
        public IntPtr owner;
        public IntPtr group;
        public IntPtr sacl;
        public IntPtr dacl;
    }

    #region _STARTUPINFO
    //typedef struct _STARTUPINFO {  
    //    DWORD cb;  
    //    LPTSTR lpReserved;  
    //    LPTSTR lpDesktop;  
    //    LPTSTR lpTitle;  
    //    DWORD dwX;  
    //    DWORD dwY;  
    //    DWORD dwXSize;  
    //    DWORD dwYSize;  
    //    DWORD dwXCountChars;  
    //    DWORD dwYCountChars;  
    //    DWORD dwFillAttribute;  
    //    DWORD dwFlags;  
    //    Word wShowWindow;  
    //    Word cbReserved2;  
    //    LPBYTE lpReserved2;  
    //    HANDLE hStdInput;  
    //    HANDLE hStdOutput;  
    //    HANDLE hStdError; 
    //} STARTUPINFO,  *LPSTARTUPINFO;
    #endregion
    struct STARTUPINFO
    {
        public uint cb;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string Reserved;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string Desktop;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string Title;
        public uint X;
        public uint Y;
        public uint XSize;
        public uint YSize;
        public uint XCountChars;
        public uint YCountChars;
        public uint FillAttribute;
        public uint Flags;
        public ushort ShowWindow;
        public ushort Reserverd2;
        public byte bReserverd2;
        public IntPtr StdInput;
        public IntPtr StdOutput;
        public IntPtr StdError;
    }

    #region _PROCESS_INFORMATION
    //typedef struct _PROCESS_INFORMATION {  
    //  HANDLE hProcess;  
    //  HANDLE hThread;  
    //  DWORD dwProcessId;  
    //  DWORD dwThreadId; } 
    //  PROCESS_INFORMATION,  *LPPROCESS_INFORMATION;
    #endregion
    [StructLayout(LayoutKind.Sequential)]
    struct PROCESS_INFORMATION
    {
        public IntPtr Process;
        public IntPtr Thread;
        public uint ProcessId;
        public uint ThreadId;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool InitializeSecurityDescriptor(IntPtr pSecurityDescriptor, uint dwRevision);
    const uint SECURITY_DESCRIPTOR_REVISION = 1;

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool daclPresent, IntPtr dacl, bool daclDefaulted);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    extern static bool DuplicateTokenEx(
        IntPtr hExistingToken,
        uint dwDesiredAccess,
        ref SECURITY_ATTRIBUTES lpTokenAttributes,
        SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
        TOKEN_TYPE TokenType,
        out IntPtr phNewToken);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(
        string lpszUsername,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        out IntPtr phToken
        );

    #region GetTokenInformation
    //BOOL WINAPI GetTokenInformation(
    //  __in       HANDLE TokenHandle,
    //  __in       TOKEN_INFORMATION_CLASS TokenInformationClass,
    //  __out_opt  LPVOID TokenInformation,
    //  __in       DWORD TokenInformationLength,
    //  __out      PDWORD ReturnLength
    //);
    #endregion
    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool GetTokenInformation(
        IntPtr TokenHandle,
        TOKEN_INFORMATION_CLASS TokenInformationClass,
        IntPtr TokenInformation,
        int TokenInformationLength,
        out int ReturnLength
        );


    #region CreateProcessAsUser
    //        BOOL WINAPI CreateProcessAsUser(
    //  __in_opt     HANDLE hToken,
    //  __in_opt     LPCTSTR lpApplicationName,
    //  __inout_opt  LPTSTR lpCommandLine,
    //  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
    //  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
    //  __in         BOOL bInheritHandles,
    //  __in         DWORD dwCreationFlags,
    //  __in_opt     LPVOID lpEnvironment,
    //  __in_opt     LPCTSTR lpCurrentDirectory,
    //  __in         LPSTARTUPINFO lpStartupInfo,
    //  __out        LPPROCESS_INFORMATION lpProcessInformation);
    #endregion
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern bool CreateProcessAsUser(
        IntPtr Token, 
        [MarshalAs(UnmanagedType.LPTStr)] string ApplicationName,
        [MarshalAs(UnmanagedType.LPTStr)] string CommandLine,
        ref SECURITY_ATTRIBUTES ProcessAttributes, 
        ref SECURITY_ATTRIBUTES ThreadAttributes, 
        bool InheritHandles,
        uint CreationFlags, 
        IntPtr Environment, 
        [MarshalAs(UnmanagedType.LPTStr)] string CurrentDirectory, 
        ref STARTUPINFO StartupInfo, 
        out PROCESS_INFORMATION ProcessInformation);

    #region CloseHandle
    //BOOL WINAPI CloseHandle(
    //      __in          HANDLE hObject
    //        );
    #endregion
    [DllImport("Kernel32.dll")]
    extern static int CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string Host, string name, ref long pluid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
        public int Count;
        public long Luid;
        public int Attr;
    }

    //static internal const int TOKEN_QUERY = 0x00000008;
    internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
    //static internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

    internal const int TOKEN_QUERY = 0x00000008;
    internal const int TOKEN_DUPLICATE = 0x0002;
    internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;

    #endregion

    [STAThread]
    static void Main(string[] args)
    {
        string username, domain, password, applicationName;
        username = args[2];
        domain = args[1];
        password = args[3];
        applicationName = @args[0];

        IntPtr token = IntPtr.Zero;
        IntPtr primaryToken = IntPtr.Zero;
        try
        {
            bool result = false;

            result = LogonUser(username, domain, password, (int)LOGON_TYPE.LOGON32_LOGON_NETWORK, (int)LOGON_PROVIDER.LOGON32_PROVIDER_DEFAULT, out token);
            if (!result)
            {
                int winError = Marshal.GetLastWin32Error();
            }

            string commandLine = null;

            #region security attributes
            SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES();

            SECURITY_DESCRIPTOR sd = new SECURITY_DESCRIPTOR();
            IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(sd));
            Marshal.StructureToPtr(sd, ptr, false);
            InitializeSecurityDescriptor(ptr, SECURITY_DESCRIPTOR_REVISION);
            sd = (SECURITY_DESCRIPTOR)Marshal.PtrToStructure(ptr, typeof(SECURITY_DESCRIPTOR));

            result = SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false);
            if (!result)
            {
                int winError = Marshal.GetLastWin32Error();
            }

            primaryToken = new IntPtr();
            result = DuplicateTokenEx(token, 0, ref processAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
            if (!result)
            {
                int winError = Marshal.GetLastWin32Error();
            }
            processAttributes.SecurityDescriptor = ptr;
            processAttributes.Length = (uint)Marshal.SizeOf(sd);
            processAttributes.InheritHandle = true;
            #endregion

            SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
            threadAttributes.SecurityDescriptor = IntPtr.Zero;
            threadAttributes.Length = 0;
            threadAttributes.InheritHandle = false;

            bool inheritHandles = true;
            //CreationFlags creationFlags = CreationFlags.CREATE_DEFAULT_ERROR_MODE;
            IntPtr environment = IntPtr.Zero;
            string currentDirectory = currdir;

            STARTUPINFO startupInfo = new STARTUPINFO();
            startupInfo.Desktop = "";

            PROCESS_INFORMATION processInformation;

            result = CreateProcessAsUser(primaryToken, applicationName, commandLine, ref processAttributes, ref threadAttributes, inheritHandles, 16, environment, currentDirectory, ref startupInfo, out processInformation);
            if (!result)
            {
                int winError = Marshal.GetLastWin32Error();
                File.AppendAllText(logfile, DateTime.Now.ToLongTimeString() + " " + winError + Environment.NewLine);
            }
        }
        catch
        {
            int winError = Marshal.GetLastWin32Error();
            File.AppendAllText(logfile, DateTime.Now.ToLongTimeString() + " " + winError + Environment.NewLine);
        }
        finally
        {
            if (token != IntPtr.Zero)
            {
                int x = CloseHandle(token);
                if (x == 0)
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                x = CloseHandle(primaryToken);
                if (x == 0)
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
    }

Das grundlegende Verfahren ist:

  1. Melden Sie den Benutzer an
  2. wandelt das angegebene Token in ein primäres Token um
  3. Führen Sie den Prozess mit diesem Token aus
  4. Schließen Sie den Griff, wenn Sie fertig sind.

Dies ist der Entwicklungscode, der frisch von meiner Maschine stammt, und keinesfalls für den Einsatz in Produktionsumgebungen bereit. Der Code hier ist immer noch fehlerhaft - Für den Anfang: Ich bin nicht sicher, ob die Ziehpunkte an der richtigen Stelle geschlossen sind, und es gibt einige oben definierte Interop-Funktionen, die nicht erforderlich sind. Der separate Starterprozess nervt mich auch wirklich. Im Idealfall möchte ich, dass all diese Job-Artikel in einer Assembly verpackt sind und von unserer API sowie diesem Service verwendet werden. Wenn jemand hier Vorschläge hat, wäre er dankbar.

23
Matt Jacobsen

Nur eine Vermutung - verwenden Sie LoadUserProfile = true mit der Startinfo? CreateProcessWithLogonW lädt die Benutzerregistrierungsstruktur nicht standardmäßig, sofern Sie dies nicht mitteilen.

1
liggett78

Der Grund dafür, dass der Aufruf nach dem ersten Mal fehlschlägt, ist sehr wahrscheinlich, weil er eine "Standard" -Sicherheitsbeschreibung verwendet (was auch immer das ist).

von msdn :

lpProcessAttributes [in, optional]

Ein Zeiger auf eine Struktur mit SECURITY_ATTRIBUTES , Die einen Sicherheitsdeskriptor Für das neue Prozessobjekt Angibt und bestimmt, ob untergeordnete Prozesse Den zurückgegebenen Handle an . Wenn für lpProcessAttributes NULL oder lpSecurityDescriptor NULL angegeben ist, Erhält der Prozess eine Standard-Sicherheitsbeschreibung , Und das Handle kann nicht Geerbt werden. Die voreingestellte Sicherheitsbeschreibung Ist die des Benutzers , Auf den im Parameter hToken verwiesen wird. Diese Sicherheitsbeschreibung erlaubt möglicherweise keinen Zugriff für den Aufrufer, in In diesem Fall kann der Prozess nach dem Ausführen möglicherweise nicht erneut geöffnet werden. Der Prozess-Handle Ist gültig und hat weiterhin Volle Zugriffsrechte.

Ich denke, CreateProcessWithLogonW erstellt diese Standardsicherheitsbeschreibung (auf jeden Fall gebe ich keine an). 

Zeit für Interopping ...

1
Matt Jacobsen

Ich werde weder Psexec noch den Taskplaner vorschlagen. Aber haben Sie Sudowin gesehen?

Es macht fast genau das, was Sie möchten, mit der Ausnahme, dass vor der Ausführung des Vorgangs ein Kennwort abgefragt wird. 

Da Sie Open Source und alle sind, können Sie auch immer wieder sehen, wie Prozesse vom zugehörigen Dienst ausgeführt werden.

1
Vinko Vrsalovic

Ich habe diesen Kommentar gerade unter msdn gelesen ( http://msdn.Microsoft.com/en-us/library/ms682431(VS.85).aspx ):

Rufen Sie keine Benutzeranwendungen mit dieser Funktion Auf! ChristianWimmer |
Bearbeiten | Verlauf anzeigen Bitte warten Wenn Sie den Anwendermodus Aufrufen, in dem Dokumentbearbeitung Und ähnliches (wie Word) ausgeführt wird, gehen Alle nicht gespeicherten Daten verloren . Dies ist , Da die gewöhnliche Abschaltsequenz Nicht für Prozesse gilt, die Mit CreateProcessWithLogonW gestartet wurden. Auf diese Weise erhalten die gestarteten Anwendungen Keine WM_QUERYENDSESSION, WM_ENDSESSION Und die wichtigste WM_QUIT - Nachricht. Sie bitten also nicht, die Daten zu speichern oder ihre Daten aufzuräumen. Sie Werden einfach ohne Vorwarnung aufhören. Diese Funktion Ist nicht benutzerfreundlich und Sollte mit Vorsicht verwendet werden.

Es ist nur "schlechte Benutzererfahrung". Niemand erwartet es.

Das könnte erklären, was ich beobachtet habe: Funktioniert beim ersten Mal. Schlägt jedes weitere Mal fehl Das bestärkt mich in meinem Glauben, dass etwas nicht richtig aufgeräumt wird

0
Matt Jacobsen

Sie benötigen kein Fensterhandle, um CreateProcessWithLogonW zu verwenden. Ich bin nicht sicher, woher Ihre Informationen stammen.

Die Anwendung konnte den Fehler nicht initialisieren, hat viele Ursachen, hängt jedoch fast immer mit der Sicherheit oder mit erschöpften Benutzerressourcen zusammen. Es ist äußerst schwierig, dies zu diagnostizieren, ohne viel mehr Informationen über das, was Sie ausführen, und den Kontext, in dem Sie ausgeführt werden, zu beachten. Folgende Punkte sind jedoch zu beachten: Hat der Benutzer die richtigen Berechtigungen, um auf das Verzeichnis der ausführbaren Datei zuzugreifen? Der Benutzer hat die Berechtigung, auf die Fensterstation und den Desktop zuzugreifen, in dem sie gestartet wird. Verfügt sie über die richtigen Berechtigungen für alle DLL-Dateien, die beim Initialisieren geladen werden müssen, usw.

0
Stephen Martin

Ich hatte ähnliche Probleme, als ich versuchte, das PhantomJS-Binary mit dem "runas" -Verb in einem Windows-Dienst zu starten. Ich habe das Problem jetzt mit dem folgenden Verfahren gelöst:

  • Identifizieren Sie sich für den Benutzer
  • Prozess starten (ohne UI)
  • Identifizieren Sie sich zurück

Sie können die Imitatorenklasse zum Identitätswechsel verwenden. Es ist auch wichtig, die folgenden Eigenschaften in ProcessStartInfo festzulegen, damit die Anwendung nicht versucht, auf die Windows-Benutzeroberfläche zuzugreifen:

var processStartInfo = new ProcessStartInfo()
{
    FileName = [email protected]"{assemblyFolder}\PhantomJS\phantomjs.exe",
    Arguments = $"--webdriver={port}",
    RedirectStandardOutput = true,
    RedirectStandardError = true,
    RedirectStandardInput = true,
    UseShellExecute = false,
    CreateNoWindow = true,
    ErrorDialog = false,
    WindowStyle = ProcessWindowStyle.Hidden
};
0
Harry Berry

Sie sagen, dass "der Windows-Dienst mit" Administrator-Berechtigungsnachweisen "gestartet wird.

Meinen Sie das tatsächliche "Administratorkonto" oder einen Benutzer in der Gruppe "Administratoren"? Das Starten des Dienstes als Administrator hat das für mich gelöst.

0
Fiona