# File Share and Permissions Migration Script # Parameters param ( [string]$SourceServer, [string]$DestinationServer, [switch]$DryRun, [switch]$Help, [ValidateSet('Skip', 'Replace', 'Prompt')] [string]$ExistingShareAction = 'Prompt' ) # Function to display usage information function Show-UsageInfo { @" File Share Migration Script Usage: .\MigrateFileShares.ps1 -SourceServer -DestinationServer [-DryRun] [-ExistingShareAction ] Parameters: -SourceServer (Required) Name of the source file server -DestinationServer (Required) Name of the destination file server -DryRun (Optional) Preview migration actions without making changes -Help (Optional) Show this usage information -ExistingShareAction (Optional) How to handle existing shares Skip - Skip shares that already exist Replace - Remove and recreate existing shares Prompt - Ask for each existing share (default) Examples: # Preview migration actions .\MigrateFileShares.ps1 -SourceServer SOURCESVR -DestinationServer DESTSVR -DryRun # Perform actual migration, skipping existing shares .\MigrateFileShares.ps1 -SourceServer SOURCESVR -DestinationServer DESTSVR -ExistingShareAction Skip # Perform actual migration, replacing existing shares .\MigrateFileShares.ps1 -SourceServer SOURCESVR -DestinationServer DESTSVR -ExistingShareAction Replace Notes: - Requires administrative privileges - Ensure PowerShell remoting is enabled between servers - Test in a staged environment before production use "@ } # Check if help is requested or required parameters are missing if ($Help -or [string]::IsNullOrWhiteSpace($SourceServer) -or [string]::IsNullOrWhiteSpace($DestinationServer)) { Show-UsageInfo exit } # Logging function function Write-MigrationLog { param ( [string]$Message, [switch]$DryRun ) $logPrefix = if ($DryRun) { "[DRY RUN] " } else { "[ACTUAL] " } Write-Host "$logPrefix$Message" } # Function to get detailed share information function Get-ShareDetails { param ( [string]$ServerName ) # Get all file shares $shares = Get-SmbShare -CimSession $ServerName | Where-Object { $_.Special -eq $false -and $_.Name -notlike "IPC$" -and $_.Name -notlike "ADMIN$" } $shareDetails = @() foreach ($share in $shares) { # Get share path $sharePath = $share.Path # Safely get NTFS permissions $ntfsPermissions = $null try { $ntfsPermissions = Get-Acl $sharePath -ErrorAction Stop } catch { Write-Warning "Could not retrieve NTFS permissions for $sharePath. Using minimal default permissions." $ntfsPermissions = New-Object System.Security.AccessControl.DirectorySecurity } # Safely get SMB share permissions $smbPermissions = $null try { $smbPermissions = Get-SmbShareAccess -Name $share.Name -CimSession $ServerName -ErrorAction Stop } catch { Write-Warning "Could not retrieve SMB permissions for share $($share.Name). Using minimal default permissions." $smbPermissions = @() } $shareDetails += [PSCustomObject]@{ Name = $share.Name Path = $sharePath Description = $share.Description NTFSPermissions = $ntfsPermissions SMBPermissions = $smbPermissions } } return $shareDetails } # Function to check if share exists on destination function Test-ShareExists { param ( [string]$ShareName, [string]$DestServer ) $existingShare = Get-SmbShare -Name $ShareName -CimSession $DestServer -ErrorAction SilentlyContinue return ($existingShare -ne $null) } # Function to create shares and set permissions function Create-ShareAndPermissions { param ( [PSCustomObject]$ShareDetail, [bool]$IsDryRun, [string]$ExistingAction ) # Check if share already exists $shareExists = Test-ShareExists -ShareName $ShareDetail.Name -DestServer $DestinationServer # Determine action for existing share $processShare = $true if ($shareExists) { switch ($ExistingAction) { 'Skip' { Write-MigrationLog -Message "Skipping existing share: $($ShareDetail.Name)" -DryRun:$IsDryRun $processShare = $false } 'Replace' { Write-MigrationLog -Message "Will replace existing share: $($ShareDetail.Name)" -DryRun:$IsDryRun if (-not $IsDryRun) { Remove-SmbShare -Name $ShareDetail.Name -Force -CimSession $DestinationServer } } 'Prompt' { $userChoice = Read-Host "Share '$($ShareDetail.Name)' already exists. Replace? (Y/N)" if ($userChoice -ne 'Y') { Write-MigrationLog -Message "Skipping existing share: $($ShareDetail.Name)" -DryRun:$IsDryRun $processShare = $false } else { if (-not $IsDryRun) { Remove-SmbShare -Name $ShareDetail.Name -Force -CimSession $DestinationServer } } } } } # Proceed with share creation if required if ($processShare) { # Log directory creation if (-not (Test-Path $ShareDetail.Path)) { Write-MigrationLog -Message "Would create directory: $($ShareDetail.Path)" -DryRun:$IsDryRun if (-not $IsDryRun) { New-Item -ItemType Directory -Path $ShareDetail.Path -Force | Out-Null } } # Log share creation Write-MigrationLog -Message "Would create SMB Share: $($ShareDetail.Name)" -DryRun:$IsDryRun if (-not $IsDryRun) { New-SmbShare -Name $ShareDetail.Name -Path $ShareDetail.Path -Description $ShareDetail.Description -CimSession $DestinationServer | Out-Null } # Log and set NTFS Permissions Write-MigrationLog -Message "Would set NTFS Permissions for: $($ShareDetail.Path)" -DryRun:$IsDryRun if (-not $IsDryRun) { if ($ShareDetail.NTFSPermissions) { $ShareDetail.NTFSPermissions | Set-Acl $ShareDetail.Path } } # Log and set SMB Share Permissions if ($ShareDetail.SMBPermissions) { foreach ($permission in $ShareDetail.SMBPermissions) { Write-MigrationLog -Message "Would grant SMB Access: $($permission.AccountName) on $($ShareDetail.Name)" -DryRun:$IsDryRun if (-not $IsDryRun) { Grant-SmbShareAccess -Name $ShareDetail.Name -AccountName $permission.AccountName -AccessRight $permission.AccessRight -Force -CimSession $DestinationServer | Out-Null } } } } } # Main Migration Process function Migrate-FileShares { param ( [bool]$IsDryRun, [string]$ExistingAction ) # Get share details from source server $sourceShares = Get-ShareDetails -ServerName $SourceServer Write-Host "=== Share Migration Summary ====" Write-Host "Source Server: $SourceServer" Write-Host "Destination Server: $DestinationServer" Write-Host "Dry Run Mode: $IsDryRun" Write-Host "Existing Share Action: $ExistingAction" Write-Host "Total Shares Found: $($sourceShares.Count)" Write-Host "===============================" # Create shares and set permissions on destination server foreach ($share in $sourceShares) { Create-ShareAndPermissions -ShareDetail $share -IsDryRun $IsDryRun -ExistingAction $ExistingAction } } # Execute Migration Migrate-FileShares -IsDryRun:$DryRun -ExistingAction $ExistingShareAction # Optional: Completion message if (-not $DryRun) { Write-Host "File share migration completed." }