Reputation: 3592
I am saving my SMB Share information to disk so I can restore it later as needed.
For this I'm using the MSFT_SMB class. I get all SMB shares available on my local machine and save the data to disk. Security descriptor fetched like this is in string format.
This is the code that gets all the shares:
private const string SmbNamespace = "\\\\.\\ROOT\\Microsoft\\Windows\\SMB";
private const string SmbShareClass = "MSFT_SmbShare";
private const string CreateShareMethod = "CreateShare";
private const string GetShareMethod = "GetShare";
public virtual List<SmbShareInfo> GetAllSmbShares()
{
ManagementClass SmbShares = new ManagementClass(SmbNamespace + ":" + SmbShareClass);
List<SmbShareInfo> sharesPresent = new List<SmbShareInfo>();
try
{
foreach (ManagementObject smbObject in SmbShares.GetInstances())
{
sharesPresent.Add(constructSmbShareInfo(smbObject));
}
return sharesPresent;
}
catch (ManagementException e)
{
throw new Exception(e.ToString());
}
}
private SmbShareInfo constructSmbShareInfo(ManagementObject smbObject)
{
return new SmbShareInfo(
Convert.ToString(smbObject["Name"]),
Convert.ToString(smbObject["Path"]),
Convert.ToString(smbObject["Description"]),
Convert.ToBoolean(smbObject["Special"]),
Convert.ToUInt32(smbObject["ConcurrentUserLimit"]),
Convert.ToString(smbObject["SecurityDescriptor"]),
Convert.ToUInt32(smbObject["ShareType"]),
Convert.ToUInt32(smbObject["FolderEnumerationMode"]),
Convert.ToBoolean(smbObject["EncryptData"]),
Convert.ToUInt32(smbObject["CachingMode"]));
}
Where SmbShareInfo
is a class I've defined to store SMB share information locally.
Now when I'm trying to create the share again (on a new windows machine), the CreateShare method expects "The name of the security descriptor of the share".
How do I get the "name" of the security descriptor and create the share? I just have string based security descriptors like this:
O:SYG:SYD:(A;;GA;;;BA)(A;;GA;;;BO)(A;;GA;;;IU)
This is my code to create share:
ManagementObject managementObject = new ManagementClass(SmbNamespace + ":" + SmbShareClass);
managementObject.Get();
string[] accountNames = { "Everyone" };
ManagementBaseObject createShareInParameters = managementObject.GetMethodParameters(CreateShareMethod);
createShareInParameters["Name"] = fileShare.Name;
createShareInParameters["Path"] = fileShare.Path;
createShareInParameters["Description"] = fileShare.Description;
createShareInParameters["ConcurrentUserLimit"] = fileShare.ConcurrentUserLimit;
// Enable this
//createShareInParameters["SecurityDescriptor"] = fileShare.SecurityDescriptor;
createShareInParameters["FolderEnumerationMode"] = fileShare.FolderEnumerationMode;
createShareInParameters["EncryptData"] = fileShare.EncryptData;
createShareInParameters["CachingMode"] = fileShare.CachingMode;
createShareInParameters["FullAccess"] = accountNames;
managementObject.InvokeMethod(CreateShareMethod, createShareInParameters, null);
Upvotes: 2
Views: 1405
Reputation: 3592
My code had a bug, along with the security descriptor I was also using the attribute FullAccess
, which was given precedence over the security descriptors. This code worked finally:
ManagementObject managementObject = new ManagementClass(SmbNamespace + ":" + SmbShareClass); managementObject.Get();
ManagementBaseObject createShareInParameters = managementObject.GetMethodParameters(CreateShareMethod);
createShareInParameters["Name"] = fileShare.Name;
createShareInParameters["Path"] = fileShare.Path;
createShareInParameters["Description"] = fileShare.Description;
createShareInParameters["ConcurrentUserLimit"] = fileShare.ConcurrentUserLimit;
createShareInParameters["SecurityDescriptor"] = fileShare.SecurityDescriptor;
createShareInParameters["FolderEnumerationMode"] = fileShare.FolderEnumerationMode;
createShareInParameters["EncryptData"] = fileShare.EncryptData;
createShareInParameters["CachingMode"] = fileShare.CachingMode;
managementObject.InvokeMethod(CreateShareMethod, createShareInParameters, null);
Upvotes: 0
Reputation: 17091
I realised you are asking for c#, but let me offer you an interesting alternative.
You could use PowerShell's Get-SmbShare along with New-SmbShare, persisting settings if needed to a config file perhaps in the middle. Which would be trivial compared to c#.
EDIT: And Get-SmbShareAccess / Grant-SmbShareAccess for the security description (ACL) bit.
Of course I'm not aware of the full scope of project you are making, but things like system automation is where PowerShell shines. PowerShell does in fact mostly wrap c# libraries and presents an easy to consume API.
I say this as a die hard c# developer who has recently been enlightened to the power of powershell (needed for our DevOps landscape).
I realise this isn't the answer, but perhaps an interesting alternative to suit some scenarios.
Upvotes: 1