Як вказати ім’я користувача та пароль під час підключення до загальної мережі


191

Під час підключення до спільної мережі, для якої поточний користувач (у моєму випадку користувач мережі з підтримкою мережі) не має прав, ім'я та пароль повинні бути вказані.

Я знаю, як це зробити за допомогою функцій Win32 ( WNet*родина з mpr.dll), але хотів би це зробити з функцією .Net (2.0).

Які варіанти доступні?

Можливо, ще трохи інформації допоможе:

  • Випадок використання - це служба Windows, а не програма Asp.Net.
  • Послуга працює під обліковим записом, який не має прав на акцію.
  • Обліковий запис користувача, необхідний для частки, не відомий на стороні клієнта.
  • Клієнт і сервер не є членами одного домену.

7
Поки я не даю вам корисної відповіді, я можу надати антивідповідь. Подання себе і нерестування як Марк, на який посилається, не працюватиме, коли сервер і клієнт не в одному домені, якщо між ними не буде довіри два домени. Якщо є довіра, то я думаю, що це спрацює. Я б просто відповів як коментар до Марка, але мені не вистачає респондентів для коментарів. : - /
Moose

Відповіді:


152

Ви можете або змінити ідентифікацію потоку, або P / Invoke WNetAddConnection2. Я віддаю перевагу останньому, оскільки мені іноді потрібно підтримувати кілька облікових даних для різних місць. Я загортаю його в ідентифікатор і закликаю WNetCancelConnection2, щоб потім видалити записи (уникаючи помилок декількох імен користувачів):

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

4
Служба не є членом цільового домену - себе за особою не може працювати, оскільки ви не зможете локально створити маркер безпеки та впоратись з нею. PInvoke - єдиний спосіб.
stephbu

@MarkBrackett Я знаю, що це стара відповідь, але, можливо, ти все ще знаєш ... чи буде наданий доступ лише програмі або також користувачеві, який увійшов у систему через Explorer?
Бриз

@Breeze - я не перевіряв його, але очікую, що він засвідчить аутентифікацію для сеансу входу; тож якщо ваша програма працює як зареєстрований користувач, вони також матимуть доступ (принаймні на час дії).
Марк Брекетт

8
Визначення readCredentials та writeCredentials можуть бути включені у відповідь.
Андерс Лінден

2
Якщо ви отримуєте помилку 53 , переконайтеся, що шлях не закінчується знаком "\"
Мустафа С.

326

Мені так сподобалась відповідь Марка Браткета, що я зробив власну швидку реалізацію. Ось це, якщо комусь іншому потрібно поспішати:

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
Це дійсно повинно бути throw new Win32Exception(result);, оскільки WNetAddConnection2 повертає коди помилок win32 ( ERROR_XXX)
torvin

2
Це блискучий маленький фрагмент коду. Потрібно ввійти в систему UNIX, щоб отримати список каталогів для друку у веб-програмі MVC5, і це зробило трюк. +1 !!!
Tay

3
Для компіляції вищевказаного коду необхідні наступні оператори: використання System.Net; використання System.Runtime.InteropServices; за допомогою System.ComponentModel;
Метт Нельсон

4
вибачте, щоб оновити старий потік, але схоже, що він не закриває з'єднання після завершення блоку. У мене є програма для завантаження декількох фотографій, перша - добре, друга - не дає. Підключення відпускається, коли програма закрита. Будь-яка порада?
арти

3
У нас була така ж проблема, як у вас, @arti. Просто встановивши ім'я користувача та пароль на NetworkCredentialоб’єкт, програма змогла один раз підключитися до мережевого диска. Після цього ми отримували ERROR_LOGON_FAILURE за кожну спробу, доки програма не перезапустилася. Потім ми спробували поставити домен і на NetworkCredentialоб’єкт, і раптом це спрацювало! Я поняття не маю, чому це вирішило проблему, особливо той факт, що вона працювала, щоб підключитися один раз без домену.
lsmeby

50

Сьогодні через 7 років я зіткнувся з тим же питанням, і я хотів би поділитися своєю версією рішення.

Це готове копіювання та вставка :-) Ось це:

Крок 1

У своєму коді (коли потрібно робити щось із дозволами)

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

Крок 2

Файл Helper, який робить магію

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 Відповідно до документації про LogonUser , вона працює лише для користувачів на локальному комп'ютері: "Функція LogonUser намагається ввійти користувача на локальний комп'ютер. Локальний комп'ютер - це комп'ютер, з якого викликали LogonUser. Ви не можете використовувати LogonUser щоб увійти на віддалений комп'ютер. "Ви отримаєте помилку" Win32Exception: ім'я користувача або пароль невірні. " Тому я припускаю, що машини повинні бути принаймні на одному домені.
Чарльз Чен

1
@CharlesChen Тільки довів, що це чудово працює в усіх доменах, FYI. Сервер, на якому я запускаю, знаходиться в DMZ і, безумовно, підключається до файлового сервера на іншому домені через брандмауер. Фрагмент вбивці Павло, ти людина, і це, мабуть, має бути прийнятою сьогодні відповіддю.
Брайан Маккей

Це ВЕЛИКИЙ РІШЕННЯ! Дякую, Павло Ковальов.
STLDev

це працює на ldap? там сказано, що у мене немає сервера входу. я використовую ldap auth
Джуліус Лімсон

28

Я шукав багато методів, і я робив це по-своєму. Вам потрібно відкрити з'єднання між двома машинами за допомогою командного рядка команди NET USE і після закінчення роботи очистити з'єднання за допомогою командного рядка NET USE "myconnection" / delete.

Ви повинні використовувати командний рядок із коду, який знаходиться за цим:

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

Використання просте:

SaveACopyfileToServer(filePath, savePath);

Ось функції:

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);
    }

А також функцією 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;
    } 

Ця функція працювала для мене дуже швидко і стабільно.


1
У разі невдалого відображення частки, що було б повернення кодів?
surega

14

Рішення Luke Quinane виглядає добре, але воно працювало лише частково в моєму додатку ASP.NET MVC. Маючи дві спільні папки на одному сервері з різними обліковими даними, я міг би використати себе за перше.

Проблема WNetAddConnection2 також полягає в тому, що він поводиться по-різному в різних версіях Windows. Тому я шукав альтернативи і знайшов функцію LogonUser . Ось мій код, який також працює в 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;
    }
}

Використання:

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

//do your stuff here

impersonationContext.Leave();

2
цей підхід для мене добре працював, але на моєму тестуванні зауважив, що при використанні неправильного пароля з обліковим записом користувача домену цей користувач негайно переходить у заблокований статус. наша політика домену вимагає 3 невдалих спроб входу до того, як це станеться, але завдяки такому підходу одна погана спроба, і ви заблоковані. Отже, використовуйте обережно ...
келіб

5

Для VB.lovers еквівалент VB.NET коду Люка Кінана (дякую Люку!)

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

Один з варіантів , який може працювати використовують WindowsIdentity.Impersonate(і змінити нитки основний) , щоб стати потрібним користувач, як так . Назад до p / call, проте, боюся ...

Інший зухвалий (і настільки ж далеко від ідеалу) варіант може породити процес , щоб зробити роботу ... ProcessStartInfoприймає .UserName, .Passwordі.Domain .

Нарешті - можливо, запустіть службу в спеціальному обліковому записі, який має доступ? (видалено, коли ви уточнили, що це не варіант).


я не думаю, що процес є такою поганою ідеєю. google виклав кілька відомостей про переваги багатопроцесорної обробки хрому.
Дастін Гетц

Чи можна змінити головний потік на користувача без жодного облікового запису на локальній машині?
gyrolf

Якщо чесно, я просто не знаю ... Вам доведеться спробувати LogonUser з іншим доменом, щоб дізнатися це.
Марк Гравелл

3

Гаразд ... я можу передзвонити ..

Відмова: У мене щоденно (знову) був 18-годинний день .. Я старий і незабудкий .. Я не можу заклинання .. У мене короткий проміжок уваги, тому я краще швидко реагую .. :-)

Питання:

Чи можна змінити головний потік на користувача без жодного облікового запису на локальній машині?

Відповідь:

Так, ви можете змінити головний потік, навіть якщо використовувані вами облікові дані не визначені локально або знаходяться поза "лісом".

Я щойно зіткнувся з цією проблемою, коли намагався підключитися до сервера SQL з аутентифікацією NTLM від служби. Цей виклик використовує облікові дані, пов’язані з процесом, що означає, що вам потрібно мати або локальний рахунок, або обліковий запис домену, щоб підтвердити автентифікацію, перш ніж ви можете себе представити. Бла, бла ...

Але ...

Виклик LogonUser (..) з атрибутом ???? _ NEW_CREDENTIALS поверне маркер безпеки, не намагаючись перевірити автентифікацію даних. Kewl .. Не потрібно визначати рахунок у "лісі". Отримавши маркер, можливо, вам доведеться зателефонувати в DuplicateToken () з можливістю ввімкнути себе, внаслідок чого новий маркер. Тепер зателефонуйте SetThreadToken (NULL, маркер); (Це може бути & токен?) .. Виклик ImpersonateLoggedonUser (маркер); може знадобитися, але я не думаю. Подивіться ..

Робіть те, що вам потрібно зробити ..

Зателефонуйте RevertToSelf (), якщо ви назвали ImpersonateLoggedonUser (), то SetThreadToken (NULL, NULL); (Я думаю ... подивіться), а потім CloseHandle () на створених ручках ..

Ніяких обіцянок, але це спрацювало для мене ... Це з моєї голови (як у мого волосся), і я не можу написати !!!


1

Якщо ви не можете створити локально дійсний маркер безпеки, схоже, ви виключили всі панелі параметрів API Win32 та WNetAddConnection *.

Тут відомості про MSDN про WNet - інформація про PInvoke та зразок коду, який підключається до шляху UNC тут:

http://www.pinvoke.net/default.aspx/mpr/WNetAddConnection2.html#

Посилання MSDN тут:

http://msdn.microsoft.com/en-us/library/aa385391(VS.85).aspx


1

Також переноситься на F # для використання з 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

Ви повинні дивитись на додавання подібного:

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

У ваш web.config.

Більше інформації.


Деяка корпоративна безпека перешкоджає використанню підроблених осіб, оскільки вони не в змозі відстежувати програму, використовуючи її, і повинні бути в тому ж довіреному домені. Я думаю, що виявляється непомітна підтримка. Очевидно, шлях до облікового запису служби домену з пінвоке.
Джим
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.