Changing Shared Folders’ Path


As usual, the ideas for the posts start as a question from a colleague or a customer.

In this case, the customer had to distribute differently the folders in his FileServers’ volumes.

He had added an additional drive, copied all the relevant folders, and now needed to change the shares (non cluster resources) settings.

If there were only two or three, there is no problem doing it “manually”, but when you have more than 150 of them… it’s PowerShell time!

All the shares information and settings are stored in the registry, under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares key (as described briefly in KB125996).

Each value represents a share, and the mutli-string value data contains the settings for it.

So by looping on each value, searching for the relevant folder in the value-data text (e.g. “Path=C:\myOldSharePath”) and replacing it with the new value, we could easily change them all in a script.

This led to the PowerShell function below:

function Change-SharePath {
    [cmdletbinding(SupportsShouldProcess=$true)]
    param(
        $OldPath,
        $NewPath
    )
 
    $RegPath = ‘HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares’
    dir -Path $RegPath | Select-Object -ExpandProperty Property | ForEach-Object {
        $ShareName = $_
        $ShareData = Get-ItemProperty -Path $RegPath -Name $ShareName |
                Select-Object -ExpandProperty $ShareName
        if ($ShareData | Where-Object { $_ -eq  “Path=$OldPath}) {
            $ShareData = $ShareData -replace [regex]::Escape(“Path=$OldPath), “Path=$NewPath
 
            if ($PSCmdlet.ShouldProcess($ShareName, ‘Change-SharePath’)) {
                Set-ItemProperty -Path $RegPath -Name $ShareName -Value $ShareData
            }
        }
    }
}
 

Where we would use it:

– With the -WhatIf parameter for testing purposes:

Change-SharePath -OldPath D:\myShare -NewPath E:\Subfolder\myNewSharePath -WhatIf

– With the -Verbose parameter for details during the changes:

Change-SharePath -OldPath D:\myShare -NewPath E:\Subfolder\myNewSharePathVerbose
 

And don’t forget to restart the Server service (aka lanmanserver) after all the changes, for the new settings to take effect:

Restart-Service -Name lanmanserver
 

HTH,

\Martin.

Comments (6)

  1. Jay says:

    looks good. but i have one question. if you need modify shares one by one from the tow differents txt files. For example $OldPath = get-content C:\oldpath.txt where oldpath is = test1,test,2,test3.. and newpath is = share1,share2,share3. With the only 1 share the script works good. but with multiple entries from txt files. doesnt work..

    1. @Jay,
      The function supports only one path per change. But assuming the paths in your files match one another (by line number), you can do something like:
      $OldPath = Get-Content C:\oldpath.txt
      $Newpath = Get-Content C:\newpaths.txt
      for ($i = 0; $i -lt $OldPath.count-1 ; $i++) {
      Change-SharePath -OldPath $OldPath[$i] -NewPath $NewPath[$i]
      }

  2. SaiValaboju says:

    Hi,
    I am new to Power shell scripting, I am having a task where I need to fetch share folders details like(Share Path, Directory Path of the share folder, Share permissions and NTFS permissions), for this I have googled and got the below Code, when I run the code I am getting the Output but few things are missing(Directory Path of the share folder, and share permissions). So expecting some to help me to complete the task.

    Code:
    *******************************
    Function Get-NtfsRights($name,$path,$comp)
    {
    $path = [regex]::Escape($path)
    $share = “\\$comp\$name”
    $wmi = gwmi Win32_LogicalFileSecuritySetting -filter “path=’$path'” -ComputerName $comp
    $wmi.GetSecurityDescriptor().Descriptor.DACL | where {$_.AccessMask -as [Security.AccessControl.FileSystemRights]} |select `
    @{name=”Principal”;Expression={“{0}\{1}” -f $_.Trustee.Domain,$_.Trustee.name}},
    @{name=”Rights”;Expression={[Security.AccessControl.FileSystemRights] $_.AccessMask }},
    @{name=”AceFlags”;Expression={[Security.AccessControl.AceFlags] $_.AceFlags }},
    @{name=”AceType”;Expression={[Security.AccessControl.AceType] $_.AceType }},
    @{name=”ShareName”;Expression={$share}}
    }

    gc serverlist.txt | foreach {
    if ($shares = Get-WmiObject Win32_Share -ComputerName $_ | Where {$_.Path})
    {
    $shares | Foreach { Write-Progress -Status “Get share information on $($_.__Server)” $_.Name
    Get-NtfsRights $_.Name $_.Path $_.__Server}
    }
    else {“Failed to get share information from {0}.” -f $($_.ToUpper())}
    } | ft Principal,Rights,AceFlags,AceType -GroupBy ShareName -Wrap | Out-File result1.txt
    *****************************************
    Output I am getting is below:
    **************************************
    ShareName: \\Server Name\test

    Principal Rights AceFlags AceType
    ——— —— ——– ——-
    BUILTIN\Administrators FullControl None AccessAllowed
    XXXXX\mfp_service_account FullControl ObjectInherit, ContainerInher AccessAllowed
    it
    BUILTIN\Administrators FullControl ObjectInherit, ContainerInher AccessAllowed
    it, Inherited
    NT AUTHORITY\SYSTEM FullControl ObjectInherit, ContainerInher AccessAllowed
    it, Inherited
    BUILTIN\Users ReadAndExecute, Synchronize ObjectInherit, ContainerInher AccessAllowed
    it, Inherited
    BUILTIN\Users AppendData ContainerInherit, Inherited AccessAllowed
    BUILTIN\Users CreateFiles ContainerInherit, Inherited AccessAllowed
    ******************************************************
    Please help me…. Thanks!!!

    1. Try this:

      function Get-NtfsRights {
      param($ComputerName, $ShareName, $Path)

      $filter = “Path=’$([regex]::Escape($Path))'”
      $wmi = Get-WmiObject -Class Win32_LogicalFileSecuritySetting -Filter $filter -ComputerName $ComputerName
      $wmi.GetSecurityDescriptor().Descriptor.DACL | Where-Object { $_.AccessMask -as [Security.AccessControl.FileSystemRights] } |
      Select-Object @{N=’ComputerName’; E={$ComputerName}},
      @{N=’SharePath’; E={‘{0}\{1}’ -f $ComputerName, $ShareName}},
      @{N=’LocalPath’; E={$Path}},
      @{N=’Principal’; E={‘{0}\{1}’ -f $_.Trustee.Domain, $_.Trustee.name}},
      @{N=’Rights’; E={[Security.AccessControl.FileSystemRights] $_.AccessMask }},
      @{N=’AceFlags’; E={[Security.AccessControl.AceFlags] $_.AceFlags }},
      @{N=’AceType’; E={[Security.AccessControl.AceType] $_.AceType }}
      }

      Get-Content serverlist.txt | ForEach-Object {
      try {
      $shares = Get-WmiObject -Class Win32_Share -ComputerName $_ | Where-Object { $_.Path }
      $shares | ForEach-Object {
      Write-Progress -Status “Get share information on $($_.__Server)” $_.Name
      Get-NtfsRights -ComputerName $_.__Server -ShareName $_.Name -Path $_.Path }
      } catch {
      ‘Failed to get share information from {0}.{1}’ -f $($_.ToUpper()), $_.Exception.Message
      }
      }

      1. SaiValaboju says:

        Hi Martin,

        Thanks for your reply!!

        I tried your code, but getting some errors(Pl find below), i want the output in some text file or CSV. and even i want the share permissions in the output. plz help. Thanks!!!
        ****************************************
        PS C:\Users\sai_valaboju> function Get-NtfsRights {
        >> param($ComputerName, $ShareName, $Path)
        >>
        >> $filter = “Path=’$([regex]::Escape($Path))'”
        >> $wmi = Get-WmiObject -Class Win32_LogicalFileSecuritySetting -Filter $filter -ComputerName $ComputerName
        >> $wmi.GetSecurityDescriptor().Descriptor.DACL | Where-Object { $_.AccessMask -as [Security.AccessControl.FileSystemRi
        ghts] } |
        >> Select-Object @{N=’ComputerName’; E={$ComputerName}},
        >> @{N=’SharePath’; E={`{0}\{1}’ -f $ComputerName, $ShareName}},
        >> @{N=’LocalPath’; E={$Path}},
        >> @{N=’Principal’; E={`{0}\{1}’ -f $_.Trustee.Domain, $_.Trustee.name}},
        >> @{N=’Rights’; E={[Security.AccessControl.FileSystemRights] $_.AccessMask }},
        >> @{N=’AceFlags’; E={[Security.AccessControl.AceFlags] $_.AceFlags }},
        >> @{N=’AceType’; E={[Security.AccessControl.AceType] $_.AceType }}
        >> }
        >>
        PS C:\Users\sai_valaboju> Get-Content serverlist.txt | ForEach-Object {
        >> try {
        >> $shares = Get-WmiObject -Class Win32_Share -ComputerName $_ | Where-Object { $_.Path }
        >> $shares | ForEach-Object {
        >> Write-Progress -Status “Get share information on $($_.__Server)” $_.Name
        >> Get-NtfsRights -ComputerName $_.__Server -ShareName $_.Name -Path $_.Path }
        >> } catch {
        >> `Failed to get share information from {0}.{1}’ -f $($_.ToUpper()), $_.Exception.Message
        >> }
        >> }
        >>
        Get-WmiObject : Invalid query
        At line:4 char:21
        + $wmi = Get-WmiObject <<<< -Class Win32_LogicalFileSecuritySetting -Filter $filter -ComputerName $ComputerName
        + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException
        + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

        Method invocation failed because [System.Management.Automation.ErrorRecord] doesn't contain a method named 'ToUpper'.
        At line:8 char:63
        + `Failed to get share information from {0}.{1}' -f $($_.ToUpper <<<< ()), $_.Exception.Message
        + CategoryInfo : InvalidOperation: (ToUpper:String) [], RuntimeException
        + FullyQualifiedErrorId : MethodNotFound

Skip to main content