Windows PowerShellPermisos del shell

Don Jones

Descargar el código de este artículo: PowerShell2008_02.exe (151KB)

Al hablar de Windows PowerShell, a menudo me preguntan acerca de los permisos, en especial si el shell permite automatizar los cambios en los permisos y cómo puede hacerlo. La consulta más común sea posiblemente acerca de los permisos de archivos, aunque también son frecuentes las consultas sobre los permisos de directorios y del Registro. En lo referente a los permisos y a cualquier

interfaz de línea de comandos o de scripting (incluidos Windows PowerShellTM y VBScript), tengo que dar tanto buenas como malas noticias.

Las malas noticias son que los permisos de Windows® son, por naturaleza, bastante complicados y Windows PowerShell no puede hacer mucho para corregirlo. El problema proviene del hecho de que en un sistema operativo Windows, hay varios objetos relacionados con los permisos, independientemente de si busca en el sistema de archivos, Active Directory®, el Registro o en cualquier otro lugar.

En primer lugar, tenemos el recurso propiamente dicho, por ejemplo, un objeto de directorio, un archivo o una carpeta. A continuación, encontramos el objeto de lista de control de acceso (ACL, Access Control List), que está adjunto al recurso. ACL consta de una o más entradas de control de acceso u objetos ACE. Una ACE enlaza una entidad de seguridad (un usuario o grupo, que es otro objeto) con un permiso (como, por ejemplo, de lectura o de control total) y un estado Conceder o Denegar. Son cinco objetos: El recurso, la ACL, la ACE, la entidad de seguridad y un permiso.

Los permisos se complican aún más por el hecho de que cada tipo de recurso tiene distintos tipos de permisos. Por ejemplo, los objetos de directorio disponen de permisos complejos que controlan el acceso a atributos de objetos individuales. En comparación, los permisos de archivos son un poco menos complicados.

Además, técnicamente, en el caso de las auditorías todo se duplica. Todos los recursos disponen de dos ACL. En primer lugar, existe la lista de control de acceso discrecional (DACL, Discretionary ACL), que controla el acceso al recurso. También hay una lista de control de acceso de seguridad (SACL, Security ACL), que controla la auditoría del recurso. Intentar trabajar con estos permisos significa navegar a través de una pila de objetos de programación que parecen bastante complicados, y mucho nos tememos que un shell como Windows PowerShell no puede hacer mucho para simplificarlo.

Limitado por .NET Framework

¿Quiere más?

Para obtener más recursos de Windows PowerShell, incluida una biblioteca de cmdlets que permite búsquedas, y para ponerse en contacto con Don Jones y otros expertos en Windows PowerShell, visite www.PowerShellCommunity.org.

La naturaleza de Windows PowerShell complica un poco las cosas. Creado a partir de Microsoft® .NET Framework, Windows PowerShell usa las clases subyacentes de .NET Framework para representar y trabajar con permisos. Estas clases subyacentes de .NET Framework se diseñaron para ofrecer a los desarrolladores de software un control granular y preciso sobre los permisos. Por supuesto, "granular y preciso" significa mucha información y, a menudo, se traduce como "muy complicado".

Además, .NET Framework no ofrece clases que representen permisos en todos los tipos de recursos de Windows. Por ejemplo, aunque .NET Framework ofrece clases que le permiten manipular la seguridad de archivos, no ofrece clases que le permitan trabajar con la seguridad de la carpetas compartidas. Como resultado, Windows PowerShell no puede manipular los permisos en cada tipo de recurso de Windows. En otras palabras, Windows PowerShell está limitado a las capacidades expuestas por .NET Framework.

Permisos en el shell

La administración de permisos en Windows PowerShell se deriva de dos cmdlets: Get-ACL y Set-ACL. Como cabría esperar, Get-ACL recupera la ACL a partir de un recurso. A continuación, puede modificar la ACL para que se adapte a sus necesidades y usar Set-ACL para volver a escribirla en el recurso. Ambos cmdlets son genéricos y dependen del sistema de proveedores PSDrive de Windows PowerShell. De este modo, ambos cmdlets ACL podrían trabajar, en teoría, con cualquier tipo de recurso, siempre que haya un proveedor PSDrive capaz de entender un tipo de recurso dado y capaz de modificar los permisos en ese tipo de recurso. Los proveedores PSDrive FileSystem y Registry, incluidos en Windows PowerShell, admiten la administración de permisos a través de dos cmdlets ACL. Puede que otros proveedores PSDrive no la admitan.

El script de muestra que aparece en la Figura 1 le permite especificar un directorio de inicio, una entidad de seguridad y un permiso. A continuación, el script aplica el permiso que ha especificado para esa entidad de seguridad a todos los archivos y carpetas del directorio especificado. El script también permite la recursividad de subdirectorios.

Figure 1 Aplicar un permiso para una entidad de seguridad a los archivos y carpetas de un directorio

#ChangeACL.ps1
$Right="FullControl"

#The possible values for Rights are 
# ListDirectory, ReadData, WriteData 
# CreateFiles, CreateDirectories, AppendData 
# ReadExtendedAttributes, WriteExtendedAttributes, Traverse
# ExecuteFile, DeleteSubdirectoriesAndFiles, ReadAttributes 
# WriteAttributes, Write, Delete 
# ReadPermissions, Read, ReadAndExecute 
# Modify, ChangePermissions, TakeOwnership
# Synchronize, FullControl

$StartingDir=Read-Host "What directory do you want to start at?"
$Principal=Read-Host "What security principal do you want to grant" `
"$Right to? `n Use format domain\username or domain\group"

#define a new access rule.
#note that the $rule line has been artificially broken for print purposes.
#it needs to be one line. the online version of the script is properly
#formatted.
$rule=new-object System.Security.AccessControl.FileSystemAccessRule
($Principal,$Right,"Allow")

foreach ($file in $(Get-ChildItem $StartingDir -recurse)) {
  $acl=get-acl $file.FullName
 
  #Add this access rule to the ACL
  $acl.SetAccessRule($rule)
  
  #Write the changes to the object
  set-acl $File.Fullname $acl
  }

La sustancia del script está donde define una nueva regla de acceso en la variable $rule. Para esto, uso una clase .NET Framework "sin formato", que es posiblemente la parte más complicada de la administración de permisos en Windows PowerShell. A continuación, el script recupera la ACL de todos los archivos y carpetas mediante Get-ACL, aplica la nueva regla mediante el método SetAccessRule de la ACL, y vuelve a escribir la ACL modificada en el recurso por medio de Set-ACL.

En realidad, no es tan complicado, aunque se requieren operaciones más complejas como eliminar una ACE de una ACL. En mi opinión, lo que lo hace parecer complicado es el hecho de que implica muchos pasos: obtener la ACL, definir una regla, modificar la ACL y escribir la ACL. No hay un único comando que haga todo de una sola vez. Como deseaba modificar las ACL en varios archivos, tuve que incluirlo todo en un bucle foreach, usando Get-ChildItem para obtener acceso a todos los archivos y carpetas.

Elegiré la opción más fácil

Cmdlet del mes: Get-QADUser

Este cmdlet es imprescindible si administra Active Directory. No está integrado en Windows PowerShell, pero está disponible a modo de descarga gratuita como parte del shell de administración ActiveRoles para Active Directory de Quest Software (www.quest.com/activeroles-server/arms.aspx).

Cuando haya instalado el complemento, podrá usar Get-QADUser para recuperar objetos de usuario desde el directorio. Por supuesto, con sólo ejecutarlo, cmdlet devuelve todo sus usuarios, lo que no resulta muy útil para la mayoría de las tareas administrativas. Cmdlet le permite especificar criterios de filtrado, que se aplican en el controlador de dominio para que sólo se devuelvan a Windows PowerShell aquellos usuarios que le interesen. Esta técnica es más rápida que obtener primero todos los usuarios y filtrarlos a continuación con el cmdlet Where-Object. Por ejemplo, Get-QADUser -l Redmond sólo devolverá aquellos usuarios cuyo atributo "l" contenga "Redmond" (el atributo "l" corresponde a localidad y se incluye como ciudad en GUI). A continuación, puede canalizar esos usuarios a otros cmdlets para generar un informe HTML, colocarlos en un grupo o incluso eliminarlos.

Creo que mi ejemplo es sencillo, pero sé que muchos administradores preferirían una forma más simplificada de trabajar con permisos. Tal vez deseen eliminar un grupo de usuarios específico de un conjunto de carpetas de una sola vez sin escribir un script compuesto por varios pasos como el que aparece en la Figura 1.

Por suerte, Windows PowerShell ofrece un medio simplificado para trabajar con permisos y, probablemente, ya esté familiarizado con él.

Windows PowerShell no le obliga a abandonar su manera habitual de hacer las cosas. Puede continuar usando herramientas de línea de comandos como Dsacls.exe, Cacls.exe y Xcacls.exe, que se diseñaron específicamente para simplificar el trabajo con varios tipos de permisos. Aunque su sintaxis es completamente diferente a la sintaxis estándar usada por los cmdlets de Windows PowerShell, éstas utilidades de línea de comandos ya no tienen que usarse de una forma ad hoc en la línea de comandos, tal y como ocurría en el antiguo shell cmd.exe. Puede usar Windows PowerShell para automatizar estas utilidades.

Me he encontrado con muchas personas, los llamaré "puristas", que insisten en que no es correcto usar una línea de comandos antigua con Windows PowerShell. No lo entiendo. Estoy a punto de acabar el trabajo y si la forma más fácil de hacerlo es usar una utilidad de línea de comandos de hace 10 años, dígame dónde tengo que firmar. No voy a dedicar horas extra a intentar hacer algo de una forma concreta sólo porque parece "más puro". Y el equipo de Microsoft Windows PowerShell tiene una actitud similar. Si una herramienta existente hace el trabajo, entonces Windows PowerShell le permite usar dicha herramienta en el shell. ¿Por qué volver a inventar la rueda?

La Figura 2 muestra un breve script, tomado de mi libro Windows PowerShell: TFM (SAPIEN Press, 2006), que usa Windows PowerShell para automatizar Cacls.exe. Este script es sólo una demostración, lo que significa que tendrá que ajustarlo si desea convertirlo en una herramienta de automatización real. Sin embargo, muestra cómo un script de Windows PowerShell puede recopilar información y usarla para iniciar Cacls.exe, como si Cacls.exe fuera un comando "nativo" de Windows PowerShell. Aunque este script recopila información solicitándosela al usuario, los parámetros también se pueden leer desde un archivo o una base de datos.

Figure 2 Automatizar Cacls.exe

#SetPermsWithCACLS.ps1
# CACLS rights are usually
# F = FullControl
# C = Change
# R = Readonly
# W = Write

$StartingDir=Read-Host "What directory do you want to start at?"
$Right=Read-Host "What CACLS right do you want to grant? Valid choices are F, C, R or W"
Switch ($Right) {
  "F" {$Null}
  "C" {$Null}
  "R" {$Null}
  "W" {$Null}
  default {
    Write-Host -foregroundcolor "Red" `
    `n $Right.ToUpper() " is an invalid choice. Please Try again."`n
    exit
  }
}

$Principal=Read-Host "What security principal do you want to grant?" `
"CACLS right"$Right.ToUpper()"to?" `n `
"Use format domain\username or domain\group"

$Verify=Read-Host `n "You are about to change permissions on all" `
"files starting at"$StartingDir.ToUpper() `n "for security"`
"principal"$Principal.ToUpper() `
"with new right of"$Right.ToUpper()"."`n `
"Do you want to continue? [Y,N]"

if ($Verify -eq "Y") {

 foreach ($file in $(Get-ChildItem $StartingDir -recurse)) {
  #display filename and old permissions
  write-Host -foregroundcolor Yellow $file.FullName
  #uncomment if you want to see old permissions
  #CACLS $file.FullName
  
  #ADD new permission with CACLS
  CACLS $file.FullName /E /P "${Principal}:${Right}" >$NULL
  
  #display new permissions
  Write-Host -foregroundcolor Green "New Permissions"
  CACLS $file.FullName
 }
}

¿Eficaz con los permisos?

He oído que Windows PowerShell no cumple las expectativas en lo que respecta a permisos porque no proporciona un cmdlet nativo que ofrezca administración de permisos simplificada y universal. No estoy de acuerdo. En primer lugar, este argumento normalmente proviene de administradores con mucha experiencia en UNIX, y el sistema de permisos de Windows es mucho más complicado que el de UNIX. Al exponer este sistema, Windows PowerShell también se complica. Sin embargo, esto no es un problema de Windows PowerShell.

Además, Windows PowerShell le permite usar herramientas simplificadas como las tradicionales utilidades de línea de comandos, tal y como ya se ha demostrado aquí. Es cierto que .NET Framework necesita una expansión para cubrir mejor la administración de permisos en toda la plataforma de Windows. En general, Windows PowerShell le ofrece ambas opciones: la administración simplificada de permisos y el acceso a herramientas de administración granulares y precisas.

Don Jones es editor colaborador de la revista TechNet Magazine y coautor de Windows PowerShell: TFM (SAPIEN Press, 2007). Se dedica a enseñar Windows PowerShell (consulte www.ScriptingTraining.com) y puede ponerse en contacto con él a través del sitio web www.ScriptingAnswers.com.

© 2008 Microsoft Corporation and CMP Media, LLC. Reservados todos los derechos; queda prohibida la reproducción parcial o total sin previa autorización.