#Requires -Version 3 -RunAsAdministrator #Requires -Modules ActiveDirectory, GroupPolicy <# .Synopsis Import TIER GPO policy .DESCRIPTION Import GPO policy for TIERing and the necessary structure of objects .EXAMPLE .EXAMPLE .EXAMPLE .INPUTS .NOTES Author: Petr Štěpán Email: pstepan@totalservice.cz Release date: 13.2.2024 Revision date: 13.2.2024 Version: 1.0 .LINK https://git.totalservice.cz/xxxxxxxx https://totalservice.atlassian.net/browse/KB-316 #> Param ( # WorkFolderPath - working dir for script and download assets [String] $WorkFolderPath = (Join-Path -Path $env:homedrive -ChildPath 'Temp\TIER'), # TranscriptFileName - File name of script log [String] $TranscriptFileName = "Script_$(Get-Date -Format 'yyyMMdd_HHmmss').log", # GPOBackupZipFileName - Name of GPO backup zip file [String] $GPOBackupZipFileName = 'GPO_TIER.zip', # DownloadURLGPOBackup - URL for downloading GPO backup file [String] $DownloadURLGPOBackup = 'https://git.totalservice.cz/public/AD-TIER/raw/branch/main/GPO_TIER.zip' ) Begin { $ErrorActionPreference = "Stop" #Start Transcript Start-Transcript -Path (Join-Path -Path $WorkFolderPath -ChildPath $TranscriptFileName) #Script start running time $StartScriptTime = Get-Date #### FUNCTIONS ### #Sending messages to console function Write-Message([string]$Message, [ValidateSet("Info","Warning","Error","Success")]$Severity="Info") { [string]$Time = (Get-Date -Format "HH:mm:ss").Trim() [string]$Count = ((Get-Date) - $StartScriptTime) switch($Severity) { "Info" {Write-Host $Time"|"$Count "-" $Message; Break} "Warning" {Write-Host $Time"|"$Count "-" $Message -ForegroundColor Yellow; Break} "Error" {Write-Host $Time"|"$Count "-" $Message -ForegroundColor Red; Break} "Success" {Write-Host $Time"|"$Count "-" $Message -ForegroundColor Green; Break} } } function Create-ADTierStructure([string]$DistinguishedName) { Write-Message -Message "Creating OU structure" New-ADOrganizationalUnit -Name "Admins" -Path $DistinguishedName New-ADOrganizationalUnit -Name "Domain" -Path "OU=Admins,$DistinguishedName" New-ADOrganizationalUnit -Name "Servers" -Path "OU=Admins,$DistinguishedName" New-ADOrganizationalUnit -Name "Workstations" -Path "OU=Admins,$DistinguishedName" Write-Message -Message "Creating Security Groups" $group = New-ADGroup -Name "AD Managers" -SamAccountName "AD Managers" -GroupCategory Security -GroupScope Global -DisplayName "AD Managers" -Path "OU=Domain,OU=Admins,$DistinguishedName" -Description "Group for managing un-privileged accounts in AD." -PassThru $ADGroupMapping.ADManagers = "$($group.SamAccountName)@$FQDN" $group = New-ADGroup -Name "Server Admins" -SamAccountName "Server Admins" -GroupCategory Security -GroupScope Global -DisplayName "Server Admins" -Path "OU=Servers,OU=Admins,$DistinguishedName" -Description "Managing servers in TIER 1" -PassThru $ADGroupMapping.ServerAdmins = "$($group.SamAccountName)@$FQDN" $group = New-ADGroup -Name "Workstation Admins" -SamAccountName "Workstation Admins" -GroupCategory Security -GroupScope Global -DisplayName "Workstation Admins" -Path "OU=Workstations,OU=Admins,$DistinguishedName" -Description "Managing workstations TIER 2" -PassThru $ADGroupMapping.WorkstationAdmins = "$($group.SamAccountName)@$FQDN" Write-Message -Message "Moving privileged grups to Admin\Domain OU." Get-ADGroup "Domain Admins" | Move-ADObject -TargetPath "OU=Domain,OU=Admins,$DistinguishedName" Get-ADGroup "Enterprise Admins" | Move-ADObject -TargetPath "OU=Domain,OU=Admins,$DistinguishedName" Get-ADGroup "Schema Admins" | Move-ADObject -TargetPath "OU=Domain,OU=Admins,$DistinguishedName" } #### FUNCTIONS END ### #Find FQDN and NetBIOS names Write-Message -Message "Finding FQDN and NetBIOS name" $FQDN = (Get-ADDomain).DNSRoot $DistinguishedName = (Get-ADDomain).DistinguishedName Write-Message -Message ('FQDN is: {0} and DistinguishedName is: {1}' -f $FQDN, $DistinguishedName) #### VARIABLES #### $ADGroupMapping = @{ "ServerAdmins" = "" "WorkstationAdmins" = "" "ADManagers" = "" "Administrator" = "Administrator@$FQDN" "DomainAdmins" = "Domain Admins@$FQDN" "EnterpriseAdmins" = "Enterprise Admins@$FQDN" } #### END VARIABLES #### #Find GPO backup file zip Write-Message -Message ("Finding GPO backup zip file ({0})" -f $GPOBackupZipFileName) If (!(Test-Path -Path (Join-Path -Path $WorkFolderPath -ChildPath $GPOBackupZipFileName))) { Write-Message -Message ("{0} not found. Starting downloading ..." -f $GPOBackupZipFileName) #Download GPO Backup zip file Write-Message -Message "Downloading GPO backup file" $DownloadStartTime = Get-Date #Certificate work around [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri $DownloadURLGPOBackup -OutFile (Join-Path -Path $WorkFolderPath -ChildPath $GPOBackupZipFileName) Write-Message -Message ('Downloaded in: {0} second(s)' -f ((Get-Date) - $DownloadStartTime)) -Severity Success }else{ Write-Message -Message ("{0} found in shared folder" -f $GPOBackupZipFileName) -Severity Success } #Unpack GPO backupfile Write-Message -Message ("Unpacking GPO backup file {0}" -f $GPOBackupZipFileName) Expand-Archive -LiteralPath (Join-Path -Path $WorkFolderPath -ChildPath $GPOBackupZipFileName) -DestinationPath $WorkFolderPath -Force } Process { Write-Host "Example: fqdn.contoso.com/ ├─ Admins/ │ ├─ Domain/ │ │ ├─ AD Managers │ ├─ Servers/ │ │ ├─ Server Admins │ ├─ Workstations/ │ │ ├─ Workstation Admins ├─ .../ ├─ .../ ├─ Computers/" $createDefaultADStructure = '' do { $answer = $(Write-Host "Do you want to import default OU and Security Groups structure? [Y/N] " -ForegroundColor Yellow -NoNewline; Read-Host) switch (($answer).ToLower()) { "y" { $createDefaultADStructure = $true; break; } "n" { $createDefaultADStructure = $false; break;} Default {} } } until ( ($createDefaultADStructure -eq $true) -or ($createDefaultADStructure -eq $false) ) if($createDefaultADStructure){ Write-Message -Message "Generating OU a Security Groups structure" Create-ADTierStructure($DistinguishedName) }else { Write-Message -Message "Manual Security Group mapping choosen" Write-Message -Message "Getting group name for Server Admins" # Server Admins do { $exist = $false $group = $(Write-Host "Enter SamAccount name of group for SERVER ADMINS: " -ForegroundColor Yellow -NoNewline; Read-Host) $exist = Get-ADGroup -Filter {SamAccountName -eq $group} if($exist -eq $null) { Write-Message -Message ("Group {0} doesn't exist" -f $group) -Severity Error }else{ $ADGroupMapping.ServerAdmins = "$($group)@$FQDN" } } until ( $exist -ne $null ) Write-Message -Message "Getting group name for Workstation Admins" # Workstation Admins do { $exist = $false $group = $(Write-Host "Enter SamAccount name of group for WORKSTATION ADMINS: " -ForegroundColor Yellow -NoNewline; Read-Host) $exist = Get-ADGroup -Filter {SamAccountName -eq $group} if($exist -eq $null) { Write-Message -Message ("Group {0} doesn't exist" -f $group) -Severity Error }else{ $ADGroupMapping.WorkstationAdmins = "$($group)@$FQDN" } } until ( $exist -ne $null ) Write-Message -Message "Getting group name for AD Managers" # AD Managers do { $exist = $false $group = $(Write-Host "Enter SamAccount name of group for AD MANAGERS: " -ForegroundColor Yellow -NoNewline; Read-Host) $exist = Get-ADGroup -Filter {SamAccountName -eq $group} if($exist -eq $null) { Write-Message -Message ("Group {0} doesn't exist" -f $group) -Severity Error }else{ $ADGroupMapping.ADManagers = "$($group)@$FQDN" } } until ( $exist -ne $null ) } # DEBUG $ADGroupMapping #Prepare GPO #Reference https://gallery.technet.microsoft.com/Migrate-Group-Policy-2b5067d8#content #Change variables in the GPO migration table to suit environment by recursing through the migration table and then changing the values to suit the current environment. Write-Message -Message "Modifying GPO migration table" $MigrationTable = "$WorkFolderPath\Migration.migtable" (Get-Content $MigrationTable).replace("\\SHAREFOLDER", "$ShareFolder") | Set-Content $MigrationTable Write-Message -Message "Modifying GPO migration table for SEC-ADMIN-DOMAIN" $MigrationTable = "$WorkFolderPath\SEC-Admin-Domain.migtable" $content = Get-Content $MigrationTable foreach($object in $ADGroupMapping){ $content.Replace("[[$($object.Name)]]", $object.Value) } Set-Content $MigrationTable Write-Message -Message "Modifying GPO migration table for SEC-ADMIN-SERVERS" $MigrationTable = "$WorkFolderPath\SEC-Admin-Servers.migtable" $content = Get-Content $MigrationTable foreach($object in $ADGroupMapping){ $content.Replace("[[$($object.Name)]]", $object.Value) } Set-Content $MigrationTable Write-Message -Message "Modifying GPO migration table for SEC-ADMIN-WORKSTATIONS" $MigrationTable = "$WorkFolderPath\SEC-Admin-Workstations.migtable" $content = Get-Content $MigrationTable foreach($object in $ADGroupMapping){ $content.Replace("[[$($object.Name)]]", $object.Value) } Set-Content $MigrationTable #Import GPO Write-Message -Message "Importing GPO policy SEC-ADMIN-DOMAIN" $GPOName = $(Write-Host "Enter name for GPO policy DOMAIN TIER (T0) [SEC-Admin-Domain] " -ForegroundColor Yellow -NoNewline; Read-Host) if ($GPOName -eq '') {$GPOName = "SEC-Admin-Domain"} Import-GPO -CreateIfNeeded -path "$WorkFolderPath" -BackupGpoName 'SEC-Admin-Domain' -TargetName $GPOName -MigrationTable "$WorkFolderPath\SEC-Admin-Domain.migtable" Write-Message -Message "Importing GPO policy SEC-ADMIN-SERVERS" $GPOName = $(Write-Host "Enter name for GPO policy SERVERS TIER (T1) [SEC-Admin-Servers] " -ForegroundColor Yellow -NoNewline; Read-Host) if ($GPOName -eq '') {$GPOName = "SEC-Admin-Servers"} Import-GPO -CreateIfNeeded -path "$WorkFolderPath" -BackupGpoName 'SEC-Admin-Servers' -TargetName $GPOName -MigrationTable "$WorkFolderPath\SEC-Admin-Servers.migtable" Write-Message -Message "Importing GPO policy SEC-ADMIN-WORKSTATIONS" $GPOName = $(Write-Host "Enter name for GPO policy SERVERS TIER (T1) [SEC-Admin-Workstations] " -ForegroundColor Yellow -NoNewline; Read-Host) if ($GPOName -eq '') {$GPOName = "SEC-Admin-Workstations"} Import-GPO -CreateIfNeeded -path "$WorkFolderPath" -BackupGpoName 'SEC-Admin-Workstations' -TargetName $GPOName -MigrationTable "$WorkFolderPath\SEC-Admin-Workstations.migtable" # TODO #- doplnit upozornění, aby všechny GPO politiky zkontrolovali a zvážili dopad na infastrukutru než je nalinkuji } End { Write-Message -Message "Hotovo!" -Severity Success Write-Message -Message "!!!POZOR!!! Před nalinkováním GPO politik na OU kde jsou servery nebo stanice si nejprve všechny nové politiky pozorně projdi a zvaž jejich dopad na konkrétní infrastrukturu klienta. Je doporučeno politiky nasazovat postupně a nejprve na malou pilotní skupinu. Nezapomeň také vytvořit nebo přidat uživatele do nově vytvořených security skupin." -Severity Warning #Stop Transcript Write-Message -Message $(Stop-Transcript) }