Moving Windows File Shares to A New Server

Published on 19 October 2019

Ugh. File Shares.

File servers always seem to end up a mess, and eventually the time comes to lift-and-shift all of that good stuff to another server. Typically you can use something like Robocopy to move the data from the old server to the new one but, alas, that won't do the file shares.

This is what I used for each drive I needed to copy:

    .\robocopy i:\ \\newserver\f$\newroot\i /MIR /COPYALL /ZB /XD $Recycle.bin /r:1 /w:1 /a-:sh /log:c:\temp\job-i.txt

In many cases, recreating the shares isn't actually as big an issue as it sounds. If you data is well organised, and you only have a few shares, you can just recreate them manually. Even if you have a lot, and you are not making any changes to the paths, you can use the method in this Microsoft article to backup the data from the the registry and import it on the new server.

Sometimes though, you need to change the path for the shares when they are created on the destination server. And sometimes, you are dealing with a file server where you need to do that, and someone has created not just NTFS permissions, but share level permissions as well.

why?

Anyway, the good news is, you can get the securitydescriptor from existing shares, and then apply it to new shares. You can't specify a -computer when using the SMB cmdlets, but you can just invoke it remotely.

I have used a regex to get the drive letter for each share. Regex are so useful, it is worth using them whenever you get the opportunity to build up your experience with them.

    # Move SMB shares to new server
    # Greg Heywood
    # v 1.0
    # Read the shares off the source server
    # Check if they are for drives we have moved i, j, k, l, m
    # Modify the path
    # if the share doesn't exist, create it.
    ##################################################
    # Variables
    ##################################################
    $sourceserver = "sourceserver"
    $destinationserver = "destinationserver"
    $newroot = "f:\newpath\"
    if (!$cred) { $cred = (get-credential) } # used to connect to the servers
    # Sets the maxiumum number of shares to create. Can be useful for testing.
    $Count = 90
    ##################################################
    # Get shares from source server
    ##################################################
    $scriptblock = {
        get-smbshare 
    }
    $shares = Invoke-Command -ComputerName $sourceserver -Credential $cred -ScriptBlock $scriptblock
    ##################################################
    # Do any processing for the shares, and then create
    ##################################################

    foreach ($share in $Shares) {

        write-debug ("*****************************")
        write-debug ("Value for Count is $Count")
        write-debug ("Share path is $($Share.path)")
        $Count = $Count - 1
        #Get the first letter
        #$drive = ($shares[0].path -split(":"))[0]
        $regex = "^([\w]:)([\s\S]*)"
        $share.path -match $regex > $null
        $newpath = $newroot + $matches[1].trimend(":") + $matches[2]
        write-debug ("Old path is $($Share.path)")
        write-debug ("Newpath = $newpath")
                
        switch ($matches[1]) {
            "i:" { $create = $true }
            "j:" { $create = $true }
            "k:" { $create = $true }
            "l:" { $create = $true }
            "m:" { $create = $true }
            default { $create = $false }
        }
        write-debug ("Create is $create")
                
        if ($create -eq $true) {
            $NewShName = $Share.Name
            $NewShpath = $newpath
            $NewShSecurityDescriptor = $Share.SecurityDescriptor
            write-debug "Share name to create is $($NewShName)"
            write-debug "Share path to create is $($NewShpath)"
            write-debug "Share SD to create is $($NewShSecurityDescriptor)"
            ##################################################
            # check if the share exists
            ##################################################
            $scriptblock = {
                get-smbshare -name $using:NewShname -ErrorAction SilentlyContinue
            }
            $result = Invoke-Command -ComputerName $destinationserver -Credential $cred -ScriptBlock $scriptblock 
            write-debug "Result is $result"

            #if the share doesn't exist, create it
            if ($result -eq $null) {
                # Create the share
                write-debug "** Need to create $Newshname **"
                $scriptblock = {
                    new-smbshare -name $using:NewShname -path $using:NewShpath -SecurityDescriptor $using:NewShSecurityDescriptor 
                }
                        
                $result = Invoke-Command -ComputerName $destinationserver -Credential $cred -ScriptBlock $scriptblock
                $result
            }
            if ($Count -lt 1) { break }
        }

    }

So the end script is actually nowhere near as horrendous as I thought it was going to be. The lesson though, is don't use share level permissions AND file level, just use file level..

comments powered by Disqus