Public/New-FSMTargetShares.ps1
|
function New-FSMTargetShares { <# .SYNOPSIS Creates folders and SMB shares on a target file server from an exported CSV. .DESCRIPTION Reads a share CSV and, for each entry, creates the backing folder (if missing) and the SMB share on the target server, carrying over description, enumeration mode, caching, continuous availability and encryption where present. SAFETY: this runs in preview mode by default and changes nothing. Add -Execute to actually create folders and shares. Each share is handled independently in a try/catch, so one failure produces a 'Failed' result row instead of aborting the whole batch. .PARAMETER TargetServer The file server to create shares on. .PARAMETER ShareCsvPath Path to the share inventory CSV (optionally already remapped). .PARAMETER DefaultFullAccess Initial share-level Full Access principal(s) applied at creation. Real permissions are applied separately by Grant-FSMTargetSharePermissions; use -RemoveEveryone there to strip the default afterwards. Defaults to 'Everyone'. .PARAMETER ScopeName Optional. For clustered (scale-out / classic) file server roles, the scope name the share belongs to. Leave blank for a standalone server. .PARAMETER Credential Optional credentials for the remote connection. .PARAMETER Execute Actually create folders and shares. Without it, you get a preview only. .EXAMPLE New-FSMTargetShares -TargetServer newfs01 -ShareCsvPath C:\Temp\remapped.csv .EXAMPLE New-FSMTargetShares -TargetServer newfs01 -ShareCsvPath C:\Temp\remapped.csv -Execute #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Uses an explicit -Execute switch instead of ShouldProcess/-WhatIf, because ShouldProcess does not propagate into the remote Invoke-Command scriptblock where the change actually happens. Preview is the default; nothing changes without -Execute.')] [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$TargetServer, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ShareCsvPath, [string[]]$DefaultFullAccess = @('Everyone'), [string]$ScopeName, [pscredential]$Credential, [switch]$Execute ) if (-not (Test-Path -Path $ShareCsvPath)) { throw "Share CSV not found: '$ShareCsvPath'." } $shares = @(Import-Csv -Path $ShareCsvPath) Assert-FSMCsvColumn -InputObject $shares -RequiredColumn 'Name', 'Path' -Path $ShareCsvPath # Each cast is parenthesised: in argument-parsing mode an unparenthesised # [bool]$Execute is read as the literal string '[bool]False', not a cast, # which then fails to bind to the remote [bool]$Execute parameter. Invoke-FSMRemote -ComputerName $TargetServer -Credential $Credential ` -ArgumentList $shares, $DefaultFullAccess, $ScopeName, ([bool]$Execute) -ScriptBlock { param($Shares, [string[]]$DefaultFullAccess, [string]$ScopeName, [bool]$Execute) # Local, robust string-to-bool used for CSV round-tripped values. $toBool = { param($value) if ($null -eq $value) { return $false } if ($value -is [bool]) { return $value } $text = "$value".Trim() if ($text -in @('1', 'true', 'yes', 'y', 'on')) { return $true } if ($text -in @('0', 'false', 'no', 'n', 'off', '')) { return $false } return [bool]$text } foreach ($share in $Shares) { try { $existingShare = Get-SmbShare -Name $share.Name -ErrorAction SilentlyContinue if ($existingShare) { [pscustomobject]@{ ShareName = $share.Name; Path = $existingShare.Path Action = 'Skipped'; Reason = 'Share already exists' } continue } if (-not $Execute) { [pscustomobject]@{ ShareName = $share.Name; Path = $share.Path Action = 'WhatIf'; Reason = 'Would create folder and share. Re-run with -Execute to apply.' } continue } if (-not (Test-Path -Path $share.Path)) { New-Item -Path $share.Path -ItemType Directory -Force -ErrorAction Stop | Out-Null } $newShareParams = @{ Name = $share.Name Path = $share.Path FullAccess = $DefaultFullAccess ErrorAction = 'Stop' } if ($ScopeName) { $newShareParams.ScopeName = $ScopeName } if ($share.PSObject.Properties.Name -contains 'Description' -and $share.Description) { $newShareParams.Description = $share.Description } if ($share.PSObject.Properties.Name -contains 'FolderEnumerationMode' -and $share.FolderEnumerationMode) { $newShareParams.FolderEnumerationMode = $share.FolderEnumerationMode } if ($share.PSObject.Properties.Name -contains 'CachingMode' -and $share.CachingMode) { $newShareParams.CachingMode = $share.CachingMode } if ($share.PSObject.Properties.Name -contains 'ContinuouslyAvailable') { $newShareParams.ContinuouslyAvailable = (& $toBool $share.ContinuouslyAvailable) } if ($share.PSObject.Properties.Name -contains 'EncryptData') { $newShareParams.EncryptData = (& $toBool $share.EncryptData) } New-SmbShare @newShareParams | Out-Null [pscustomobject]@{ ShareName = $share.Name; Path = $share.Path Action = 'Created'; Reason = 'Share created successfully' } } catch { [pscustomobject]@{ ShareName = $share.Name Path = $share.Path Action = 'Failed' Reason = $_.Exception.Message } } } } } |