[Active Directory]–Subir fotos de usuarios al AD

Viernes, 20 de noviembre de 2015 Sin comentarios

Hola a todos,

Como muchos ya sabéis, desde Windows Server 2003 funcionando como Domain Controller y nivel funcional 2003, se pueden almacenar fotos de los usuarios en el entorno.

Bien, pues después de mucho buscar por Internet y no encontrar un script de PowerShell medio decente, me aventuré a hacer el mío propio adaptado de otro.

Este es el código

##############################################################################################

# PowerShell Skript to  upload multiple Photos to Active Directory with

# automatic Logging management and Prechecks  before uploading

Author: Marc Salvador

#

# Version 1.0 – Inicial adaptada  de Internet

# Version 1.1 – Control de  errores con “Try/Catch”

# Versión 1.2 – Control de la existencia de carpetas para trabajar

##############################################################################################

 

$Date $(Get-Date -Uformat “%d.%m.%Y-%H.%M”)

# Variables de ejecución

# Se han de crear las carpetas “UploadPics” y sus subdirectorios o modificar el valor de las

# variables con el dato correcto.

# ——————————————————————

$overwrite =
“false” #Si  es necesario actualizar una foto de usuario, dejad el valor en “true”

$pathToPictures “E:\UploadPics\Pics” #only path to folder

$maxPictureSize “20000” # in byte

$pathToLog = “E:\UploadPics\PicUpload.log” #with name of the file

$maxLogSize = “10000000” #in byte

$backupFolder = “E:\UploadPics\Logs\”  #Ubicación de los backups

$backupDays = “7” #Días antes de borrar un backup

#
——————————————————————

# Existencia de la carpeta con  las fotos

if (!(Test-Path -Path $pathToPictures))

{

    Write-Host “No se encuentra la ruta de los archivos con las  fotos” -ForegroundColor Red

    Break

}

#
——————————————————————

# Existencia de la carpeta de  logs

if (Test-Path  -Path $pathToLog)

{

    $log = Get-Item $pathToLog

}

else

{

    Write-Host “No se encuentra la ruta de los archivos de  log” -ForegroundColor Red

    Break

}

# Revisar tamaño del fichero de  logs

if ($log.length -gt $maxLogSize)

{

$backupLog $backupFolder\PicUpload-$Date.log”

Copy-Item $pathToLog $backupLog

Clear-Content $pathToLog

Write-Host “Fichero de logs copiado a $backupLog -ForegroundColor Green

}

#Borrar los backups antiguos

$backupFiles =
Get-ChildItem $backupFolder

 

$old = $backupFiles | ? { $_.CreationTime -lt ((get-date).adddays($backupDays)) }

if ($old -eq $Null)

       {

       Write-Host “No hay backups de más de $backupDays días en ‘$backupFolder‘!” -ForegroundColor Yellow

       }

else

       {

       $old | % { Remove-Item $backupFolder$_ }

       Write-Host “Backups antiguos eliminados!”

       }

 

#Fecha actual

$Date=$(Get-Date -format g) | add-content $pathToLog

 

#Using hashtable for logs.

$errorlist=@{} #Errores de log

 

#
———————————————————————————————————————

# Cargamos el módulo de AD. Si se  ejecuta desde un Windows client,

# hay que bajar primero las RSAT para ese cliente e instalarlas.

# Control de error de carga del módulo

Try {

    Import-Module ActiveDirectory

}

Catch {

    $ErrorMessage = $_.Exception.Message

    $FailedItem = $_.Exception.ItemName

    $wshell = New-Object -ComObject Wscript.Shell   

    $wshell.Popup(“Error en la operación $ErrorMessage $FailedItem,0,“Error de ejecución”,0x0)

    Break

}

 

#Cargamos todas las imágenes desde el directorio donde están almacenadas

$queryPics Get-ChildItem $pathToPictures -ErrorAction Stop

 

foreach ($pic  in $queryPics)

{

    $username = $pic.basename

    $dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()

    $root = $dom.GetDirectoryEntry()

    $search = [System.DirectoryServices.DirectorySearcher]$root

    $search.Filter = “(&(objectclass=user)(objectcategory=person)(samAccountName=$username))”

    $result = $search.FindOne()

 

#Check if user exists

if ($result  -ne $null)

       {

       $user = $result.GetDirectoryEntry()

       $thumbnailPhoto = $user.thumbnailPhoto

       #Revisar si tiene o no una imagen en el AD

       if ($thumbnailPhoto.Value -eq $null)

             {

             #Añadir la foto al usuario

             [byte[]]$jpg = Get-Content $pic.FullName -encoding byte

            #Control de errores

            Try

            {

                $user.put(“thumbnailPhoto”,  $jpg )

                $user.setinfo()

            }

 

            Catch

            {

                 $ErrorMessage = $_.Exception.Message

                 $errorlist.Add($username, $ErrorMessage)

            Break

            }

       }

       else #Sobreescribimos la foto existente

             {

             if ($overwrite -eq $true)

                    {

                    #Add picture to user property

                    [byte[]]$jpg = Get-Content $pic.FullName -encoding byte

 

            #Control de errores

            Try

            {

                $user.put(“thumbnailPhoto”,  $jpg )

                $user.setinfo()

            }

 

            Catch

            {

                 $ErrorMessage = $_.Exception.Message

                 $errorlist.Add($username, $ErrorMessage)

                Break

            }

          }

          else

              {

                    Write-Host $user.displayname “ya  tiene una imagen en el AD” -ForegroundColor  Yellow

                    $errorlist.Add($username, “ya tiene una imagen”)

                    }

             }

       }

else

       {

       Write-Host  $username ” no encontrado” -ForegroundColor Red

       $errorlist.Add($username, “no encontrado”)

       }

}

 

#Notificación

$maxLogSize =
$maxLogSize/1000000

Write-Host “#Nota:  el archivos de log se puede encontrar en $pathtopictures y se llama ‘PicUpload.log’. Este archivo se moverá a ‘”$backupFolder“PicUpload-Date-Time.log’ cuando exceda los $maxLogSize MB.`n” -ForegroundColor Cyan

 

#Añadir los errores en el fichero

$errorlist | out-string | add-content $pathToLog

 

Como todo en esta vida, el script es mejorable así que acepto sugerencias

Saludos,

Marc

[Exchange] – Revisar errores de los calendarios de los usuarios

Jueves, 19 de noviembre de 2015 Sin comentarios

Hola a todos,

Estoy en un cliente con unos pocos buzones de Exchange, sobre los 16.000, cuyos usuarios hacen experimentos con las convocatorias de Exchange como borrarlas sin avisar a los convocados, moverlas, no aceptarlas…. cosa que produce errores en el subsistema de Calendar Repair de Exchange en forma de bastantes avisos.

El caso es que el cliente quiere que se cree un script de PowerShell que busque una sèrie de errores y los vuelque en ficheros. Así que, después de experimentar un poco dado que no soy un experto en teclear me ha salido esto:

 

#############################################################################################

# PowerShell Script to check errors in Exchange calendars in recursion

Author: Marc Salvador

Version 1.0 – Versión inicial con control de errores y logs de salida

# Version 1.1 – Versión con descarte por fechas 

# Version 1.2 – Eliminación de los logs de anteriores ejecuciones. NO PREGUNTA!!!

################################################################################################

 

# Definición de variables

$path “D:\PowerShell\Calendar Repair Assistant”

$pathLog “D:\PowerShell\Log”

# Se usan arrays para almacenar los datos de los ficheros y los errores en las citas

$filesInPath @()

$CitesErronies @()

#
———————————————————————-

# Control de errores: Existencia  de la carpeta con los ficheros a tratar

#

if (!(Test-Path -Path $path))

{

    Write-Host “No se encuentra la ruta de los archivos de ‘Calendar Repair Assistant’ en $path -ForegroundColor Red

    Break

}

#  ———————————————————————-

# Control de errores: Creamos un  directorio para guardar los logs del

# resultado del tratamiento de ficheros LOG/XML

if (!(Test-Path -Path $pathLog))

{

    Write-Host “No se encuentra la ruta de los archivos de log en $pathlog”  -ForegroundColor Red

    New-Item -ItemType Directory  -Path $pathLog  -ErrorAction Stop

    Write-Host “Directorio Log creado correctamente en $pathLog”  -ForegroundColor Green

}

else

{

    $directoryInfo  = Get-ChildItem  $pathLog Measure-Object

    # Contamos el número  de elementos del directorio.

    $ficherosTotales  = $directoryInfo.count

    # Si no es cero, es que no está vacío y se puede borrar

    If ($directoryInfo.count  -ne 0)

        {

        Remove-Item  $pathLog\*.txt -Recurse -ErrorAction  SilentlyContinue

        Write-Host  $ficherosTotales ficheros de logs antiguos borrados en $pathlog-ForegroundColor Yellow

        }

}

#########################################################################

# Cuerpo principal del programa

#########################################################################

 

# Capturamos la fecha/hora del  sistema.

$Date Get-Date

# Fechas de inicio y finalización  de la ejecución

$DateScriptH Get-Date -Format t

$DateScriptD Get-Date -Format  d/M/y

 

# Obtenemos los nombres de los ficheros a analizar

$filesInPath Get-ChildItem -Path  $path -ErrorAction Stop

Try

{

    Write-Host “Inicio de la ejecución del script a las $DateScriptH del día  $DateScriptD -ForegroundColor cyan

    ForEach ($logs in $filesInPath)

    {

        # Obtenemos  los nombres de los ficheros a analizar junto con el path donde se encuentran

        $filesInPath  = $path  + “\”  + $logs

        #  Convertimos los datos a XML

        $xml  = [xml](Get-Content $filesInPath  -ErrorAction Stop)

         # Seleccionamos los datos del XML que queremos tratar

        $meetings  = $xml.SelectNodes(“/CalendarRepairLog/Meetings/Meeting”| Where-Object  {([DateTime]$_.StartTime) -ge  $Date}

         #  Tratatamos los datos seleccionados

        foreach  ($meeting in  $meetings)

        {

              # Buscamos los usuarios convocados en las citas

              $attendees  = $meeting.Attendees.Attendee

              foreach  ($attendee in  $attendees)

              {

                    # Buscamos los errores de en los calendarios de cada usuarios

                    $ConsistencyChecks  = $attendee.ConsistencyChecks.ConsistencyCheck  | Where-Object  {$_.Result -eq “Failed”}

                    foreach  ($ConsistencyCheck in $ConsistencyChecks)

                    {

                          # Guardamos los datos de error de cada cita de cada usuario en un array y

                          # lo guardamos en un fichero para cada usuario

                          $CitesErronies += ,($meeting.Subject, $meeting.StartTime, $meeting.Organizer, $attendee.EmailAddress, $ConsistencyCheck.Description) Out-File -FilePath $pathLog\$logs-Resultado.txt  -Force -ErrorAction  SilentlyContinue

                    }

              }

        }

    }

}

Catch [System.exception]

{

    $ErrorMessage  = $_.Exception.Message

    $FailedItem  = $_.Exception.ItemName

    Write-host “Se ha producido un error de ejecución $FailedItem en el  entorno $ErrorMessage -ForegroundColor  Red

    Break

}

Catch

{

    $ErrorMessage  = $_.Exception.Message

    $FailedItem = $_.Exception.ItemName

    Write-host “Se ha producido un error de ejecución $FailedItem en el entorno $ErrorMessage -ForegroundColor Red

    Break

}

Finally

{

    # Fechas de inicio y finalización de la ejecución

    $DateScriptH  = Get-Date -Format t

    $DateScriptD  = Get-Date -Format d/M/y

    Write-Host “Finalización de la ejecución del script a las $DateScriptH del día  $DateScriptD -ForegroundColor cyan

    write-host “Los logs de ejecución están en $pathLog”  -ForegroundColor Green

}

 

 

 

Acepto comentarios de mejora como, por ejemplo, que genere un HTML por cada usuario y se lo envíe por correo…

Saludos,

Marc

 

 

Categories: Dia a dia, Exchange Tags:

MCP: Advanced Solutions of Microsoft Exchange Server 2013

Viernes, 25 de septiembre de 2015 Sin comentarios

Hola,

Si hace un mes ponía por aquí que obtuve el MCP de Exchange (el  70-341 Core Solutions of Microsoft Exchange Server 2013) y puedo poner que me he sacado el 70-342 Advanced Solutions of Microsoft Exchange Server 2013

Así que… ya tengo el MCSE: Messaging!!!

 

Saludos,

Marc

Categories: Certificaciones, Exchange Tags:

MCP: Core Solutions of Microsoft Exchange Server 2013

Jueves, 27 de agosto de 2015 Sin comentarios

Hola,

Sí, estoy de nuevo por aquí.

Y no, no me he ido de vacaciones, todavía.

¿Por què?

Porque he estado estudiando, trabajando y sobreviviendo al típico resfriado de verano (sí, ese que provocan los AACC)

Pues lo dicho en el título, me he sacado el 70-341 Core Solutions of Microsoft Exchange Server 2013 después de mucho tiempo pidiéndolo con lo que la cosa está así

image

 

Tendremos pronto el 342? Flirt male

 

Saludos,

Marc

Categories: Certificaciones, Dia a dia, Microsoft Tags:

[AD FS] Cómo sustituir un AD FS 3.0 por otro AD FS 3.0

Jueves, 9 de julio de 2015 Sin comentarios

Hola de nuevo,

No sé si es muy normal lo que os voy a contar pero, oye, pasar os puede pasar. Y como no he encontrado nada por Internet ni medio decente sobre el tema… pues me he liado yo solo.

Por necesidades de un cliente, he tenido que migrar un servidor AD FS 3.0 (ya sabéis, sobre Windows Server 2012 R2 Update) de un CPD a otro CPD, que está a unos 100 Kms.

Como un vMotion (o Live Migration) no era posible, se decidió tirar por el camino del medio, esto es, instalar otro servidor en el CPD destino y mover la federación.

Bien, los pasos son sencillos pero… han tenido algunos efectos, llamémosles, imprevistos.

 

Pasos seguidos

  • Montar el nuevo servidor de AD FS 3.0, junto con su Windows Update y demás
  • Exportar el certificado de la federación desde el servidor viejo al nuevo
  • Modificar el fichero host del AD FS Proxy (Web Application Proxy o WAP, para ser exactos) para que apunte al nuevo AD FS
  • Ejecutar un Update-MSOLFederatedDomain y…
  • Revisar que en el Visor de sucesos esté todo bien (aparentemente), tal como se ve a continuación

image

 

Los errores

El caso es que todo ha ido bien hasta pasadas unas 12 horas… de tal modo que tanto en el nuevo AD FS como en el WAP, el Visor de sucesos se ha llenado de errores como los que siguen

AD FS

 

image

WAP

 

image

 

Y la solución

Recuerdo que en la versión 2.0/2.1 de AD FS Proxy, re-ejecutando el Wizard de configuración, estas cosas se arreglaban. Pero claro, en la era de Powershell hay que tirar de comandos de teletexto así que… la cosa se arregla de esta manera

  • Primero, buscar el thumbprint del certificado de la federación, dentro de la MMC de Certificados.
  • Seguidamente, ejecutar estos cmdlet con los valores adecuados:

$federationServiceCreds = Get-Credential

Install-WebApplicationProxy -FederationServiceTrustCredential $federationServiceCreds -CertificateThumbprint ‘Thumbprint‘ –FederationServiceName ‘nombreDeLaFederacion’

Si todo va bien, veremos un mensaje como el que sigue.

image

Y ya está arreglado? No, sólo hemos hecho el 50% del trabajo.

El último paso, volver a publicar la federación en nuesto WAP.

Revisamos el visor de sucesos de ambos equipos y hemos de encontrarnos con mensajes del estilo

AD FS

image

 

WAP

 

image

image

 

Ahora sí hemos acabado.

Saludos,

Marc