Mostrando las entradas con la etiqueta SCRIPTING EN POWER SHELL. Mostrar todas las entradas
Mostrando las entradas con la etiqueta SCRIPTING EN POWER SHELL. Mostrar todas las entradas

miércoles, 9 de agosto de 2017

Creando Nuget Server Local y haciendo la instalación con WebDeploy

La forma práctica, ordenada y ágil en que podemos compartir el código dentro de nuestra organización es a través de paquetes nuget, los cuales no son mas que bibliotecas de código reutilizable que podemos incluir en nuestros proyectos de Visual Studio fácilmente.  Por lo que lo que necesitamos es un "Repositorio" de estos paguetes de código reutilizable llamados Nuget.

Para crear este repositorio tenemos 3 opciones:

1) Una Carpeta Compartida en la red
2) Un servidor de Nuget Local
3) Utilizar los servidores de Nuget.Org para compartir nuestro código al rededor del mundo con infraestructura de terceros

Análisis de las opciones
Crear una Carpeta Compartida es una opción muy fácil poco segura, ordenada y elegante, por lo que no recomiendo esta opción más que para una prueba de concepto.

Utilizar los servidores de Nuget.Org de forma privada es una opción la cual puede evaluar primordial mente si su equipo esta distribuido geográficamente, sino recomiendo la opción de un Servidor Nuget.  Para más información ver el siguiente enlace: https://www.myget.org/nuget 

Nuestro análisis nos lleva a ver la opción 2 de crear un servidor Nuget con nuestra propia infraestructura disponible dentro de nuestra organización y esto es el lo que vamos a ver en el desarrollo del artículo.

Prerequisitos

Requerimientos de Hardware
Procesador: 1 Nucleo
Memoria RAM: 1 GB
Disco: 127 GB

Requerimientos de Software
Windows Server 2012 Standard Edition
IIS 8.0 con las siguientes features activadas:
DisplayName
-----------
Web Server (IIS)
Web Server
Common HTTP Features
Default Document
Directory Browsing
HTTP Errors
Static Content
Health and Diagnostics
HTTP Logging
Logging Tools
Request Monitor
Performance
Static Content Compression
Security
Request Filtering
Windows Authentication
Application Development
.NET Extensibility 3.5
.NET Extensibility 4.5
ASP.NET 3.5
ASP.NET 4.5
ISAPI Extensions
ISAPI Filters
Management Tools
IIS Management Console
IIS Management Scripts and Tools
Management Service

Nota:  Para obtener este listado puede ejecutar la siguiente línea en powershell:

 Import-module servermanager ; Get-WindowsFeature | where {$_.Installed -eq $True -and $_.Path
 -like "*web*" }| select displayname

Como vamos a realizar la instalación con WebDeploy necesitamos instalarlo para IIS 8.0
https://www.iis.net/downloads/microsoft/web-deploy 

Debemos validar que el servicio Management Services esta levantado así que ejecute esta línea de comando en el servidor web:
net start wmsvc

Por último como el proyecto Nuget Server que vamos a instalar require Framework 4.6 es necesario instalar dicho framework que no viene con Windows Server 2012.   Para ello utitlizar el siguiente enlace:

https://www.microsoft.com/en-us/download/details.aspx?id=53344

Listos ahora pasemos a Visual Studio para crear el proyecto Web Nuget Server

Creación de Proyecto Web Nuget Server




Desde Visual Studio Cree un Nuevo Proyecto Web Vacio

Y ejecute desde la consola de Package Manager la siguiente línea:

Install-Package NuGet.Server -Version 2.11.3

Le Preguntará si permite modificar el archivo web.config del proyecto seleccione afirmativamente la opción.

Recomiendo revise las configuraciones del archivo web.config siguientes:

 



Ahora vamos a crear un perfil de publicación en VS para realizar la instalación automatizada del Servidor Nuget en el Servidor Web recién configurado.



Valide la conexión y si le de errror revise los prerequisitos o vaya al siguiente enlace:
https://docs.microsoft.com/en-us/iis/publish/troubleshooting-web-deploy/web-deploy-error-codes

Si vemos el resumen del Perfil de publicación notaremos que el servicio referenciado es Web Management Services o WMSvc



Y finalmente si publicamos el proyecto a través del perfil de publicación obtendremos el resultado final... Nuestro servidor Nuget Listo!:



Y eso es todo amigos, en este articulo revisamos como crear un servidor Nuget Local para crear nuestros paquetes de bibliotecas de código para compartir con el equipo de una forma ágil y eficiente desde Visual Studio 2017, Y lo hicimos de forma automatizada ya que utilizamos Web Deploy para instalar el Proyecto Web del Servidor Nuget en un Servidor Windows 2012 con el Web Server Habilitado y el Servicio Web Management Service para realizar instalaciones remotas a través de la aplicación Web Deploy de Microsoft.

Code4Fun!,

Juan Manuel Herrera Ocheita

sábado, 30 de enero de 2016

Script para listar cantidad de elementos en todas las listas y bibliotecas de todas las colecciones de sitios

En esta ocasión vamos a contar el total de elemntos de cada lista y biblioteca de SharePoint.  Para identificar si es una biblioteca u otra lista utilizamos la propiead BaseTemplate.
Para comprender mejor el Script es bueno repasar la arquitectura del Modelo de Objectos de Servidor de SharePoint. A través de la siguiente imagen:

En resumen el objeto SPWebApplication contiene uno o mas objectos SPSite que representa cada colección de sitios y dentro de cada colección de sitios accedemos uno o mas sub-sitios o sitios web con el objeto SPWeb. Dentro de cada SPWeb podemos acceder las listas y/o bibliotecas con el objeto SPList.  y por ultimo aunque no lo utilicemos en este script el objeto SPListItem que representa cada elemento del objeto SPList.
Ahora vamos a describir el contenido del script que nos generará el listado del total de elementos de cada lista.
--- Inicio del Archivo ListAllListElements.ps1 ----
#Obtenemos la aplicación Web
$spWebApp = get-SPWebApplication http://misitio
#Declaramos el nombre del archivo CSV donde guararemos la información
$OutputFile ="d:\infoware\totaldocumentos.csv"
#Escribimos el encabezado del contenido del archivo csv
Add-Content $OutputFile "Titulo,Sitio,Url,Lista-Id,Lista,Tipo,Cantidad Elementos"
#Obtenemos todas las colecciones de sitios de la aplicación Web
$allSites = $spWebApp.Sites
foreach($site in $allSites)
{
    #Obtenemos todos los subisitos de la la colección de sitios actuales.
$webs = $site.AllWebs
    foreach($Web in $webs)
    {
        foreach($list in $Web.Lists)
        {
        #Establecemos el valor de la variable $row con la url, titulo del sitio y la información de la lista        $row = $web.URL+","+$web.Title + ","
        +$list.Id+","+$list.Title+","+$list.BaseTemplate+","+$list.Items.Count                       
        Add-Content $OutputFile $row
        }
    }
}
--- Fin del Archivo ListAllListElements.ps1 ----
Para ejecutar el script utilizamos Management Shell for SharePoint 2013:
c:\> .\ListAllListElements.ps1
El resultado será similar a la siguiente imagen:




SharePoint4fun Amigos!.
Hasta la próxima,
Juan Manuel Herrera Ocheita

Script para obtener el espacio ocupado y la ultima modificación realizada a los documentospor sitio para SharePoint OnPremises

Estimar el espacio ocupado de un sitio no es algo fácil de obtener ya que cada estructura de sitio y de las listas y bibliotecas de SharePoint ocupan un espacio no determinado del todo.  Lo que mejor podemos hacer es sumar el espacio de los archivos almacenados en las bibliotecas de SharePoint.
Resultado de imagen para sharepoint powershell
Este script corre en SharePoint 2010 y estimo también en 2013.
A continuación veremos un script que recorre todos los sitios de una colección de sitios:
-----Inicio del script ListadoSitios.ps1 -----
$File = "D:\scripts\MiSitio-EspacioOcupado.CSV"
#Escribimos el encabezado en el archivoAdd-Content -Path $File  -Value "Titulo,Url,Size,LastDate"
#definimos la fecha más antigua para que tengamos un punto de comparación inicial la definimos global para que podamos obtener su valor fuera del método donde se asigna.
$global:LastDate = Get-Date
$global:LastDate = $global:LastDate.AddDays(-10000)

#Método que Obtiene el sitio primario y llama el método que obtenien los sub.sitios.
function GetWebSizes ($StartWeb)
{
    $web = Get-SPWeb $StartWeb
    GetSubWebSizes -Web $web
    $web.Dispose()    # Importante destruir el objeto SPWeb para liberar la memoria RAM
}

Cuando utilizar el Dispose en el siguiente enlace: https://blogs.technet.microsoft.com/stefan_gossner/2008/12/05/disposing-spweb-and-spsite-objects/

function GetSubWebSizes ($Web)
{

    #Inicializamos nuevamente la fecha de partida para comparación
    $global:LastDate = Get-Date
    $global:LastDate = $global:LastDate.AddDays(-10000)
    #Recorremos cada subsitio de forma recursiba
    foreach ($subweb in $Web.GetSubwebsForCurrentUser())
    {
        [long]$webtotal = 0
        #Recorremos cada carpeta del subistio para obtener el espacio ocupado
    foreach ($folder in $subweb.Folders)
        {
            $webtotal += GetFolderSize -Folder $folder
        }
    $content = $subweb.Url + "," + $subweb.Title + "," +  $webtotal + "," + $global:LastDate
    Add-Content -Path $File  -Value $content
        write-host $content

       #LLamada recursiva al mismo método
        GetSubWebSizes -Web $subweb
   
    }
}

function GetFolderSize ($Folder)
{
    [long]$folderSize = 0 
    foreach ($file in $Folder.Files)
    {

    #Compara la fecha de la ultima modificación del archivo con la fecha de punto de partida y si es mas reciente la del archivo entonces la reemplaza
    if ($file.TimeLastModified -gt $global:LastDate){
        $global:LastDate = $file.TimeLastModified
    }
            #Acumula el valor de cada archivo en bytes
        $folderSize += $file.Length;
    }
    foreach ($fd in $Folder.SubFolders)
    {
        $folderSize += GetFolderSize -Folder $fd
    }
    return $folderSize
}

GetWebSizes -StartWeb HTTP://MiSharePoint
-----fin del script ListadoSitios.ps1 -----
Si necesitamos recorrer todas las colecciones de sitio solo hay que agregar las siguientes lineas de comando:
function GetWebSizes ($StartWeb)
{
$sites = Get-SPSite –StartWeb -Limit All
foreach($site in $Sites){
    $web = $site.RootWeb
    GetSubWebSizes -Web $web
    $web.Dispose()    # Importante destruir el objeto SPWeb para liberar la memoria RAM
}

}
Eso es todo amigos. SharePoint4Fun!,
Juan Manuel Herrera Ocheita

viernes, 29 de enero de 2016

Como migrar el contenido de un sitio de WordPress a las bibliotecas de SharePoint Online

La estrategia es muy sencilla y va ser la siguiente:
1) Descargar el contenido a un almacenamiento local a través de una herramienta FTP.
2) Definir una estrategia para almacenar el contenido en SharePoint Online
2) Crear un Script que lea el contenido migrado y suba los archivos a bibliotecas de SharePoint.
La herramienta
Describamos un poco la herramienta llamada FileZila.   Esta herramienta de FTP es gratuita y esta disponible para los sistemas operativos más populares.   Lo mas importante si estamos en un entrono Windows es que vamos a poder acceder el contenido de WordPress que esta en Linux.
El enlace para descargar la herramienta es el siguiente: https://filezilla-project.org/ 
Veamos ahora la conexión hacia el servicio ftp


La información que debes de solicitar para hacer la conexión es la siguiente:
Dirección IP del servidor Linux
Puerto (Opcional solo si el cliente utiliza un puerto en especifico diferente el predeterminado [21] colocarlo allí).
Luego Las credenciales un usuario con acceso y una contraseña.
Seleccionamos lo que deseamos descargar y con el clic derecho del ratón seleccionamos la opción Download.


La estrategia
Para la estrategia vamos a crear bibliotecas por cada carpeta principal ya que en SPO hay un límite de despliegue de documentos de 5,000 por razones de rendimiento.  Por lo que debemos de tomar eso en cuenta.








Para reducir el trabajo en el script vamos a crear manualmente las bibliotecas porque tampoco son muchas en mi este caso de lo contrario deberíamos tomar eso en cuenta en el script y crear con comandos de Powershell las bibliotecas.



El Script
A través de este script invocamos los comandos de CSOM Client SharePoint Object Model y no el Modelo de objetos de SharePoint.   Porque razón?, bueno porque SharePoint Online no esta local sino en la nube y la forma de acceder remotamente las librerias de SharePoint es através de CSOM que no es mas que llamadas de servicios Web por medio de un módelo de objetos definido para ese propósito.

Ahora vemos el script que hace la magia:
/* Cargamos las librerias de CSOM */
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"

/* El método Ensure_Folder nos asegurará que la carpeta este creada antes de copiar el contenido */
Function Ensure-Folder()
{
Param(
  [Parameter(Mandatory=$True)]
  [Microsoft.SharePoint.Client.Web]$Web,

  [Parameter(Mandatory=$True)]
  [Microsoft.SharePoint.Client.Folder]$ParentFolder,

  [Parameter(Mandatory=$True)]
  [String]$FolderUrl

)
    $folderNames = $FolderUrl.Trim().Split("/",[System.StringSplitOptions]::RemoveEmptyEntries)
    $folderName = $folderNames[0]
    Write-Host "Creating folder [$folderName] ..."
    $curFolder = $ParentFolder.Folders.Add($folderName)
    $Web.Context.Load($curFolder)
    $web.Context.ExecuteQuery()
    Write-Host "Folder [$folderName] has been created succesfully. Url: $($curFolder.ServerRelativeUrl)"

    if ($folderNames.Length -gt 1)
    {
        $curFolderUrl = [System.String]::Join("/", $folderNames, 1, $folderNames.Length - 1)
        Ensure-Folder -Web $Web -ParentFolder $curFolder -FolderUrl $curFolderUrl
    }
}

/* El método Upload-File  recibe como parametros el url relativo de la carpeta destino y la ubicación local del archivo */
Function Upload-File()
{
Param(
  [Parameter(Mandatory=$True)]
  [Microsoft.SharePoint.Client.Web]$Web,

  [Parameter(Mandatory=$True)]
  [String]$FolderRelativeUrl,

  [Parameter(Mandatory=$True)]
  [System.IO.FileInfo]$LocalFile

)
    try {
     $folderUrl = $LocalFile.Name.ToLower().Replace($SourceFolderPath.ToLower(),"")
    
     $fileUrl = $FolderRelativeUrl + "/" + $folderUrl

       write-host "FileUrl:" $fileUrl
       Write-Host "Uploading file [$($LocalFile.FullName)] ..."
       [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($Web.Context, $fileUrl, $LocalFile.OpenRead(), $true)
       Write-Host "File [$($LocalFile.FullName)] has been uploaded succesfully. Url: $fileUrl"
    }
    catch {
       write-host "An error occured while uploading file [$($LocalFile.FullName)]"
    }
}

/* El método Upload-Files es la principal ya que localiza cata archivo local y define la url destino para subir el archivo  a SPO.  Este método recibe como parameto la url destino, el usuario de O365, la contraeña, el nombre de la biblioteca de SharePoint destino, y la rutal local donde esta ubicado el contenido.  Como es recursivo solo debemos de dar el punto de partida de donde deseamos iniciar la carga de información. */

function Upload-Files()
{

Param(
  [Parameter(Mandatory=$True)]
  [String]$Url,

  [Parameter(Mandatory=$True)]
  [String]$UserName,

  [Parameter(Mandatory=$False)]
  [String]$Password,

  [Parameter(Mandatory=$True)]
  [String]$TargetListTitle,

  [Parameter(Mandatory=$True)]
  [String]$SourceFolderPath

)
    if($Password) {
       $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
    }
    else {
      $SecurePassword = Read-Host -Prompt "Enter the password" -AsSecureString
    }

# Abajo la autenticación a O365 para acceder los objetos de SharePoint Online
    $Context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
    $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,$SecurePassword)
    $Context.Credentials = $Credentials
    #Instanciamos el Web Site que vamos acceder
    $web = $Context.Web
    $Context.Load($web)

    # Instanciamos la biblioteca destino
    $list = $web.Lists.GetByTitle($TargetListTitle);
    $Context.Load($list.RootFolder)

#Ejecutamos el conjunto de lineas anteriores
    $Context.ExecuteQuery()
#Recorremos cada directorio local del parametró de ruta origen que indicamos al ejecutar el método

    Get-ChildItem $SourceFolderPath -Recurse | % {
       if ($_.PSIsContainer -eq $True) {
          $folderUrl = $_.FullName.ToLower().Replace($SourceFolderPath.ToLower(),"")
          $folderUrl = $folderUrl.Replace("\","/").Replace(".","")  
          if($folderUrl) {
             Ensure-Folder -Web $web -ParentFolder $list.RootFolder -FolderUrl $folderUrl
          } 
       }
       else{

          # Basado en la ubicación local creamos un Url Relativo reciproco en la biblioteca de SPO
          $folderRelativeUrl = $list.RootFolder.ServerRelativeUrl + $_.DirectoryName.ToLower().Replace($SourceFolderPath.ToLower(),"").Replace("\","/").Replace(".","") 

          #Ejecutamos el métod que subira el archivo a la ruta destino
          Upload-File -Web $web -FolderRelativeUrl $folderRelativeUrl -LocalFile $_
       }
    }
}

#End of file
La ejecución
Para ejecutar el archivo uploadfiles-csom.ps1 deberemos declarar los siguientes parámetros:

$Url =
https://miempresa.sharepoint.com/sites/miSitio
$UserName = misuario@midominio.onmicrosoft.com
$Password = "******"
$TargetListTitle = "BibliotecaDestino"   #Target Library
$SourceFolderPath = "X:\www\data\uploads\CarpetaOrigen"  #Source Physical Path


#Comando
Upload-Files -Url $Url -UserName $UserName -Password $Password -TargetListTitle $TargetListTitle -SourceFolderPath $SourceFolderPath


Y eso es todo amigos.
Hasta la próxima, SharePoint4Fun!
Juan Manuel Herrera Ocheita

viernes, 27 de noviembre de 2015

Script para saber el tamaño de una carpeta de una biblioteca en SharePoint 2010-2013

 

Esta solicitud me hicieron hace un momento y como no vi un ejemplo en especifico para esto decidi compartirlo con mis amigos lectores.

Los tres parametros que necesitamos son: url del sitio web en cuestion, el nombre de la biblioteca y el nombre de la carpeta.  Como se muestra abajo:

$urlWebSite = “http://hostname/siteurl/sub-siteurl

$nombreLibreria = "Nombre-Libreria"

$nombreCarpeta = "Nombre-Carpeta"

Luego debemos de obtener el objeto SPWeb para encontrar la bilioteca de la siguiente forma:

$web = get-SPWeb $urlWebSite

Una vez que lla obtuvimos el objeto SPWeb que representa el sitio web en SharePoint obtenemos la biblioteca con la colección Folders del objeto SPWeb, como se muestra a continuación:

$folder =  $web.Folders[$nombreLibreria]

Ahora que almacenamos en la variable $folder la bilbioteca en cuestion, necesitamos obtener la carpeta que buscamos a través de la colección SubFolerds del objeto SPFolder, de la siguiente forma:

$subfolder = $folder.SubFolders[$nombreCarpeta]

Con eso tenemos ya la ubicación deseada para iniciar el proceso de lectura de los bytes ocupados en la carpeta y sub carpetas, para ello necesitamos crear un funcion que llamemos de forma recursiva hasta que obtengamos el espacio total ocupado.

[long]$total = 0

$total = GetFolderSize($subfolder)

La función es la siguiente:

function GetFolderSize ($Folder)

{

    [long]$folderSize = 0 

    foreach ($file in $Folder.Files)

    {

        write-host "Nombre documento" $file.Name

        $folderSize += $file.Length;

        write-host "Total en bytes que va acumulando:" $folderSize

    }

    foreach ($fd in $Folder.SubFolders)

    {

        $folderSize += GetFolderSize -Folder $fd

    }

    return $folderSize

}

Lo que nos falta entonces es convertir los bytes en megas, y en gigas es es lo que hacemos a continuación:

$totalInMb = ($total/1024)/1024

$totalInMb = "{0:N2}" -f $totalInMb

$totalInGb = (($total/1024)/1024)/1024

$totalInGb = "{0:N2}" -f $totalInGb

write-host "Tamaño total de la carpeta" $StartWeb "es" $total " Bytes,"

write-host "son " $totalInMb "MB o " $totalInGb "GB"

Y ahora necesitamos indicarle a Windows que libere el recurso en memoria que ocupamos a través del objeto SPWeb la invocar el comando  $web = get-SPWeb $urlWebSite , y lo hacemos de la siguiente forma:

$web.Dispose()

Para poner todo en orden debemo de prepar un contenedor de este script en un archivo con extension .ps1, por ejemplo:

C:\>GetFolderSize.ps1

y debera contener el siguiente orden del código descripto arriba:

<!--- Begin of File –->

function GetFolderSize ($Folder)

{

    [long]$folderSize = 0 

    foreach ($file in $Folder.Files)

    {

        write-host "Nombre documento" $file.Name

        $folderSize += $file.Length;

        write-host "Total en bytes que va acumulando:" $folderSize

    }

    foreach ($fd in $Folder.SubFolders)

    {

        $folderSize += GetFolderSize -Folder $fd

    }

    return $folderSize

}

$urlWebSite = “http://hostname/siteurl/sub-siteurl

$nombreLibreria = "Nombre-Libreria"

$nombreCarpeta = "Nombre-Carpeta"

$web = get-SPWeb $urlWebSite

$folder =  $web.Folders[$nombreLibreria]

$subfolder = $folder.SubFolders[$nombreCarpeta]

$totalInMb = ($total/1024)/1024

$totalInMb = "{0:N2}" -f $totalInMb

$totalInGb = (($total/1024)/1024)/1024

$totalInGb = "{0:N2}" -f $totalInGb

write-host "Tamaño total de la carpeta" $StartWeb "es" $total " Bytes,"

write-host "son " $totalInMb "MB o " $totalInGb "GB"

$web.Dispose()

<!--- End of File –->

Y por ultimo utilizamo el Management Shell for SharePoint para ejecutar el script de la siguiente forma:

c:\>.\GetFolderSize.ps1

Eso es todo amigos.

SharePoint4Fun!,

Juan Manuel Herrera Ocheita

domingo, 15 de septiembre de 2013

Cómo subir masivamente fotografías a los perfiles de usuario de SharePoint 2013

Hay algunos artículos en la red sobre este tema que me ayudaron a realizar el script en PowerShell para subir de forma masiva las fotografías de los usuarios a los perfiles de usuario de SharePoint 2013.

Gracias a Toni Frankola por su artículo que me sirvicio de base para crear script personalizado para subir las fotografías de los usuarios a SharePoint 2013.  Abajo el artículo base:

http://www.sharepointusecases.com/index.php/2012/12/use-case-automatically-importing-user-profile-pictures-to-sharepoint-2013-and-2010/

El Problema:

En este escenario se cuenta con un archivo de Excel que tiene asociado un código de empleado con la ubicación de la fotografía del usuario y no con la cuenta de dominio.  Por lo que el procedimiento que se realizó para este caso en particular fue el siguiente:

1) Se actualizó el código de empleado en el Directorio Activo y para ello se utilizó un campo disponible en el Directorio como lo es la ciudad o City.

http://technet.microsoft.com/en-us/library/hh524307.aspx

3) En el servicio de aplicación perfiles de usuario en SharePoint se mapeo esta propiedad del directorio activo con una propiedad personalizada en las propiedades del perfil de usuario en SharePoint

4) Se realizó una sincronización completa de los usuarios del directorio activo en SharePoint

5) Se validó que el campo se había actualizado

6) Se creó el script que hiciera lo siguiente:

1) Lea un archivo CSV que obtuviera el código de empleado y la ruta de la imagen

2) Comparará con cada uno de los perfiles de los usuarios importados en SharePoint, el código de empleado del archivo con el código de empleado del perfil de usuario para obtener su cuenta de dominio

3) Que cargará la fotografía en memoria

4) Que la subiera a la biblioteca de imágenes de los perfiles de usuario asociada a cada perfil.

 

El Mapeo de propiedad en el UPA

En el servicio de Aplicación User Profiles o Perfiles de Usuario seleccionamos la opción “administrar propiedades del usuario” o “Manage User Profile Properties”

image

Ahora seleccionamos “Nueva Propiedad” o “New Property”

image

Llenamos el campo Nombre y nombre para desplegar, seleccionamos el tipo de dato que para este ejemplo es una cadena de caracteres o String.

image

Luego indicamos que la configuración de privacidad predeterminada es todos para que nos permita seleccionar la opción “Replicable”, luego seleccionamos la opción de configuración de edición de no permitirlo y luego las opciones de presentación que nos permita mostrar la propiedad en la sección de propiedades del perfil de usuario.

 

image

En esta área de la página de edición de la propiedad del perfil es donde se mapea con el AD, para ello seleccionamos la conexión de datos de origen hacia el AD Previamente creada y luego seleccionamos el atributo del Directorio Activo que para City es L minúscula según la tabla de abajo y seleccionamos para la dirección de actualización en Importar.

La Estructura del archivo CSV

CODIGO , FOTOGRAFIA

1009, C:\FOTOS\JUAN MARTINEZ.JPG

1010, C:\FOTOS\ROBERTO AZURDIA.JPG

1020, C:\FOTOS\ANA GONZALEZ.JPG

El Script:

#  DEFINIMOS LAS VARIABLES A UTILIZAR

$InvFile = "ListadoUsuarioYRutas.csv"

# LA DIRECCION DE MY SITES O MIS SITIOS ESTO VARIA DE INSTALACIÓN EN INSTALACIÓN DE SHAREPOINT CONSULTE AL ADMINISTRADOR O REVISE EL CENTRAL ADMINISTRACION PARA DESCUBRIR ESTA URL


$farmUrl =  http://misitio.midominio/

$site=Get-SPSite $farmUrl
$web=$site.RootWeb
$serverContext=[Microsoft.Office.Server.ServerContext]::GetContext($site)

# SE CARGA EN MEMORIA EL USER PROFILE MANAGER PARA MAS TARDE OBTENER LOS PERFILES DE LOS USUARIOS EN SHAREPOINT
$upm=New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($serverContext)


# SE CARGA EN MEMORIA EL ARCHIVO CSV

$FileExists = (Test-Path $InvFile -PathType Leaf)
if ($FileExists) {
   "Loading $InvFile for processing..."
   $tblData = Import-CSV $InvFile
} else {
   "$InvFile not found - stopping import!"
   exit
}

# Leyendo Archivo de Codigos y Fotos ..."
$contador = 0
$perfiles = $upm.GetEnumerator()
foreach ($row in $tblData)
{
   $picture = $row."FOTOGRAFIA"
   if( $picture)
   {

    # LEE CADA FILA Y CADA COLUMNA DEL ARCHIVO CSV Y OBTIENE LE CODIGO Y LA RUTA DE LA IMAGEN
    $codigoLista = $row."CODIGO".ToString()
    $PicturePath = "e:\" + $row."FOTOGRAFIA".ToString()
    $perfiles = $upm.GetEnumerator()
    # SE OBTIENE LOS PERFILES DE USUARIO DEL USER PROFILE MANGER 
    foreach($up in $perfiles)
    {

        $codigoUPA = $up["CodigoEmpleado"]

#  SI ENCONTRO UN CODIGO DE EMPLEADO EN EL PERFIL
        if ($codigoUPA)
        {

          # SE COMPARA SI EL CODIGO DE EMPLEADO DEL PERFIL DE USUARIO ES IGUAL  A DEL ARCHIVO
         if ($codigoUPA -eq $codigoLista)
         {
            $FileExists = (Test-Path $PicturePath -PathType Leaf)

            # SE VALIDA SI EL ARCHIVO IMAGEN EXISTE EN LA RUTA INDICADA
            if ($FileExists) {
                $account = $up.AccountName
                $contador = $contador + 1
               write-host $contador " - " $account " - " $codigoUPA " - " $PicturePath

         # SE EJECUTA UN METODO SET-SPPROFILEPICTURES PARA SUBIR LA IMAGEN A SHAREPOINT

    # USER PHOTOS ES LA BIBLIOTECA DE MI SITES DONDE SE GUARDA LAS IMAGENES DE LOS PERFILES DE USUARIO

         set-SPProfilePictures -weburl $farmUrl -picLibraryName "User Photos"  -localFolderPath $PicturePath -accountName $account -up $up
             }
         }
        }
    }
 
    }
}
Write-Host "End of file"

# METODO PARA SUBIR LA IMAGEN DE SHAREPOINT

function set-SPProfilePictures([string]$webUrl, [string]$picLibraryName, [string]$localFolderPath, [string]$accountName, $up)
{
    # CARGA EL SITIO WEB DONDE ESTA LA BIBLIOTECA DE IMAGENES

    $web = Get-SPWeb $webUrl

    # $picLibraryName = “USER PHOTOS”
    $picFolder = $web.Folders[$picLibraryName]
    if(!$picFolder)
    {
        Write-Host "Picture Library Folder not found"
        return
     }
 
        $username = [IO.Path]::GetFileNameWithoutExtension($localFolderPath);
        $fileName = [IO.Path]::GetFileName($localFolderPath);
 
        #SE CARGA EN MEMORIA LA IMAGEN

        $fileStream = ([System.IO.FileInfo] ($localFolderPath)).OpenRead()
        $contents = new-object byte[] $fileStream.Length
        $fileStream.Read($contents, 0, [int]$fileStream.Length);
        $fileStream.Close();
 
        write-host "Copying" $username "to" $picLibraryName "in" $web.Title "..."
 
        #SE ADICIONAL LA IMAGEN EN MEMORIA EN LA BIBLIOTECA USER PHOTOS
        $spFile = $picFolder.Files.Add($picFolder.Url + "/" + $fileName, $contents, $true)
        $spItem = $spFile.Item
 
        # SE OBTIENE LA PROPIEDAD DEL USUARIO QUE GUARDA EL URL DONDE ESTA ALMACENADA LA IMAGEN O FOTOGRAFIA
        $picturePropertyName = GetProfilePropertyName -UserProfileManager $upm -PropertyName "PictureUrl";
 
        if($up -ne $null)
        {
            if (-not [System.String]::IsNullOrEmpty($picturePropertyName))
            {
                $PortraitUrl = CombineUrls -baseUrl $spFile.Web.Url -relUrl $spFile.ServerRelativeUrl;
                Write-Host $PortraitUrl

                # SE ACTUALIZA
                $up.get_Item($picturePropertyName).Value = $PortraitUrl;
                $up.Commit();
            }
        }
 
   
 
    Write-Host "Updating User Profile Photo Store..." -foregroundcolor yellow

    # FINALMENTE ACTUALIZA LA FOTO. MY IMPORTANTE EL PARAMETRO CreateThumbnailsForImportedPhotos SI NO SE INCLUYE A UN ERROR QUE NO PUEDE SER SUBIDA LA IMAGEN SIGUIENTE
    Update-SPProfilePhotoStore -CreateThumbnailsForImportedPhotos 1  –MySiteHostLocation $webUrl
    Write-Host "Done" -foregroundcolor green
}

Y eso es todo, demora la actualización, le sugiero ejecute un debug con el editor de power shell para comprender mejor lo que hace y comentarle que esto demora y esta sujeto a errores sino la imagen no esta correctamente copiada o bien tiene caracteres especiales como tíldes y eñes.  Por lo demás funciona muy bien, pero demora la actualización, al final es mejor que subirla manualmente y pueda que el script lo mejore y optimice para su conveniencia pero depende de usted.  Abajo lo dejo con el script completo que utilice para actualizar las fotografías.

Scripting4Fun!,

Juan Manuel Herrera Ocheita

#--- PRINCIPIO DEL SCRIPT -----

if((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null) {
    Add-PSSnapin Microsoft.SharePoint.PowerShell;
}
function ToSimpleString([string]$value, [bool]$trim = $true, [bool]$removeSpaces = $true,

[bool]$toLower = $true)
{
    if ($value -eq $null) { return [System.String]::Empty; }
 
    if ($trim)
    {
        $value = $value.Trim();
    }
 
    if ($removeSpaces)
    {
        $value = $value.Replace(" ", "");
    }
 
    if ($toLower)
    {
        $value = $value.ToLower();
    }
 
    return $value;
}

function CombineUrls([string]$baseUrl, [string]$relUrl)
{
    [System.Uri]$base = New-Object System.Uri($baseUrl, [System.UriKind]::Absolute);
    [System.Uri]$rel = New-Object System.Uri($relUrl, [System.UriKind]::Relative);
 
    return (New-Object System.Uri($base, $rel)).ToString();
}

function GetProfilePropertyName($userProfileManager, $propertyName)
{
    $propertyName = (ToSimpleString -value $propertyName);
    $propertyName = $propertyName.Replace("sps-", "");
 
    foreach($prop in $userProfileManager.Properties)
    {
        [string]$n = (ToSimpleString -value $prop.DisplayName);
        $n = $n.Replace("sps-", "");
        if ($propertyName -eq $n) { return $prop.Name.ToString(); }
 
        $n = (ToSimpleString -value $prop.Name);
        $n = $n.Replace("sps-", "");
        if ($propertyName -eq $n) { return $prop.Name.ToString(); }
    }
 
    return $null;
}
 
function set-SPProfilePictures([string]$webUrl, [string]$picLibraryName, [string]$localFolderPath, [string]$accountName, $up)
{
    #Get web and picture library folder that will store the pictures
    $web = Get-SPWeb $webUrl
    $picFolder = $web.Folders[$picLibraryName]
    if(!$picFolder)
    {
        Write-Host "Picture Library Folder not found"
        return
     }
 
        $username = [IO.Path]::GetFileNameWithoutExtension($localFolderPath);
        $fileName = [IO.Path]::GetFileName($localFolderPath);
 
        #Create file stream object from file
        $fileStream = ([System.IO.FileInfo] ($localFolderPath)).OpenRead()
        $contents = new-object byte[] $fileStream.Length
        $fileStream.Read($contents, 0, [int]$fileStream.Length);
        $fileStream.Close();
 
        write-host "Copying" $username "to" $picLibraryName "in" $web.Title "..."
 
        #Add file
        $spFile = $picFolder.Files.Add($picFolder.Url + "/" + $fileName, $contents, $true)
        $spItem = $spFile.Item
 
       
        $picturePropertyName = GetProfilePropertyName -UserProfileManager $upm -PropertyName "PictureUrl";
 
        if($up -ne $null)
        {
            if (-not [System.String]::IsNullOrEmpty($picturePropertyName))
            {
                $PortraitUrl = CombineUrls -baseUrl $spFile.Web.Url -relUrl $spFile.ServerRelativeUrl;
                Write-Host $PortraitUrl
                $up.get_Item($picturePropertyName).Value = $PortraitUrl;
                $up.Commit();
            }
        }
 
   
 
    Write-Host "Updating User Profile Photo Store..." -foregroundcolor yellow
    Update-SPProfilePhotoStore –MySiteHostLocation $webUrl
    Write-Host "Done" -foregroundcolor green
}

$InvFile = "arhivoCodigosyRutas.csv"
$farmUrl =  http://misitio.sudominio/

$site=Get-SPSite $farmUrl
$web=$site.RootWeb
$serverContext=[Microsoft.Office.Server.ServerContext]::GetContext($site)
$upm=New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($serverContext)


# Get Data from Inventory CSV File
$FileExists = (Test-Path $InvFile -PathType Leaf)
if ($FileExists) {
   "Loading $InvFile for processing..."
   $tblData = Import-CSV $InvFile
} else {
   "$InvFile not found - stopping import!"
   exit
}

# Loop through file  compare an get an account

"Uploading data to SharePoint...."
$contador = 0
$perfiles = $upm.GetEnumerator()
foreach ($row in $tblData)
{
   $picture = $row."FOTOGRAFIA"
   if( $picture)
   {
    $codigoLista = $row."CODIGO".ToString()
    $PicturePath = "e:\" + $row."FOTOGRAFIA".ToString()
    $perfiles = $upm.GetEnumerator()
 
    foreach($up in $perfiles)
    {
        $codigoUPA = $up["Codigo"]
        if ($codigoUPA)
        {
         if ($codigoUPA -eq $codigoLista)
         {
            $FileExists = (Test-Path $PicturePath -PathType Leaf)
            if ($FileExists) {
                $account = $up.AccountName
                $contador = $contador + 1
                write-host $contador " - " $account " - " $codigoUPA " - " $PicturePath
                set-SPProfilePictures -weburl $farmUrl -picLibraryName "User Photos"  -localFolderPath $PicturePath -accountName $account -up $up
             }
         }
        }
    }
 
    }
}
#User%20Photos
Write-Host "End of file"
# -- FINAL DEL SCRIPT ----

 

Tabla de propiedades del Directorio Activo

Active Directory user attribute
Microsoft.AD.User property
physicaldeliveryofficename Office
displayname displayname
company Company
employeeid Employeeid
department Department
telephonenumber BusinessPhone
homePhone HomePhone
facsimileTelephoneNumber Fax
mobile Mobile
pager Pager
mail Email
givenname FirstName
initials Initials
sn LastName
distinguishedname Distinguishedname
title Title
manager manager
samaccountname UserName
l City
StreetAddress StreetAddress
st State
postalCode Zip
co Country
localeID Locale
msRTCSIP-PrimaryUserAddress SipAddress
objectSid SID
Domain Domain

Referencia oficial y completa en http://technet.microsoft.com/en-us/library/hh524307.aspx