Como fornecer nome de usuário e senha ao conectar-se a um compartilhamento de rede


191

Ao conectar-se a um compartilhamento de rede para o qual o usuário atual (no meu caso, um usuário de serviço habilitado para rede) não tem direitos, é necessário fornecer nome e senha.

Eu sei como fazer isso com as funções Win32 (a WNet*família de mpr.dll), mas gostaria de fazê-lo com a funcionalidade .Net (2.0).

Quais opções estão disponíveis?

Talvez mais algumas informações ajudem:

  • O caso de uso é um serviço do Windows, não um aplicativo Asp.Net.
  • O serviço está sendo executado em uma conta que não possui direitos sobre o compartilhamento.
  • A conta de usuário necessária para o compartilhamento não é conhecida no lado do cliente.
  • Cliente e servidor não são membros do mesmo domínio.

7
Embora eu não esteja fornecendo uma resposta útil, posso fornecer uma resposta anti-resposta. A representação e a geração de um processo como Marc postou não funcionarão quando o servidor e o cliente não estiverem no mesmo domínio, a menos que haja uma confiança entre eles. os dois domínios. Se houver confiança, acho que funcionará. Eu teria respondido apenas como um comentário ao Marc, mas não tenho representante suficiente para comentar. : - /
Moose

Respostas:


152

Você pode alterar a identidade do encadeamento ou P / Invoke WNetAddConnection2. Prefiro o último, pois às vezes preciso manter várias credenciais para diferentes locais. Envolvo-o em um IDisposable e chamo WNetCancelConnection2 para remover os creds posteriormente (evitando o erro de vários nomes de usuário):

using (new NetworkConnection(@"\\server\read", readCredentials))
using (new NetworkConnection(@"\\server2\write", writeCredentials)) {
   File.Copy(@"\\server\read\file", @"\\server2\write\file");
}

4
O serviço não é membro do domínio de destino - a representação não pode funcionar, pois você não poderá criar o token de segurança localmente e se passar por ele. PInvoke é o único caminho.
21138 stephbu

@ MarkBrackett Eu sei que essa é uma resposta antiga, mas talvez você ainda saiba ... o acesso será concedido apenas ao programa ou também ao usuário conectado via explorer?
Brisa

@ Breeze - não testei, mas esperaria que fosse autenticado para a sessão de logon; portanto, se seu programa estiver sendo executado como usuário conectado, eles também terão acesso (pelo menos durante a operação).
Mark Brackett

8
As definições de readCredentials e writeCredentials podem ser incluídas na resposta.
Anders Lindén

2
Se você está recebendo erro 53 , verifique se o caminho não está terminando com um "\"
Mustafa S.

326

Gostei tanto da resposta de Mark Brackett que fiz minha própria implementação rápida. Aqui está, se mais alguém precisar com pressa:

public class NetworkConnection : IDisposable
{
    string _networkName;

    public NetworkConnection(string networkName, 
        NetworkCredential credentials)
    {
        _networkName = networkName;

        var netResource = new NetResource()
        {
            Scope = ResourceScope.GlobalNetwork,
            ResourceType = ResourceType.Disk,
            DisplayType = ResourceDisplaytype.Share,
            RemoteName = networkName
        };

        var userName = string.IsNullOrEmpty(credentials.Domain)
            ? credentials.UserName
            : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);

        var result = WNetAddConnection2(
            netResource, 
            credentials.Password,
            userName,
            0);

        if (result != 0)
        {
            throw new Win32Exception(result);
        }   
    }

    ~NetworkConnection()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        WNetCancelConnection2(_networkName, 0, true);
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NetResource netResource, 
        string password, string username, int flags);

    [DllImport("mpr.dll")]
    private static extern int WNetCancelConnection2(string name, int flags,
        bool force);
}

[StructLayout(LayoutKind.Sequential)]
public class NetResource
{
    public ResourceScope Scope;
    public ResourceType ResourceType;
    public ResourceDisplaytype DisplayType;
    public int Usage;
    public string LocalName;
    public string RemoteName;
    public string Comment;
    public string Provider;
}

public enum ResourceScope : int
{
    Connected = 1,
    GlobalNetwork,
    Remembered,
    Recent,
    Context
};

public enum ResourceType : int
{
    Any = 0,
    Disk = 1,
    Print = 2,
    Reserved = 8,
}

public enum ResourceDisplaytype : int
{
    Generic = 0x0,
    Domain = 0x01,
    Server = 0x02,
    Share = 0x03,
    File = 0x04,
    Group = 0x05,
    Network = 0x06,
    Root = 0x07,
    Shareadmin = 0x08,
    Directory = 0x09,
    Tree = 0x0a,
    Ndscontainer = 0x0b
}

10
Ele realmente deve ser throw new Win32Exception(result);, desde WNetAddConnection2 retornos win32 códigos de erro ( ERROR_XXX)
torvin

2
Este é um pequeno pedaço de código brilhante. Necessário fazer logon em um sistema UNIX para obter uma lista de diretórios para impressão em um aplicativo da Web MVC5 e isso foi o que fez. +1 !!!
Tay #

3
As seguintes instruções de uso são necessárias para que o código acima seja compilado: using System.Net; using System.Runtime.InteropServices; using System.ComponentModel;
Matt Nelson

4
desculpe atualizar esse segmento antigo, mas parece que ele não fecha a conexão após o término do bloco. Eu tenho um programa para fazer upload de algumas fotos, a primeira vai bem, a segunda dá falha. A conexão é liberada quando o programa é fechado. Algum conselho?
Art

3
Tivemos o mesmo problema que você, @arti. Ao definir apenas o nome de usuário e a senha no NetworkCredentialobjeto, o aplicativo conseguiu se conectar uma vez à unidade de rede. Depois disso, obtivemos um ERROR_LOGON_FAILURE em cada tentativa até que o aplicativo fosse reiniciado. Tentamos também fornecer o domínio no NetworkCredentialobjeto, e de repente ele funcionou! Não faço ideia por que isso resolveu o problema, especialmente o fato de ele ter se conectado uma vez sem o domínio.
precisa saber é o seguinte

50

Hoje, sete anos depois, estou enfrentando o mesmo problema e gostaria de compartilhar minha versão da solução.

Está pronto para copiar e colar :-) Aqui está:

Passo 1

No seu código (sempre que você precisar fazer algo com permissões)

ImpersonationHelper.Impersonate(domain, userName, userPassword, delegate
                            {
                                //Your code here 
                                //Let's say file copy:
                                if (!File.Exists(to))
                                {
                                    File.Copy(from, to);
                                }
                            });

Passo 2

O arquivo Helper que faz uma mágica

using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;    
using Microsoft.Win32.SafeHandles;


namespace BlaBla
{
    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);
        }
    }

    public class ImpersonationHelper
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

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

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public static void Impersonate(string domainName, string userName, string userPassword, Action actionToExecute)
        {
            SafeTokenHandle safeTokenHandle;
            try
            {

                const int LOGON32_PROVIDER_DEFAULT = 0;
                //This parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_INTERACTIVE = 2;

                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(userName, domainName, userPassword,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                    out safeTokenHandle);
                //Facade.Instance.Trace("LogonUser called.");

                if (returnValue == false)
                {
                    int ret = Marshal.GetLastWin32Error();
                    //Facade.Instance.Trace($"LogonUser failed with error code : {ret}");

                    throw new System.ComponentModel.Win32Exception(ret);
                }

                using (safeTokenHandle)
                {
                    //Facade.Instance.Trace($"Value of Windows NT token: {safeTokenHandle}");
                    //Facade.Instance.Trace($"Before impersonation: {WindowsIdentity.GetCurrent().Name}");

                    // Use the token handle returned by LogonUser.
                    using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
                    {
                        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                        {
                            //Facade.Instance.Trace($"After impersonation: {WindowsIdentity.GetCurrent().Name}");
                            //Facade.Instance.Trace("Start executing an action");

                            actionToExecute();

                            //Facade.Instance.Trace("Finished executing an action");
                        }
                    }
                    //Facade.Instance.Trace($"After closing the context: {WindowsIdentity.GetCurrent().Name}");
                }

            }
            catch (Exception ex)
            {
                //Facade.Instance.Trace("Oh no! Impersonate method failed.");
                //ex.HandleException();
                //On purpose: we want to notify a caller about the issue /Pavel Kovalev 9/16/2016 2:15:23 PM)/
                throw;
            }
        }
    }
}

2
@MohammadRashid De acordo com a documentação do LogonUser , ele funciona apenas para usuários no computador local: "A função LogonUser tenta fazer logon de um usuário no computador local. O computador local é o computador do qual o LogonUser foi chamado. Você não pode usar o LogonUser para fazer logon em um computador remoto. "Você receberá um erro" Win32Exception: o nome de usuário ou a senha está incorreta. " Então, suponho que as máquinas precisem estar no mesmo domínio, pelo menos.
Charles Chen

1
@CharlesChen Acabei de provar que isso funciona bem em todos os domínios, FYI. O servidor em que estou executando isso está em uma DMZ e definitivamente está se conectando a um servidor de arquivos em um domínio diferente, através de um firewall. Trecho do assassino Pavel, você é o cara, e essa provavelmente deve ser a resposta aceita hoje.
Brian MacKay

Esta é uma otima soluçao! Obrigado, Pavel Kovalev.
STLDev 27/09/19

isso funciona no LDAP? diz que não tenho um servidor de logon disponível. Estou usando o ldap auth
Julius Limson 11/11/19

28

Eu pesquisei muitos métodos e fiz do meu jeito. Você deve abrir uma conexão entre duas máquinas via prompt de comando NET USE e, após concluir o trabalho, limpe a conexão com o prompt de comando NET USE "myconnection" / delete.

Você deve usar o processo do Prompt de Comando do código por trás desta maneira:

var savePath = @"\\servername\foldername\myfilename.jpg";
var filePath = @"C:\\temp\myfileTosave.jpg";

O uso é simples:

SaveACopyfileToServer(filePath, savePath);

Aqui estão as funções:

using System.IO
using System.Diagnostics;


public static void SaveACopyfileToServer(string filePath, string savePath)
    {
        var directory = Path.GetDirectoryName(savePath).Trim();
        var username = "loginusername";
        var password = "loginpassword";
        var filenameToSave = Path.GetFileName(savePath);

        if (!directory.EndsWith("\\"))
            filenameToSave = "\\" + filenameToSave;

        var command = "NET USE " + directory + " /delete";
        ExecuteCommand(command, 5000);

        command = "NET USE " + directory + " /user:" + username + " " + password;
        ExecuteCommand(command, 5000);

        command = " copy \"" + filePath + "\"  \"" + directory + filenameToSave + "\"";

        ExecuteCommand(command, 5000);


        command = "NET USE " + directory + " /delete";
        ExecuteCommand(command, 5000);
    }

E também a função ExecuteCommand é:

public static int ExecuteCommand(string command, int timeout)
    {
        var processInfo = new ProcessStartInfo("cmd.exe", "/C " + command)
                              {
                                  CreateNoWindow = true, 
                                  UseShellExecute = false, 
                                  WorkingDirectory = "C:\\",
                              };

        var process = Process.Start(processInfo);
        process.WaitForExit(timeout);
        var exitCode = process.ExitCode;
        process.Close();
        return exitCode;
    } 

Essas funções funcionaram muito rápido e estável para mim.


1
Caso o mapeamento de compartilhamento falhe, quais seriam os códigos de retorno?
Surega # 23/18

14

A solução Luke Quinane parece boa, mas funcionou apenas parcialmente no meu aplicativo ASP.NET MVC. Tendo dois compartilhamentos no mesmo servidor com credenciais diferentes, eu poderia usar a representação apenas para o primeiro.

O problema com o WNetAddConnection2 também é que ele se comporta de maneira diferente em diferentes versões do Windows. Por isso, procurei alternativas e encontrei a função LogonUser . Aqui está o meu código que também funciona no ASP.NET:

public sealed class WrappedImpersonationContext
{
    public enum LogonType : int
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        NetworkClearText = 8,
        NewCredentials = 9
    }

    public enum LogonProvider : int
    {
        Default = 0,  // LOGON32_PROVIDER_DEFAULT
        WinNT35 = 1,
        WinNT40 = 2,  // Use the NTLM logon provider.
        WinNT50 = 3   // Use the negotiate logon provider.
    }

    [DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain,
        String lpszPassword, LogonType dwLogonType, LogonProvider dwLogonProvider, ref IntPtr phToken);

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

    private string _domain, _password, _username;
    private IntPtr _token;
    private WindowsImpersonationContext _context;

    private bool IsInContext
    {
        get { return _context != null; }
    }

    public WrappedImpersonationContext(string domain, string username, string password)
    {
        _domain = String.IsNullOrEmpty(domain) ? "." : domain;
        _username = username;
        _password = password;
    }

    // Changes the Windows identity of this thread. Make sure to always call Leave() at the end.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Enter()
    {
        if (IsInContext)
            return;

        _token = IntPtr.Zero;
        bool logonSuccessfull = LogonUser(_username, _domain, _password, LogonType.NewCredentials, LogonProvider.WinNT50, ref _token);
        if (!logonSuccessfull)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        WindowsIdentity identity = new WindowsIdentity(_token);
        _context = identity.Impersonate();

        Debug.WriteLine(WindowsIdentity.GetCurrent().Name);
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Leave()
    {
        if (!IsInContext)
            return;

        _context.Undo();

        if (_token != IntPtr.Zero)
        {
            CloseHandle(_token);
        }
        _context = null;
    }
}

Uso:

var impersonationContext = new WrappedImpersonationContext(Domain, Username, Password);
impersonationContext.Enter();

//do your stuff here

impersonationContext.Leave();

2
essa abordagem funcionou bem para mim, mas notei nos meus testes que, ao usar uma senha incorreta com uma conta de usuário de domínio, esse usuário é imediatamente colocado no status de bloqueado. nossa política de domínio exige três tentativas de login com falha antes que isso aconteça, mas, com essa abordagem, uma tentativa incorreta e você está bloqueado. Então, use com cuidado ...
kellyb

5

Para VB.lovers, o equivalente em VB.NET do código de Luke Quinane (obrigado Luke!)

Imports System
Imports System.Net
Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class NetworkConnection
    Implements IDisposable

    Private _networkName As String

    Public Sub New(networkName As String, credentials As NetworkCredential)
        _networkName = networkName

        Dim netResource = New NetResource() With {
             .Scope = ResourceScope.GlobalNetwork,
             .ResourceType = ResourceType.Disk,
             .DisplayType = ResourceDisplaytype.Share,
             .RemoteName = networkName
        }

        Dim userName = If(String.IsNullOrEmpty(credentials.Domain), credentials.UserName, String.Format("{0}\{1}", credentials.Domain, credentials.UserName))

        Dim result = WNetAddConnection2(NetResource, credentials.Password, userName, 0)

        If result <> 0 Then
            Throw New Win32Exception(result, "Error connecting to remote share")
        End If
    End Sub

    Protected Overrides Sub Finalize()
        Try
            Dispose (False)
        Finally
            MyBase.Finalize()
        End Try
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose (True)
        GC.SuppressFinalize (Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        WNetCancelConnection2(_networkName, 0, True)
    End Sub

    <DllImport("mpr.dll")> _
    Private Shared Function WNetAddConnection2(netResource As NetResource, password As String, username As String, flags As Integer) As Integer
    End Function

    <DllImport("mpr.dll")> _
    Private Shared Function WNetCancelConnection2(name As String, flags As Integer, force As Boolean) As Integer
    End Function

End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class NetResource
    Public Scope As ResourceScope
    Public ResourceType As ResourceType
    Public DisplayType As ResourceDisplaytype
    Public Usage As Integer
    Public LocalName As String
    Public RemoteName As String
    Public Comment As String
    Public Provider As String
End Class

Public Enum ResourceScope As Integer
    Connected = 1
    GlobalNetwork
    Remembered
    Recent
    Context
End Enum

Public Enum ResourceType As Integer
    Any = 0
    Disk = 1
    Print = 2
    Reserved = 8
End Enum

Public Enum ResourceDisplaytype As Integer
    Generic = &H0
    Domain = &H1
    Server = &H2
    Share = &H3
    File = &H4
    Group = &H5
    Network = &H6
    Root = &H7
    Shareadmin = &H8
    Directory = &H9
    Tree = &HA
    Ndscontainer = &HB
End Enum

3

Uma opção que pode funcionar é usar WindowsIdentity.Impersonate(e alterar o principal do encadeamento) para se tornar o usuário desejado, assim . De volta a p / invocar, no entanto, eu tenho medo ...

Outra opção atrevida (e igualmente longe do ideal) pode ser gerar um processo para fazer o trabalho ... ProcessStartInfoaceita a .UserName, .Passworde .Domain.

Finalmente - talvez execute o serviço em uma conta dedicada que tenha acesso? (removido porque você esclareceu que isso não é uma opção).


não acho que a coisa do processo seja uma má idéia. o google publicou alguns documentos técnicos sobre os benefícios do multiprocessamento no chrome.
Dustin Getz

É possível alterar o objeto principal do segmento para um usuário sem conta na máquina local?
Gyrolf 17/11/2008

Para ser sincero, simplesmente não sei ... Você precisaria tentar o LogonUser com um domínio diferente para descobrir.
Marc Gravell

3

OK ... eu posso voltar ..

Disclaimer: Acabei de ter um dia com mais de 18 horas (de novo) .. Estou velho e esquecido .. Não sei soletrar .. Tenho um curto período de atenção, por isso é melhor responder rapidamente .. :-)

Questão:

É possível alterar o objeto principal do segmento para um usuário sem conta na máquina local?

Responda:

Sim, você pode alterar uma entidade de segmento, mesmo que as credenciais que você está usando não estejam definidas localmente ou estejam fora da "floresta".

Eu acabei de encontrar esse problema ao tentar conectar-me a um servidor SQL com autenticação NTLM de um serviço. Essa chamada usa as credenciais associadas ao processo, o que significa que você precisa de uma conta local ou uma conta de domínio para se autenticar antes de poder se representar. Blá, blá ...

Mas...

Chamar LogonUser (..) com o atributo ???? _ NEW_CREDENTIALS retornará um token de segurança sem tentar autenticar as credenciais. Kewl .. Não é necessário definir a conta na "floresta". Depois de ter o token, você poderá chamar DuplicateToken () com a opção de habilitar a representação, resultando em um novo token. Agora chame SetThreadToken (NULL, token); (Pode ser um token?) .. Uma chamada para ImpersonateLoggedonUser (token); pode ser necessário, mas acho que não. Procure..

Faça o que você precisa fazer..

Chame RevertToSelf () se você chamou ImpersonateLoggedonUser () e SetThreadToken (NULL, NULL); (Eu acho ... procure) e, em seguida, CloseHandle () nas alças criadas.

Sem promessas, mas isso funcionou para mim ... Isso está no topo da minha cabeça (como meu cabelo) e não sei soletrar !!!



1

Também portado para F # para usar com FAKE

module NetworkShare

open System
open System.ComponentModel
open System.IO
open System.Net
open System.Runtime.InteropServices

type ResourceScope =
| Connected = 1
| GlobalNetwork = 2
| Remembered = 3
| Recent = 4
type ResourceType =
| Any = 0
| Disk = 1
| Print = 2
| Reserved = 8
type ResourceDisplayType =
| Generic = 0x0
| Domain = 0x01
| Server = 0x02
| Share = 0x03
| File = 0x04
| Group = 0x05
| Network = 0x06
| Root = 0x07
| Shareadmin = 0x08
| Directory = 0x09
| Tree = 0x0a
| Ndscontainer = 0x0b

//Uses of this construct may result in the generation of unverifiable .NET IL code.
#nowarn "9"
[<StructLayout(LayoutKind.Sequential)>]
type NetResource =
  struct
    val mutable Scope : ResourceScope
    val mutable ResourceType : ResourceType
    val mutable DisplayType : ResourceDisplayType
    val mutable Usage : int
    val mutable LocalName : string
    val mutable RemoteName : string
    val mutable Comment : string
    val mutable Provider : string
    new(name) = {
      // lets preset needed fields
      NetResource.Scope = ResourceScope.GlobalNetwork
      ResourceType = ResourceType.Disk
      DisplayType = ResourceDisplayType.Share
      Usage = 0
      LocalName = null
      RemoteName = name
      Comment = null
      Provider = null
    }
  end

type WNetConnection(networkName : string, credential : NetworkCredential) =
  [<Literal>]
  static let Mpr = "mpr.dll"
  [<DllImport(Mpr, EntryPoint = "WNetAddConnection2")>]
  static extern int connect(NetResource netResource, string password, string username, int flags)
  [<DllImport(Mpr, EntryPoint = "WNetCancelConnection2")>]
  static extern int disconnect(string name, int flags, bool force)

  let mutable disposed = false;

  do
    let userName = if String.IsNullOrWhiteSpace credential.Domain
                   then credential.UserName
                   else credential.Domain + "\\" + credential.UserName
    let resource = new NetResource(networkName)

    let result = connect(resource, credential.Password, userName, 0)

    if result <> 0 then
      let msg = "Error connecting to remote share " + networkName
      new Win32Exception(result, msg)
      |> raise

  let cleanup(disposing:bool) =
    if not disposed then
      disposed <- true
      if disposing then () // TODO dispose managed resources here
      disconnect(networkName, 0, true) |> ignore

  interface IDisposable with
    member __.Dispose() =
      disconnect(networkName, 0, true) |> ignore
      GC.SuppressFinalize(__)

  override __.Finalize() = cleanup(false)

type CopyPath =
  | RemotePath of string * NetworkCredential
  | LocalPath of string

let createDisposable() =
  {
    new IDisposable with
      member __.Dispose() = ()
  }

let copyFile overwrite destPath srcPath : unit =
  use _srcConn =
    match srcPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  use _destConn =
    match destPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  match srcPath, destPath with
  | RemotePath(src, _), RemotePath(dest, _)
  | LocalPath(src), RemotePath(dest, _)
  | RemotePath(src, _), LocalPath(dest)
  | LocalPath(src), LocalPath(dest) ->
    if FileInfo(src).Exists |> not then
      failwith ("Source file not found: " + src)
    let destFilePath =
      if DirectoryInfo(dest).Exists then Path.Combine(dest, Path.GetFileName src)
      else dest
    File.Copy(src, destFilePath, overwrite)

let rec copyDir copySubDirs filePattern destPath srcPath =
  use _srcConn =
    match srcPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  use _destConn =
    match destPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  match srcPath, destPath with
  | RemotePath(src, _), RemotePath(dest, _)
  | LocalPath(src), RemotePath(dest, _)
  | RemotePath(src, _), LocalPath(dest)
  | LocalPath(src), LocalPath(dest) ->
    let dir = DirectoryInfo(src)
    if dir.Exists |> not then
      failwith ("Source directory not found: " + src)

    let dirs = dir.GetDirectories()
    if Directory.Exists(dest) |> not then
      Directory.CreateDirectory(dest) |> ignore

    let files = dir.GetFiles(filePattern)
    for file in files do
      let tempPath = Path.Combine(dest, file.Name)
      file.CopyTo(tempPath, false) |> ignore

    if copySubDirs then
      for subdir in dirs do
        let subdirSrc =
          match srcPath with
          | RemotePath(_, credential) -> RemotePath(Path.Combine(dest, subdir.Name), credential)
          | LocalPath(_) -> LocalPath(Path.Combine(dest, subdir.Name))
        let subdirDest =
          match destPath with
          | RemotePath(_, credential) -> RemotePath(subdir.FullName, credential)
          | LocalPath(_) -> LocalPath(subdir.FullName)
        copyDir copySubDirs filePattern subdirDest subdirSrc

0

Você deve adicionar algo parecido com isto:

<identity impersonate="true" userName="domain\user" password="****" />

No seu web.config.

Mais Informações.


Alguma segurança corporativa impede o uso de representação, porque eles não conseguem rastrear o aplicativo usando-o e devem estar no mesmo domínio ou em um domínio confiável. Eu acho que o apoio da personificação está manchado. Uma conta de serviço de domínio com pinvoke parece ser o caminho a seguir.
19719 Jim
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.