使用 WMI 将用户添加到远程 windows 共享
Add user to remote windows share using WMI
我在远程计算机 IMPC-1111 的 C:\ 根目录中有一个共享,我正在尝试添加一个用户 /w 访问掩码:
FullControl = 2032127
Change = 1245631
[ReadOnly] = 1179817
我已经想出了如何阅读它们....但无法弄清楚如何 write/change 它们。这是我用来阅读它们的代码。
Private Function GetSharedFolderAccessRule() As DataTable
Dim DT As DataTable = New DataTable()
Try
DT.Columns.Add("ShareName")
DT.Columns.Add("Caption")
DT.Columns.Add("Path")
DT.Columns.Add("Domain")
DT.Columns.Add("User")
DT.Columns.Add("AccessMask")
DT.Columns.Add("AceType")
Dim Con As ConnectionOptions = New ConnectionOptions
Con.Username = "Username"
Con.Password = "Password"
'Dim Scope As ManagementScope = New ManagementScope("\.\root\cimv2", Con)
Dim Scope As ManagementScope = New ManagementScope("\IMPC-1111\root\cimv2", Con)
Scope.Connect()
Dim Query As ObjectQuery = New ObjectQuery("SELECT * FROM Win32_LogicalShareSecuritySetting")
Dim Searcher As ManagementObjectSearcher = New ManagementObjectSearcher(Scope, Query)
Dim QueryCollection As ManagementObjectCollection = Searcher.[Get]()
For Each SharedFolder As ManagementObject In QueryCollection
If True Then
Dim ShareName As String = CType(SharedFolder("Name"), String)
Dim Caption As String = CType(SharedFolder("Caption"), String)
Dim LocalPath As String = String.Empty
Dim Win32Share As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Path FROM Win32_share WHERE Name = '" & ShareName & "'")
For Each ShareData As ManagementObject In Win32Share.[Get]()
LocalPath = CType(ShareData("Path"), String)
Next
Dim Method As ManagementBaseObject = SharedFolder.InvokeMethod("GetSecurityDescriptor", Nothing, New InvokeMethodOptions())
Dim Descriptor As ManagementBaseObject = CType(Method("Descriptor"), ManagementBaseObject)
Dim DACL As ManagementBaseObject() = CType(Descriptor("DACL"), ManagementBaseObject())
For Each ACE As ManagementBaseObject In DACL
Dim Trustee As ManagementBaseObject = CType(ACE("Trustee"), ManagementBaseObject)
Dim Row As DataRow = DT.NewRow()
Row("ShareName") = ShareName
Row("Caption") = Caption
Row("Path") = LocalPath
Row("Domain") = CType(Trustee("Domain"), String)
Row("User") = CType(Trustee("Name"), String)
Row("AccessMask") = CType(ACE("AccessMask"), UInt32)
Row("AceType") = CType(ACE("AceType"), UInt32)
DT.Rows.Add(Row)
DT.AcceptChanges()
Next
End If
Next
Catch ex As Exception
MessageBox.Show(ex.StackTrace, ex.Message)
End Try
Return DT
End Function
任何人都可以指出我正确的方向吗?这甚至可以使用 WMI 编写吗?
谢谢!
您可以使用Win32_LogicalShareSecuritySetting
.SetSecurityDescriptor()
method修改共享权限。修改现有权限的工作方式如下...
- 获取所需的
Win32_LogicalShareSecuritySetting
实例。
- 调用
GetSecurityDescriptor()
to get the share's security descriptor as a Win32_SecurityDescriptor
实例。
- 通过其
DACL
属性. 获取安全描述符的自由访问控制列表
- 创建一个新的访问控制条目。
- 得到一个reference to the
Win32_ACE
class.
- 创建
Win32_ACE
class 的实例。
- 设置访问控制条目的
AccessMask
、AceFlags
、AceType
和Trustee
属性。
- 得到一个reference to the
Win32_Trustee
class.
- 创建
Win32_Trustee
class 的实例。
- 通过设置受托人的
SIDString
或Name
(和Domain
)属性来指定条目的委托人。
- 查询
Win32_Account
class 或其衍生物的实例是获取这些值的一种方法。
- 创建一个结合现有条目和新条目的新访问控制列表。
- 根据 Order of ACEs in a DACL,确保
Deny
个条目排在 Allow
个条目之前。
- 将安全描述符的
DACL
属性 设置为新的访问控制列表。
- 调用
SetSecurityDescriptor()
保存共享的安全描述符。
以下 class 包含获取共享属性的方法,特别是通过 AddAccessControlEntry()
方法添加新的访问控制条目...
Imports System.Management
Imports System.Security.AccessControl
Friend Class ShareSecurity
Private ReadOnly Property ShareName As String
Private ReadOnly Property GetOptions As ObjectGetOptions
Private ReadOnly Property Scope As ManagementScope
Public Sub New(host As String, shareName As String, username As String, password As String)
Me.ShareName = shareName
GetOptions = New ObjectGetOptions()
Scope = New ManagementScope(
New ManagementPath() With {
.NamespacePath = "root\cimv2",
.Server = host
},
New ConnectionOptions() With {
_ ' ***** For demonstration purposes only! *****
_ 'TODO: Find a secure way to store the remote password
.Password = password,
.Username = username
}
)
End Sub
Public Function GetShareProperties() As IDictionary(Of String, Object)
Dim sharePath As New ManagementPath($"Win32_Share.Name=""{ShareName}""")
Using share As New ManagementObject(Scope, sharePath, GetOptions)
Return GetPropertyDictionary(share)
End Using
End Function
Public Function GetShareSecurityDescriptorProperties() As IDictionary(Of String, Object)
Using shareSecurity As ManagementObject = GetShareSecurity()
Using securityDescriptor As ManagementBaseObject = GetShareSecurityDescriptor(shareSecurity)
Return GetPropertyDictionary(securityDescriptor)
End Using
End Using
End Function
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, securityIdentifier As String)
AddAccessControlEntry(
entryType,
entryRights,
Sub(trustee)
trustee("SIDString") = securityIdentifier
End Sub
)
End Sub
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, domain As String, account As String)
AddAccessControlEntry(
entryType,
entryRights,
Sub(trustee)
trustee("Domain") = domain
trustee("Name") = account
End Sub
)
End Sub
''' <param name="trusteeInitializer">Initializes the Win32_Trustee instance for the access control entry to be added.</param>
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, trusteeInitializer As Action(Of ManagementObject))
Using shareSecurity As ManagementObject = GetShareSecurity()
Using securityDescriptor As ManagementBaseObject = GetShareSecurityDescriptor(shareSecurity)
Dim accessControlEntries As ManagementBaseObject() = DirectCast(securityDescriptor("DACL"), ManagementBaseObject())
' The class must not be created in the remote scope otherwise CreateInstance()
' throws "System.UnauthorizedAccessException: 'Access is denied'."
Using accessControlEntryClass As New ManagementClass("Win32_ACE")
Using accessControlEntry As ManagementObject = accessControlEntryClass.CreateInstance()
accessControlEntry("AccessMask") = CUInt(entryRights)
accessControlEntry("AceFlags") = CUInt(AceFlags.None)
accessControlEntry("AceType") = CUInt(entryType)
' The class must not be created in the remote scope otherwise CreateInstance()
' throws "System.UnauthorizedAccessException: 'Access is denied'."
Using trusteeClass As New ManagementClass("Win32_Trustee")
Using trustee As ManagementObject = trusteeClass.CreateInstance()
trusteeInitializer.Invoke(trustee)
accessControlEntry("Trustee") = trustee
' Create a new access control list including the new access control
' entry, sorted with Deny entries first (true sorts after false)
' https://docs.microsoft.com/windows/win32/secauthz/order-of-aces-in-a-dacl
securityDescriptor("DACL") = accessControlEntries _
.Append(accessControlEntry) _
.OrderByDescending(Function(entry) CType(entry("AceType"), AceType)) _
.ToArray()
SetShareSecurityDescriptor(shareSecurity, securityDescriptor)
End Using
End Using
End Using
End Using
End Using
End Using
End Sub
Private Function GetShareSecurity() As ManagementObject
Dim shareSecurityPath As New ManagementPath($"Win32_LogicalShareSecuritySetting.Name=""{ShareName}""")
Return New ManagementObject(Scope, shareSecurityPath, GetOptions)
End Function
Private Function GetShareSecurityDescriptor(shareSecurity As ManagementObject) As ManagementBaseObject
' Create an array to store the output parameter
Dim invokeParameters(0) As ManagementBaseObject
Dim invokeResult As UInteger = shareSecurity.InvokeMethod("GetSecurityDescriptor", invokeParameters)
If invokeResult = 0 Then
Return invokeParameters(0)
Else
'TODO: Handle failure of GetSecurityDescriptor()...
Return Nothing
End If
End Function
Private Sub SetShareSecurityDescriptor(shareSecurity As ManagementObject, securityDescriptor As ManagementBaseObject)
' Create an array to store the input parameter
Dim invokeParameters() As ManagementBaseObject = {securityDescriptor}
Dim invokeResult As UInteger = shareSecurity.InvokeMethod("SetSecurityDescriptor", invokeParameters)
If invokeResult <> 0 Then
'TODO: Handle failure of SetSecurityDescriptor()...
End If
End Sub
Private Shared Function GetPropertyDictionary(obj As ManagementBaseObject) As IDictionary(Of String, Object)
Return obj.Properties _
.Cast(Of PropertyData)() _
.ToDictionary(
Function([property]) [property].Name,
Function([property])
' Recursively create dictionaries in place of management objects
Dim baseObjectArray As ManagementBaseObject() = TryCast([property].Value, ManagementBaseObject())
If baseObjectArray IsNot Nothing Then
Return baseObjectArray.Select(AddressOf GetPropertyDictionary).ToArray()
Else
Dim baseObject As ManagementBaseObject = TryCast([property].Value, ManagementBaseObject)
If baseObject IsNot Nothing Then
Return GetPropertyDictionary(baseObject)
Else
Return [property].Value
End If
End If
End Function
)
End Function
End Class
下面的程序使用上面的 ShareSecurity
class 来显示远程共享的属性,并且可以选择向它添加一个新的访问控制条目...
Imports System.Security.AccessControl
Public Class Program
Public Shared Sub Main(args As String())
If args Is Nothing OrElse args.Length = 0 Then
DisplayUsage()
ElseIf args.Length < 4 Then
DisplayError("Too few arguments.")
Else
Dim host As String = args(0)
Dim shareName As String = args(1)
Dim username As String = args(2)
' ***** For demonstration purposes only! *****
'TODO: Find a secure way to store the remote password
Dim password As String = args(3)
Dim shareSecurity As New ShareSecurity(host, shareName, username, password)
DisplayShareProperties(shareSecurity)
DisplaySecurityDescriptor(shareSecurity)
If args.Length > 4 Then
If args.Length <> 7 AndAlso args.Length <> 8 Then
DisplayError("Argument count mismatch.")
Else
Dim entryType As AceType
If Not [Enum].TryParse(args(4), True, entryType) Then
DisplayError($"Invalid <type> value ""{args(4)}"".")
Else
Dim entryRights As FileSystemRights
If Not [Enum].TryParse(args(5), True, entryRights) Then
DisplayError($"Invalid <rights> value ""{args(5)}"".")
Else
DisplayTextWithSeparator("New access control entry")
Console.WriteLine($" Type: {entryType}")
Console.WriteLine($" Rights: {entryRights}")
If args.Length = 7 Then
Dim securityIdentifier As String = args(6)
Console.WriteLine($" SID: {securityIdentifier}")
shareSecurity.AddAccessControlEntry(entryType, entryRights, securityIdentifier)
Else ' args.Length = 8
Dim domain As String = args(6)
Dim account As String = args(7)
Console.WriteLine($" Domain: {domain}")
Console.WriteLine($"Account: {account}")
shareSecurity.AddAccessControlEntry(entryType, entryRights, domain, account)
End If
Console.WriteLine()
DisplaySecurityDescriptor(shareSecurity)
End If
End If
End If
End If
End If
End Sub
Private Shared Sub DisplayUsage()
Dim entryAssemblyPath As String = System.Reflection.Assembly.GetEntryAssembly().Location
Dim entryAssemblyName As String = System.IO.Path.GetFileName(entryAssemblyPath)
Console.WriteLine("Display share properties:")
Console.WriteLine()
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password>")
Console.WriteLine()
Console.WriteLine("Add access control entry:")
Console.WriteLine()
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <sid>")
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <domain> <account>")
Console.WriteLine()
Console.WriteLine(vbTab & $" <type> - A {GetType(AceType).FullName} enumeration value.")
Console.WriteLine(vbTab & $"<rights> - A {GetType(FileSystemRights).FullName} enumeration value.")
Console.WriteLine(vbTab & " <sid> - An account security identifier.")
Console.WriteLine()
End Sub
Private Shared Sub DisplayError(message As String)
Console.WriteLine($"ERROR: {message}")
Console.WriteLine()
DisplayUsage()
End Sub
Private Shared Sub DisplayTextWithSeparator(text As String)
Console.WriteLine(text)
Console.WriteLine(New String("-"c, text.Length))
End Sub
Private Shared Sub DisplayShareProperties(shareSecurity As ShareSecurity)
Dim shareProperties As IDictionary(Of String, Object) = shareSecurity.GetShareProperties()
DisplayTextWithSeparator("Share properties")
For Each propertyName As String In New String() {"Description", "Name", "Path"}
DisplayProperty(shareProperties, propertyName)
Next
Console.WriteLine()
End Sub
Private Shared Sub DisplaySecurityDescriptor(shareSecurity As ShareSecurity)
Dim securityDescriptorProperties As IDictionary(Of String, Object) = shareSecurity.GetShareSecurityDescriptorProperties()
DisplayTextWithSeparator("Share security descriptor")
DisplayProperty(securityDescriptorProperties, "ControlFlags", Function(value) CType(value, ControlFlags))
Console.WriteLine()
Dim accessControlList As IDictionary(Of String, Object)() = securityDescriptorProperties("DACL")
For i As Integer = 0 To accessControlList.Length - 1
Dim accessControlEntryProperties As IDictionary(Of String, Object) = accessControlList(i)
DisplayTextWithSeparator($"Access control entry #{i}")
DisplayProperty(accessControlEntryProperties, "AccessMask", Function(value) CType(value, FileSystemRights))
DisplayProperty(accessControlEntryProperties, "AceFlags", Function(value) CType(value, AceFlags))
DisplayProperty(accessControlEntryProperties, "AceType", Function(value) CType(value, AceType))
DisplayProperty(accessControlEntryProperties, "Trustee", Function(value) DirectCast(value, IDictionary(Of String, Object))("Name"))
Console.WriteLine()
Next
End Sub
Private Shared Sub DisplayProperty(properties As IDictionary(Of String, Object), propertyName As String)
DisplayProperty(properties, propertyName, Nothing)
End Sub
Private Shared Sub DisplayProperty(properties As IDictionary(Of String, Object), propertyName As String, selector As Func(Of Object, Object))
Dim propertyValue As Object = properties(propertyName)
Dim displayValue As Object = If(
selector IsNot Nothing,
selector.Invoke(propertyValue),
If(propertyValue, "<null>")
)
Console.WriteLine($"{propertyName}: {displayValue}")
End Sub
End Class
给这样的分享...
...将 Full Control
授予 Administrators
,将 Read
授予 Everyone
,这样调用程序...
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" S-1-5-32-546
...或者像这样...
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" BUILTIN Guests
...产生这样的输出...
Share properties
----------------
Description: This is the share description.
Name: My Share
Path: C:\My Share
Share security descriptor
-------------------------
ControlFlags: DiscretionaryAclPresent, SelfRelative
Access control entry #0
-----------------------
AccessMask: ReadAndExecute, Synchronize
AceFlags: None
AceType: AccessAllowed
Trustee: Everyone
Access control entry #1
-----------------------
AccessMask: FullControl
AceFlags: None
AceType: AccessAllowed
Trustee: Administrators
New access control entry
------------------------
Type: AccessDenied
Rights: Modify, Synchronize
SID: S-1-5-32-546
Share security descriptor
-------------------------
ControlFlags: DiscretionaryAclPresent, SelfRelative
Access control entry #0
-----------------------
AccessMask: Modify, Synchronize
AceFlags: None
AceType: AccessDenied
Trustee: Guests
Access control entry #1
-----------------------
AccessMask: ReadAndExecute, Synchronize
AceFlags: None
AceType: AccessAllowed
Trustee: Everyone
Access control entry #2
-----------------------
AccessMask: FullControl
AceFlags: None
AceType: AccessAllowed
Trustee: Administrators
由于 VB.NET 不是我的母语,这里是我开始使用的等效 C# 代码,以使一切正常...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Security.AccessControl;
namespace SO60271689.CSharp
{
internal class ShareSecurity
{
private string ShareName
{
get;
}
private ObjectGetOptions GetOptions
{
get;
}
private ManagementScope Scope
{
get;
}
public ShareSecurity(string host, string shareName, string username, string password)
{
ShareName = shareName;
GetOptions = new ObjectGetOptions();
Scope = new ManagementScope(
new ManagementPath() {
NamespacePath = @"root\cimv2",
Server = host
},
new ConnectionOptions() {
// ***** For demonstration purposes only! *****
//TODO: Find a secure way to store the remote password
Password = password,
Username = username
}
);
}
public IDictionary<string, object> GetShareProperties()
{
ManagementPath sharePath = new ManagementPath($"Win32_Share.Name=\"{ShareName}\"");
using (ManagementObject share = new ManagementObject(Scope, sharePath, GetOptions))
return GetPropertyDictionary(share);
}
public IDictionary<string, object> GetShareSecurityDescriptorProperties()
{
using (ManagementObject shareSecurity = GetShareSecurity())
using (ManagementBaseObject securityDescriptor = GetShareSecurityDescriptor(shareSecurity))
return GetPropertyDictionary(securityDescriptor);
}
public void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, string securityIdentifier)
{
AddAccessControlEntry(
entryType,
entryRights,
trustee => trustee["SIDString"] = securityIdentifier
);
}
public void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, string domain, string account)
{
AddAccessControlEntry(
entryType,
entryRights,
trustee => {
trustee["Domain"] = domain;
trustee["Name"] = account;
}
);
}
/// <param name="trusteeInitializer">Initializes the Win32_Trustee instance for the access control entry to be added.</param>
private void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, Action<ManagementObject> trusteeInitializer)
{
using (ManagementObject shareSecurity = GetShareSecurity())
using (ManagementBaseObject securityDescriptor = GetShareSecurityDescriptor(shareSecurity))
{
ManagementBaseObject[] accessControlEntries = (ManagementBaseObject[]) securityDescriptor["DACL"];
// The class must not be created in the remote scope otherwise CreateInstance()
// throws "System.UnauthorizedAccessException: 'Access is denied'."
using (ManagementClass accessControlEntryClass = new ManagementClass("Win32_ACE"))
using (ManagementObject accessControlEntry = accessControlEntryClass.CreateInstance())
{
accessControlEntry["AccessMask"] = (uint) entryRights;
accessControlEntry["AceFlags"] = (uint) AceFlags.None;
accessControlEntry["AceType"] = (uint) entryType;
// The class must not be created in the remote scope otherwise CreateInstance()
// throws "System.UnauthorizedAccessException: 'Access is denied'."
using (ManagementClass trusteeClass = new ManagementClass("Win32_Trustee"))
using (ManagementObject trustee = trusteeClass.CreateInstance())
{
trusteeInitializer.Invoke(trustee);
accessControlEntry["Trustee"] = trustee;
// Create a new access control list including the new access control
// entry, sorted with Deny entries first (true sorts after false)
// https://docs.microsoft.com/windows/win32/secauthz/order-of-aces-in-a-dacl
securityDescriptor["DACL"] = accessControlEntries
.Append(accessControlEntry)
.OrderByDescending(entry => (AceType) (uint) entry["AceType"] == AceType.AccessDenied)
.ToArray();
SetShareSecurityDescriptor(shareSecurity, securityDescriptor);
}
}
}
}
private ManagementObject GetShareSecurity()
{
ManagementPath shareSecurityPath = new ManagementPath($"Win32_LogicalShareSecuritySetting.Name=\"{ShareName}\"");
return new ManagementObject(Scope, shareSecurityPath, GetOptions);
}
private ManagementBaseObject GetShareSecurityDescriptor(ManagementObject shareSecurity)
{
// Create an array to store the output parameter
ManagementBaseObject[] invokeParameters = new ManagementBaseObject[1];
uint invokeResult = (uint) shareSecurity.InvokeMethod("GetSecurityDescriptor", invokeParameters);
if (invokeResult == 0)
return invokeParameters[0];
else
{
//TODO: Handle failure of GetSecurityDescriptor()...
return null;
}
}
private void SetShareSecurityDescriptor(ManagementObject shareSecurity, ManagementBaseObject securityDescriptor)
{
// Create an array to store the input parameter
ManagementBaseObject[] invokeParameters = new ManagementBaseObject[1] { securityDescriptor };
uint invokeResult = (uint) shareSecurity.InvokeMethod("SetSecurityDescriptor", invokeParameters);
if (invokeResult != 0)
{
//TODO: Handle failure of SetSecurityDescriptor()...
}
}
private static IDictionary<string, object> GetPropertyDictionary(ManagementBaseObject obj)
{
return obj.Properties
.Cast<PropertyData>()
.ToDictionary(
property => property.Name,
// Recursively create dictionaries in place of management objects
property => property.Value is ManagementBaseObject[] baseObjectArray
? baseObjectArray.Select(GetPropertyDictionary).ToArray()
: property.Value is ManagementBaseObject baseObject
? GetPropertyDictionary(baseObject)
: property.Value
);
}
}
}
using System;
using System.Collections.Generic;
using System.Security.AccessControl;
namespace SO60271689.CSharp
{
class Program
{
public static void Main(string[] args)
{
if (args == null || args.Length == 0)
DisplayUsage();
else if (args.Length < 4)
DisplayError("Too few arguments.");
else
{
string host = args[0];
string shareName = args[1];
string username = args[2];
// ***** For demonstration purposes only! *****
//TODO: Find a secure way to store the remote password
string password = args[3];
ShareSecurity shareSecurity = new ShareSecurity(host, shareName, username, password);
DisplayShareProperties(shareSecurity);
DisplaySecurityDescriptor(shareSecurity);
if (args.Length > 4)
{
if (args.Length != 7 && args.Length != 8)
DisplayError("Argument count mismatch.");
else
{
if (!Enum.TryParse(args[4], true, out AceType entryType))
DisplayError($"Invalid <type> value \"{args[4]}\".");
else if (!Enum.TryParse<FileSystemRights>(args[5], true, out FileSystemRights entryRights))
DisplayError($"Invalid <rights> value \"{args[5]}\".");
else
{
DisplayTextWithSeparator("New access control entry");
Console.WriteLine($" Type: {entryType}");
Console.WriteLine($" Rights: {entryRights}");
if (args.Length == 7)
{
string securityIdentifier = args[6];
Console.WriteLine($" SID: {securityIdentifier}");
shareSecurity.AddAccessControlEntry(entryType, entryRights, securityIdentifier);
}
else // args.Length == 8
{
string domain = args[6];
string account = args[7];
Console.WriteLine($" Domain: {domain}");
Console.WriteLine($"Account: {account}");
shareSecurity.AddAccessControlEntry(entryType, entryRights, domain, account);
}
Console.WriteLine();
DisplaySecurityDescriptor(shareSecurity);
}
}
}
}
}
private static void DisplayUsage()
{
string entryAssemblyPath = System.Reflection.Assembly.GetEntryAssembly().Location;
string entryAssemblyName = System.IO.Path.GetFileName(entryAssemblyPath);
Console.WriteLine("Display share properties:");
Console.WriteLine();
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password>");
Console.WriteLine();
Console.WriteLine("Add access control entry:");
Console.WriteLine();
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <sid>");
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <domain> <account>");
Console.WriteLine();
Console.WriteLine($"\t <type> - A {typeof(AceType).FullName} enumeration value.");
Console.WriteLine($"\t<rights> - A {typeof(FileSystemRights).FullName} enumeration value.");
Console.WriteLine("\t <sid> - An account security identifier.");
Console.WriteLine();
}
private static void DisplayError(string message)
{
Console.WriteLine($"ERROR: {message}");
Console.WriteLine();
DisplayUsage();
}
private static void DisplayTextWithSeparator(string text)
{
Console.WriteLine(text);
Console.WriteLine(new string('=', text.Length));
}
private static void DisplayShareProperties(ShareSecurity shareSecurity)
{
IDictionary<string, object> shareProperties = shareSecurity.GetShareProperties();
DisplayTextWithSeparator("Share properties");
foreach (string propertyName in new string[] { "Description", "Name", "Path" })
DisplayProperty(shareProperties, propertyName);
Console.WriteLine();
}
private static void DisplaySecurityDescriptor(ShareSecurity shareSecurity)
{
IDictionary<string, object> securityDescriptorProperties = shareSecurity.GetShareSecurityDescriptorProperties();
DisplayTextWithSeparator("Share security descriptor");
DisplayProperty(securityDescriptorProperties, "ControlFlags", value => (ControlFlags) (uint) value);
Console.WriteLine();
IDictionary<string, object>[] accessControlList = (IDictionary<string, object>[]) securityDescriptorProperties["DACL"];
for (int i = 0; i < accessControlList.Length; i++)
{
IDictionary<string, object> accessControlEntryProperties = accessControlList[i];
DisplayTextWithSeparator($"Access control entry #{i}");
DisplayProperty(accessControlEntryProperties, "AccessMask", value => (FileSystemRights) (uint) value);
DisplayProperty(accessControlEntryProperties, "AceFlags", value => (AceFlags) (uint) value);
DisplayProperty(accessControlEntryProperties, "AceType", value => (AceType) (uint) value);
DisplayProperty(accessControlEntryProperties, "Trustee", value => ((IDictionary<string, object>) value)["Name"]);
Console.WriteLine();
}
}
private static void DisplayProperty(IDictionary<string, object> properties, string propertyName)
{
DisplayProperty(properties, propertyName, null);
}
private static void DisplayProperty(IDictionary<string, object> properties, string propertyName, Func<object, object> selector)
{
object propertyValue = properties[propertyName];
object displayValue = selector != null
? selector.Invoke(propertyValue)
: propertyValue ?? "<null>";
Console.WriteLine($"{propertyName}: {displayValue}");
}
}
}
我在远程计算机 IMPC-1111 的 C:\ 根目录中有一个共享,我正在尝试添加一个用户 /w 访问掩码:
FullControl = 2032127
Change = 1245631
[ReadOnly] = 1179817
我已经想出了如何阅读它们....但无法弄清楚如何 write/change 它们。这是我用来阅读它们的代码。
Private Function GetSharedFolderAccessRule() As DataTable
Dim DT As DataTable = New DataTable()
Try
DT.Columns.Add("ShareName")
DT.Columns.Add("Caption")
DT.Columns.Add("Path")
DT.Columns.Add("Domain")
DT.Columns.Add("User")
DT.Columns.Add("AccessMask")
DT.Columns.Add("AceType")
Dim Con As ConnectionOptions = New ConnectionOptions
Con.Username = "Username"
Con.Password = "Password"
'Dim Scope As ManagementScope = New ManagementScope("\.\root\cimv2", Con)
Dim Scope As ManagementScope = New ManagementScope("\IMPC-1111\root\cimv2", Con)
Scope.Connect()
Dim Query As ObjectQuery = New ObjectQuery("SELECT * FROM Win32_LogicalShareSecuritySetting")
Dim Searcher As ManagementObjectSearcher = New ManagementObjectSearcher(Scope, Query)
Dim QueryCollection As ManagementObjectCollection = Searcher.[Get]()
For Each SharedFolder As ManagementObject In QueryCollection
If True Then
Dim ShareName As String = CType(SharedFolder("Name"), String)
Dim Caption As String = CType(SharedFolder("Caption"), String)
Dim LocalPath As String = String.Empty
Dim Win32Share As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Path FROM Win32_share WHERE Name = '" & ShareName & "'")
For Each ShareData As ManagementObject In Win32Share.[Get]()
LocalPath = CType(ShareData("Path"), String)
Next
Dim Method As ManagementBaseObject = SharedFolder.InvokeMethod("GetSecurityDescriptor", Nothing, New InvokeMethodOptions())
Dim Descriptor As ManagementBaseObject = CType(Method("Descriptor"), ManagementBaseObject)
Dim DACL As ManagementBaseObject() = CType(Descriptor("DACL"), ManagementBaseObject())
For Each ACE As ManagementBaseObject In DACL
Dim Trustee As ManagementBaseObject = CType(ACE("Trustee"), ManagementBaseObject)
Dim Row As DataRow = DT.NewRow()
Row("ShareName") = ShareName
Row("Caption") = Caption
Row("Path") = LocalPath
Row("Domain") = CType(Trustee("Domain"), String)
Row("User") = CType(Trustee("Name"), String)
Row("AccessMask") = CType(ACE("AccessMask"), UInt32)
Row("AceType") = CType(ACE("AceType"), UInt32)
DT.Rows.Add(Row)
DT.AcceptChanges()
Next
End If
Next
Catch ex As Exception
MessageBox.Show(ex.StackTrace, ex.Message)
End Try
Return DT
End Function
任何人都可以指出我正确的方向吗?这甚至可以使用 WMI 编写吗?
谢谢!
您可以使用Win32_LogicalShareSecuritySetting
.SetSecurityDescriptor()
method修改共享权限。修改现有权限的工作方式如下...
- 获取所需的
Win32_LogicalShareSecuritySetting
实例。 - 调用
GetSecurityDescriptor()
to get the share's security descriptor as aWin32_SecurityDescriptor
实例。 - 通过其
DACL
属性. 获取安全描述符的自由访问控制列表
- 创建一个新的访问控制条目。
- 得到一个reference to the
Win32_ACE
class. - 创建
Win32_ACE
class 的实例。 - 设置访问控制条目的
AccessMask
、AceFlags
、AceType
和Trustee
属性。- 得到一个reference to the
Win32_Trustee
class. - 创建
Win32_Trustee
class 的实例。 - 通过设置受托人的
SIDString
或Name
(和Domain
)属性来指定条目的委托人。- 查询
Win32_Account
class 或其衍生物的实例是获取这些值的一种方法。
- 查询
- 得到一个reference to the
- 得到一个reference to the
- 创建一个结合现有条目和新条目的新访问控制列表。
- 根据 Order of ACEs in a DACL,确保
Deny
个条目排在Allow
个条目之前。
- 根据 Order of ACEs in a DACL,确保
- 将安全描述符的
DACL
属性 设置为新的访问控制列表。 - 调用
SetSecurityDescriptor()
保存共享的安全描述符。
以下 class 包含获取共享属性的方法,特别是通过 AddAccessControlEntry()
方法添加新的访问控制条目...
Imports System.Management
Imports System.Security.AccessControl
Friend Class ShareSecurity
Private ReadOnly Property ShareName As String
Private ReadOnly Property GetOptions As ObjectGetOptions
Private ReadOnly Property Scope As ManagementScope
Public Sub New(host As String, shareName As String, username As String, password As String)
Me.ShareName = shareName
GetOptions = New ObjectGetOptions()
Scope = New ManagementScope(
New ManagementPath() With {
.NamespacePath = "root\cimv2",
.Server = host
},
New ConnectionOptions() With {
_ ' ***** For demonstration purposes only! *****
_ 'TODO: Find a secure way to store the remote password
.Password = password,
.Username = username
}
)
End Sub
Public Function GetShareProperties() As IDictionary(Of String, Object)
Dim sharePath As New ManagementPath($"Win32_Share.Name=""{ShareName}""")
Using share As New ManagementObject(Scope, sharePath, GetOptions)
Return GetPropertyDictionary(share)
End Using
End Function
Public Function GetShareSecurityDescriptorProperties() As IDictionary(Of String, Object)
Using shareSecurity As ManagementObject = GetShareSecurity()
Using securityDescriptor As ManagementBaseObject = GetShareSecurityDescriptor(shareSecurity)
Return GetPropertyDictionary(securityDescriptor)
End Using
End Using
End Function
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, securityIdentifier As String)
AddAccessControlEntry(
entryType,
entryRights,
Sub(trustee)
trustee("SIDString") = securityIdentifier
End Sub
)
End Sub
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, domain As String, account As String)
AddAccessControlEntry(
entryType,
entryRights,
Sub(trustee)
trustee("Domain") = domain
trustee("Name") = account
End Sub
)
End Sub
''' <param name="trusteeInitializer">Initializes the Win32_Trustee instance for the access control entry to be added.</param>
Public Sub AddAccessControlEntry(entryType As AceType, entryRights As FileSystemRights, trusteeInitializer As Action(Of ManagementObject))
Using shareSecurity As ManagementObject = GetShareSecurity()
Using securityDescriptor As ManagementBaseObject = GetShareSecurityDescriptor(shareSecurity)
Dim accessControlEntries As ManagementBaseObject() = DirectCast(securityDescriptor("DACL"), ManagementBaseObject())
' The class must not be created in the remote scope otherwise CreateInstance()
' throws "System.UnauthorizedAccessException: 'Access is denied'."
Using accessControlEntryClass As New ManagementClass("Win32_ACE")
Using accessControlEntry As ManagementObject = accessControlEntryClass.CreateInstance()
accessControlEntry("AccessMask") = CUInt(entryRights)
accessControlEntry("AceFlags") = CUInt(AceFlags.None)
accessControlEntry("AceType") = CUInt(entryType)
' The class must not be created in the remote scope otherwise CreateInstance()
' throws "System.UnauthorizedAccessException: 'Access is denied'."
Using trusteeClass As New ManagementClass("Win32_Trustee")
Using trustee As ManagementObject = trusteeClass.CreateInstance()
trusteeInitializer.Invoke(trustee)
accessControlEntry("Trustee") = trustee
' Create a new access control list including the new access control
' entry, sorted with Deny entries first (true sorts after false)
' https://docs.microsoft.com/windows/win32/secauthz/order-of-aces-in-a-dacl
securityDescriptor("DACL") = accessControlEntries _
.Append(accessControlEntry) _
.OrderByDescending(Function(entry) CType(entry("AceType"), AceType)) _
.ToArray()
SetShareSecurityDescriptor(shareSecurity, securityDescriptor)
End Using
End Using
End Using
End Using
End Using
End Using
End Sub
Private Function GetShareSecurity() As ManagementObject
Dim shareSecurityPath As New ManagementPath($"Win32_LogicalShareSecuritySetting.Name=""{ShareName}""")
Return New ManagementObject(Scope, shareSecurityPath, GetOptions)
End Function
Private Function GetShareSecurityDescriptor(shareSecurity As ManagementObject) As ManagementBaseObject
' Create an array to store the output parameter
Dim invokeParameters(0) As ManagementBaseObject
Dim invokeResult As UInteger = shareSecurity.InvokeMethod("GetSecurityDescriptor", invokeParameters)
If invokeResult = 0 Then
Return invokeParameters(0)
Else
'TODO: Handle failure of GetSecurityDescriptor()...
Return Nothing
End If
End Function
Private Sub SetShareSecurityDescriptor(shareSecurity As ManagementObject, securityDescriptor As ManagementBaseObject)
' Create an array to store the input parameter
Dim invokeParameters() As ManagementBaseObject = {securityDescriptor}
Dim invokeResult As UInteger = shareSecurity.InvokeMethod("SetSecurityDescriptor", invokeParameters)
If invokeResult <> 0 Then
'TODO: Handle failure of SetSecurityDescriptor()...
End If
End Sub
Private Shared Function GetPropertyDictionary(obj As ManagementBaseObject) As IDictionary(Of String, Object)
Return obj.Properties _
.Cast(Of PropertyData)() _
.ToDictionary(
Function([property]) [property].Name,
Function([property])
' Recursively create dictionaries in place of management objects
Dim baseObjectArray As ManagementBaseObject() = TryCast([property].Value, ManagementBaseObject())
If baseObjectArray IsNot Nothing Then
Return baseObjectArray.Select(AddressOf GetPropertyDictionary).ToArray()
Else
Dim baseObject As ManagementBaseObject = TryCast([property].Value, ManagementBaseObject)
If baseObject IsNot Nothing Then
Return GetPropertyDictionary(baseObject)
Else
Return [property].Value
End If
End If
End Function
)
End Function
End Class
下面的程序使用上面的 ShareSecurity
class 来显示远程共享的属性,并且可以选择向它添加一个新的访问控制条目...
Imports System.Security.AccessControl
Public Class Program
Public Shared Sub Main(args As String())
If args Is Nothing OrElse args.Length = 0 Then
DisplayUsage()
ElseIf args.Length < 4 Then
DisplayError("Too few arguments.")
Else
Dim host As String = args(0)
Dim shareName As String = args(1)
Dim username As String = args(2)
' ***** For demonstration purposes only! *****
'TODO: Find a secure way to store the remote password
Dim password As String = args(3)
Dim shareSecurity As New ShareSecurity(host, shareName, username, password)
DisplayShareProperties(shareSecurity)
DisplaySecurityDescriptor(shareSecurity)
If args.Length > 4 Then
If args.Length <> 7 AndAlso args.Length <> 8 Then
DisplayError("Argument count mismatch.")
Else
Dim entryType As AceType
If Not [Enum].TryParse(args(4), True, entryType) Then
DisplayError($"Invalid <type> value ""{args(4)}"".")
Else
Dim entryRights As FileSystemRights
If Not [Enum].TryParse(args(5), True, entryRights) Then
DisplayError($"Invalid <rights> value ""{args(5)}"".")
Else
DisplayTextWithSeparator("New access control entry")
Console.WriteLine($" Type: {entryType}")
Console.WriteLine($" Rights: {entryRights}")
If args.Length = 7 Then
Dim securityIdentifier As String = args(6)
Console.WriteLine($" SID: {securityIdentifier}")
shareSecurity.AddAccessControlEntry(entryType, entryRights, securityIdentifier)
Else ' args.Length = 8
Dim domain As String = args(6)
Dim account As String = args(7)
Console.WriteLine($" Domain: {domain}")
Console.WriteLine($"Account: {account}")
shareSecurity.AddAccessControlEntry(entryType, entryRights, domain, account)
End If
Console.WriteLine()
DisplaySecurityDescriptor(shareSecurity)
End If
End If
End If
End If
End If
End Sub
Private Shared Sub DisplayUsage()
Dim entryAssemblyPath As String = System.Reflection.Assembly.GetEntryAssembly().Location
Dim entryAssemblyName As String = System.IO.Path.GetFileName(entryAssemblyPath)
Console.WriteLine("Display share properties:")
Console.WriteLine()
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password>")
Console.WriteLine()
Console.WriteLine("Add access control entry:")
Console.WriteLine()
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <sid>")
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <domain> <account>")
Console.WriteLine()
Console.WriteLine(vbTab & $" <type> - A {GetType(AceType).FullName} enumeration value.")
Console.WriteLine(vbTab & $"<rights> - A {GetType(FileSystemRights).FullName} enumeration value.")
Console.WriteLine(vbTab & " <sid> - An account security identifier.")
Console.WriteLine()
End Sub
Private Shared Sub DisplayError(message As String)
Console.WriteLine($"ERROR: {message}")
Console.WriteLine()
DisplayUsage()
End Sub
Private Shared Sub DisplayTextWithSeparator(text As String)
Console.WriteLine(text)
Console.WriteLine(New String("-"c, text.Length))
End Sub
Private Shared Sub DisplayShareProperties(shareSecurity As ShareSecurity)
Dim shareProperties As IDictionary(Of String, Object) = shareSecurity.GetShareProperties()
DisplayTextWithSeparator("Share properties")
For Each propertyName As String In New String() {"Description", "Name", "Path"}
DisplayProperty(shareProperties, propertyName)
Next
Console.WriteLine()
End Sub
Private Shared Sub DisplaySecurityDescriptor(shareSecurity As ShareSecurity)
Dim securityDescriptorProperties As IDictionary(Of String, Object) = shareSecurity.GetShareSecurityDescriptorProperties()
DisplayTextWithSeparator("Share security descriptor")
DisplayProperty(securityDescriptorProperties, "ControlFlags", Function(value) CType(value, ControlFlags))
Console.WriteLine()
Dim accessControlList As IDictionary(Of String, Object)() = securityDescriptorProperties("DACL")
For i As Integer = 0 To accessControlList.Length - 1
Dim accessControlEntryProperties As IDictionary(Of String, Object) = accessControlList(i)
DisplayTextWithSeparator($"Access control entry #{i}")
DisplayProperty(accessControlEntryProperties, "AccessMask", Function(value) CType(value, FileSystemRights))
DisplayProperty(accessControlEntryProperties, "AceFlags", Function(value) CType(value, AceFlags))
DisplayProperty(accessControlEntryProperties, "AceType", Function(value) CType(value, AceType))
DisplayProperty(accessControlEntryProperties, "Trustee", Function(value) DirectCast(value, IDictionary(Of String, Object))("Name"))
Console.WriteLine()
Next
End Sub
Private Shared Sub DisplayProperty(properties As IDictionary(Of String, Object), propertyName As String)
DisplayProperty(properties, propertyName, Nothing)
End Sub
Private Shared Sub DisplayProperty(properties As IDictionary(Of String, Object), propertyName As String, selector As Func(Of Object, Object))
Dim propertyValue As Object = properties(propertyName)
Dim displayValue As Object = If(
selector IsNot Nothing,
selector.Invoke(propertyValue),
If(propertyValue, "<null>")
)
Console.WriteLine($"{propertyName}: {displayValue}")
End Sub
End Class
给这样的分享...
...将 Full Control
授予 Administrators
,将 Read
授予 Everyone
,这样调用程序...
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" S-1-5-32-546
...或者像这样...
SO60271689.exe MyComputer "My Share" MyUser MyPassword AccessDenied "Modify, Synchronize" BUILTIN Guests
...产生这样的输出...
Share properties
----------------
Description: This is the share description.
Name: My Share
Path: C:\My Share
Share security descriptor
-------------------------
ControlFlags: DiscretionaryAclPresent, SelfRelative
Access control entry #0
-----------------------
AccessMask: ReadAndExecute, Synchronize
AceFlags: None
AceType: AccessAllowed
Trustee: Everyone
Access control entry #1
-----------------------
AccessMask: FullControl
AceFlags: None
AceType: AccessAllowed
Trustee: Administrators
New access control entry
------------------------
Type: AccessDenied
Rights: Modify, Synchronize
SID: S-1-5-32-546
Share security descriptor
-------------------------
ControlFlags: DiscretionaryAclPresent, SelfRelative
Access control entry #0
-----------------------
AccessMask: Modify, Synchronize
AceFlags: None
AceType: AccessDenied
Trustee: Guests
Access control entry #1
-----------------------
AccessMask: ReadAndExecute, Synchronize
AceFlags: None
AceType: AccessAllowed
Trustee: Everyone
Access control entry #2
-----------------------
AccessMask: FullControl
AceFlags: None
AceType: AccessAllowed
Trustee: Administrators
由于 VB.NET 不是我的母语,这里是我开始使用的等效 C# 代码,以使一切正常...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Security.AccessControl;
namespace SO60271689.CSharp
{
internal class ShareSecurity
{
private string ShareName
{
get;
}
private ObjectGetOptions GetOptions
{
get;
}
private ManagementScope Scope
{
get;
}
public ShareSecurity(string host, string shareName, string username, string password)
{
ShareName = shareName;
GetOptions = new ObjectGetOptions();
Scope = new ManagementScope(
new ManagementPath() {
NamespacePath = @"root\cimv2",
Server = host
},
new ConnectionOptions() {
// ***** For demonstration purposes only! *****
//TODO: Find a secure way to store the remote password
Password = password,
Username = username
}
);
}
public IDictionary<string, object> GetShareProperties()
{
ManagementPath sharePath = new ManagementPath($"Win32_Share.Name=\"{ShareName}\"");
using (ManagementObject share = new ManagementObject(Scope, sharePath, GetOptions))
return GetPropertyDictionary(share);
}
public IDictionary<string, object> GetShareSecurityDescriptorProperties()
{
using (ManagementObject shareSecurity = GetShareSecurity())
using (ManagementBaseObject securityDescriptor = GetShareSecurityDescriptor(shareSecurity))
return GetPropertyDictionary(securityDescriptor);
}
public void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, string securityIdentifier)
{
AddAccessControlEntry(
entryType,
entryRights,
trustee => trustee["SIDString"] = securityIdentifier
);
}
public void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, string domain, string account)
{
AddAccessControlEntry(
entryType,
entryRights,
trustee => {
trustee["Domain"] = domain;
trustee["Name"] = account;
}
);
}
/// <param name="trusteeInitializer">Initializes the Win32_Trustee instance for the access control entry to be added.</param>
private void AddAccessControlEntry(AceType entryType, FileSystemRights entryRights, Action<ManagementObject> trusteeInitializer)
{
using (ManagementObject shareSecurity = GetShareSecurity())
using (ManagementBaseObject securityDescriptor = GetShareSecurityDescriptor(shareSecurity))
{
ManagementBaseObject[] accessControlEntries = (ManagementBaseObject[]) securityDescriptor["DACL"];
// The class must not be created in the remote scope otherwise CreateInstance()
// throws "System.UnauthorizedAccessException: 'Access is denied'."
using (ManagementClass accessControlEntryClass = new ManagementClass("Win32_ACE"))
using (ManagementObject accessControlEntry = accessControlEntryClass.CreateInstance())
{
accessControlEntry["AccessMask"] = (uint) entryRights;
accessControlEntry["AceFlags"] = (uint) AceFlags.None;
accessControlEntry["AceType"] = (uint) entryType;
// The class must not be created in the remote scope otherwise CreateInstance()
// throws "System.UnauthorizedAccessException: 'Access is denied'."
using (ManagementClass trusteeClass = new ManagementClass("Win32_Trustee"))
using (ManagementObject trustee = trusteeClass.CreateInstance())
{
trusteeInitializer.Invoke(trustee);
accessControlEntry["Trustee"] = trustee;
// Create a new access control list including the new access control
// entry, sorted with Deny entries first (true sorts after false)
// https://docs.microsoft.com/windows/win32/secauthz/order-of-aces-in-a-dacl
securityDescriptor["DACL"] = accessControlEntries
.Append(accessControlEntry)
.OrderByDescending(entry => (AceType) (uint) entry["AceType"] == AceType.AccessDenied)
.ToArray();
SetShareSecurityDescriptor(shareSecurity, securityDescriptor);
}
}
}
}
private ManagementObject GetShareSecurity()
{
ManagementPath shareSecurityPath = new ManagementPath($"Win32_LogicalShareSecuritySetting.Name=\"{ShareName}\"");
return new ManagementObject(Scope, shareSecurityPath, GetOptions);
}
private ManagementBaseObject GetShareSecurityDescriptor(ManagementObject shareSecurity)
{
// Create an array to store the output parameter
ManagementBaseObject[] invokeParameters = new ManagementBaseObject[1];
uint invokeResult = (uint) shareSecurity.InvokeMethod("GetSecurityDescriptor", invokeParameters);
if (invokeResult == 0)
return invokeParameters[0];
else
{
//TODO: Handle failure of GetSecurityDescriptor()...
return null;
}
}
private void SetShareSecurityDescriptor(ManagementObject shareSecurity, ManagementBaseObject securityDescriptor)
{
// Create an array to store the input parameter
ManagementBaseObject[] invokeParameters = new ManagementBaseObject[1] { securityDescriptor };
uint invokeResult = (uint) shareSecurity.InvokeMethod("SetSecurityDescriptor", invokeParameters);
if (invokeResult != 0)
{
//TODO: Handle failure of SetSecurityDescriptor()...
}
}
private static IDictionary<string, object> GetPropertyDictionary(ManagementBaseObject obj)
{
return obj.Properties
.Cast<PropertyData>()
.ToDictionary(
property => property.Name,
// Recursively create dictionaries in place of management objects
property => property.Value is ManagementBaseObject[] baseObjectArray
? baseObjectArray.Select(GetPropertyDictionary).ToArray()
: property.Value is ManagementBaseObject baseObject
? GetPropertyDictionary(baseObject)
: property.Value
);
}
}
}
using System;
using System.Collections.Generic;
using System.Security.AccessControl;
namespace SO60271689.CSharp
{
class Program
{
public static void Main(string[] args)
{
if (args == null || args.Length == 0)
DisplayUsage();
else if (args.Length < 4)
DisplayError("Too few arguments.");
else
{
string host = args[0];
string shareName = args[1];
string username = args[2];
// ***** For demonstration purposes only! *****
//TODO: Find a secure way to store the remote password
string password = args[3];
ShareSecurity shareSecurity = new ShareSecurity(host, shareName, username, password);
DisplayShareProperties(shareSecurity);
DisplaySecurityDescriptor(shareSecurity);
if (args.Length > 4)
{
if (args.Length != 7 && args.Length != 8)
DisplayError("Argument count mismatch.");
else
{
if (!Enum.TryParse(args[4], true, out AceType entryType))
DisplayError($"Invalid <type> value \"{args[4]}\".");
else if (!Enum.TryParse<FileSystemRights>(args[5], true, out FileSystemRights entryRights))
DisplayError($"Invalid <rights> value \"{args[5]}\".");
else
{
DisplayTextWithSeparator("New access control entry");
Console.WriteLine($" Type: {entryType}");
Console.WriteLine($" Rights: {entryRights}");
if (args.Length == 7)
{
string securityIdentifier = args[6];
Console.WriteLine($" SID: {securityIdentifier}");
shareSecurity.AddAccessControlEntry(entryType, entryRights, securityIdentifier);
}
else // args.Length == 8
{
string domain = args[6];
string account = args[7];
Console.WriteLine($" Domain: {domain}");
Console.WriteLine($"Account: {account}");
shareSecurity.AddAccessControlEntry(entryType, entryRights, domain, account);
}
Console.WriteLine();
DisplaySecurityDescriptor(shareSecurity);
}
}
}
}
}
private static void DisplayUsage()
{
string entryAssemblyPath = System.Reflection.Assembly.GetEntryAssembly().Location;
string entryAssemblyName = System.IO.Path.GetFileName(entryAssemblyPath);
Console.WriteLine("Display share properties:");
Console.WriteLine();
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password>");
Console.WriteLine();
Console.WriteLine("Add access control entry:");
Console.WriteLine();
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <sid>");
Console.WriteLine($"{entryAssemblyName} <host> <share> <username> <password> <type> <rights> <domain> <account>");
Console.WriteLine();
Console.WriteLine($"\t <type> - A {typeof(AceType).FullName} enumeration value.");
Console.WriteLine($"\t<rights> - A {typeof(FileSystemRights).FullName} enumeration value.");
Console.WriteLine("\t <sid> - An account security identifier.");
Console.WriteLine();
}
private static void DisplayError(string message)
{
Console.WriteLine($"ERROR: {message}");
Console.WriteLine();
DisplayUsage();
}
private static void DisplayTextWithSeparator(string text)
{
Console.WriteLine(text);
Console.WriteLine(new string('=', text.Length));
}
private static void DisplayShareProperties(ShareSecurity shareSecurity)
{
IDictionary<string, object> shareProperties = shareSecurity.GetShareProperties();
DisplayTextWithSeparator("Share properties");
foreach (string propertyName in new string[] { "Description", "Name", "Path" })
DisplayProperty(shareProperties, propertyName);
Console.WriteLine();
}
private static void DisplaySecurityDescriptor(ShareSecurity shareSecurity)
{
IDictionary<string, object> securityDescriptorProperties = shareSecurity.GetShareSecurityDescriptorProperties();
DisplayTextWithSeparator("Share security descriptor");
DisplayProperty(securityDescriptorProperties, "ControlFlags", value => (ControlFlags) (uint) value);
Console.WriteLine();
IDictionary<string, object>[] accessControlList = (IDictionary<string, object>[]) securityDescriptorProperties["DACL"];
for (int i = 0; i < accessControlList.Length; i++)
{
IDictionary<string, object> accessControlEntryProperties = accessControlList[i];
DisplayTextWithSeparator($"Access control entry #{i}");
DisplayProperty(accessControlEntryProperties, "AccessMask", value => (FileSystemRights) (uint) value);
DisplayProperty(accessControlEntryProperties, "AceFlags", value => (AceFlags) (uint) value);
DisplayProperty(accessControlEntryProperties, "AceType", value => (AceType) (uint) value);
DisplayProperty(accessControlEntryProperties, "Trustee", value => ((IDictionary<string, object>) value)["Name"]);
Console.WriteLine();
}
}
private static void DisplayProperty(IDictionary<string, object> properties, string propertyName)
{
DisplayProperty(properties, propertyName, null);
}
private static void DisplayProperty(IDictionary<string, object> properties, string propertyName, Func<object, object> selector)
{
object propertyValue = properties[propertyName];
object displayValue = selector != null
? selector.Invoke(propertyValue)
: propertyValue ?? "<null>";
Console.WriteLine($"{propertyName}: {displayValue}");
}
}
}