PoshCode Logo PowerShell Code Repository

Copy-Shares by Sysiphus 18 months ago
View followups from simesch | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/4001"></script>download | new post

This script “copies” shares and share permissions from one computer to another. The drive letter can change between computers, but the path(s) on the drive may not. This script does not copy the data; for that you will need another solution, such as xcopy or a decent SAN that can do it for you. It works on OSes as old as Windows 2000, and at least as new as Server 2008 R2. It probably has a hundred possible improvements.

  1. <#  
  2. .SYNOPSIS  
  3.         Recreates shares and copies share permissions.
  4. .DESCRIPTION
  5.         Recreates shares and copies share permissions.
  6. .NOTES  
  7.         Name: Copy-Shares
  8.         Author: Sysiphus
  9.         DateCreated: 2013:03:06
  10.         Inspiration: http://poshcode.org/935
  11.                 http://gallery.technet.microsoft.com/scriptcenter/a231026a-3fdb-4190-9915-38d8cd827348
  12.                 http://serverfault.com/questions/9011/creating-a-share-with-permissions-with-windows-powershell
  13.         Info: This script "copies" shares and share permissions from one computer to another. The drive
  14.                 letter can change between computers, but the path(s) on the drive may not. This script does not
  15.                 copy the data; for that you will need another solution, such as xcopy or a decent SAN that can
  16.                 do it for you. It works on OSes as old as Windows 2000, and at least as new as Server 2008 R2.
  17.                 It probably has a hundred possible improvements.
  18.        
  19. .EXAMPLE  
  20.     Copy-Shares -SourceComputer Oldbox -SourceDrive E -DestComputer Newbox -DestDrive K
  21. #>  
  22. Param (
  23.         [Parameter(
  24.                 Position=0,
  25.                 ValueFromRemainingArguments=$true,
  26.                 HelpMessage="Name of computer to get shares from, with no domain or slashes."
  27.                 )]
  28.         [Alias("Old")]
  29.         [ValidatePattern("^[^\\]")]
  30.         [ValidateNotNullOrEmpty()]
  31.         [String]$SourceComputer = "OldAndBusted",
  32.        
  33.         [Parameter(
  34.                 Position=1,
  35.                 ValueFromRemainingArguments=$true,
  36.                 HelpMessage="Source drive letter, with no colon or slash."
  37.                 )]
  38.         [ValidatePattern('[^:]$')]
  39.         [ValidateNotNullOrEmpty()]
  40.         [String]$SourceDrive = "D",
  41.        
  42.         [Parameter(
  43.                 Position=2,
  44.                 ValueFromRemainingArguments=$true,
  45.                 HelpMessage="Name of computer to create shares on, with no domain or slashes."
  46.                 )]
  47.         [Alias("New")]
  48.         [ValidatePattern("^[^\\]")]
  49.         [ValidateNotNullOrEmpty()]
  50.         [String]$DestComputer = "NewHotness",
  51.        
  52.         [Parameter(
  53.                 Position=3,
  54.                 ValueFromRemainingArguments=$true,
  55.                 HelpMessage="Destination drive letter, with no colon or slash."
  56.                 )]
  57.         [ValidatePattern('[^:]$')]
  58.         [ValidateNotNullOrEmpty()]
  59.         [String]$DestDrive = "F"
  60.         )
  61.  
  62.  
  63. #Format the drives to include ":\". I know there's a much better way to do it out there.
  64. $SourceDrive = $SourceDrive + ":\"
  65. $DestDrive =  $DestDrive + ":\"
  66.  
  67. #Some early WMI queries to establish what needs to be done
  68. [Array]$SourceShares = Get-WmiObject -ComputerName $SourceComputer -Class Win32_Share -Filter "Type = '0'" # To eliminate all admin and non-disk shares
  69. [Array]$SourcePerms  = Get-WmiObject -ComputerName $SourceComputer -Class Win32_LogicalShareSecuritySetting
  70. [Array]$DestShares   = Get-WmiObject -ComputerName $DestComputer   -Class Win32_Share -Filter "Type = '0'" # see http://msdn.microsoft.com/en-us/library/windows/desktop/aa394435%28v=vs.85%29.aspx
  71. [Array]$DestPerms    = Get-WmiObject -ComputerName $DestComputer   -Class Win32_LogicalShareSecuritySetting
  72.  
  73.  
  74. #Region Limit to shares on specified source drive, warn on others
  75. $SourceShareWrongDrive = $SourceShares | Where {$_.Path -notlike "$SourceDrive*"}
  76. [Array]$SourceShares = $SourceShares | Where {$_.Path -like "$SourceDrive*"}
  77. If ($SourceShareWrongDrive) {
  78.         Write-Host -Fore Cyan -No "`nThe following shares are on a different source drive than the one you specified ($SourceDrive):"
  79.         $SourceShareWrongDrive
  80.         Write-Host -Fore Cyan "You will need to either do these shares manually, skip them, or re-run the script again for each additional drive.`n"   
  81.         }
  82. #EndRegion
  83.  
  84. #Region Limit to shares with security settings
  85. #This little line of voodoo gets just the names of $SourceShares, and selects only those which are not in just the names of $SourcePerms
  86. #Feel free to pick it apart and make it cleaner, I just didn't want four more free variables running amok.
  87. #I also confess that I do these lines sometimes just to see if they really work...
  88. [Array]$MissingPerms = $SourceShares | %{$_.Name} | %{ if (($SourcePerms | %{$_.Name}) -notcontains $_) {$_} }
  89. If ($MissingPerms) {
  90.         Write-Host -Fore Yellow -No "`nThe following shares do not have share permissions that can be read by a script:"
  91.         $SourceShares | Where {$MissingPerms -contains $_.Name}
  92.         Write-Host -Fore Yellow "These shares cannot be processed and will be skipped. To fix this, for each share" `
  93.         "listed, manually open the Share permissions on the source computer, uncheck and recheck any box, and apply." `
  94.         "Rerun this script and it will read the share permissions and work properly. Sadly, I'm not sure why this works.`n"
  95.                 #Update, it works because http://qa.social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/e9e9c619-ef54-4ce6-a520-202c7a3ffabc
  96.                 #and could probably be scripted around. Ah, well.
  97.         $SourceShares = $SourceShares | Where {$MissingPerms -notcontains $_.Name}
  98.         }
  99. #EndRegion
  100.  
  101. #Region Don't create shares that already exist
  102. #Like above, just go with the voodoo...
  103. [Array]$DuplicateShares = $SourceShares | %{$_.Name} | %{if (($DestShares | %{$_.Name}) -contains $_) {$_} }
  104. If ($DuplicateShares) {
  105.         Write-Host -Fore Green "`nDuplicate share(s) found on source and destination computers. You need to fix these manually if this is a problem."
  106.         ForEach ($Duplicate in $DuplicateShares) {
  107.                 Write-Host -Fore Green "           Share :" $Duplicate
  108.                 Write-Host -Fore Green "     Source path :" ($SourceShares | where {$_.Name -like $Duplicate}).Path
  109.                 Write-Host -Fore Green "Destination Path :" ($DestShares | where {$_.Name -like $Duplicate}).Path
  110.                 }
  111.                 $SourceShares = $SourceShares | where {$DuplicateShares -notcontains $_.Name}
  112.         }
  113. #EndRegion
  114.  
  115.  
  116.  
  117. #Main bit happens here
  118. ForEach ($SourceShare in $SourceShares) {
  119.         #Get the perms that match the share...
  120.         $SourcePerm = $SourcePerms | Where {$_.Name -like $SourceShare.Name}
  121.        
  122.         #And grab its SecurityDescriptor to re-use on the destination share
  123.         $ShareSecurity = $SourcePerm.GetSecurityDescriptor().Descriptor
  124.        
  125.         #Then get the share info, like the (modified) path and other stuff
  126.         $DestPath = $SourceShare.Path -replace "$SourceDrive\", $DestDrive
  127.                 #The regex needed the extra "\" in the replacement string and that really bugs me. :-(
  128.         $ShareName = $SourceShare.Name
  129.         If ($SourceShare.MaximumAllowed) {$ShareMax = $SourceShare.MaximumAllowed}
  130.         Else {[Void]$ShareMax = $null}
  131.         $ShareDescription = $SourceShare.Description
  132.        
  133.        
  134.        
  135.         #Then create a new share WMI object on the destination computer's runspace...
  136.         [wmiclass]$NewShare = "\\$DestComputer\root\cimv2:win32_share"
  137.         #And create the share there! (Oh, and snag the return value...)
  138.         Write-Host "Attempting to create the share $ShareName..."
  139.         $Return = $NewShare.Create($DestPath, $ShareName, 0, $ShareMax, $ShareDescription, $null, $ShareSecurity)
  140.         #Hint about that line, it is Path, Name, Type (Disk Drive is 0), Max connections, Description,
  141.         #       Password (null because using user-level security), and Access (a Win32_SecurityDescriptor)
  142.        
  143.         #Filter the return value into something readable...
  144.     Switch ($return.returnvalue) {
  145.         0 {$ReturnVal = "Success"}
  146.         2 {$ReturnVal = "Access Denied"}
  147.         8 {$ReturnVal = "Unknown Failure"}
  148.         9 {$ReturnVal = "Invalid Name"}
  149.         10 {$ReturnVal = "Invalid Level"}
  150.         21 {$ReturnVal = "Invalid Parameter"}
  151.         22 {$ReturnVal = "Duplicate Share"}
  152.         23 {$ReturnVal = "Redirected Path"}
  153.         24 {$ReturnVal = "Unknown Device or Directory"}
  154.         25 {$ReturnVal = "Net Name Not Found"}
  155.         }
  156.        
  157.         If ($Return.ReturnValue -eq 0) {
  158.                 Write-Host -Fore Green "Success!"
  159.                 }
  160.         Else {
  161.                 Write-Host -Fore Yellow "Error" $ReturnVal "creating share" $ShareName "on $DestComputer. Good luck."
  162.                 }
  163.        
  164.        
  165.         }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me