2010-04-06 26 views
3

J'ai un utilitaire que j'ai écrit dans VB.net qui s'exécute en tant que tâches planifiées. Il appelle en interne un autre exécutable et doit accéder à un lecteur mappé. Apparemment, Windows a des problèmes avec les tâches planifiées accédant aux lecteurs mappés lorsque l'utilisateur n'est pas connecté, même lorsque les informations d'authentification sont fournies à la tâche elle-même. OK bien.Définition de ProcessStartInfo.WorkingDirectory sur un chemin UNC

Pour contourner cela, je viens de passer mon application le chemin UNC.

process.StartInfo.FileName = 'name of executable' 
process.StartInfo.WorkingDirectory = '\\unc path\' 
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden 
process.StartInfo.Arguments = 'arguments to executable' 
process.Start() 

C'est la même implémentation je avec le lecteur mappé, mais en utilisant le chemin UNC, le processus ne se comporte pas comme si le chemin UNC est le répertoire de travail.

Y a-t-il des problèmes connus qui affectent ProcessStartInfo.WorkingDirectory à un chemin UNC? Sinon, qu'est-ce que je fais de mal?

Répondre

7

Votre problème avec les lecteurs mappés lorsque les utilisateurs ne sont pas connectés est qu'ils n'existent pas. Les lecteurs sont uniquement mappés et disponibles pour l'utilisateur actuellement connecté. Si personne n'est connecté, aucun lecteur n'est mappé. En guise de solution de contournement, vous pouvez exécuter CMD, appelez PUSHD pour mapper votre UNC à un lecteur en arrière-plan, puis exécuter votre code. J'ai copié le fichier tree.com depuis mon system32 et l'ai placé sur mon serveur de fichiers sous le nom "tree4.com" et ce code fonctionne comme prévu (je redirige également la sortie standard pour que je puisse voir les résultats de l'appel mais c'est pas nécessaire)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 

    Using P As New Process() 
     'Launch a standard hidden command window 
     P.StartInfo.FileName = "cmd.exe" 
     P.StartInfo.WindowStyle = ProcessWindowStyle.Hidden 
     P.StartInfo.CreateNoWindow = True 

     'Needed to redirect standard error/output/input 
     P.StartInfo.UseShellExecute = False 

     P.StartInfo.RedirectStandardInput = True 
     P.StartInfo.RedirectStandardOutput = True 

     'Add handler for when data is received 
     AddHandler P.OutputDataReceived, AddressOf SDR 

     'Start the process 
     P.Start() 

     'Begin async data reading 
     P.BeginOutputReadLine() 

     '"Map" our drive 
     P.StandardInput.WriteLine("pushd \\file-server\File-Server") 

     'Call our command, you could pass args here if you wanted 
     P.StandardInput.WriteLine("tree2.com c:\3ea7025b247d0dfb7731a50bf2632f") 

     'Once our command is done CMD.EXE will still be sitting around so manually exit 
     P.StandardInput.WriteLine("exit") 
     P.WaitForExit() 
    End Using 

    Me.Close() 
End Sub 
Private Sub SDR(ByVal sender As Object, ByVal e As DataReceivedEventArgs) 
    Trace.WriteLine(e.Data) 
End Sub 
0

J'ai rencontré ce problème et la solution acceptée est un peu compliquée pour moi. Ce que j'ai fait était de prendre le chemin UNC et de copier le contenu de celui-ci à [Path.GetTempDir()]\[Guid.NewGuid().ToString()] puis d'utiliser cela comme mon répertoire de travail pour le process.StartInfo.WorkingDirectory. Enveloppez cette fonctionnalité dans une classe appelée "Environnement" qui implémentera IDisposable et nettoiera le répertoire temp que vous avez créé. Quelque chose comme ceci (ignorer les paramètres références):

using (var env = new ProcessEnvironment(settings)) 
       { 
        filePath = Path.Combine(env.WorkingDirectory, settings.ApplicationEXE); 
        var psi = new ProcessStartInfo 
        { 
         UseShellExecute = false, 
         FileName = filePath, 
         WorkingDirectory = env.WorkingDirectory, 
         Arguments = (args != null && args.Length > 0 ? String.Join(" ", args) : null) 
        }; 

        var proc = Process.Start(psi); 

        if (env.ExecutingFromTempDir || settings.WaitForExit) 
         proc.WaitForExit(); 
       } 

Et ProcessEnvironment ressemble:

class ProcessEnvironment : IDisposable 
    { 
     private Settings itsSettings; 
     private string itsTempDestDirectory; 
     public string WorkingDirectory { get; set; } 
     public bool ExecutingFromTempDir { get { return !String.IsNullOrEmpty(itsTempDestDirectory); } } 

     public ProcessEnvironment(Settings settings) 
     { 
      this.itsSettings = settings; 

      WorkingDirectory = GetWorkingDirectory(); 
     } 

     private string GetWorkingDirectory() 
     { 
      var dirInfo = new DirectoryInfo(itsSettings.StartupFolder); 

      if (!IsUncDrive(dirInfo)) 
       return itsSettings.StartupFolder; 

      return CreateWorkingDirectory(dirInfo); 
     } 

     private string CreateWorkingDirectory(DirectoryInfo dirInfo) 
     { 
      var srcPath = dirInfo.FullName; 
      itsTempDestDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); 
      Directory.CreateDirectory(itsTempDestDirectory); 

      //Now Create all of the directories 
      foreach (string dirPath in Directory.GetDirectories(srcPath, "*", SearchOption.AllDirectories)) 
       Directory.CreateDirectory(dirPath.Replace(srcPath, itsTempDestDirectory)); 

      //Copy all the files & Replaces any files with the same name 
      foreach (string newPath in Directory.GetFiles(srcPath, "*.*", SearchOption.AllDirectories)) 
       File.Copy(newPath, newPath.Replace(srcPath, itsTempDestDirectory), true); 

      return itsTempDestDirectory; 
     } 

     private bool IsUncDrive(DirectoryInfo dirInfo) 
     { 
      Uri uri = null; 
      if (!Uri.TryCreate(dirInfo.FullName, UriKind.Absolute, out uri)) 
      { 
       return false; 
      } 
      return uri.IsUnc; 
     } 



     public void Dispose() 
     { 
      try 
      { 
       if (ExecutingFromTempDir) 
        Directory.Delete(itsTempDestDirectory, true); 

      } 
      catch (Exception ex) 
      { //do nothing - if we can't delete then we can't do it 
       Console.WriteLine("Failed in Dispose: " + ex); 
      } 
     } 
    }