Private/Sql/Get-SqlBackupDirectoryAcl.ps1
|
function Get-SqlBackupDirectoryAcl { [CmdletBinding()] [OutputType([object[]])] param( [Parameter(Mandatory)][System.Management.Automation.Runspaces.PSSession]$Session, [AllowNull()][AllowEmptyString()][string]$BackupDirectory ) if ([string]::IsNullOrWhiteSpace($BackupDirectory)) { return } $paths = @($BackupDirectory -split ';' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) # The probe runs against any path on the host where it's invoked. Used for both # jumphost-side (no double-hop, full Kerberos) and target-side (Kerberos can't # forward to a UNC server beyond the first hop) reads. $probeAcl = { param($p) $reachable = Test-Path -LiteralPath $p -ErrorAction SilentlyContinue if (-not $reachable) { return [pscustomobject]@{ Path = $p PathType = if ($p.StartsWith('\\')) { 'UNC' } else { 'Local' } Error = 'Path not accessible' } } $owner = $null; $inherit = 'Unknown'; $aces = @(); $sourceKind = 'GetAcl' # NTFSSecurity ships these three cmdlets as a set — but partial / older installs # sometimes have Get-NTFSAccess without the others. Require all three before # taking the NTFSSecurity branch; otherwise fall through to built-in Get-Acl. $hasNtfsSec = (Get-Command Get-NTFSAccess,Get-NTFSAccessInheritance,Get-NTFSOwner -ErrorAction SilentlyContinue).Count -eq 3 try { if ($hasNtfsSec) { $sourceKind = 'NTFSSecurity' $owner = (Get-NTFSOwner -Path $p -ErrorAction Stop).Owner $inherit = if ((Get-NTFSAccessInheritance -Path $p -ErrorAction Stop).AccessInheritanceEnabled) { 'Enabled' } else { 'Disabled' } $aces = @(Get-NTFSAccess -Path $p -ErrorAction Stop) } else { $sourceKind = 'GetAcl' $acl = Get-Acl -Path $p -ErrorAction Stop $owner = [string]$acl.Owner $inherit = if ($acl.AreAccessRulesProtected) { 'Disabled' } else { 'Enabled' } $aces = @($acl.Access) } } catch { return [pscustomobject]@{ Path = $p PathType = if ($p.StartsWith('\\')) { 'UNC' } else { 'Local' } Error = $_.Exception.Message } } [pscustomobject]@{ Path = $p PathType = if ($p.StartsWith('\\')) { 'UNC' } else { 'Local' } Owner = $owner Inheritance = $inherit RawAces = $aces SourceKind = $sourceKind } } foreach ($path in $paths) { $isUnc = $path.StartsWith('\\') # For UNC paths, prefer the jumphost. Reading the share from inside the target # session usually fails with "Access is denied" — that's the Kerberos double-hop # constraint, since the target can't forward the user's creds to the file server. # The jumphost holds primary creds and can reach the UNC directly. # For local paths (D:\Backup etc.), only the target can see them. $probe = $null $source = $null if ($isUnc) { $probe = & $probeAcl $path $source = 'Jumphost' if ($probe.Error) { $jumphostErr = $probe.Error $probe = Invoke-Command -Session $Session -ArgumentList $path -ScriptBlock $probeAcl $source = 'Target' if ($probe.Error) { $probe.Error = "Jumphost: $jumphostErr; Target: $($probe.Error)" } } } else { $probe = Invoke-Command -Session $Session -ArgumentList $path -ScriptBlock $probeAcl $source = 'Target' } if ($probe.Error) { [pscustomobject]@{ Path = $probe.Path PathType = $probe.PathType ReadFrom = $source Error = $probe.Error } continue } # Normalize and filter to non-inherited only. # ConvertTo-NtfsPermissionEntry outputs: Path, Account, Rights, AppliesTo, Inherited, AccessControlType. $entries = foreach ($ace in $probe.RawAces | Where-Object { -not $_.IsInherited }) { ConvertTo-NtfsPermissionEntry -Ace $ace -Path $probe.Path -SourceKind $probe.SourceKind } [pscustomobject]@{ Path = $probe.Path PathType = $probe.PathType ReadFrom = $source Owner = $probe.Owner Inheritance = $probe.Inheritance Entries = @($entries) } } } |