Powershell – WMI: Working with Shares – Part 1: Creating a Share with Custom Permissions
Download Script: NewShareWithPermissions-0.0.1.zip 2.3 KB
Downloaded 105 times
Intro:
Last week, i was teaching a Powershell course (MOC6434), when a student asked me, how to create a share with custom permissions via WMI.
I tried to find an answer for him, but could not really find any examples, cmdlets or functions for it.
I found some examples and help in vbscript, so i decided to make some powershell functions of my own.
I Created these functions that uses the Win32_Share class of WMI. They support remote creation and multiple permissions.
New-Share is for creating a share.
New-ACE is for creating one or more ACEs for use with New-Share
New-SecurityDescriptor is used by New-Share to combine the ACE’s into a SecurityDescriptor for the WMI Method.
Functions:
New-Share
SYNOPSIS
Creates a new Share on local or remote PC. Support for Custom Permissions
SYNTAX
New-Share [-FolderPath] <string> [-ShareName] <string> [-ACEs <Win32_ACE Object>] [-Description <string>] [-Computer] <string>
DETAILED DESCRIPTION
Create new share, either on local or remote PC.
Shares can be created without the use of –ACEs parameter, this will create a share with standard permissions. If the ACEs parameter if used, custom permissions can be added.
PARAMETERS
FolderPath <string>
Specifies the local path for folder that is to be shared.
| Required? | true |
| Position? | 1 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
ShareName <string>
Specifies the name of the share.
Please notice that duplicate share names are not supported in windows.
| Required? | true |
| Position? | 2 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
ACEs <(Array of) Win32_ACE Objects>
Specifies the custom permissions.
Create the Win32_ACE object by using New-ACE function.
This parameter either support a single object or an array of objects
| Required? | false |
| Position? | 3 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
Description <string>
Description for the share
| Required? | false |
| Position? | 4 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
Computer <string>
Specify computername for the target computer
| Required? | false |
| Position? | 4 |
| Default value | . (localhost) |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
INPUT TYPE
No Pipe input in version 0.0.1
RETURN TYPE
System.Object
Properties: ReturnCode, Message
————————– EXAMPLE 1 ————————–
New-Share -FolderPath “C:\Temp” -ShareName “Temp4″ -ACEs $ACE `
–Description “Test Description” -Computer “localhost”
This examples creates one Win32_ACE object that specifies “CORETECH\Domain Users”, to have read permission and use it to share C:\Temp on the local machine.
————————– EXAMPLE 2 ————————–
$ACE2 = New-ACE -Name “CCO” -Domain “CORETECH” -Permission “Full”
New-Share -FolderPath “C:\Temp” -ShareName “Temp4″ -ACEs $ACE,$ACE2 `
-Description “Test Description” -Computer “localhost”
This examples create both a users ACE and a group ACE, and send them both with the New-Share function
————————– EXAMPLE 3 ————————–
This is the shortest way to run the function. Using default permissions (which is decided from whom, who run the function). and using position parameters, ignoring all optional parameters
New-ACE
SYNOPSIS
Creates a Win32_ACE object contains permissions for use with New-share (or another function that need Win32_ACE objects)
SYNTAX
New-ACE [-Name] <string> [-Domain] <string> [-Permission] <string> [-Computer <string>] [-Group]
NOTICE
Due to the limitations of the WMI_Account class, it is only possible to get local accounts when connecting to WMI via a remote machine (as far as i know, please contact me if you have input).
This means that usually you should not use the –ComputerName paramter, only use it if you are connecting to a workgroup computer, and using local user/groups for the permissions
PARAMETERS
Name <string>
Specifies the name of the user or group.
| Required? | true |
| Position? | 1 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
Domain <string>
Specifies the domain for the user or group.
| Required? | true |
| Position? | 2 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
Permission <string>
Specifies the permission granted for the user/group.
Possible values are “Read”, “Change”, “Full”
| Required? | true |
| Position? | 3 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
Computername <string>
Specify computername for the target computer to get the user info from.
NB! Please read the Notice above this.
| Required? | false |
| Position? | 4 |
| Default value | . (localhost) |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
Group <switch>
This is a switch parameter, add it if you are creating an ACE for a group instead of a user.
| Required? | false |
| Position? | 5 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
INPUT TYPE
No Pipe input in version 0.0.1
RETURN TYPE
Win32_ACE Object
————————– EXAMPLE 1 ————————–
This examples creates one Win32_ACE object that specifies “CORETECH\Domain Users”.
————————– EXAMPLE 2 ————————–
This examples creates a user ACE
New-SecurityDescriptor
SYNOPSIS
Creates a Win32_SecurityDescriptor object from on or more Win32_ACEs, for use by New-Share.
SYNTAX
New-SecurityDescriptor [-ACEs] <[array of] Win32_ACE Object(s)> [-ComputerName <string>]
NOTICE
Due to the limitations of the WMI_Account class, it is only possible to get local accounts when connecting to WMI via a remote machine (as far as i know, please contact me if you have input).
This means that usually you should not use the –ComputerName paramter, only use it if you are connecting to a workgroup computer, and using local user/groups for the permissions
PARAMETERS
ACEs <[Array of] Win32_ACE object(s)>
Specifies one or more Win32ACE object that should be added to the SecurityDescriptor
| Required? | true |
| Position? | 1 |
| Default value | |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
ComputerName <string>
Specify computername for the target computer to get the user info from.
NB! Please read the Notice above this.
| Required? | false |
| Position? | 2 |
| Default value | . (localhost) |
| Accept pipeline input? | false |
| Accept wildcard characters? | false |
INPUT TYPE
No Pipe input in version 0.0.1
RETURN TYPE
Win32_SecurityDescriptor Object
————————– EXAMPLE 1 ————————–
New-SecurityDescriptor $ACE
This examples creates a Win32_SecurityDescriptor from one Win32_ACE object
————————– EXAMPLE 2 ————————–
$ACE2 = New-ACE -Name “CCO” -Domain “CORETECH” -Permission “Full”
New-SecurityDescriptor $ACE,$ACE2
This examples creates a Win32_SecurityDescriptor from more than one Win32_ACE object
Source:
# //************************************************************************************************************ # // ***** Script Header ***** # // # // Solution: Coretech Share Functions # // File: NewShareWithPermission.ps1 # // Author: Jakob Gottlieb Svendsen, Coretech A/S. http://blog.coretech.dk # // Purpose: # // New-Share: Creates new Share on local or remote PC, with custom permissions. # // Required Parameters: FolderPath, ShareName # // # // New-ACE: Creates ACE Objects, for use when running New-Share. # // Required Parameters: Name, Domain # // # // New-SecurityDescriptor: used by New-Share to prepare the permissions. # // Required Parameters: ACEs #// # // Usage Examples: # // New-Share -FolderPath "C:\Temp" -ShareName "Temp" -ACEs $ACE,$ACE2 -Description "Test Description" -Computer "localhost" # // Sharing of folder C:\Temp, with the Name "Temp". ACE's (Permissions) are sent via the -ACEs parameter. # // Create them with New-ACE and send one or more, seperated by comma (or create and array and use that) # // # // This is the first in a couple of share-administration scripts i am planning to make and release on the blog. # // # // Please comment the blog post, if you have any suggestions, questions or feedback. # // Contact me if you need us to make a custom script (or cause not for free) # // # // CORETECH A/S History: # // 0.0.1 JGS 30/06/2009 Created initial version. # // # // Customer History: # // # // ***** End Header ***** # //************************************************************************************************************** #//---------------------------------------------------------------------------- #// Procedures #//---------------------------------------------------------------------------- Function New-SecurityDescriptor ( $ACEs = (throw "Missing one or more Trustees"), [string] $ComputerName = ".") { #Create SeCDesc object $SecDesc = ([WMIClass] "\\$ComputerName\root\cimv2:Win32_SecurityDescriptor").CreateInstance() #Check if input is an array or not. if ($ACEs -is [System.Array]) { #Add Each ACE from the ACE array foreach ($ACE in $ACEs ) { $SecDesc.DACL += $ACE.psobject.baseobject } } else { #Add the ACE $SecDesc.DACL = $ACEs } #Return the security Descriptor return $SecDesc } Function New-ACE ( [string] $Name = (throw "Please provide user/group name for trustee"), [string] $Domain = (throw "Please provide Domain name for trustee"), [string] $Permission = "Read", [string] $ComputerName = ".", [switch] $Group = $false) { #Create the Trusteee Object $Trustee = ([WMIClass] "\\$ComputerName\root\cimv2:Win32_Trustee").CreateInstance() #Search for the user or group, depending on the -Group switch if (!$group) { $account = [WMI] "\\$ComputerName\root\cimv2:Win32_Account.Name='$Name',Domain='$Domain'" } else { $account = [WMI] "\\$ComputerName\root\cimv2:Win32_Group.Name='$Name',Domain='$Domain'" } #Get the SID for the found account. $accountSID = [WMI] "\\$ComputerName\root\cimv2:Win32_SID.SID='$($account.sid)'" #Setup Trusteee object $Trustee.Domain = $Domain $Trustee.Name = $Name $Trustee.SID = $accountSID.BinaryRepresentation #Create ACE (Access Control List) object. $ACE = ([WMIClass] "\\$ComputerName\root\cimv2:Win32_ACE").CreateInstance() #Select the AccessMask depending on the -Permission parameter switch ($Permission) { "Read" { $ACE.AccessMask = 1179817 } "Change" { $ACE.AccessMask = 1245631 } "Full" { $ACE.AccessMask = 2032127 } default { throw "$Permission is not a supported permission value. Possible values are 'Read','Change','Full'" } } #Setup the rest of the ACE. $ACE.AceFlags = 3 $ACE.AceType = 0 $ACE.Trustee = $Trustee #Return the ACE return $ACE } Function New-Share ( [string] $FolderPath = (throw "Please provide the share folder path (FolderPath)"), [string] $ShareName = (throw "Please provide the Share Name"), $ACEs, [string] $Description = "", [string] $ComputerName=".") { #Start the Text for the message. $text = "$ShareName ($FolderPath): " #Package the SecurityDescriptor via the New-SecurityDescriptor Function. $SecDesc = New-SecurityDescriptor $ACEs #Create the share via WMI, get the return code and create the return message. $Share = [WMICLASS] "\\$ComputerName\Root\Cimv2:Win32_Share" $result = $Share.Create($FolderPath, $ShareName, 0, $false , $Description, $false , $SecDesc) switch ($result.ReturnValue) { 0 {$text += "has been success fully created" } 2 {$text += "Error 2: Access Denied" } 8 {$text += "Error 8: Unknown Failure" } 9 {$text += "Error 9: Invalid Name"} 10 {$text += "Error 10: Invalid Level" } 21 {$text += "Error 21: Invalid Parameter" } 22 {$text += "Error 22 : Duplicate Share"} 23 {$text += "Error 23: Redirected Path" } 24 {$text += "Error 24: Unknown Device or Directory" } 25 {$text += "Error 25: Net Name Not Found" } } #Create Custom return object and Add results $return = New-Object System.Object $return | Add-Member -type NoteProperty -name ReturnCode -value $result.ReturnValue $return | Add-Member -type NoteProperty -name Message -value $text #Return result object $return } #//---------------------------------------------------------------------------- #// Main routines #//---------------------------------------------------------------------------- #Create ACE's for the securitydescriptor for the share: #a group ACE, containing Group info, please notice the -Group switch $ACE = New-ACE -Name "Domain Users" -Domain "CORETECH" -Permission "Read" -Group #a user ACE. $ACE2 = New-ACE -Name "CCO" -Domain "CORETECH" -Permission "Full" #Create the share on the local machine $result = New-Share -FolderPath "C:\Temp" -ShareName "Temp4" -ACEs $ACE,$ACE2 -Description "Test Description" -Computer "localhost" #Output result message from new-share Write-Output $result.Message #Check if the share was succesfully created If ($result.ReturnCode -eq 0) { #Creation was succesfull, put your next code here. } #//---------------------------------------------------------------------------- #// End Script #//----------------------------------------------------------------------------
Last Words:
Script is version 0.0.1. Tested on Windows Vista and Windows XP local and remote, in my enviroment.
There might be a lot that i have not thought of yet, please comment this post if you have suggestions/bugs/
Next Part:
Next time i will try to look into changing existing shares, adding and remove permissions to the list.
Replacing the permissions seems easy, but editing the existing ones might be a challenge.
I will look at it as soon as i have some spare time
As usual, please contact me/us if you need any help on a custom scripting project (at standard price rate of cause).
I hope you all have a nice summer!

James:
Nice script. I had to modify it slightly for my env though.
This line:
$result = $Share.Create($FolderPath, $ShareName, 0, $false , $Description, $false, $SecDesc)
Changed to this:
$result = $Share.Create($FolderPath, $ShareName, 0, $null , $Description, $null, $SecDesc)
The $null’s work better for the optional arguments. Especially argument 4. Maximum users. I found $false was setting it to 0. So nobody could connect to the share.
James
21st September 2009, 23:34Jakob:
Great to hear that someone is using my script
and thanks alot for the bug fix!
22nd September 2009, 10:08Tom:
Hello!
Thanks!!! Your script rescued my goal to create a script for sharing folders remote.
But I’ve two problems.
- How can I change the “user limit” in the creating share from now 1 user to “maximum allowed”?
- How can I grant access to the created share to the “Authenticated Users”?
Maybe you have an idea….
thanks a lot
29th September 2009, 15:28Tom
Jonathan Warnken:
Nice work!!
I added support for setting permissions for Everyone and Authenticated users. Also Updated the New-Share function to address the bug James found.
# //************************************************************************************************************
# // ***** Script Header *****
# //
# // Solution: Coretech Share Functions
# // File: NewShareWithPermission.ps1
# // Author: Jakob Gottlieb Svendsen, Coretech A/S. http://blog.coretech.dk
# // Purpose:
# // New-Share: Creates new Share on local or remote PC, with custom permissions.
# // Required Parameters: FolderPath, ShareName
# //
# // New-ACE: Creates ACE Objects, for use when running New-Share.
# // Required Parameters: Name, Domain
# //
# // New-SecurityDescriptor: used by New-Share to prepare the permissions.
# // Required Parameters: ACEs
#//
# // Usage Examples:
# // New-Share -FolderPath “C:\Temp” -ShareName “Temp” -ACEs $ACE,$ACE2 -Description “Test Description” -Computer “localhost”
# // Sharing of folder C:\Temp, with the Name “Temp”. ACE’s (Permissions) are sent via the -ACEs parameter.
# // Create them with New-ACE and send one or more, seperated by comma (or create and array and use that)
# //
# // This is the first in a couple of share-administration scripts i am planning to make and release on the blog.
# //
# // Please comment the blog post, if you have any suggestions, questions or feedback.
# // Contact me if you need us to make a custom script (or cause not for free )
# //
# // CORETECH A/S History:
# // 0.0.1 JGS 30/06/2009 Created initial version.
# //
# // Customer History:
# // 0.0.2 – Jonathan Warnken(jon.warnken@gmail.com) 16/12/2009
# // – Added logic to all permissions to be set using Everyone and Authenticated Users. These use well known SIDs and are easier to hard code then lookup.
# // – Usage Examples:
# // – (Everyone) $ACE = New-ACE -Name “Everyone” -Domain “.” -Permission “Read” -Group
# // – (Authenticated Users) $ACE = New-ACE -Name “Authenticated Users” -Domain “NT AUTHORITY” -Permission “Read” -Group
# // –
# // – Updated New-Share so that -MaxUsers and -Password are optional parameters. The default values are $null.
# // – Updated the Main Code examples to use an Array for the Access Control objects
# //
# // ***** End Header *****
# //**************************************************************************************************************
#//—————————————————————————-
#// Procedures
#//—————————————————————————-
Function New-SecurityDescriptor (
$ACEs = (throw “Missing one or more Trustees”),
[string] $ComputerName = “.”)
{
#Create SeCDesc object
$SecDesc = ([WMIClass] “\\$ComputerName\root\cimv2:Win32_SecurityDescriptor”).CreateInstance()
#Check if input is an array or not.
if ($ACEs -is [System.Array])
{
#Add Each ACE from the ACE array
foreach ($ACE in $ACEs )
{
$SecDesc.DACL += $ACE.psobject.baseobject
}
}
else
{
#Add the ACE
$SecDesc.DACL = $ACEs
}
#Return the security Descriptor
return $SecDesc
}
Function New-ACE (
[string] $Name = (throw “Please provide user/group name for trustee”),
[string] $Domain = (throw “Please provide Domain name for trustee”),
[string] $Permission = “Read”,
[string] $ComputerName = “.”,
[switch] $Group = $false)
{
#Create the Trusteee Object
$Trustee = ([WMIClass] “\\$ComputerName\root\cimv2:Win32_Trustee”).CreateInstance()
#Check for Special cases Everyone and Authenticated Users)
switch ($Name.ToUpper()) {
“EVERYONE” {
$Trustee.Domain = $Null
$Trustee.Name = “EVERYONE”
$Trustee.SID = @(1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)
}
“AUTHENTICATED USERS” {
$Trustee.Domain = “NT AUTHORITY”
$Trustee.Name = “Authenticated Users”
$Trustee.SID = @(1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0)
}
default {
#Search for the user or group, depending on the -Group switch
if (!$group)
{ $account = [WMI] “\\$ComputerName\root\cimv2:Win32_Account.Name=’$Name’,Domain=’$Domain’” }
else
{ $account = [WMI] “\\$ComputerName\root\cimv2:Win32_Group.Name=’$Name’,Domain=’$Domain’” }
#Get the SID for the found account.
$accountSID = [WMI] “\\$ComputerName\root\cimv2:Win32_SID.SID=’$($account.sid)’”
#Setup Trusteee object
$Trustee.Domain = $Domain
$Trustee.Name = $Name
$Trustee.SID = $accountSID.BinaryRepresentation
}
}
#Create ACE (Access Control List) object.
$ACE = ([WMIClass] “\\$ComputerName\root\cimv2:Win32_ACE”).CreateInstance()
#Select the AccessMask depending on the -Permission parameter
switch ($Permission)
{
“Read” { $ACE.AccessMask = 1179817 }
“Change” { $ACE.AccessMask = 1245631 }
“Full” { $ACE.AccessMask = 2032127 }
default { throw “$Permission is not a supported permission value. Possible values are ‘Read’,'Change’,'Full’” }
}
#Setup the rest of the ACE.
$ACE.AceFlags = 3
$ACE.AceType = 0
$ACE.Trustee = $Trustee
#Return the ACE
return $ACE
}
Function New-Share (
[string] $FolderPath = (throw “Please provide the share folder path (FolderPath)”),
[string] $ShareName = (throw “Please provide the Share Name”),
$ACEs,
[string] $Description = “”,
[string] $ComputerName = “.”,
$MaxUsers = $null,
$Password = $null)
{
#Start the Text for the message.
$text = “$ShareName ($FolderPath): ”
#Package the SecurityDescriptor via the New-SecurityDescriptor Function.
$SecDesc = New-SecurityDescriptor $ACEs
#Create the share via WMI, get the return code and create the return message.
$Share = [WMICLASS] “\\$ComputerName\Root\Cimv2:Win32_Share”
$result = $Share.Create($FolderPath, $ShareName, 0, $MaxUsers, $Description, $Password, $SecDesc)
switch ($result.ReturnValue)
{
0 {$text += “has been success fully created” }
2 {$text += “Error 2: Access Denied” }
8 {$text += “Error 8: Unknown Failure” }
9 {$text += “Error 9: Invalid Name”}
10 {$text += “Error 10: Invalid Level” }
21 {$text += “Error 21: Invalid Parameter” }
22 {$text += “Error 22 : Duplicate Share”}
23 {$text += “Error 23: Redirected Path” }
24 {$text += “Error 24: Unknown Device or Directory” }
25 {$text += “Error 25: Net Name Not Found” }
}
#Create Custom return object and Add results
$return = New-Object System.Object
$return | Add-Member -type NoteProperty -name ReturnCode -value $result.ReturnValue
$return | Add-Member -type NoteProperty -name Message -value $text
#Return result object
$return
}
#//—————————————————————————-
#// Main routines
#//—————————————————————————-
#Create ACE’s for the securitydescriptor for the share:
#a group ACE, containing Group info, please notice the -Group switch
$ACE = @(New-ACE -Name “Domain Users” -Domain “CORETECH” -Permission “Read” -Group)
$ACE += New-ACE -Name “Authenticated Users” -Domain “NT AUTHORITY” -Permission “Read” -Group
$ACE += New-ACE -Name “everyone” -Domain “.” -Permission “Read” -Group
#a user ACE.
$ACE += New-ACE -Name “CCO” -Domain “CORETECH” -Permission “Full”
#Create the share on the local machine
$result = New-Share -FolderPath “C:\Temp” -ShareName “Temp4″ -ACEs $ACE -Description “Test Description” -Computer “localhost”
#Output result message from new-share
Write-Output $result.Message
#Check if the share was succesfully created
If ($result.ReturnCode -eq 0)
{
#Creation was succesfull, put your next code here.
}
#//—————————————————————————-
16th December 2009, 22:47#// End Script
#//—————————————————————————-
Jakob:
thnx alot!
i havent had time myself to do it, its great to see other helping out!
merry christmas to you all.
17th December 2009, 11:23Joe:
Thank you so much for this script. It saved me a lot of time.
4th March 2010, 21:02