我使用此代码共享文件夹:
Public Sub Share()
Dim managementClass As New ManagementClass("Win32_Share")
Dim inParams As ManagementBaseObject = managementClass.GetMethodParameters("Create")
inParams("Description") = "My Description"
inParams("Name") = "Share Name"
inParams("Path") = "D:\Folder"
inParams("Type") = &H0
Dim outParams As ManagementBaseObject = managementClass.InvokeMethod("Create", inParams, Nothing)
If Convert.ToUInt32(outParams.Properties("ReturnValue").Value) <> 0 Then MessageBox.Show("Unable to share directory.")
MessageBox.Show("Shared folder successfully!")
End
Sub
现在我想要的是定义可以通过网络访问该文件夹的用户? 我怎么能这样做?
谢谢!
答案 0 :(得分:2)
此博客文章介绍了如何为共享设置权限:
代码在C#中,因此将它移植到VB并不是一个问题。
答案 1 :(得分:0)
下面请找到类似的NetShare代码,但这次全部都在C#中。 它还正确处理ACL指针的LocalFree(); 用法非常简单:
NetShare.Add(pathToShare, shareName, description, sharePermissions);
NetShare.DeleteIfExist(shareName);
public class NetShare
{
#region PInvoke functions, enums and structs
[DllImport("netapi32.dll")]
private static extern NET_API_STATUS NetShareAdd(
[In, MarshalAs(UnmanagedType.LPWStr)] string strServer,
[In] Int32 dwLevel,
[In] ref SHARE_INFO_502 buf,
[Out] out uint parm_err);
[DllImport("netapi32.dll")]
private static extern NET_API_STATUS NetShareDel(
[In, MarshalAs(UnmanagedType.LPWStr)] string strServer,
[In, MarshalAs(UnmanagedType.LPWStr)] string netName,
Int32 dwReserved);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool InitializeSecurityDescriptor(
[Out] out SECURITY_DESCRIPTOR SecurityDescriptor,
[In] uint dwRevision);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern uint SetEntriesInAcl(
int cCountOfExplicitEntries,
[In] ref EXPLICIT_ACCESS pListOfExplicitEntries,
[In] IntPtr OldAcl,
out IntPtr NewAcl);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool SetSecurityDescriptorDacl(
[In] ref SECURITY_DESCRIPTOR sd,
[In] bool daclPresent,
IntPtr dacl,
[In] bool daclDefaulted);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool IsValidSecurityDescriptor(
[In] ref SECURITY_DESCRIPTOR sd);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LocalFree(IntPtr hMem);
private enum NET_API_STATUS : uint
{
NERR_Success = 0,
ERROR_ACCESS_DENIED = 5,
ERROR_NOT_ENOUGH_MEMORY = 8,
ERROR_INVALID_PARAMETER = 87,
ERROR_INVALID_NAME = 123,
ERROR_INVALID_LEVEL = 124,
ERROR_MORE_DATA = 234,
NERR_BASE = 2100,
NERR_UnknownDevDir = (NERR_BASE + 16),
NERR_RedirectedPath = (NERR_BASE + 17),
NERR_DuplicateShare = (NERR_BASE + 18),
NERR_BufTooSmall = (NERR_BASE + 23),
NERR_NetNameNotFound = (NERR_BASE + 210) // Sharename not found
}
private enum SHARE_TYPE : uint
{
STYPE_DISKTREE = 0,
STYPE_PRINTQ = 1,
STYPE_DEVICE = 2,
STYPE_IPC = 3,
STYPE_TEMPORARY = 0x40000000,
STYPE_SPECIAL = 0x80000000,
}
private enum SHARE_PERMISSIONS : uint
{
ACCESS_NONE = 0,
ACCESS_READ = 1,
ACCESS_WRITE = 2,
ACCESS_CREATE = 4,
ACCESS_EXEC = 8,
ACCESS_DELETE = 0x10,
ACCESS_ATRIB = 0x20,
ACCESS_PERM = 0x40,
ACCESS_ALL = ACCESS_READ | ACCESS_WRITE | ACCESS_CREATE | ACCESS_EXEC | ACCESS_DELETE | ACCESS_ATRIB | ACCESS_PERM,
ACCESS_GROUP = 0x8000
}
[StructLayout(LayoutKind.Sequential)]
private struct SHARE_INFO_502
{
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_netname;
public SHARE_TYPE shi502_type;
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_remark;
public SHARE_PERMISSIONS shi502_permissions;
public Int32 shi502_max_uses;
public Int32 shi502_current_uses;
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_path;
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_passwd;
public Int32 shi502_reserved;
public IntPtr shi502_security_descriptor;
}
[Flags]
private enum ACCESS_MASK : uint
{
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,
STANDARD_RIGHTS_ALL = 0x001F0000,
SPECIFIC_RIGHTS_ALL = 0x0000FFFF,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000,
DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,
WINSTA_ENUMDESKTOPS = 0x00000001,
WINSTA_READATTRIBUTES = 0x00000002,
WINSTA_ACCESSCLIPBOARD = 0x00000004,
WINSTA_CREATEDESKTOP = 0x00000008,
WINSTA_WRITEATTRIBUTES = 0x00000010,
WINSTA_ACCESSGLOBALATOMS = 0x00000020,
WINSTA_EXITWINDOWS = 0x00000040,
WINSTA_ENUMERATE = 0x00000100,
WINSTA_READSCREEN = 0x00000200,
WINSTA_ALL_ACCESS = 0x0000037F
}
private enum ACCESS_MODE : uint
{
NOT_USED_ACCESS,
GRANT_ACCESS,
SET_ACCESS,
DENY_ACCESS,
REVOKE_ACCESS,
SET_AUDIT_SUCCESS,
SET_AUDIT_FAILURE
}
private enum MULTIPLE_TRUSTEE_OPERATION : uint
{
NO_MULTIPLE_TRUSTEE,
TRUSTEE_IS_IMPERSONATE
}
private enum TRUSTEE_FORM : uint
{
TRUSTEE_IS_SID,
TRUSTEE_IS_NAME,
TRUSTEE_BAD_FORM,
TRUSTEE_IS_OBJECTS_AND_SID,
TRUSTEE_IS_OBJECTS_AND_NAME
}
private enum TRUSTEE_TYPE : uint
{
TRUSTEE_IS_UNKNOWN,
TRUSTEE_IS_USER,
TRUSTEE_IS_GROUP,
TRUSTEE_IS_DOMAIN,
TRUSTEE_IS_ALIAS,
TRUSTEE_IS_WELL_KNOWN_GROUP,
TRUSTEE_IS_DELETED,
TRUSTEE_IS_INVALID,
TRUSTEE_IS_COMPUTER
}
[StructLayout(LayoutKind.Sequential)]
private struct TRUSTEE
{
public IntPtr pMultipleTrustee;
public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
public TRUSTEE_FORM TrusteeForm;
public TRUSTEE_TYPE TrusteeType;
[MarshalAs(UnmanagedType.LPTStr)]
public string ptstrName;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct SECURITY_DESCRIPTOR
{
public byte Revision;
public byte Size;
public ushort Control;
public IntPtr Owner;
public IntPtr Group;
public IntPtr Sacl;
public IntPtr Dacl;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct EXPLICIT_ACCESS
{
public ACCESS_MASK grfAccessPermissions;
public ACCESS_MODE grfAccessMode;
public UInt32 grfInheritance;
public TRUSTEE Trustee;
}
private const byte SECURITY_DESCRIPTOR_REVISION = 1;
private const uint NO_INHERITANCE = 0;
private const uint ERROR_NONE_MAPPED = 1332;
private class AclPtrSafeHandle : SafeHandle
{
public AclPtrSafeHandle() : base(IntPtr.Zero, true) { }
public override bool IsInvalid
{
get
{
return false;
}
}
public void Replace(IntPtr newAclPtr)
{
ReleaseHandle();
this.handle = newAclPtr;
}
protected override bool ReleaseHandle()
{
return (IntPtr.Zero == LocalFree(this.handle));
}
}
#endregion
#region SharePermissionEntry
public enum SharePermissions : uint
{
Read = ACCESS_MASK.GENERIC_READ | ACCESS_MASK.STANDARD_RIGHTS_READ | ACCESS_MASK.GENERIC_EXECUTE,
FullControl = ACCESS_MASK.GENERIC_ALL
}
public class SharePermissionEntry
{
/// <summary>
/// The account name in the following format: [DomainName]\[UserOrGroupName]
/// Where DomainName that the user/group in the UserOrGroupName belongs to
/// Where UserOrGroupName the user or group that should be granted/denied permission
/// Note: DomainName with backslash is optional
/// </summary>
/// <example>
/// Everyone
/// REDMOND\elize
/// AV\AVSubmit Samples RW
/// </example>
public readonly string AccountName;
/// <summary>
/// The share permission to grant or deny for the account in UserOrGroupName
/// </summary>
public readonly SharePermissions Permission;
/// <summary>
/// Set to True to allow the rights specified in the Permission property and False to deny the rights specified in the Permission property.
/// </summary>
public readonly bool AllowOrDeny;
/// <summary>
/// Creates a new instance of the SharePermissionEntry class and populates each of the properties within the instance
/// </summary>
/// <param name="AccountName">[DomainName]\[UserOrGroupName] of username or group name that this permission entry relates to
/// You may just pass [UserOrGroupName] if you are specifying a 'well known' identity such as the Everyone group in the AccountName argument
/// </param>
/// <param name="DesiredPermission">The share permission to grant/deny</param>
/// <param name="AlloworDenyPermission">True to allow the permission, False to deny the permission</param>
public SharePermissionEntry(string accountName, SharePermissions desiredPermission, bool alloworDenyPermission)
{
Guard.ArgumentNotNullOrEmptyString(accountName, nameof(accountName));
this.AccountName = accountName;
this.Permission = desiredPermission;
this.AllowOrDeny = alloworDenyPermission;
}
}
#endregion
/// <summary>
/// Shares local path with specified share name, description and permissions
/// </summary>
/// <param name="pathToShare">Local path to folder to share</param>
/// <param name="shareName">Name of a shared resource</param>
/// <param name="shareDescription">Optional comment about the shared resource</param>
/// <param name="sharePermissions">List of share permissions to apply</param>
/// <exception cref="Win32Exception">Will throw Win32Exception with relevant error code in case of failure</exception>
/// <remarks>
/// Only members of the Administrators, System Operators, or Power Users local group can add file shares with a call to the NetShareAdd function.
/// </remarks>
public static void Add(string pathToShare, string shareName, string shareDescription, IEnumerable<SharePermissionEntry> sharePermissions)
{
Guard.ArgumentNotNullOrEmptyString(pathToShare, nameof(pathToShare));
Guard.ArgumentNotNullOrEmptyString(shareName, nameof(shareName));
Guard.ArgumentCollectionNotEmpty(sharePermissions, nameof(sharePermissions));
DirectoryInfo di = new DirectoryInfo(pathToShare);
if (!di.Exists)
{
throw new DirectoryNotFoundException(pathToShare);
}
pathToShare = di.FullName.TrimEnd(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); // Remove last / or \
// This pointer will hold the full ACL (access control list) once the loop below has completed
using (AclPtrSafeHandle aclPtr = new AclPtrSafeHandle())
{
// Loop through each entry in our list of explicit access rules, build each one and add it to the ACL
foreach (SharePermissionEntry spe in sharePermissions)
{
// Create a TRUSTEE structure and populate it with the user account details
TRUSTEE account = new TRUSTEE()
{
MultipleTrusteeOperation = MULTIPLE_TRUSTEE_OPERATION.NO_MULTIPLE_TRUSTEE,
pMultipleTrustee = IntPtr.Zero,
TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME,
ptstrName = spe.AccountName,
TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_UNKNOWN
};
// Populate the explicit access rule for this user/permission specified in the SharePermissions argument
EXPLICIT_ACCESS explicitAccessRule = new EXPLICIT_ACCESS()
{
// Set this to an Allow or Deny entry based on what was specified in the AllowOrDeny property
grfAccessMode = (spe.AllowOrDeny) ? ACCESS_MODE.GRANT_ACCESS : ACCESS_MODE.DENY_ACCESS,
// Build the access mask for the share permission specified for this user
grfAccessPermissions = (ACCESS_MASK)spe.Permission,
// Not relevant for share permissions so just set to NO_INHERITANCE
grfInheritance = NetShare.NO_INHERITANCE,
// Set the Trustee to the TRUSTEE structure we created earlier in the loop
Trustee = account
};
// Add this explicit access rule to the ACL
IntPtr newAclPtr;
uint setEntriesResult = SetEntriesInAcl(1, ref explicitAccessRule, aclPtr.DangerousGetHandle(), out newAclPtr);
aclPtr.Replace(newAclPtr);
// Check the result of the SetEntriesInAcl API call
if (setEntriesResult == ERROR_NONE_MAPPED)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), $"The account {spe.AccountName} could not be mapped to a security identifier (SID). Check that the account name is correct and that the domain where the account is held is contactable. The share has not been created.");
}
else if (setEntriesResult != 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), $"The account {spe.AccountName} could not be added to the ACL as the follow error was encountered: {setEntriesResult}. The share has not been created.");
}
}
// Create a SECURITY_DESCRIPTOR structure and set the Revision number
SECURITY_DESCRIPTOR secDesc = new SECURITY_DESCRIPTOR()
{
Revision = NetShare.SECURITY_DESCRIPTOR_REVISION
};
// Initialise the SECURITY_DESCRIPTOR instance - returns False if an error was encountered
if (!InitializeSecurityDescriptor(out secDesc, NetShare.SECURITY_DESCRIPTOR_REVISION))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "An error was encountered during the call to the InitializeSecurityDescriptor API. The share has not been created.");
}
// Add the ACL to the SECURITY_DESCRIPTOR
if (!SetSecurityDescriptorDacl(ref secDesc, true, aclPtr.DangerousGetHandle(), false))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "An error was encountered during the call to the SetSecurityDescriptorDacl API. The share has not been created.");
}
// Check to make sure the SECURITY_DESCRIPTOR is valid
if (!IsValidSecurityDescriptor(ref secDesc))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "No errors were reported from previous API calls but the security descriptor is not valid. The share has not been created.");
}
// Create a pointer for the SECURITY_DESCRIPTOR so that we can pass this in to the SHARE_INFO_502 structure
IntPtr secDescPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(secDesc));
Marshal.StructureToPtr(secDesc, secDescPtr, false);
// Create and populate the SHARE_INFO_502 structure that specifies all of the share settings
SHARE_INFO_502 shareInfo = new SHARE_INFO_502()
{
shi502_netname = shareName,
shi502_type = SHARE_TYPE.STYPE_DISKTREE,
shi502_remark = shareDescription,
shi502_permissions = SHARE_PERMISSIONS.ACCESS_NONE,
shi502_max_uses = -1,
shi502_current_uses = 0,
shi502_path = pathToShare,
shi502_passwd = null,
shi502_reserved = 0,
shi502_security_descriptor = secDescPtr
};
// Call the NetShareAdd API to create the share
uint parm_error = 0;
NET_API_STATUS r = NetShareAdd(null /*localhost*/, 502, ref shareInfo, out parm_error);
// Clean up and return the result of NetShareAdd
Marshal.FreeCoTaskMem(secDescPtr);
if (r != NET_API_STATUS.NERR_Success)
{
throw new Win32Exception((int)r, $"An error {r} was encountered during the call to the NetShareAdd API. The share has not been created.");
}
}
}
/// <summary>
/// Deletes a share name from a server's list of shared resources, disconnecting all connections to the shared resource.
/// </summary>
/// <param name="shareName">Name of a shared resource</param>
/// <exception cref="Win32Exception">Will throw Win32Exception with relevant error code in case of failure</exception>
/// <remarks>
/// Only members of the Administrators, Server Operators, or Power Users local group, or those with Server Operator group membership,
/// can successfully delete file shares with a call to the NetShareDel function.
/// </remarks>
public static void DeleteIfExist(string shareName)
{
Guard.ArgumentNotNullOrEmptyString(shareName, nameof(shareName));
var r = NetShareDel(null /* localhost */, shareName, 0);
if ((r != NET_API_STATUS.NERR_Success) && (r != NET_API_STATUS.NERR_NetNameNotFound))
{
throw new Win32Exception((int)r, "An error was encountered during the call to the NetShareDel API. The share has not been deleted.");
}
}
}