Your basic ITPro blog... What's going on at work, what I'm interested in.

Friday, March 14, 2008

New Shared Folders

We are working on implementing a new file server at work. That means new user folder and new group folders. Our current 'shared' storage is a bit of a mess, security-wise.

In creating our new file server, we came up with the following security model.

For USER shares: 'Share Admins' have full control; each user has modify rights to his/her own folder.

For GROUP shares: 'Share Admins' have full control; each group folder has two security groups in its ACL, one with MODify rights and one with ReadOnly rights.

Users get a drive mapped to their USER share and a drive mapped to the 'Groups' folder (which contains all of the individual folders described above.

We are using Access Based Enumeration on this server, so users only see the folders they have access to.

I quickly realized that migrating all of our shared data to the new file structure was going to be a huge chore. Specifically, I was not looking forward to having to:

- Create the shared folder
- Create the two security groups in AD
- Modify the ACL on the folder, assigning modify and readonly rights as appropriate.

This doesn't sound like a big deal, until you think about having to do this for dozens of folders! So, I wrote a PowerShell script to do this for me. This script is by no means perfect. I am sure that there are scripters out there who will cringe. But, it gets the job done. I am tweaking it and welcome any suggestions.

Some points:

  • The 30-Second Pause: I have found that, without the pause, when the ACL is getting applied, the server does not always see the security groups in AD. By pausing for a bit, it seems that AD changes have time to propagate/refresh/whatever. I am still looking for a better solution.
  • I also have a 'tear-down' script that deletes the security groups and folders. I will publish this later.

Here is the script:

###############################################################################################
##
##   MakeGroup.ps1
##
## Creates File Shares and associated Security Groups:
##         - Creates MOD, RO, groups for security assignments to group shares
##         - Creates the shared folders themselves
##
## If using a TXT file for input, it contains a list of folder names.
##
## TXT File Format:
##   One Column
##       - First row = NAME (used as data element identifier)
##       - Subsequent rows = <name of the folder to be created>
##            - Longer names will be truncated to 13 characters for Security Group creation!!
## TXT file example:
##    NAME
##    Folder001
##    Folder 002
##  Folder for Group 3
##
## Best if run on GC of Domain
##
###############################################################################################

function get_option {
    # This function allows user to select input type
    #   - single folder entered at command line or .TXT file
    Clear-Host
    Write-Host -ForegroundColor Cyan "WELCOME TO THE 'CREATE NEW SHARED FOLDER(S) SCRIPT'"
    Write-Host "Do you want to enter a single folder name or use a .TXT file for input?"
    Write-Host "  Please enter '1' to type a single folder name"
    Write-Host "  Please enter '2' to use a .TXT input file"
    $script:chosen = Read-Host "1 or 2"
    switch ($script:chosen) {
        1 {
            Write-Host "You selected to enter a single folder name."
            $script:foldername = Read-Host "Enter the folder name"
            Write-Host "You entered '$script:foldername'"
            $script:isBatch = $FALSE
            $script:MayProceed = $TRUE
        }
        2 {
            Write-Host "You selected to enter a .TXT file name for input."
            $script:ListOfFolders = Read-Host "Enter the .TXT filename"
            Write-Host "You entered '$script:ListOfFolders'"
            $script:MayProceed = Test-Path $script:ListOfFolders
            if ($script:MayProceed) {
                Write-Host "File exists... Proceeding"
                $script:isBatch = $TRUE
            }
            else {
                Write-Host -ForegroundColor Red "File does not exist... Try again"
                Start-Sleep -Seconds 2
            }
        }
        default {
            Write-Host -ForegroundColor Red "You did not choose a valid option... Please try again..."
            Start-Sleep -Seconds 3
        }
    }
}

function assign_rights {
    # This function assigns rights to the folder
    param([string]$Rights, [string]$GroupName)
    $acl = get-acl $FullPath
    $Inherit = [Security.AccessControl.InheritanceFlags] "ContainerInherit, ObjectInherit"
    $Prop = [Security.AccessControl.PropagationFlags] "None"
    $NewRule = new-object Security.AccessControl.FileSystemAccessRule $GroupName, $Rights, $Inherit, $Prop, Allow
    $modified = $FALSE
    $modded = $acl.ModifyAccessRule("Add", $NewRule, [ref]$modified)
    set-acl -path $FullPath -AclObject $acl
    if ($modded)
    {
        Write-Host "ACL for $GroupName successfully applied."
    }
    else
    {
        Write-Host -ForegroundColor Red "WARNING!!! ACL for $GroupName failed to apply!"
    }
}

function process_folder {
    param([string]$foldername)
    # This Function creates folder and groups
    # Do we actually have a folder name?
    if ($foldername.length -ne 0) {
        Write-Host "************************************************"
        Write-Host "Now processing folder name:" $foldername "..."

        # Defining path to folder
        $FullPath = "\\W2003\Groups\" + $foldername
        #Does this folder already exist?
        $isThere = Test-Path $FullPath   
        if ($isThere) {
            #Folder already exists. Abort operation.
            Write-Host -ForegroundColor Red "The folder $FullPath already exists and is being skipped. Please verify the folder name."
        }
        else {
            # Create variables holding group names and descriptions
            # If necessary, shorten folder name to 13 characters
            if ($foldername.length  -gt 13) {
                $MODgroup = "s_" + $foldername.substring(0,13) + "_MOD"
                $MODdesc = "$foldername MODify security group"
                $ROgroup  = "s_" + $foldername.substring(0,13) + "_RO"
                $ROdesc = "$foldername ReadOnly security group"
            }
            else {
                $MODgroup = "s_" + $foldername + "_MOD"
                $MODdesc = "$foldername -- MODify security group"
                $ROgroup  = "s_" + $foldername + "_RO"
                $ROdesc = "$foldername -- ReadOnly security group"
            }
            # Defines OU location for Security Group Creation
            $GroupContainer = "OU=Security Groups,OU=Groups,OU=Resources,DC=mydom,DC=local"
            # Create Groups
            Write-Host "Creating MODify security group for this folder..." -NoNewline
            $null = New-QADGroup -ParentContainer $GroupContainer -name $MODgroup -samAccountName $MODgroup -GroupType 'security' -GroupScope 'GLOBAL' -description $MODdesc
            Write-Host "  DONE!"
            Write-Host "Creating ReadOnly security group for this folder..." -NoNewline
            $null = New-QADGroup -ParentContainer $GroupContainer -name $ROgroup -samAccountName $ROgroup -GroupType 'security' -GroupScope 'GLOBAL' -description $ROdesc
            Write-Host "  DONE!"

            # Create Folder
            Write-Host "Creating folder under \\W2003\Groups ..." -NoNewline
            $null = New-Item -path \\W2003\Groups -name $foldername -type directory
            Write-Host "  DONE!"
            # Pause for a bit, otherwise ACL modification may balk for not finding the Group in AD
            Write-Host "Pausing processing for 30 seconds..."
            Start-Sleep -s 10
            Write-Host "20 more seconds to go..."
            Start-Sleep -s 10
            Write-Host "10 more seconds to go..."
            Start-Sleep -s 10
            Write-Host "I know I need to find a better way to do this step... but... Moving On!"
            # Assign rights to the folder for the groups
            # MODIFY RIGHTS
            Write-Host "Assigning MODify ACL entries for this folder to the MOD group..."
            assign_rights "Modify" $MODgroup
            #READONLY RIGHTS
            Write-Host "Assigning ReadOnly ACL entries for this folder to the RO group..."
            assign_rights "Read" $ROgroup
        }
    }
}

$chosen = "0"
$ListOfFolders = ""
$foldername = ""
$isBatch = $FALSE
$MayProceed = $FALSE

do {get_option} until ($chosen -eq "1" -or $chosen -eq "2" -and $MayProceed -eq $TRUE)

# Process folder name list - batch or not
if ($isBatch) {
    $ListOfFolderNames = Import-CSV $ListOfFolders
    foreach ($folder in $ListOfFolderNames) {
        $foldername = $folder.NAME
        process_folder $foldername
    }
}
else {
    process_folder $foldername
}

Write-Host "All Finished. Thank you."

No comments:

Additional Info

My photo
email: support (AT) mangrumtech (DOT) com
mobile: 480-270-4332