2016-07-18 17 views
0

서버에 바로 가기를 만드는 데 문제가 있습니다. 항상 예외가 throw됩니다.C# : ShortCut 및 가장

액세스가 거부되었습니다. 0x80070005

바로 가기 위치 또는 바로 가기 대상 때문에 문제가 발생하는지 정말 모르겠습니다.

파일 시스템에 액세스하려면 가장을 사용해야합니다. IO.FileIO.Directory을 사용하여 디렉토리를 만들거나 파일을 복사 및 제거하는 등의 작업을 아무런 문제없이 수행 할 수 있습니다. 또한 파일 리포지토리에 대한 원격 데스크톱을 가장 사용자와 함께 열면 모든 문제가있는 바로 가기를 만들 수 있습니다.

그러나 바로 가기를 만들려면 WHSell을 사용하고 있으며 가장이라는 문제가있는 것으로 보입니다. 어떤 아이디어?

이 내 코드입니다 :

#region Impersonation 
     public const int LOGON32_LOGON_INTERACTIVE = 2; 
     public const int LOGON32_PROVIDER_DEFAULT = 0; 

     [DllImport("advapi32.dll")] 
     public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); 

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

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

     [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     public static extern bool CloseHandle(IntPtr handle); 

     private void LogonAsUser(String userName, String domain, String password) 
     { 

      if (!LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle)) 
      { 
       int ret = Marshal.GetLastWin32Error(); 
       throw new System.ComponentModel.Win32Exception(ret); 
      } 
     } 

     private void LogonAsUserEnd(IntPtr token) 
     { 
      if (!IntPtr.Equals(token, IntPtr.Zero)) 
      { 
       CloseHandle(token); 
      } 

     } 

     public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid 
     { 
      private SafeTokenHandle() 
       : base(true) 
      { 
      } 

      [DllImport("kernel32.dll")] 
      [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
      [SuppressUnmanagedCodeSecurity] 
      [return: MarshalAs(UnmanagedType.Bool)] 
      private static extern bool CloseHandle(IntPtr handle); 

      protected override bool ReleaseHandle() 
      { 
       return CloseHandle(handle); 
      } 
     } 
     #endregion 

private void CreateShortCut(string shorcutPath, string shortcutTarget) 
     { 

      IWshRuntimeLibrary.WshShell wshShell = new IWshRuntimeLibrary.WshShell(); 
      IWshRuntimeLibrary.IWshShortcut shortcut; 
      shortcut = (IWshRuntimeLibrary.IWshShortcut)wshShell.CreateShortcut(shorcutPath); 

      shortcut.TargetPath = shortcutTarget; 
      shortcut.WorkingDirectory = shorcutPath; 
      shortcut.Description = "Presupuestos del servicio"; 
      shortcut.Save(); 
     } 

public void CreateServicioRepository(presupuestos p) 
     { 
      LogonAsUser(userName, domain, password); 
      using (safeTokenHandle) 
      { 
       using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle())) 
       { 
        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) 
        { 
         try 
         { 
          if (Directory.Exists(serviceBasePath)) // serviceBasePath = "\\myserver\myfolder" 
          { 
           //Creamos el directorio para el servicio 
           string year = p.Fecha_alta.Year.ToString(); 
           string serviceFolderName = p.Codigo + "_" + p.productos.Siglas; 
           if (p.IdObra.HasValue) serviceFolderName += "_" + p.obras.TituloCorto; 
           serviceFolderName = formatePath(serviceFolderName); 

           string servicePaht = Path.Combine(serviceBasePath, year, serviceFolderName); 
           if (!Directory.Exists(servicePaht)) Directory.CreateDirectory(servicePaht); 

           //Comprobamos que existe la carpeta de backend de los informes 
           string presupuestosFolder = getPresupuestoReporthPath(p); //persupuestosFolder = "\\anotherServer\anotherfolder 

           if (!Directory.Exists(presupuestosFolder)) Directory.CreateDirectory(presupuestosFolder); 

           //Creamos el acceso directo a la carpeta de informes generados en presupuesto 
           if (!string.IsNullOrWhiteSpace(presupuestosFolder)) 
           { 
            string shortCutName = "001_" + p.Codigo + "_Presupuesto.lnk"; 
            string shortCutPath = Path.Combine(servicePaht, shortCutName); 

            if (!File.Exists(shortCutPath)) CreateShortCut(shortCutPath, presupuestosFolder); 
           } 

           //Comprobamos que existe la carpeta de backend de los informes 
           string pavoFolder = Path.Combine(System.Configuration.ConfigurationManager.AppSettings["pavoPath"], p.Codigo); 

           if (!Directory.Exists(pavoFolder)) Directory.CreateDirectory(pavoFolder); 

           //Creamos el acceso directo a la carpeta de PAVO 
           if (p.productos.IdModulo == (int)EnumsHelper.Modulos.Obras) 
           { 
            string pavoShortCutName = "002_" + p.Codigo + "_PVOD.lnk"; 
            string pavoShortCutPath = Path.Combine(servicePaht, pavoShortCutName); 

            if (!File.Exists(pavoShortCutPath)) CreateShortCut(pavoShortCutPath, pavoFolder); 
           } 

           //Copiamos las plantilla de la estructura de carpetas del servicio 
           if (Directory.Exists(directoryTemplate) && p.IdEstado == (int)EnumsHelper.EstadoPresupuesto.Aprobado) 
           { 
            foreach (string dirName in Directory.GetDirectories(directoryTemplate)) 
            { 
             if (dirName.Trim().ToLower().Contains(p.productos.Nombre.Trim().ToLower())) 
             { 
              string originalPath = Path.Combine(directoryTemplate, dirName); 
              CopyDirectory(originalPath, servicePaht, p.Codigo); 
              break; 
             } 
            } 
           } 

          } 
         } 
         catch (Exception ex) 
         { 
          LogHelper.Error(ex); 
          throw ex; 
         } 
        } 
       } 
      }      
     } 

답변

0

해결 방법으로, 당신은 가장을 해제 한 후 임시 디렉토리에 바로 가기 파일을 만들 쉘을 사용할 수 있습니다. 그런 다음이 파일을 올바른 경로에 저장할 수있는 가장 된 코드에 바이트 배열로 전달할 수 있습니다.

public void CreateShortCut(string shorcutPath, string shortcutTarget) 
{ 
    byte[] bytes = null; 

    // Disable impersonation 
    using (System.Security.Principal.WindowsImpersonationContext ctx = System.Security.Principal.WindowsIdentity.Impersonate(IntPtr.Zero)) 
    { 
     // Get a temp file name (the shell commands won't work without .lnk extension) 
     var path = Path.GetTempPath(); 
     string temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".lnk"); 
     try 
     { 
      WshShell shell = new WshShell(); 
      IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(temp); 
      shortcut.TargetPath = shortcutTarget; 
      shortcut.Save(); 
      bytes = System.IO.File.ReadAllBytes(temp); 
     } 
     finally 
     { 
      if (System.IO.File.Exists(temp)) System.IO.File.Delete(temp); 
     } 
    } 

    // Impersonation resumed 
    System.IO.File.WriteAllBytes(shorcutPath, bytes); 
} 
+0

내 상황에는 적용되지 않습니다. 귀하의 코드에서'shortcut.Save()'를 사용하면 사용 된 사용자가 대상 위치에 액세스 할 수있는 권한이 다시 필요합니다. IIS_IUSER (기본적으로 사용되는 사용자)가 대상 디렉터리에 액세스 할 수 없기 때문에 가장에 대한 액세스 권한을 부여 할 수 없기 때문에 가장을 사용하지 않도록 설정할 수 없습니다. 따라서이 줄은 예외를 throw합니다. – Rumpelstinsk

+0

"기본"사용자 (가장을 사용하지 않도록 설정된 ID)에 쓰기 권한이있는 디렉터리가 있으면이 작업이 작동합니다. 나의 발췌 문장에서이 "스테이징"디렉토리는 IIS 응용 프로그램 풀의 ID로 작동 한 이후 Path.GetTempPath()가 제공 한 임시 디렉토리가됩니다. – nedmund