El Blog de Gualtrysoft

Windows 2000/2003/2008, Active Directory, VBScript, Hyper-V, PowerShell y todo aquello interesante a la hora de usar, configurar y administrar Windows Server. También tenemos longanizas…

PowerShell: Cmdlet para invocar Get-WmiObject con credenciales alternativas controlando error por equipo local

Posted by urpiano en Jueves 9 \09\UTC diciembre \09\UTC 2010

Una particularidad de WMI es que no se puede acceder con credenciales alternativas al equipo local, pues eso provoca un error. Cuando queremos realizar un script que vaya obteniendo los objetos que son instancias de una clase de WMI en varios equipos (obtenidos sus nombres, por ejemplo, de un fichero de texto) se puede dar el caso de que entre los nombres de equipo de la lista esté el equipo local, lo que provocará un error si estamos accediendo a WMI con credenciales alternativas. Este Cmdlet permite conectar a WMI con o sin credenciales de manera transparente y obtener los resultados, independientemente de cómo se ha conectado.

Para evitar este problema de conexión con o sin credenciales según sea equipo local o remoto, tendríamos que comprobar si se trata del equipo local y en ese caso conectar a WMI sin las credenciales alternativas, o en su defecto conectar con las credenciales alternativas, detectar el error que se produce y volver a intentarlo sin ellas. Si una vez obtenido el objeto se van a realizar determinadas tareas, el código será algo engorroso, pues o se ponen infinidad de comprobaciones previas a realizar las tareas o si no se duplican las líneas, realizando lo mismo en un bloque de conexión con credenciales y en otro sin ellas; un ejemplo de esta duplicidad de código lo podemos ver en el Cmdlet Get-PhysicalMemory que publiqué anteriormente. Este Cmdlet permite que en el script o función donde debamos invocar a Get-WmiObject lo hagamos sin preocuparnos de este tipo de comprobaciones, pues obtendremos los objetos sin necesidad de verificar nada, lo que hará el código más claro de depurar y fácil de desarrollar. El resultado es que sólo se controla si la devolución a este Cmdlet es nula o no. El resultado de su uso lo podemos ver en Get-PhysicalMemory (2), que obtiene lo mismo que Get-PhysicalMemory con un código más breve y simple.

El Cmdlet incluye ayuda, pego a continuación la ayuda con modificador -Detailed (esta ayuda se basa en la prestación de ayuda basada en comentarios de PowerShell 2.0 ¿Qué todavía tienes la versión 1.0 y no la 2.0? ¿A qué esperas para instalarla si es mucho mejor?):

NOMBRE
    Invoke-WmiExpression
    
SINOPSIS
    Devuelve el resultado de una llamada que se hace a Get-WmiObject con la
    cadena que se recibe como parámetro y que es pasada a Execute-Expression,
    realizando control de errores.
    
SINTAXIS
    Invoke-WmiExpression [[-Expression] <String>] [[-Credential] <Object>] [<CommonParameters>]
    
DESCRIPCIÓN
    La princpal tarea de esta función es evitar la redundancia de código que
    se produce al controlar el error que se genera si se realiza una llamada
    a Get-WmiObject con credenciales alternativas al equipo local. En toda
    función que realice este tipo de llamadas y que se quiera controlar este 
    error, cuando usamos Try/Catch, el bloque de la función se coloca en la
    parte Try y en el Catch hay que controlar si el error es por las
    credenciales alternativas y en caso afirmativo volver a invocar
    Get-WmiObject sin pasarlas, para a continuación volver a poner el bloque de
    código, lo que lo duplica. En el código de la función que usa ésta, sólo se
    tendrá que poner el bloque principal una vez, pues se convierte en
    transparente si es el equipo local o no.

PARÁMETROS
    -Expression <String>
        Cadena que es una llamada a Get-WmiObject.
        
    -Credential <Object>
        Nombre de usuario o credenciales completas del usuario con el que se
        conectara a WMI. En caso de pasarse sólo el nombre de usuario, se pedirá
        entrar la contraseña del mismo. Si se pasan credenciales y se consulta el
        equipo local, las credenciales serán ignoradas, pues no se puede conectar
        a WMI del equipo local con credenciales alternativas. Tiene también los
        alias "Usuario","U","Credenciales" y "Cred".
        
    <CommonParameters>
        Este cmdlet admite los parámetros comunes Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer y OutVariable. Para obtener más información, escriba:
        "get-help about_commonparameters".
    
    -------------------------- EJEMPLO 1 --------------------------
    
    PS >Invoke-WmiExpression "Get-WmiObject Win32_Process -ComputerName mortadelo-pc" -Credential (Get-Credential TIA\Bac
    terio)
    
    Muestra por pantalla los procesos del equipo mortadelo-pc, pasando las
    credenciales de un prestigioso científico y no importando si se trata del
    equipo local o no; se pedirá al insigne profesor que entre su contraseña.
    
    -------------------------- EJEMPLO 2 --------------------------
    
    PS >$Usr = Get-Credential
    
    PS >Invoke-WmiExpression "Get-WmiObject Win32_Process -ComputerName mortadelo-pc" -Credential (Get-Credential TIA\Bac
    terio)
    Muestra por pantalla los procesos del equipo mortadelo-pc, pasando las
    credenciales contenidas en $Usr y que fueron obtenidas invocando
    Get-Credential.

Este es el código del Cmdlet:

Function Invoke-WmiExpression([string]$Expression,$Credential)
{
    # Si se ha recibido credenciales, las añadimos al comando
    If($Credential -ne $null -and `
      ($Credential.GetType()).Name -eq "PsCredential")
    {
        # Guadamos el comando sin credenciales
        $ExpressionNoCredential = $Expression
        # Agregamos las credenciales al comando
        $Expression = "$Expression -Credential `$Credential"
    }
    # Limpiamos la variable de errores
    $Error.Clear()
    # Nos guardamos la configuración existente ante los errores que no
    # interrumpen
    $AccionError = $ErrorActionPreference
    # Establecemos que los errores que no interrumpen sí lo hagan, así
    # podremos capturarlos con Try/Catch
    $ErrorActionPreference = "Stop"
    Try
    {
        # Obtenemos los módulos de memoria del equipo
        $Devolucion = Invoke-Expression $Expression
    }
    Catch
    {
        # Si el error producido es provocado porque se ha intentado
        # pasar credenciales al equipo local...
        If($Error[0].Exception.ErrorCode -eq "LocalCredentials")
        {
            # Restituimos el comando para que sea sin pedir credenciales
            $Expression = $ExpressionNoCredential
            # Volvemos a invocar el comando para obtener los volúmenes
            $Devolucion = Invoke-Expression $Expression
        }
        Else
        {
            $Devolucion = $null
        }
    }
    # Restituimos la acción que estaba configurada para los errores que
    # no interrumpen
    $ErrorActionPreference = $AccionError
    $Devolucion
#.SYNOPSIS
#   Devuelve el resultado de una llamada que se hace a Get-WmiObject con la
#   cadena que se recibe como parámetro y que es pasada a Execute-Expression,
#   realizando control de errores.
#.DESCRIPTION
#   La princpal tarea de esta función es evitar la redundancia de código que
#   se produce al controlar el error que se genera si se realiza una llamada
#   a Get-WmiObject con credenciales alternativas al equipo local. En toda
#   función que realice este tipo de llamadas y que se quiera controlar este 
#   error, cuando usamos Try/Catch, el bloque de la función se coloca en la
#   parte Try y en el Catch hay que controlar si el error es por las
#   credenciales alternativas y en caso afirmativo volver a invocar
#   Get-WmiObject sin pasarlas, para a continuación volver a poner el bloque de
#   código, lo que lo duplica. En el código de la función que usa ésta, sólo se
#   tendrá que poner el bloque principal una vez, pues se convierte en
#   transparente si es el equipo local o no.
#.PARAMETER Expression
#   Cadena que es una llamada a Get-WmiObject.
#.PARAMETER Credential
#   Nombre de usuario o credenciales completas del usuario con el que se
#   conectara a WMI. En caso de pasarse sólo el nombre de usuario, se pedirá
#   entrar la contraseña del mismo. Si se pasan credenciales y se consulta el
#   equipo local, las credenciales serán ignoradas, pues no se puede conectar
#   a WMI del equipo local con credenciales alternativas. Tiene también los
#   alias "Usuario","U","Credenciales" y "Cred".
#.NOTES
#   Desarrollado por Fernando Reyes López
#   Noviembre de 2010
#.LINK
#   http://freyes.svetlian.com -> Artículos de Fernando reyes
#.LINK
#   https://urpiano.wordpress.com -> El Blog de GualtrySoft
#.EXAMPLE
#     PS >Invoke-WmiExpression "Get-WmiObject Win32_Process -ComputerName mortadelo-pc" -Credential (Get-Credential TIA\Bacterio)
#   Muestra por pantalla los procesos del equipo mortadelo-pc, pasando las
#   credenciales de un prestigioso científico y no importando si se trata del
#   equipo local o no; se pedirá al insigne profesor que entre su contraseña.
#.EXAMPLE
#     PS >$Usr = Get-Credential
#     PS >Invoke-WmiExpression "Get-WmiObject Win32_Process -ComputerName mortadelo-pc" -Credential $Usr
#   Muestra por pantalla los procesos del equipo mortadelo-pc, pasando las
#   credenciales contenidas en $Usr y que fueron obtenidas invocando
#   Get-Credential.
}

4 comentarios to “PowerShell: Cmdlet para invocar Get-WmiObject con credenciales alternativas controlando error por equipo local”

  1. […] PowerShell: Cmdlet para invocar Get-WmiObject con credenciales alternativas controlando error por eq… […]

  2. […] PowerShell: Cmdlet para invocar Get-WmiObject con credenciales alternativas controlando error por eq… […]

  3. […] PowerShell: Cmdlet para invocar Get-WmiObject con credenciales alternativas controlando error por eq… […]

  4. […] su funcionamiento requiere la función Invoke-WmiExpression, incluída en el código que acompaña a esta […]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

 
A %d blogueros les gusta esto: