#This script enumerates the shares on one cluster scope and shares them on another scope in the same cluster group. #Run the script in an elevated PowerShell v2 window on a machine that has the FailoverClusters PowerShell module. #It is meant to be as a sample only. # #TODO: Change the variables as follows: #TODO: $cluster is the name of the cluster. Use "." if you are running the script on a cluster node. #TODO: $from is the name of the network name resource (or scope name) that is the source of the share copy. #TODO: $to is the name of the network name resource (or scope name) that is the target of the share copy. # $cluster = "." $from = "ahmedbc4fsy1" $to = "ahmedbc4fsnew" # #TODO: Optional: You can filter the shares you want to share out in the target scope. #TODO: As is, this script shares all non-admin shares. #TODO: Optional: You can add a share description/remark. # #Using Win32 API NetShareAdd via p/invoke to be able to specify the scope in SHARE_INFO_503 $signature = @" using System; using System.Runtime.InteropServices; using System.Collections; public class NativeMethods { [DllImport("Netapi32.dll")] public static extern uint NetShareAdd([MarshalAs(UnmanagedType.LPWStr)] string strServer, Int32 dwLevel, ref SHARE_INFO_503 buf, out uint parm_err); [StructLayoutAttribute(LayoutKind.Sequential)] struct SECURITY_DESCRIPTOR { public byte revision; public byte size; public short control; public IntPtr owner; public IntPtr group; public IntPtr sacl; public IntPtr dacl; } public enum SHARE_TYPE : uint { STYPE_DISKTREE = 0, STYPE_PRINTQ = 1, STYPE_DEVICE = 2, STYPE_IPC = 3, STYPE_SPECIAL = 0x80000000 }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SHARE_INFO_503 { public string shi503_netname; [MarshalAs(UnmanagedType.U4)] public SHARE_TYPE shi503_type; public string shi503_remark; [MarshalAs(UnmanagedType.U4)] public int shi503_permissions; [MarshalAs(UnmanagedType.U4)] public int shi503_max_uses; [MarshalAs(UnmanagedType.U4)] public int shi503_current_uses; public string shi503_path; public string shi503_passwd; public string shi503_servername; [MarshalAs(UnmanagedType.U4)] public int shi503_reserved; public IntPtr shi503_security_descriptor; } public static uint ShareFolder(string servername, string sharename, string path, string remark) { SHARE_INFO_503 shInfo = new SHARE_INFO_503(); shInfo.shi503_netname = sharename; shInfo.shi503_type = SHARE_TYPE.STYPE_DISKTREE; shInfo.shi503_remark = remark; shInfo.shi503_permissions = 0; shInfo.shi503_max_uses = -1; shInfo.shi503_current_uses = 0; shInfo.shi503_path = path; shInfo.shi503_passwd = null; shInfo.shi503_servername = servername; shInfo.shi503_reserved = 0; shInfo.shi503_security_descriptor = IntPtr.Zero; uint nRetValue = 0; uint param_err = 0; nRetValue = NetShareAdd(servername, 503, ref shInfo, out param_err); //Console.WriteLine("Sharing " + path + " on " + servername + " as " + sharename + " returned " + nRetValue + " (" + param_err+ ")"); return nRetValue; } } "@ #Import the FailoverClusters PowerShell module if it is not already imported Import-Module FailoverClusters #Add the function type that will be used to share the folder in the defined scope Add-Type -TypeDefinition $signature #Confirm that the cluster is reachable Write-Host Checking cluster ... $clusterobj = Get-Cluster $cluster if( $clusterobj -eq $null ) { Write-Host $cluster is not reachable exit } #Confirm that the two scopes entered by the user are cluster resources Write-Host Checking resources ... $fromres = Get-ClusterResource $from -Cluster $cluster if( $fromres -eq $null ) { Write-Host $from is not a valid resource on cluster $cluster exit } $tores = Get-ClusterResource $to -Cluster $cluster if( $tores -eq $null ) { Write-Host $to is not a valid resource on cluster $cluster exit } #Confirm that the two scopes entered by the user are cluster network name resources Write-Host Checking resource types ... if( $fromres.ResourceType.Name -ne "Network Name" ) { Write-Host $from is not a network name resource on cluster $cluster exit } if( $tores.ResourceType.Name -ne "Network Name" ) { Write-Host $to is not a network name resource on cluster $cluster exit } #Confirm that the two scopes entered by the user are cluster resources in the same cluster group Write-Host Checking resource groups ... if( $tores.OwnerGroup.Name -ne $fromres.OwnerGroup.Name ) { Write-Host Network name resources $from and $to are not in the same group on cluster $cluster exit } #Confirm that the cluster group is onoline Write-Host Checking group status ... if( $fromres.OwnerGroup.State -ne "Online" ) { Write-Host Cluster group $fromres.OwnerGroup is not online cluster $cluster exit } #Enumerate the non-admin shares in the source scope Write-Host Write-Host Found the following non-admin shares on source: $fromshares = gwmi -ComputerName $from Win32_Share | ?{ $_.ServerName -eq $from } | ?{ $_.Name -notlike "*$*" } $fromshares | ft Name,Path,ServerName #TODO: Here you can do fancy things like specify only certain folders to share in the target scope #For example, if I only want to share the folders ending with "1", I can filter the list: #$fromshares = $fromshares | ?{ $_.Name -like "*1" } #Share the non-admin shares found above into the destination scope foreach( $fromshare in $fromshares ) { $shareas = $fromshare.Name.SubString($fromshare.Name.LastIndexOf("\")+1) Write-Host Sharing $fromshare.Path on $to as $shareas #Here is where we do the actual sharing #TODO: The fourth parameter can be changed if you want to specify a share description/remark $ret = [NativeMethods]::ShareFolder($to, $shareas, $fromshare.Path, "") if( $ret -eq 0 ) { Write-Host " ... shared successfully." } elseif( $ret -eq 2118 ) { Write-Host " ... share already exists in this scope." } else { Write-Host " ... failed to share (error=$ret)." } }