#Requires -Modules 'NetSecurity' Param( [Parameter(Mandatory)] [hashtable]$Parameter ) # Only executed on primary or standalone Domain Controller If (@('primary','standalone') -contains $Parameter['deployment.type']) { $GetItemSplat = @{ Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', '.yml') } ForEach ($File in (Get-Item @GetItemSplat)) { Try { Write-Host "Loading/parsing file '$($File)' ..." $GetContentSplat = @{ Path = $File Raw = $True } $RawContent = Get-Content @GetContentSplat $ConvertFromYamlSplat = @{ Yaml = $RawContent AllDocuments = $True } $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat } Catch { $ParseErrors += "While processing '$($File)': $($_.Exception.Message)" Continue } # Check if the respective .yml file declared substitutions which need to be parsed If (($YamlDocuments.Count -gt 1) -and $YamlDocuments[-1].Variables) { Try { ForEach ($Pattern in $YamlDocuments[-1].Variables) { $RawContent = $RawContent -replace "\{\{ ($($Pattern.Name)) \}\}", [string](Invoke-Expression -Command $Pattern.Expression) } # Perform conversion to Yaml again, now with parsed file contents $ConvertFromYamlSplat = @{ Yaml = $RawContent AllDocuments = $True } $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat } Catch { $ParseErrors += "While processing '$($File)' (after substitutions): $($_.Exception.Message)" Continue } $Settings = $YamlDocuments[0..($YamlDocuments.Count - 2)] } Else { $Settings = $YamlDocuments } $NewGPOSplat = @{ Name = $Settings.Name } $NewGPO = New-GPO @NewGPOSplat $OpenNetGPOSplat = @{ PolicyStore = "$($Parameter['addsconfig.domainname'])\$($NewGPO.DisplayName)" } $GPOSession = Open-NetGPO @OpenNetGPOSplat ForEach ($Rule in $Settings.FirewallRules) { $NewNetFirewallRuleSplat = @{ # Using so-called string formatting with the '-f' operator (looks more complicated than it is) to create consistent policy names: # Examples: # 'DENY: Inbound port 443 (TCP)' # 'ALLOW: Inbound 'D:\MSSQL\bin\sqlservr.exe' DisplayName = ("{0}: {1} {2} {3} {4}" -f $Rule.Action.ToUpper(), $Rule.Direction, ("'$($Rule.Program)'", $NULL)[!($Rule.Program)], ("Port $($Rule.Port)", $NULL)[!($Rule.Port)], ("($($Rule.Protocol))", $NULL)[!($Rule.Protocol)] ) -replace '\s+',' ' Description = $Rule.Description Action = $Rule.Action Direction = $Rule.Direction Program = ($Rule.Program, 'Any')[!($Rule.Program)] LocalPort = ($Rule.Port.Split(','), 'Any')[!($Rule.Port)] Protocol = ($Rule.Protocol, 'Any')[!($Rule.Protocol)] GPOSession = $GPOSession PolicyStore = $NewGPO.DisplayName Confirm = $False } New-NetFirewallRule @NewNetFirewallRuleSplat } ForEach ($Profile in $Settings.FirewallProfiles) { $SetNetFirewallProfileSplat = @{ Name = $Profile.Name Enabled = $Profile.Enabled DefaultInboundAction = $Profile.Connections.Inbound DefaultOutboundAction = $Profile.Connections.Outbound LogAllowed = $Profile.Logging.LogSuccessfullConnections LogBlocked = $Profile.Logging.LogDroppedPackets LogFileName = $Profile.Logging.Name LogMaxSizeKilobytes = $Profile.Logging.SizeLimit AllowLocalFirewallRules = $Profile.Settings.ApplyLocalFirewallRules AllowLocalIPsecRules = $Profile.Settings.ApplyLocalConnectionSecurityRules NotifyOnListen = $Profile.Settings.DisplayNotification GPOSession = $GPOSession PolicyStore = $NewGPO.DisplayName Confirm = $False } Set-NetFirewallProfile @SetNetFirewallProfileSplat } $SaveNetGPOSplat = @{ GPOSession = $GPOSession } Save-NetGPO @SaveNetGPOSplat ForEach ($OU in $Settings.LinkedOUs) { If (Test-Path "AD:\$($OU + (',{0}' -f (Get-ADRootDSE).rootDomainNamingContext))") { Try { Write-Host "Linking policy '$($NewGPO.DisplayName)' to OU '$($OU)' ..." $NewGPLinkSplat = @{ Name = $NewGPO.DisplayName Target = $OU + (',{0}' -f (Get-ADRootDSE).rootDomainNamingContext) } New-GPLink @NewGPLinkSplat | Out-Null } Catch { $ParseErrors += "Could not link GPO '$($NewGPO.DisplayName)' to OU '$($OU)'" Continue } } Else { $ParseErrors += "Path not accessible (referred to by '$($NewGPO.DisplayName)'): 'AD:\$($OU + (',{0}' -f (Get-ADRootDSE).rootDomainNamingContext))'" Continue } } } If ($ParseErrors) { Throw "One or more errors occurred:`n$($ParseErrors -join "`n")" } }