jueves, 26 de septiembre de 2013

Comportamiento aparentemente errático de las Apps que muestran el contenido para algunos usuarios y a otros no en SharePoint 2013 On Premises o local con los mismos niveles de permisos

Este fue un error que me costo encontrar donde estaba el problema por lo que creo que es de utilidad compartir con ustedes la solución del problema.

Escenario:

SharePoint 2013 Idioma Español versión Standard con un hotfix de Marzo 2013 instalada.

Las apps fueron desarrolladas para para SharePoint online y nadie nos había reportado este problema pero luego de instalarla en un cliente en SharePoint 2013 On Premises, reportaron que algunos usuarios no veían el contenido de ninguna App.  Estas mostraban diferentes contenidos como imágenes, links, información de los empleados.

Probamos de todo, diferentes navegadores, diferentes computadoras, y siempre que el usuario ingresaba con su usuario y contraseña en diferentes computadoras y navegadores, n o les mostraba el contenido de ningún App.

Por lo que publique el problema en el foro de technet.microsoft.com relacionado con Apps en SharePoint 2013.

http://social.technet.microsoft.com/Forums/en-US/75b55f98-c4db-49e5-9001-4997ff5f5966/some-users-do-not-display-the-contents-of-app-part-and-do-not-show-any-errors-on-sharepoint-2013-on?prof=required

Allí me aconsejaron que descargará fiddler y revisará el tráfico entre el navegador y el servidor.  Y el error que reportaba fiddler al intentar autenticarse para acceder los archivos JS de no autorización.

Bueno luego de analizar la información y realizar muchas pruebas hayamos el problema.  Los usuarios que tenían acceso limitado al Internet eran los que las Apps no podían renderizar el contenido a pesar que tenían acceso a las listas e imágenes del App Web y  el problema se debía a que todas las Apps tenían una referencia a la librería microsoft.ajax.js en la nube y esto evitaba que el contenido lo pudiesen ver.  La línea de código era la siguiente:

<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js">

La Solución:

Bueno se descargó el archivo microsoftAjax.js en una carpeta de scripts dentro del App y se hizo referencia de esta.  Se publicó de nuevo cada App y el problema se resolvió.

Apps4Fun!,

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

domingo, 25 de agosto de 2013

Integración Continua - Creando un Build en Team Foundation Service para desplegar un App en SharePoint Online

 

Para pruebas es muy útil contar con una herramienta que nos permita instalar o desplegar el App de SharePoint automáticamente en un sitio de SharePoint Online en Office 365 y esto es precisamente lo que hace Team Foundation Service que es la versión Online de Team Foundation Server y que para 5 usuarios es gratuita (para más información ver http://tfs.visualstudio.com). 

Escenario:

Para este artículo vamos a crear un proyecto de Apps para SharePoint SharePoint Hosted es decir que se hospedará en SharePoint a diferencia de los otros proyectos Auto Hosted (Azure) y Provider Hosted (Terceros) este no utiliza código de servidor sino únicamente Javascript con lo cual tiene sus ventajas y sus desventajas, entre las ventajas es que es muy rápido para el usuario final, para el programador fácil de instalar el App pero entre las desventajas es el no poder escribir código de servidor y por ende la exposición del código de lado del cliente.

http://msdn.microsoft.com/en-us/library/office/apps/fp179887.aspx

Este proyecto debe de ser desplegado para propósitos de prueba en un sitio de SharePoint Online para desarrollador, por lo que el script deberá ser modificado para que cree el paquete y lo instale en el sitio de desarrollador en SharePoint Online.

El proceso:

Para poder automatizar el proceso es necesario contar con un Script que ejecute los comandos necesarios para instalar el App en SharePoint Online.  Para obtener este script debemos de visitar la siguiente dirección:

https://officesharepointci.codeplex.com/

Este sitio permitirá descargar un archivo OfficeSharePointCI.zip este contiene un archivo OfficeToolsAppTemplate.xaml como plantilla del proceso de Build especializado para construir e instalar las Apps de SharePoint.

También contiene los scripts necesarios para instalar el App para ello es necesario 4 scripts:

Parameters.ps1
Common.ps1
DeploymentFunctions.ps1

SharePointAppDeploy.ps1

De los cuales el último es el principal que llama a los otros y que debe de ser el seleccionado para asociarlo a la definición del Build.  Cómo se muestra en la imagen de abajo.

image

Como vamos a modificar los scripts para este ejemplo las buenas prácticas dictan que debemos de subirlas al control de versiones en TFS como se muestra en la imagen de abajo:

image

Vamos a revisar los scripts para ver que hace cada uno.  Empecemos con parameters.ps1

Este tiene los parametros que va utilizar el script SharePointAppDeploy.ps1 que ya modificado contiene lo sigueinte:

# SharePoint account used to deploy the app.
$SpDeployUsername = "micuenta@midominio.com"
$SpDeployPassword = "*******"
$SpDeployUserDomain = ""

Básicamente contiene la declaración de las variables a utilizar que como es SharePoint Online no se utiliza la variable que define el dominio.


common.ps1


image


Contiene los métodos que encapsulan los comandos de powershell comunes para realizar la instalación del App en SharePoint, más adelante veremos como estos son invocados en el script principal.


DeploymentFunctions.ps1


image


Entre las funciones que podemos destacar de este script esta Install-App el cual recibe como parámetros el contexto del client, el Web site de SharePoint la ruta del archivo de resumen.  Basicamente esta función toma el paquete del app y lo instala via comando de Powershell y basado en el contexto del cliente obtenido por medio del parámetro que recibió el método.


SharePointAppDeploy.ps1

# Recibe los parametros de la definición del Build en TFS como se muestra en la imagen de abajo.
Param (     [Parameter(Mandatory = $true)]     [string]$dropLocation,     [Parameter(Mandatory = $false)]     [string]$summaryFile
)
# Cambia la ruta para cargar los scripts arriba mencionados
cd "$(Split-Path $MyInvocation.MyCommand.Path)"

. .\ParametersSPDeploy.ps1
. ..\Common.ps1
. .\DeploymentFunctions.ps1
# La ruta donde se instalará el App y que es un sitio para desarrollador
$SharePointDeployServerUrl = "https://midominio.sharepoint.com/sites/developer"

try {     Write-Host "Connecting to $SharePointDeployServerUrl..."
    # invoca el método Create-SharePointClientContext del script common.ps1 y utiliza las variables declaradas en el script Parameters.ps1     
$clientContext = Create-SharePointClientContext $SharePointDeployServerUrl $SpDeployUserDomain $SpDeployUsername $SpDeployPassword               
# Declara la variable $web con el valor de la instancia del sitio web donde se va a instalar el app
$web = $clientContext.Web     
# Se le indica que debe de ser cargado en memoria
$clientContext.Load($web)     
# Se ejecuta los comandos arriba mencionados esto viaja al servidor y devuelve los valores solicitados
$clientContext.ExecuteQuery()     
# Varios comandos en una sola linea, el primero obtiene el paquete del App desde la ubicación de descarga o droplocation luego el paquete es instalado utilizando el método Install-App del Script DeploymentFunctions.ps1
Get-AppPackages $dropLocation | Install-App $clientContext $web $summaryFile     
}
catch {     Write-Error "Error occurred: " $_.Exception.ToString()
}

Y eso es todo en cuanto los scripts ahora como esto se integra con TFS y se ejecuta para ello vamos a crear un proyecto tipo SharePointHosted que lo denominaremos SharePointApp1


image


Luego que va a ser de tipo SharePoint Hosted App y que va ser instalada para depuración en un sitio de desarrollador en Office 365


image


Para ello es necesario tener una suscripción en Office 365 de prueba para desarrollador o bien alquilada.   Para más información visite el siguiente link: http://msdn.microsoft.com/es-es/library/office/apps/fp179924(v=office.15) 


image


o si ya tiene una haga clic en validate e ingrese sus credenciales, como se muestra abajo en la imagen.


image


Le mostrará una ventana de dialogo de conexión exitosa.


image


Presione el botón finish para continuar.


Esta App para efectos de concentrarnos en al automatización de la instalación solo mostrará además del usuario un titulo que indica Integración Continua


image


Si Presionamos F5 veremos lo que hace y muestra el App.  Nos solicitará que nos autentiquemos en Office 365


image


image


Bueno ahora con el proyecto abierto vamos a crear la definición del Build.  Para ello vamos a utilizar Team Explorer, en la sección Home en la opción Builds.


image


Seleccionamos la opción New Build Definition


image


Al hacer esto nos solicitará las credenciales para Team Foundation Service


image


Definimos un nombre para la definición SharePointApp1 Build.


image


Definimos el disparador o Trigger, Integración continua para cada Check-in construya o compile el App


image


Ahora seleccionaremos los predeterminados del Build, como lo són el controlador y la carpeta de descarga o drop folder de la fase de construcción.


image


En el Proceso esta la clave para poder desplegar el App en un sitio de SharePoint Online.  En Show details debemos seleccionar la plantilla xml para Office que descargamos del sitio de codeplex y subimos al control de versiones de TFS.


image


Seleccionamos el botón New y este levantará una ventana de dialogo New Build Process Template y selecionamos la opción Select an existing XAML file y luego el botón Browse


image


Seleccionamos la ubicación donde subimos la plantilla OfficeToolsAppTemplate.XAML, la seleccionamos y presionamos el botón ok dos veces para cerrar la ventana de dialogo anterior.


image


Ahora cargará la nueva plantilla y en la seccion 3.Advanced en el campo MSBuild Arguments colocamos el valor /p:IsPackaging=true


image


Ahora en la sección 4.Misc en el campo Deployment Script seleccionaremos el script que instalará el App en un sitio de desarrollador distinto que esta planificado sea donde se realizarán las pruebas finales del App. el cual en este ejemplo es https://midominio.sharepoint.com/sites/developer


image


Deberá visualizarse similar a la imagen de abajo.






image



Para finalizar vamos a guardar el build y a realizar un cambio para validar que la integración continua funcione.


Agregamos a la etiqueta h3 de la pagina default.aspx un texto Ready !, lo guardamos.


image


Y hacemos un Checkin del cambio


image


Luego desde el Team Explorer de Visual Studio 2012 seleccionamos Builds y nos desplegará el build que se esta ejecutando


image


Revisamos que esta en progreso y esperamos que termine


image


Y nos deberá mostrar que ha terminado con éxito. Y seleccionamos el enlace View Build Details


image


Y luego al revisar el detalle nos muestra la dirección url donde podemos abrir el App.




image


Nos solicitará autenticarnos en Office 365.




image


Y guala! aquí esta el App con el cambio listo para realizar pruebas de explorarción, de UI y otros en un sitio distinto al sitio donde depuramos la aplicación antes de hacer el checkin.


image


En este artículo vimos como automatizar el proceso de instalación de un App para SharePoint en Office 365.


Hasta la próxima,


Juan Manuel Herrera Ocheita

domingo, 18 de agosto de 2013

Error típico: El Usuario cuando busca por un sitio en especifico no encuentra nada, pero si selecciona todos los sitios si devuelve resultados en SharePoint Server

Este error es muy común desde la versión 2007 de SharePoint en cualquiera de sus ediciones hasta la última versión de SharePoint 2013.

El problema tiene un origen y se debe a que la zona predeterminada o Default Zone no es la misma que la dirección url definida en las fuentes de contenido del motor de búsqueda, y esta debe de ser la misma.

Para comprender mejor como resolverlo vamos a ver donde se define el Mapeo de Acceso Alternativo o AAM. 

Para este ejemplo vamos a utilizar SharePoint 2013 pero es aplicable a las versiones anteriores de SharePoint 2013.

En el Central Administration , seleccionamos Application Management, luego Configure alternate access mappings.

 

image

Ahora seleccionamos la Web Application del puerto 80 para el caso de este ejemplo.

image

Luego seleccionamos Edit Public URLs

image

Ahora debemos de cambiar la dirección de Intranet por la predeterminada ya que es la que esta utilizando para realizar las búsquedas en le motor de búsqueda y en intranet colocamos la default, que en este caso el el nombre del servidor o hostname.

image

Ahora deberá ejecutarse nuevamente la indagación o crawling.

image

Ahora podremos buscar a nivel específico por biblioteca o por sitio.

image

Y eso es todo!.

 

SharePoint4Fun!,

Juan Manuel Herrera

jueves, 25 de julio de 2013

Publicando un Tipo de Contenido en SharePoint Online

Iniciaremos indicando que los Tipos de Contenido o Content Type están diseñados para reutilizarse en cualquier lugar de nuestro portal online y esto lo hace a través de un Hub o Concentrador, que en SharePoint se conoce como Content Type Publishing Hubs o Concentrador de Publicación de Tipos de Contenido  que estos son replicados periódicamente por un proceso interno de la granja de SharePoint llamada Timer Job para replicar esta información a todas las colecciones de sitio existentes dentro de la instancia de la granja de SharePoint Online.

Una de las ventajas que ofrece Microsoft en SharePoint Online es que ya esta configurado debidamente para que funcione la distribución de los tipos de contenido, no nos tenemos que preocupar por la tubería como si lo debemos hacer en una versión on premises o local. Por lo que esta opción pueda que se ajuste del todo a la versión en la nube.

Donde encontrar el Hub del tipo de Contenido en SharePoint Online.  Para ello vaya a Settings, Site Settings, Content type publishing.

image

Para encontrar este sitio “escondido” tienes que ubicarte en el sitio raiz de cualquier colección de sitio a al que tengas acceso y ejecutar los pasos de arriba mencionados.

image

Haga clic sobre la dirección que le muestra en la sección Hubs

https://yourdomain.sharepoint.com/sites/contentTypeHub/_layouts/15/mngctype.aspx

image

Ahora vamos a crear un nuevo tipo de Contenido llamado Company

image

Name: Company

Select partent content type from: List Content Types

Parent Content Type: Item

New Group: [Your custom group name]

Para finalizar presione el botón OK

image

Ahora vamos agregar las otras columnas.  Para ello haga clic sobre Add from existing site columns y seleccione Address y presione el botón Add >

image

y presione el botón OK

image

Ahora vamos agregar otra columna nueva, por lo que seleccionamos la opción Add from new site column

image

En Column Name escribimos Phone numbers

image

En New Group escogemos un nombre para agrupar columnas nuevas, para finalizar presionamos el botón OK

image

Así hacemos para cada columna que deseamos agregar.  En resumen podrías tener un tipo de contenido con las siguientes columnas

image

Ahora procederemos a publicar el Tipo de Contenido para ello dentro el, tenemos una opción llamada “Manage publishing management policy settings” hagamos clic sobre ella.

image

Solo validamos que este seleccionada la opción Publish y presionamos el botón OK

image

Ahora tenemos una colección de Sitio llamada Sales

image

El trabajo de sincronización tipo de contenido no he podido determinar el tiempo pero típicamente he esperado al día siguiente, por lo que estimo sean 12 horas por lo menos. Así que después de ese tiempo, usted debería ser capaz de ver el tipo de contenido publicado en otras colecciones de sitios, en este ejemplo el sitio Sales ya muestre el nuevo tipo de contenido llamado Company.

image

Si nos vamos a la configuración del sitio de Sales y Y seleccionamos la opción Content type publishing del menú Settings y de la sección Site Collection

https://[your doamin name]/sites/sales/_layouts/15/contenttypesyndicationhubs.aspx

Encontraremos que el sitio tiene un subscripción del nuevo tipo de contenido

image

Ahora vamos aplicar el Tipo de Contenido a una lista de SharePoint, nos trasladamos para este ejemplo a la colección de sitios Sales

image

Y seleccionamos Site Contents para agregar una nueva lista

image

Y seleccionamos la opción add an app

 

image

Luego el icono Custom List

image

Luego escribimos un nombre como por ejemplo Companies

image

Seleccionamos el nuevo objeto creado haciendo clic sobre el Icono

image

Seleccionamos la opción List

image

Luego List Settings

image

Luego la opción Advanced settings para habilitar los tipos de contenido para esta lista.

image

Seleccionamos Yes para permites los tipos de contenido de la lista y presionamos el botón OK para continuar.

image

Buscamos la sección Content Types y seleccionamos la opción Add from existing site content types

image

Seleccionamos el grupo que creamos para ubicar el tipo de contenido publicado y luego presionamos el botón Add> y luego el botón OK

image

Ahora vamos a seleccionar la opción Change new button order and default content type

image

Quitamos la selección de Item en la casilla Visible y presionamos el botón OK

image

Hacemos clic sobre Companies para revisar la lista

image

Ahora hacemos clic sobre new item

image

 

Y eso es todo amigos ya podemos utilizar este nuevo tipo de contenido en cualquier colección de sitios de nuestro SharePoint Online, y cualquier cambio que se haga al origen será replicado a todas las otras colecciones de sitio.

SharePointOnline4Fun!,

Juan Manuel Herrera