задача создать группу и дать права на редактирования gpo
<#
.SYNOPSIS
Настраивает права группы для работы с GPO:
- создание новых GPO;
- редактирование существующих GPO (всех или точечно выбранных);
- линковка GPO к OU (с наследованием на дочерние OU).
.DESCRIPTION
ЧАСТЬ 1 (создание новых GPO):
Добавляет группу в встроенную группу AD "Group Policy Creator Owners".
Участники этой группы могут создавать новые GPO и автоматически
становятся их владельцами/редакторами (но только тех, что создали
сами - см. примечание ниже).
ЧАСТЬ 2 (редактирование существующих GPO):
Перебирает GPO в домене, проверяет, есть ли у группы право
редактирования, и если нет - выдаёт его через Set-GPPermission.
По умолчанию обрабатываются ВСЕ GPO домена. Если нужно применить
права точечно только к конкретным политикам - заполните массив
$SpecificGpoNames именами нужных GPO; тогда остальные GPO эта
часть скрипта не тронет.
ЧАСТЬ 3 (линковка GPO к OU):
Выдаёт ОДНО наследуемое правило на каждый "корневой" OU из списка
$LinkRootOUs. Правило распространяется на сам OU и все дочерние OU
(сколько угодно уровней вниз), но ограничено только объектами типа
OrganizationalUnit - т.е. НЕ затрагивает пользователей, компьютеров
и другие объекты внутри этих OU.
Важно: право "Link GPOs" на OU управляет только атрибутом gPLink
(какие GPO привязаны к этому OU). Оно НЕ даёт прав на редактирование
объектов внутри OU и НЕ даёт прав на содержимое самих GPO.
.NOTES
ВАЖНОЕ ОГРАНИЧЕНИЕ (проверено на практике):
Когда участник группы создаёт НОВЫЙ GPO, права редактирования на него
получает лично этот пользователь (как Creator Owner), а НЕ вся группа
целиком. Штатного механизма в GPMC, который бы автоматически выдавал
права на новые GPO всей группе, не существует (права по умолчанию для
новых GPO заданы в схеме AD на уровне всего леса и их менять не стоит
ради одной группы). Единственный практичный вариант - периодически
перезапускать Часть 2 этого скрипта (например, по расписанию через
Task Scheduler), чтобы права на новые GPO подтягивались автоматически
с небольшой задержкой.
Требует модули GroupPolicy и ActiveDirectory.
Запускать от имени пользователя с правами Domain Admin
(или эквивалентной делегированной учётки для управления GPO/AD ACL).
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param()
# =====================================================================
# ================ НАСТРОЙКИ — МЕНЯЙТЕ ЗНАЧЕНИЯ ЗДЕСЬ ================
# =====================================================================
# Имя группы, которой выдаём права
$TargetGroupName = "G-GPO Editors"
# Добавлять ли группу в "Group Policy Creator Owners" (право создавать новые GPO)
$GrantCreateNewGpoRight = $true
# Уровень прав на редактирование существующих GPO:
# "GpoEdit" - только редактирование настроек
# "GpoEditDeleteModifySecurity" - редактирование + удаление + управление правами
$EditPermissionLevel = "GpoEdit"
# Точечное применение: укажите конкретные GPO по имени (DisplayName), чтобы
# права редактирования выдавались ТОЛЬКО им, а не всем GPO в домене.
# Оставьте пустым массивом @(), чтобы обработать ВСЕ GPO домена.
# Пример: $SpecificGpoNames = @("Default Domain Policy", "Firewall Rules")
$SpecificGpoNames = @()
# "Корневые" OU (DistinguishedName), с которых право линковки распространится
# вниз на ВСЕ дочерние OU автоматически (наследование).
# Пример: $LinkRootOUs = @("OU=Company,DC=contoso,DC=com")
# Если хотите выдать право на весь домен - укажите DN корня домена,
# например: @("DC=contoso,DC=com")
$LinkRootOUs = @(
"DC=contoso,DC=com"
)
# $true - только показать, что будет сделано, БЕЗ реального изменения прав (безопасный тестовый прогон)
# $false - реально выполнить изменения
$WhatIfOnly = $true
# =====================================================================
# ============ ДАЛЬШЕ КОД, ОБЫЧНО МЕНЯТЬ НЕ НУЖНО ============
# =====================================================================
Import-Module GroupPolicy -ErrorAction Stop
Import-Module ActiveDirectory -ErrorAction Stop
$ErrorActionPreference = "Stop"
# Надёжное сравнение IdentityReference из ACE с SID нашей группы.
# Get-Acl на пути AD:... иногда возвращает IdentityReference уже
# переведённым в формат "ДОМЕН\Имя" (NTAccount), а не как SID-строку,
# поэтому прямое сравнение строк ненадёжно - переводим в SID и сравниваем так.
function Test-IdentityMatchesGroup {
param($IdentityReference, $GroupSid)
try {
$sid = $IdentityReference.Translate([System.Security.Principal.SecurityIdentifier])
return ($sid.Value -eq $GroupSid.Value)
}
catch {
return $false
}
}
# --- Проверяем, что группа существует ---
try {
$group = Get-ADGroup -Identity $TargetGroupName -ErrorAction Stop
}
catch {
throw "Группа '$TargetGroupName' не найдена в AD. Проверьте имя и повторите."
}
$groupSid = $group.SID
Write-Host "Целевая группа: $($group.Name) (SID: $groupSid)" -ForegroundColor Cyan
Write-Host ""
# =====================================================================
# ЧАСТЬ 1. Право создавать новые GPO (Group Policy Creator Owners)
# =====================================================================
if ($GrantCreateNewGpoRight) {
Write-Host "=== Право создания новых GPO ===" -ForegroundColor Yellow
$creatorOwners = Get-ADGroup -Identity "Group Policy Creator Owners"
$isMember = Get-ADGroupMember -Identity $creatorOwners | Where-Object { $_.SID -eq $groupSid }
if ($isMember) {
Write-Host "Группа уже состоит в 'Group Policy Creator Owners' - пропуск." -ForegroundColor DarkGray
}
elseif ($WhatIfOnly -or $PSCmdlet.ShouldProcess($TargetGroupName, "Add to Group Policy Creator Owners")) {
if ($WhatIfOnly) {
Write-Host "[WhatIf] Добавил бы группу '$TargetGroupName' в 'Group Policy Creator Owners'" -ForegroundColor DarkYellow
}
else {
try {
Add-ADGroupMember -Identity $creatorOwners -Members $group
Write-Host "OK: группа добавлена в 'Group Policy Creator Owners'" -ForegroundColor Green
}
catch {
Write-Warning "Ошибка при добавлении в 'Group Policy Creator Owners': $($_.Exception.Message)"
}
}
}
Write-Host ""
}
# =====================================================================
# ЧАСТЬ 2. Право редактировать существующие GPO
# =====================================================================
Write-Host "=== Проверка прав редактирования существующих GPO ===" -ForegroundColor Yellow
if ($SpecificGpoNames.Count -gt 0) {
Write-Host "Режим точечного применения: обрабатываются только указанные GPO ($($SpecificGpoNames.Count) шт.)" -ForegroundColor Cyan
$allGpos = @()
foreach ($name in $SpecificGpoNames) {
try {
$allGpos += Get-GPO -Name $name -ErrorAction Stop
}
catch {
Write-Warning "GPO с именем '$name' не найден в домене - пропуск."
}
}
}
else {
$allGpos = Get-GPO -All
}
$gposWithoutEditRights = @()
foreach ($gpo in $allGpos) {
$perms = Get-GPPermission -Guid $gpo.Id -All -ErrorAction SilentlyContinue
$hasEditRights = $perms | Where-Object {
$_.Trustee.Sid -eq $groupSid -and
$_.Permission -in @("GpoEdit", "GpoEditDeleteModifySecurity", "GpoCustom")
}
if (-not $hasEditRights) {
$gposWithoutEditRights += $gpo
}
}
Write-Host "Найдено GPO без прав редактирования у группы '$TargetGroupName': $($gposWithoutEditRights.Count)" -ForegroundColor Cyan
if ($gposWithoutEditRights.Count -gt 0) {
$gposWithoutEditRights | Select-Object DisplayName, Id | Format-Table -AutoSize
}
foreach ($gpo in $gposWithoutEditRights) {
if ($WhatIfOnly -or $PSCmdlet.ShouldProcess($gpo.DisplayName, "Grant $EditPermissionLevel to $TargetGroupName")) {
if ($WhatIfOnly) {
Write-Host "[WhatIf] Выдал бы '$EditPermissionLevel' на GPO: $($gpo.DisplayName)" -ForegroundColor DarkYellow
}
else {
try {
Set-GPPermission -Guid $gpo.Id `
-TargetName $TargetGroupName `
-TargetType Group `
-PermissionLevel $EditPermissionLevel `
-Replace:$false | Out-Null
Write-Host "OK: выдано '$EditPermissionLevel' на GPO: $($gpo.DisplayName)" -ForegroundColor Green
}
catch {
Write-Warning "Ошибка при выдаче прав на GPO '$($gpo.DisplayName)': $($_.Exception.Message)"
}
}
}
}
Write-Host ""
# =====================================================================
# ЧАСТЬ 3. Право линковки GPO к OU (с наследованием на дочерние OU)
# =====================================================================
Write-Host "=== Право линковки GPO (Link GPOs), с наследованием ===" -ForegroundColor Yellow
# GUID свойства gPLink (сама привязка GPO к контейнеру - запись в это свойство)
$gpLinkPropertyGuid = [Guid]"f30e3bbe-9ff0-11d1-b603-0000f80367c1"
# GUID класса объекта organizationalUnit - ограничиваем наследование только OU,
# чтобы правило не "утекало" на пользователей/компьютеров внутри OU
$organizationalUnitClassGuid = [Guid]"bf967aa5-0de6-11d0-a285-00aa003049e2"
foreach ($rootDn in $LinkRootOUs) {
try {
$rootObject = Get-ADObject -Identity $rootDn -ErrorAction Stop
}
catch {
Write-Warning "Не удалось найти объект '$rootDn': $($_.Exception.Message)"
continue
}
$adPath = "AD:$rootDn"
$acl = Get-Acl -Path $adPath
$existingRule = $acl.Access | Where-Object {
(Test-IdentityMatchesGroup -IdentityReference $_.IdentityReference -GroupSid $groupSid) -and
$_.ObjectType -eq $gpLinkPropertyGuid -and
$_.ActiveDirectoryRights -match "WriteProperty"
}
if ($existingRule) {
Write-Host "Пропуск (правило уже есть): $rootDn" -ForegroundColor DarkGray
continue
}
if ($WhatIfOnly -or $PSCmdlet.ShouldProcess($rootDn, "Grant inheritable Link GPOs to $TargetGroupName")) {
if ($WhatIfOnly) {
Write-Host "[WhatIf] Выдал бы наследуемое право Link GPOs на: $rootDn (и все дочерние OU)" -ForegroundColor DarkYellow
}
else {
try {
# 6-параметрический конструктор: включает objectType (какое право)
# и inheritedObjectType (к объектам какого класса это наследование применяется)
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$groupSid,
[System.DirectoryServices.ActiveDirectoryRights]"WriteProperty",
[System.Security.AccessControl.AccessControlType]::Allow,
$gpLinkPropertyGuid,
[System.DirectoryServices.ActiveDirectorySecurityInheritance]::All,
$organizationalUnitClassGuid
)
$acl.AddAccessRule($rule)
Set-Acl -Path $adPath -AclObject $acl
Write-Host "OK: выдано наследуемое право Link GPOs на: $rootDn (и все дочерние OU)" -ForegroundColor Green
}
catch {
Write-Warning "Ошибка при выдаче прав линковки на '$rootDn': $($_.Exception.Message)"
}
}
}
}
Write-Host ""
Write-Host "Готово." -ForegroundColor Cyan
Similar Posts:
- Как искать внутри GPO групповых политик.
- Как вывести список пользователей у которых не при монтировался диск fslogix и переименовать FriendlyName
- Как перенести пользователей из одной группы в другую через powershell
- Как перенести активных пользователей из одной коллекции в другую windows rds
- Как найти программу и версию с помощью powershell
