powershellsmbwindows-scriptingfileserver

How to create multiple SMB shares with different share names mapped to different paths in PowerShell


I'm trying to figure out a way to script in PowerShell the creation of multiple SMB shares on a file server with different share names pointing to different paths. What I mean is having a variable with share names I want to create and another variable to map those share names to their respective paths, example:

$ShareNames = "Share1","Share2","Share3"
$SharePaths = "C:\Temp1","C:\Temp2","C:\Temp3"

I want to be able to create the shares like so:

Share1 map to C:\Temp1    
Share2 map to C:\Temp2    
Share3 map to C:\Temp3    
and so on...

I know the command to create the SMB shares, see below, but I can't figure out how to map each share name to it's appropriate path with multiple values in each variable.

$Parameters = @{
    Name                  = $ShareName
    ScopeName             = "*"
    Path                  = $SharePath
    FolderEnumerationMode = "AccessBased"
    CachingMode           = "BranchCache"
    ContinuouslyAvailable = $true
    FullAccess            = "Everyone"
}

New-SmbShare @Parameters

I've tried using foreach statements to accomplish what I'm looking to do but just can't seem to figure out how to do the 1 to 1 mapping of share names to share paths.


Solution

  • There are two approaches depending on your needs or likes.

    Stick with two variables using for

    If you want to stick with two variables being mapped to each other, you can use the for statement.

    But it's important to ensure both variables ($ShareNames, $SharePaths) are of type array (at least when indexing into one) using the PS array subexpression operator @()!

    If they're not both of type array and one variable does only contain one string, the current index ($i) of the for iteration will be applied to an char array ([char[]]'Share1'), hence will only return the character at position of $i ('Share1'[0] → 'S' rather than @('Share1')[0] → 'Share1').

    To ensure/guarantee an array, read the comments in the code as there are two options:

    1. Enclose the values before the for statement using @()
    2. Enclose the value every time in the iteration with @() (mentioned as # alternative comment in the code).
      Note: Wrapping/Casting a string as array in each iteration could be expensive (performance-wise) for a (very) large list of "Shares".
    #! ensure $ShareNames is an array with the array subexpression operator @()
    $ShareNames = @('Share1', 'Share2', 'Share3')
    #! ensure $SharePaths is an array with the array subexpression operator @()
    $SharePaths = @('C:\Temp1', 'C:\Temp2', 'C:\Temp3')
    
    for ($i = 0; $i -lt $ShareNames.Count; $i++) {
        # try/finally to ensure no New-SmbShare gets executed in case of an error in splatting of $parameters
        try {
            $parameters = @{
                Name                  = $ShareNames[$i] # alternative to ensure an array with "@($ShareNames)[$i]"
                ScopeName             = '*'
                Path                  = $SharePaths[$i] # alternative to ensure an array with "@($SharePaths)[$i]"
                FolderEnumerationMode = 'AccessBased'
                CachingMode           = 'BranchCache'
                ContinuouslyAvailable = $true
                FullAccess            = 'Everyone'
            }
    
            New-SmbShare @parameters
        } finally {}
    }
    

    Using a hash table for the share mappings with foreach

    No issues here with arrays and there is a clear mapping in the code.
    We just need to use the .GetEnumerator() method of the hash table in the foreach statement.

    $shares = @{
        #key     = value
        'Share1' = 'C:\Temp1'
        'Share2' = 'C:\Temp2'
        'Share3' = 'C:\Temp3'
    }
    
    # we need to use the .GetEnumerator() method to iterate through the hash table
    foreach ($share in $shares.GetEnumerator()) {
        # try/finally to ensure no New-SmbShare gets executed in case of an error in splatting of $parameters
        try {
            $parameters = @{
                Name                  = $share.Key
                ScopeName             = '*'
                Path                  = $share.Value
                FolderEnumerationMode = 'AccessBased'
                CachingMode           = 'BranchCache'
                ContinuouslyAvailable = $true
                FullAccess            = 'Everyone'
            }
    
            New-SmbShare @parameters
        } finally {}
    }