Ich habe ein Problem beim Erstellen einer Verknüpfung auf einem Server. Es wird immer eine Ausnahme ausgelöst:C#: ShortCut und Identitätswechsel
Zugriff verweigert. 0x80070005
Ich weiß wirklich nicht, ob das Problem auftritt, weil der Verknüpfungsort oder das Verknüpfungsziel.
Ich muss Identitätswechsel verwenden, um auf das Dateisystem zuzugreifen. Mit IO.File
und IO.Directory
kann ich Verzeichnisse erstellen, kopieren und entfernen, etc ... ohne Probleme. Wenn ich einen Remote-Desktop für das Dateirepository mit dem Benutzer impersonate öffne, kann ich die Verknüpfung mit allen Problemen erstellen.
Allerdings zum Erstellen einer Verknüpfung verwende ich WHSell, und es scheint, dass es einige Probleme mit Identitätswechsel hat. Irgendwelche Ideen?
Dies ist mein Code:
#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;
}
}
}
}
}
Dies gilt nicht für meine Situation. Wenn Sie 'shortcut.Save()' in Ihrem Code verwenden, müssen Sie angeben, dass der Benutzer Zugriff auf den Zielspeicherort hat. Ich kann den Identitätswechsel nicht deaktivieren, weil der IIS_IUSER (der standardmäßig verwendete Benutzer) nicht auf das Zielverzeichnis zugreifen kann, und ich kann keinen Zugriff darauf gewähren. Also diese Zeile löst eine Ausnahme – Rumpelstinsk
Dies sollte funktionieren, solange es ein Verzeichnis gibt, in dem der "Standard" -Benutzer (die Identität, die angenommen wird, wenn der Identitätswechsel deaktiviert ist) Schreibzugriff hat. In meinem Snippet ist dieses "staging" -Verzeichnis das temporäre Verzeichnis, das von 'Path.GetTempPath()' bereitgestellt wird, da es für die Identität meines IIS-Anwendungspools funktioniert hat. – nedmund