376 lines
12 KiB
PowerShell
376 lines
12 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Creates a local LIAM NTFS demo share structure with AGDLP groups and ACLs.
|
|
|
|
.DESCRIPTION
|
|
This script mirrors the LIAM NTFS demo configuration for the imagoverum.com
|
|
environment:
|
|
|
|
- local folder: C:\file_shares\share2
|
|
- optional SMB share: \\<local-server>\file_shares\share2
|
|
- group strategy: Ntfs_AGDLP
|
|
- group tags: FS for global groups, UG for domain-local groups
|
|
- access tags: _O, _W, _R, _T
|
|
|
|
Run with -WhatIf first. The ActiveDirectory module is only required when
|
|
AD group creation and ACL assignment are enabled.
|
|
#>
|
|
|
|
[CmdletBinding(SupportsShouldProcess = $true)]
|
|
param(
|
|
[string]$ShareRootPath = 'C:\file_shares',
|
|
|
|
[string]$RootFolderName = 'share2',
|
|
|
|
[string]$SmbShareName = 'file_shares',
|
|
|
|
[string]$GroupOuDN = 'OU=AGP,OU=LIAM,OU=Global,DC=imagoverum,DC=com',
|
|
|
|
[string[]]$AdditionalFolderRelativePaths = @(),
|
|
|
|
[string]$GroupNameSanitizeReplacement = '_',
|
|
|
|
[switch]$PreserveAdGroupNameCase,
|
|
|
|
[switch]$SkipAdGroups,
|
|
|
|
[switch]$SkipNtfsAcl,
|
|
|
|
[switch]$SkipSmbShare
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {
|
|
throw 'Dieses Script kann nur unter Windows ausgefuehrt werden.'
|
|
}
|
|
|
|
$rootPath = Join-Path -Path $ShareRootPath -ChildPath $RootFolderName
|
|
$readRights = [System.Security.AccessControl.FileSystemRights]0x200A9
|
|
$writeRights = [System.Security.AccessControl.FileSystemRights]0x301BF
|
|
$ownerRights = [System.Security.AccessControl.FileSystemRights]0x1F01FF
|
|
|
|
function ConvertTo-LiamSafeNameSegment {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Value,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Replacement,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[bool]$PreserveCase
|
|
)
|
|
|
|
$safeReplacement = if ($null -eq $Replacement) { '_' } else { $Replacement.Trim() }
|
|
if ($safeReplacement -in @('<empty>', 'empty', 'none', 'remove')) {
|
|
$safeReplacement = ''
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($safeReplacement) -and $Replacement -notin @('<empty>', 'empty', 'none', 'remove')) {
|
|
$safeReplacement = '_'
|
|
}
|
|
|
|
$safeValue = [regex]::Replace($Value, '[\x00-\x1F\x7F/\\\[\]:;\|=,\+\*\?<>]', $safeReplacement)
|
|
if ($PreserveCase) {
|
|
return $safeValue
|
|
}
|
|
|
|
return $safeValue.ToUpperInvariant()
|
|
}
|
|
|
|
function Get-LiamFolderToken {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FolderPath
|
|
)
|
|
|
|
$itemName = Split-Path -Path $FolderPath -Leaf
|
|
if ([string]::IsNullOrWhiteSpace($itemName)) {
|
|
$itemName = $RootFolderName
|
|
}
|
|
|
|
ConvertTo-LiamSafeNameSegment `
|
|
-Value $itemName `
|
|
-Replacement $GroupNameSanitizeReplacement `
|
|
-PreserveCase $PreserveAdGroupNameCase.IsPresent
|
|
}
|
|
|
|
function Get-LiamGroupSet {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FolderPath
|
|
)
|
|
|
|
$name = Get-LiamFolderToken -FolderPath $FolderPath
|
|
|
|
[pscustomobject]@{
|
|
FolderPath = $FolderPath
|
|
Name = $name
|
|
GlobalOwner = "FS_${name}_O"
|
|
GlobalWrite = "FS_${name}_W"
|
|
GlobalRead = "FS_${name}_R"
|
|
GlobalTraverse = "FS_${name}_T"
|
|
LocalOwner = "UG_${name}_O"
|
|
LocalWrite = "UG_${name}_W"
|
|
LocalRead = "UG_${name}_R"
|
|
}
|
|
}
|
|
|
|
function Ensure-Folder {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
if (Test-Path -LiteralPath $Path) {
|
|
return
|
|
}
|
|
|
|
if ($PSCmdlet.ShouldProcess($Path, 'Create directory')) {
|
|
New-Item -ItemType Directory -Path $Path -Force | Out-Null
|
|
}
|
|
}
|
|
|
|
function Ensure-SmbShare {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Name,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
$existingShare = Get-SmbShare -Name $Name -ErrorAction SilentlyContinue
|
|
if ($existingShare) {
|
|
if ($existingShare.Path -ne $Path) {
|
|
Write-Warning "SMB share '$Name' already points to '$($existingShare.Path)', not '$Path'."
|
|
}
|
|
return
|
|
}
|
|
|
|
if ($PSCmdlet.ShouldProcess($Name, "Create SMB share for '$Path'")) {
|
|
New-SmbShare -Name $Name -Path $Path -ChangeAccess 'Authenticated Users' | Out-Null
|
|
}
|
|
}
|
|
|
|
function Ensure-AdGroup {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Name,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet('Global', 'DomainLocal')]
|
|
[string]$Scope,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Description
|
|
)
|
|
|
|
$existingGroup = Get-ADGroup -Identity $Name -ErrorAction SilentlyContinue
|
|
if ($existingGroup) {
|
|
return $existingGroup
|
|
}
|
|
|
|
if ($PSCmdlet.ShouldProcess($Name, "Create AD group in '$GroupOuDN'")) {
|
|
New-ADGroup `
|
|
-Name $Name `
|
|
-SamAccountName $Name `
|
|
-GroupCategory Security `
|
|
-GroupScope $Scope `
|
|
-Path $GroupOuDN `
|
|
-Description $Description | Out-Null
|
|
}
|
|
|
|
return Get-ADGroup -Identity $Name -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
function Ensure-AdGroupMembership {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ParentGroup,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$MemberGroup
|
|
)
|
|
|
|
$parent = Get-ADGroup -Identity $ParentGroup -Properties member -ErrorAction SilentlyContinue
|
|
$member = Get-ADGroup -Identity $MemberGroup -ErrorAction SilentlyContinue
|
|
if (-not $parent -or -not $member) {
|
|
if ($WhatIfPreference) {
|
|
if ($PSCmdlet.ShouldProcess($ParentGroup, "Add member group '$MemberGroup'")) {
|
|
}
|
|
return
|
|
}
|
|
|
|
throw "Cannot add '$MemberGroup' to '$ParentGroup' because at least one group does not exist."
|
|
}
|
|
|
|
if ($parent.member -contains $member.DistinguishedName) {
|
|
return
|
|
}
|
|
|
|
if ($PSCmdlet.ShouldProcess($ParentGroup, "Add member group '$MemberGroup'")) {
|
|
Add-ADGroupMember -Identity $parent -Members $member
|
|
}
|
|
}
|
|
|
|
function Ensure-LiamGroups {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[pscustomobject]$GroupSet
|
|
)
|
|
|
|
$groups = @(
|
|
@{ Name = $GroupSet.GlobalOwner; Scope = 'Global'; Description = "$($GroupSet.Name) - _O" }
|
|
@{ Name = $GroupSet.GlobalWrite; Scope = 'Global'; Description = "$($GroupSet.Name) - _W" }
|
|
@{ Name = $GroupSet.GlobalRead; Scope = 'Global'; Description = "$($GroupSet.Name) - _R" }
|
|
@{ Name = $GroupSet.LocalOwner; Scope = 'DomainLocal'; Description = "$($GroupSet.Name) - _O" }
|
|
@{ Name = $GroupSet.LocalWrite; Scope = 'DomainLocal'; Description = "$($GroupSet.Name) - _W" }
|
|
@{ Name = $GroupSet.LocalRead; Scope = 'DomainLocal'; Description = "$($GroupSet.Name) - _R" }
|
|
@{ Name = $GroupSet.GlobalTraverse; Scope = 'Global'; Description = "$($GroupSet.Name) - _T" }
|
|
)
|
|
|
|
foreach ($group in $groups) {
|
|
Ensure-AdGroup -Name $group.Name -Scope $group.Scope -Description $group.Description | Out-Null
|
|
}
|
|
|
|
Ensure-AdGroupMembership -ParentGroup $GroupSet.LocalOwner -MemberGroup $GroupSet.GlobalOwner
|
|
Ensure-AdGroupMembership -ParentGroup $GroupSet.LocalWrite -MemberGroup $GroupSet.GlobalWrite
|
|
Ensure-AdGroupMembership -ParentGroup $GroupSet.LocalRead -MemberGroup $GroupSet.GlobalRead
|
|
}
|
|
|
|
function Add-FolderAccessRule {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Account,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Security.AccessControl.FileSystemRights]$Rights
|
|
)
|
|
|
|
if (-not (Test-Path -LiteralPath $Path)) {
|
|
if ($WhatIfPreference) {
|
|
if ($PSCmdlet.ShouldProcess($Path, "Add NTFS ACL '$Rights' for '$Account'")) {
|
|
}
|
|
return
|
|
}
|
|
|
|
throw "Path not found: $Path"
|
|
}
|
|
|
|
$acl = Get-Acl -LiteralPath $Path
|
|
$identity = [System.Security.Principal.NTAccount]::new($Account)
|
|
try {
|
|
$sid = $identity.Translate([System.Security.Principal.SecurityIdentifier])
|
|
}
|
|
catch [System.Security.Principal.IdentityNotMappedException] {
|
|
if ($WhatIfPreference) {
|
|
if ($PSCmdlet.ShouldProcess($Path, "Add NTFS ACL '$Rights' for '$Account'")) {
|
|
}
|
|
return
|
|
}
|
|
|
|
throw
|
|
}
|
|
|
|
foreach ($rule in $acl.Access) {
|
|
if ($rule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow) {
|
|
continue
|
|
}
|
|
if ($rule.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value -ne $sid.Value) {
|
|
continue
|
|
}
|
|
if (($rule.FileSystemRights -band $Rights) -eq $Rights) {
|
|
return
|
|
}
|
|
}
|
|
|
|
$accessRule = [System.Security.AccessControl.FileSystemAccessRule]::new(
|
|
$sid,
|
|
$Rights,
|
|
[System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit',
|
|
[System.Security.AccessControl.PropagationFlags]::None,
|
|
[System.Security.AccessControl.AccessControlType]::Allow
|
|
)
|
|
|
|
$acl.AddAccessRule($accessRule)
|
|
|
|
if ($PSCmdlet.ShouldProcess($Path, "Add NTFS ACL '$Rights' for '$Account'")) {
|
|
Set-Acl -LiteralPath $Path -AclObject $acl
|
|
}
|
|
}
|
|
|
|
function Ensure-LiamNtfsAcl {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[pscustomobject]$GroupSet,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$DomainNetBiosName
|
|
)
|
|
|
|
Add-FolderAccessRule -Path $GroupSet.FolderPath -Account "$DomainNetBiosName\$($GroupSet.LocalOwner)" -Rights $ownerRights
|
|
Add-FolderAccessRule -Path $GroupSet.FolderPath -Account "$DomainNetBiosName\$($GroupSet.LocalWrite)" -Rights $writeRights
|
|
Add-FolderAccessRule -Path $GroupSet.FolderPath -Account "$DomainNetBiosName\$($GroupSet.LocalRead)" -Rights $readRights
|
|
}
|
|
|
|
$relativeFolders = @($AdditionalFolderRelativePaths) |
|
|
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
|
|
ForEach-Object { $_.Trim().TrimStart('\', '/') } |
|
|
Sort-Object -Unique
|
|
|
|
Ensure-Folder -Path $ShareRootPath
|
|
Ensure-Folder -Path $rootPath
|
|
|
|
foreach ($relativeFolder in $relativeFolders) {
|
|
Ensure-Folder -Path (Join-Path -Path $rootPath -ChildPath $relativeFolder)
|
|
}
|
|
|
|
if (-not $SkipSmbShare) {
|
|
Ensure-SmbShare -Name $SmbShareName -Path $ShareRootPath
|
|
}
|
|
|
|
$foldersToManage = @($rootPath)
|
|
foreach ($relativeFolder in $relativeFolders) {
|
|
$foldersToManage += (Join-Path -Path $rootPath -ChildPath $relativeFolder)
|
|
}
|
|
|
|
$domainNetBiosName = $null
|
|
if (-not $SkipAdGroups -or -not $SkipNtfsAcl) {
|
|
Import-Module ActiveDirectory -ErrorAction Stop
|
|
$domainNetBiosName = (Get-ADDomain).NetBIOSName
|
|
}
|
|
|
|
$summary = foreach ($folder in $foldersToManage) {
|
|
$groupSet = Get-LiamGroupSet -FolderPath $folder
|
|
|
|
if (-not $SkipAdGroups) {
|
|
Ensure-LiamGroups -GroupSet $groupSet
|
|
}
|
|
|
|
if (-not $SkipNtfsAcl) {
|
|
Ensure-LiamNtfsAcl -GroupSet $groupSet -DomainNetBiosName $domainNetBiosName
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
Folder = $folder
|
|
LocalOwnerAcl = $groupSet.LocalOwner
|
|
LocalWriteAcl = $groupSet.LocalWrite
|
|
LocalReadAcl = $groupSet.LocalRead
|
|
GlobalOwner = $groupSet.GlobalOwner
|
|
GlobalWrite = $groupSet.GlobalWrite
|
|
GlobalRead = $groupSet.GlobalRead
|
|
GlobalTraverse = $groupSet.GlobalTraverse
|
|
}
|
|
}
|
|
|
|
$summary
|
|
|
|
Write-Host ''
|
|
Write-Host 'LIAM provider RootPath for this machine:'
|
|
Write-Host ("\\{0}\{1}\{2}" -f $env:COMPUTERNAME, $SmbShareName, $RootFolderName)
|