Active Directory: Gestionar permisos de OU con PowerShell

Si gestionáis un entorno de Active Directory «multitenant» o un directorio muy grande, es posible que más pronto que tarde os toque editar los permisos de las Unidades Organizativas para aseguraros de que no todo el mundo puede verlo todo. En la entrada de hoy veremos cómo gestionar permisos de OU con PowerShell, un proceso algo más complicado de lo que nos podríamos imaginar al ponernos a ello.

Para ver las distintas funciones que podemos realizar de una forma práctica en esta entrada crearemos un script que:

  • Crea una OU con PowerShell.
  • Rompe la herencia de la OU.
  • Elimina los permisos autogenerados en dicha OU.
  • Añade permisos personalizados.
Active Directory: Gestionar permisos de OU con PowerShell

Antes de empezar

Para entender mejor el contenido de esta entrada es conveniente que tengas una base sobre cómo funcionan los permisos en Windows y, específicamente, sobre los permisos en Active Directory. Durante la entrada me referiré a dos terminos de forma constante:

  • ACL: La Access Control List, es decir, la lista de permisos completa que está asociada al objeto (en esta entrada a una OU).
  • ACE: La Access Control Entry, es decir, un permiso conceto dentro de la ACL.

¡Con esto dicho ya podemos empezar!

Crear Unidad Organizativa con PowerShell

Para poder hacer nuestras pruebas de modificación de permisos de OU con PowerShell lo primero que necesitaremos será una OU de prueba que, como no, crearemos con PowerShell.

Como siempre os recomiendo que hagáis siempre vuestros desarrollos sobre un entorno de prueba ya que es muy fácil que acabemos liando una gorda, y nadie quiere recrear permisos a mano sobre un árbol de Active Directory.

# Definimos el path donde crear nuestra OU de prueba
$OuPath = 'DC=sobrebits,DC=local'

# Creamos la OU "OUTest" en la ubicación definida
New-ADOrganizationalUnit -Name 'OUTest' -Path $OuPath

En primer lugar hemos definido el path de la OU que vamos a crear con PowerShell. Después utilizamos New-ADOrganizationalUnit para crear una OU con el nombre OUTest.

Crear OU con PowerShell

Romper la herencia de OU con PowerShell

Ahora que tenemos nuestra Unidad Organizativa creada es momento de trastear con sus permisos. Justo después de crear la OU podemos ver como existen multitud de permisos heredados del nivel superior:

Permisos de OU heredados

Lo primero que haremos para asegurarnos de que podemos juguetear con todos ellos será romper la herencia de permisos de OU:

# Generamos el Path completo de la OU creada
$OuPath = "OU=OUTest,$OuPath"

# Obtenemos las ACL de nuestra OU
$Acl = Get-Acl "AD:\\$OuPath"

# Rompemos la herencia preservando las ACLs heredadas
$Acl.SetAccessRuleProtection($True,$True)

# Escribimos la ACL en la OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

Lo que hemos hecho ha sido obtener un objeto que representa todas las entradas de permisos de nuestra OU, lo hemos modificado para que deje de heredar permisos (copiando los que ya tenía heredados) y escribiendo éste objeto modificado en la ACL de la OU. Veamos línea a línea cómo lo hemos hecho:

  • Línea 2: Construimos el path completo de la OU que acabamos de generar para operar con ella en futuras líneas mediante $OuPath.
  • 5: Utilizamos el cmdlet Get-Acl para obtener los permisos (ACL) de la OU de Active Directory.
    • AD:\\ es un PSDrive que apunta a la raíz del directorio.
  • 8: Utilizamos el método SetAccessRuleProtection de nuestro objeto de ACL (System.DirectoryServices.ActiveDirectorySecurity) con el que podemos modificar el comportamiento de la heréncia.
  • 11: Con Set-Acl escribimos la ACL modificada en el comando anterior utilizando el parámetro -AclObject junto con el objeto modificado.

Si comprobamos ahora los permisos de nuestra OU de prueba veremos como tiene los mismos permisos que anteriormente pero éstos ya no son heredados del nivel superior:

Romper herencia de OU con PowerShell

Eliminar permisos de OU con PowerShell

Lo siguiente que vamos a ver será cómo eliminar estos permisos. El procedimiento es muy parecido: obtenemos la ACL actual, eliminamos los permisos (ACE) uno a uno del objeto y escribimos nuestra ACL modificada en la OU:

# Volvemos a obtener las ACLs de nuestra OU
$Acl = Get-ACL "AD:\\$OuPath"

# Recorremos las ACLs y las eliminamos una a una
ForEach ($Ace in $Acl.Access) {
        $Acl.RemoveAccessRule($Ace) | Out-Null
    }

# Escribimos la ACL de nuevo en nuestra OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

Veamos paso por paso:

  • Línea 2: Obtenemos las ACL de la OU de nuevo.
    • Debemos tener en cuenta que tras cada modificación de los permisos de la OU deberemos «refrescar» nuestro objeto $Acl para que tenga la versión actualizada de los permisos.
  • 5: Recorremos todas las ACL contenidas en la propiedad «Access» de nuestro objeto $Acl.
    • 6: Utilizamos el método RemoveAccessRule del objeto $Acl para eliminar la ACE.
  • 10: Con Set-Acl escribimos la ACL modificada en el comando anterior utilizando el parámetro -AclObject junto con el objeto modificado.

Después de eso, si volvemos a revisar los permisos de la OU veremos como no existe ninguno:

Eliminar permisos de OU con PowerShell

Añadir permisos de OU con PowerShell

Con nuestra ACL limpia llega el momento de añadir permisos a la Unidad Organizativa. Esta es quizás la parte más compleja, puesto que deberemos construir a mano un objeto ActiveDirectoryAccessRule, es decir, deberemos crear la ACE de forma manual. Vamos a ver cómo sería la cosa:

# Volvemos a obtener las ACLs de nuestra OU
$Acl = Get-ACL "AD:\\$OuPath"

# Construimos la ACE para el usuario Marc
$User = (Get-ADUser 'Marc')
$Sid = [System.Security.Principal.SecurityIdentifier]$User.Sid
$Identity = [System.Security.Principal.IdentityReference]$Sid
$Rights = [System.DirectoryServices.ActiveDirectoryRights]"GenericRead"
$Type = [System.Security.AccessControl.AccessControlType]"Allow"
$Inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]"All"
$Ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $Identity,$Rights,$Type,$Inheritance

# Añadimos la ACE a la ACL
$Acl.AddAccessRule($Ace)

# Escribimos la ACL de nuevo en nuestra OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

Repasemos paso por paso:

  • Línea 2: Obtenemos las ACL de la OU de nuevo.
  • 5-10: Obtenemos todas las propiedades que necesitamos para construir nuestro objeto ActiveDirectoryAccessRule.
    • 5: Obtenemos el usuario a añadir en la ACE.
    • 6: Sacamos el SID (identificador de seguridad) del usuario.
    • 7: Mediante el SID obtenemos el identificador del usuario, necesario para construir el objeto.
    • 8: Creamos un objeto de permisos de Active Directory con permisos de lectura. Podéis obtener todos los valores disponibles aquí.
    • 9: Determinamos el tipo de permiso en «permitir».
    • 10: Aplicamos la herencia de permisos a todos los objetos «descendientes».
  • 11: Mediante las propiedades definidas en el bloque anterior creamos un nuevo objeto de ACE mediante New-Object.
  • 14: Añadimos la ACE generada a la ACL que hemos obtenido en la línea 2.
  • 17: Con Set-Acl escribimos la ACL modificada en el comando anterior utilizando el parámetro -AclObject junto con el objeto modificado.

Si ahora vemos la ACL de la OU podemos ver como se ha añadido la entrada:

Añadir permisos de OU con PowerShell

A partir de aquí, si queremos añadir más permisos a la ACL únicamente tendremos que generar tantas ACE como sea preciso y añadirlas a nuestra ACL mediante Set-Acl.

El resultado final del script sería este:

# Definimos el path donde crear nuestra OU de prueba
$OuPath = 'DC=sobrebits,DC=local'

# Creamos la OU "OUTest" en la ubicación definida
New-ADOrganizationalUnit -Name 'OUTest' -Path $OuPath

# Generamos el Path completo de la OU creada
$OuPath = "OU=OUTest,$OuPath"

# Obtenemos las ACL de nuestra OU
$Acl = Get-Acl "AD:\\$OuPath"

# Rompemos la herencia preservando las ACLs heredadas
$Acl.SetAccessRuleProtection($True,$True)

# Escribimos la ACL en la OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

# Volvemos a obtener las ACLs de nuestra OU
$Acl = Get-ACL "AD:\\$OuPath"

# Recorremos las ACLs y las eliminamos una a una
ForEach ($Ace in $Acl.Access) {
        $Acl.RemoveAccessRule($Ace) | Out-Null
    }

# Escribimos la ACL de nuevo en nuestra OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

# Volvemos a obtener las ACLs de nuestra OU
$Acl = Get-ACL "AD:\\$OuPath"

# Construimos la ACE para el usuario Marc
$User = (Get-ADUser 'Marc')
$Sid = [System.Security.Principal.SecurityIdentifier]$User.Sid
$Identity = [System.Security.Principal.IdentityReference]$Sid
$Rights = [System.DirectoryServices.ActiveDirectoryRights]"GenericRead"
$Type = [System.Security.AccessControl.AccessControlType]"Allow"
$Inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]"All"
$Ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $Identity,$Rights,$Type,$Inheritance

# Añadimos la ACE a la ACL
$Acl.AddAccessRule($Ace)

# Escribimos la ACL de nuevo en nuestra OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

Bola extra: Copiar los permisos de una OU a otra con PowerShell

Es posible que después de este último punto hayas pensado que escribir una ACL compleja puede hacer que te quede un script extremadamente largo (algo que muchas veces se ve como algo bueno cuando no debería serlo), y razón no te falta. Un truco si vas a estar recreando los mismos permisos muchas veces es el siguiente:

  • Creas una OU y le asignas permisos que necesites a mano (no siempre hay que hacerlo todo desde la línea de comandos).
  • Haces que el script copie esos permisos en tu nueva OU.

Lo mejor de éste método es que lo puedes implementar en dos líneas:

# Obtenemos las ACL de la OU plantilla
$Acl = Get-ACL "AD:\\OU=PlantillaPermisos,DC=sobrebits,DC=local"

# Escribimos la ACL en la nueva OU
Set-Acl "AD:\\$OuPath" -AclObject $Acl

Conclusión

Mediante esta forma de asignación de permisos en OUs con PowerShell podremos automatizar un paso más en nuestros procesos de creación de usuarios, algo que puede ahorrarnos una gran cantidad de horas.

¡Espero que os sea útil!

Deja un comentario