原始檔案
# 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 <SourceServerName> -DestinationServer <DestinationServerName> [-DryRun] [-ExistingShareAction <Skip|Replace|Prompt>]
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."
}
| 1 | # File Share and Permissions Migration Script |
| 2 | |
| 3 | # Parameters |
| 4 | param ( |
| 5 | [string]$SourceServer, |
| 6 | [string]$DestinationServer, |
| 7 | [switch]$DryRun, |
| 8 | [switch]$Help, |
| 9 | [ValidateSet('Skip', 'Replace', 'Prompt')] |
| 10 | [string]$ExistingShareAction = 'Prompt' |
| 11 | ) |
| 12 | |
| 13 | # Function to display usage information |
| 14 | function Show-UsageInfo { |
| 15 | @" |
| 16 | File Share Migration Script |
| 17 | |
| 18 | Usage: |
| 19 | .\MigrateFileShares.ps1 -SourceServer <SourceServerName> -DestinationServer <DestinationServerName> [-DryRun] [-ExistingShareAction <Skip|Replace|Prompt>] |
| 20 | |
| 21 | Parameters: |
| 22 | -SourceServer (Required) Name of the source file server |
| 23 | -DestinationServer (Required) Name of the destination file server |
| 24 | -DryRun (Optional) Preview migration actions without making changes |
| 25 | -Help (Optional) Show this usage information |
| 26 | -ExistingShareAction (Optional) How to handle existing shares |
| 27 | Skip - Skip shares that already exist |
| 28 | Replace - Remove and recreate existing shares |
| 29 | Prompt - Ask for each existing share (default) |
| 30 | |
| 31 | Examples: |
| 32 | # Preview migration actions |
| 33 | .\MigrateFileShares.ps1 -SourceServer SOURCESVR -DestinationServer DESTSVR -DryRun |
| 34 | |
| 35 | # Perform actual migration, skipping existing shares |
| 36 | .\MigrateFileShares.ps1 -SourceServer SOURCESVR -DestinationServer DESTSVR -ExistingShareAction Skip |
| 37 | |
| 38 | # Perform actual migration, replacing existing shares |
| 39 | .\MigrateFileShares.ps1 -SourceServer SOURCESVR -DestinationServer DESTSVR -ExistingShareAction Replace |
| 40 | |
| 41 | Notes: |
| 42 | - Requires administrative privileges |
| 43 | - Ensure PowerShell remoting is enabled between servers |
| 44 | - Test in a staged environment before production use |
| 45 | "@ |
| 46 | } |
| 47 | |
| 48 | # Check if help is requested or required parameters are missing |
| 49 | if ($Help -or [string]::IsNullOrWhiteSpace($SourceServer) -or [string]::IsNullOrWhiteSpace($DestinationServer)) { |
| 50 | Show-UsageInfo |
| 51 | exit |
| 52 | } |
| 53 | |
| 54 | # Logging function |
| 55 | function Write-MigrationLog { |
| 56 | param ( |
| 57 | [string]$Message, |
| 58 | [switch]$DryRun |
| 59 | ) |
| 60 | |
| 61 | $logPrefix = if ($DryRun) { "[DRY RUN] " } else { "[ACTUAL] " } |
| 62 | Write-Host "$logPrefix$Message" |
| 63 | } |
| 64 | |
| 65 | # Function to get detailed share information |
| 66 | function Get-ShareDetails { |
| 67 | param ( |
| 68 | [string]$ServerName |
| 69 | ) |
| 70 | |
| 71 | # Get all file shares |
| 72 | $shares = Get-SmbShare -CimSession $ServerName | Where-Object { |
| 73 | $_.Special -eq $false -and |
| 74 | $_.Name -notlike "IPC$" -and |
| 75 | $_.Name -notlike "ADMIN$" |
| 76 | } |
| 77 | |
| 78 | $shareDetails = @() |
| 79 | |
| 80 | foreach ($share in $shares) { |
| 81 | # Get share path |
| 82 | $sharePath = $share.Path |
| 83 | |
| 84 | # Safely get NTFS permissions |
| 85 | $ntfsPermissions = $null |
| 86 | try { |
| 87 | $ntfsPermissions = Get-Acl $sharePath -ErrorAction Stop |
| 88 | } |
| 89 | catch { |
| 90 | Write-Warning "Could not retrieve NTFS permissions for $sharePath. Using minimal default permissions." |
| 91 | $ntfsPermissions = New-Object System.Security.AccessControl.DirectorySecurity |
| 92 | } |
| 93 | |
| 94 | # Safely get SMB share permissions |
| 95 | $smbPermissions = $null |
| 96 | try { |
| 97 | $smbPermissions = Get-SmbShareAccess -Name $share.Name -CimSession $ServerName -ErrorAction Stop |
| 98 | } |
| 99 | catch { |
| 100 | Write-Warning "Could not retrieve SMB permissions for share $($share.Name). Using minimal default permissions." |
| 101 | $smbPermissions = @() |
| 102 | } |
| 103 | |
| 104 | $shareDetails += [PSCustomObject]@{ |
| 105 | Name = $share.Name |
| 106 | Path = $sharePath |
| 107 | Description = $share.Description |
| 108 | NTFSPermissions = $ntfsPermissions |
| 109 | SMBPermissions = $smbPermissions |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | return $shareDetails |
| 114 | } |
| 115 | |
| 116 | # Function to check if share exists on destination |
| 117 | function Test-ShareExists { |
| 118 | param ( |
| 119 | [string]$ShareName, |
| 120 | [string]$DestServer |
| 121 | ) |
| 122 | |
| 123 | $existingShare = Get-SmbShare -Name $ShareName -CimSession $DestServer -ErrorAction SilentlyContinue |
| 124 | return ($existingShare -ne $null) |
| 125 | } |
| 126 | |
| 127 | # Function to create shares and set permissions |
| 128 | function Create-ShareAndPermissions { |
| 129 | param ( |
| 130 | [PSCustomObject]$ShareDetail, |
| 131 | [bool]$IsDryRun, |
| 132 | [string]$ExistingAction |
| 133 | ) |
| 134 | |
| 135 | # Check if share already exists |
| 136 | $shareExists = Test-ShareExists -ShareName $ShareDetail.Name -DestServer $DestinationServer |
| 137 | |
| 138 | # Determine action for existing share |
| 139 | $processShare = $true |
| 140 | if ($shareExists) { |
| 141 | switch ($ExistingAction) { |
| 142 | 'Skip' { |
| 143 | Write-MigrationLog -Message "Skipping existing share: $($ShareDetail.Name)" -DryRun:$IsDryRun |
| 144 | $processShare = $false |
| 145 | } |
| 146 | 'Replace' { |
| 147 | Write-MigrationLog -Message "Will replace existing share: $($ShareDetail.Name)" -DryRun:$IsDryRun |
| 148 | if (-not $IsDryRun) { |
| 149 | Remove-SmbShare -Name $ShareDetail.Name -Force -CimSession $DestinationServer |
| 150 | } |
| 151 | } |
| 152 | 'Prompt' { |
| 153 | $userChoice = Read-Host "Share '$($ShareDetail.Name)' already exists. Replace? (Y/N)" |
| 154 | if ($userChoice -ne 'Y') { |
| 155 | Write-MigrationLog -Message "Skipping existing share: $($ShareDetail.Name)" -DryRun:$IsDryRun |
| 156 | $processShare = $false |
| 157 | } |
| 158 | else { |
| 159 | if (-not $IsDryRun) { |
| 160 | Remove-SmbShare -Name $ShareDetail.Name -Force -CimSession $DestinationServer |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | # Proceed with share creation if required |
| 168 | if ($processShare) { |
| 169 | # Log directory creation |
| 170 | if (-not (Test-Path $ShareDetail.Path)) { |
| 171 | Write-MigrationLog -Message "Would create directory: $($ShareDetail.Path)" -DryRun:$IsDryRun |
| 172 | |
| 173 | if (-not $IsDryRun) { |
| 174 | New-Item -ItemType Directory -Path $ShareDetail.Path -Force | Out-Null |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | # Log share creation |
| 179 | Write-MigrationLog -Message "Would create SMB Share: $($ShareDetail.Name)" -DryRun:$IsDryRun |
| 180 | if (-not $IsDryRun) { |
| 181 | New-SmbShare -Name $ShareDetail.Name -Path $ShareDetail.Path -Description $ShareDetail.Description -CimSession $DestinationServer | Out-Null |
| 182 | } |
| 183 | |
| 184 | # Log and set NTFS Permissions |
| 185 | Write-MigrationLog -Message "Would set NTFS Permissions for: $($ShareDetail.Path)" -DryRun:$IsDryRun |
| 186 | if (-not $IsDryRun) { |
| 187 | if ($ShareDetail.NTFSPermissions) { |
| 188 | $ShareDetail.NTFSPermissions | Set-Acl $ShareDetail.Path |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | # Log and set SMB Share Permissions |
| 193 | if ($ShareDetail.SMBPermissions) { |
| 194 | foreach ($permission in $ShareDetail.SMBPermissions) { |
| 195 | Write-MigrationLog -Message "Would grant SMB Access: $($permission.AccountName) on $($ShareDetail.Name)" -DryRun:$IsDryRun |
| 196 | |
| 197 | if (-not $IsDryRun) { |
| 198 | Grant-SmbShareAccess -Name $ShareDetail.Name -AccountName $permission.AccountName -AccessRight $permission.AccessRight -Force -CimSession $DestinationServer | Out-Null |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | # Main Migration Process |
| 206 | function Migrate-FileShares { |
| 207 | param ( |
| 208 | [bool]$IsDryRun, |
| 209 | [string]$ExistingAction |
| 210 | ) |
| 211 | |
| 212 | # Get share details from source server |
| 213 | $sourceShares = Get-ShareDetails -ServerName $SourceServer |
| 214 | |
| 215 | Write-Host "=== Share Migration Summary ====" |
| 216 | Write-Host "Source Server: $SourceServer" |
| 217 | Write-Host "Destination Server: $DestinationServer" |
| 218 | Write-Host "Dry Run Mode: $IsDryRun" |
| 219 | Write-Host "Existing Share Action: $ExistingAction" |
| 220 | Write-Host "Total Shares Found: $($sourceShares.Count)" |
| 221 | Write-Host "===============================" |
| 222 | |
| 223 | # Create shares and set permissions on destination server |
| 224 | foreach ($share in $sourceShares) { |
| 225 | Create-ShareAndPermissions -ShareDetail $share -IsDryRun $IsDryRun -ExistingAction $ExistingAction |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | # Execute Migration |
| 230 | Migrate-FileShares -IsDryRun:$DryRun -ExistingAction $ExistingShareAction |
| 231 | |
| 232 | # Optional: Completion message |
| 233 | if (-not $DryRun) { |
| 234 | Write-Host "File share migration completed." |
| 235 | } |