viernes, 28 de octubre de 2016

¿Por qué "no funcionan" las políticas de retención?

Recientemente un cliente me solicitó que desactivara un "contrato" de una lista de contratos una vez la fecha de "Caducidad" fuera alcanzada. Esta lista es una custom list, con un montón de metadatos personalizados y ficheros adjuntos. La fecha de "Caducidad" es un campo de tipo "Fecha y hora" (llamado "Automatic expiration") dentro de la misma lista. Por "desactivar" entendemos que hay otro campo de tipo booleano (llamado "Active"), que indica si el contrato está activo (="Yes") o inactivo (="No").

Sabiendo que el camino más fácil y rápido para lograr este objetivo es definir una política de retención, así lo hice: Creé un workflow muy sencillo que modificaba el valor del campo booleano, pasando de "Yes" a "No", y una política de retención para ejecutarlo una vez se alcanzara la fecha indicada por el campo "Automatic expiration" + 1 día (Día después de haber caducado).


Una vez implementado este sencillo proceso, creé un contrato de prueba y esperé a que se alcanzara la fecha (al día siguiente) para comprobar si había funcionado o no.

Para variar, como muchas veces en la vida, las cosas no funcionaron a la primera. La data había vencido, pero el contrato seguía activo. ¿Por qué?

La respuesta, en esta ocasión es fácil de entender y también de solucionar:

En la administración central de SharePoint existen 2 Timer Jobs encargados de ejecutar las políticas de retención:
  • "Information management policy"
  • "Expiration policy"
Por defecto estos Timer Jobs están configurados para ejecutarse semanalmente, así que este tipo de políticas basadas en un día concreto, solo se verían reflejadas una vez por semana.

Sabiendo esto, si vamos a la sección Monitoring de la administración central y pulsamos sobre "Job Definitions", podemos buscar estos dos Timer Jobs en la app web que nos concierna, pulsar sobre su nombre y modificar su ejecución para que sea diaria en lugar de semanal:


Tened en cuenta que es importante que el Timer Job "Information management policy" debe ejecutarse ANTES que el "Expiration policy". En mi caso programé el primero para las 2 a.m. y el segundo para las 3.a.m.

Guardamos nuestros cambios y, ahora sí, todas la políticas de este tipo que tengamos bajo esta aplicación web, van a funcionar perfectamente (salvo caída del servicio, claro está).

Para comprobarlo podemos forzar un "Run now" y quedarnos así, con una sonrisa al ver que todo funciona como esperábamos que lo hiciera.

¡¡Saludos y hasta la próxima!!

jueves, 20 de octubre de 2016

Control permanente para autenticarse como otro usuario

Según mi experiencia, una de las "pérdidas" más incomprensibles que sufrimos al migrar a SharePoint 2013 desde SharePoint 2010 es que el usuario pierde la capacidad de autenticarse como otra persona.

En terminales compartidos, como salas de formación, puede llegar a ser un verdadero calvario tener que explicar constantemente a los usuarios que para realizar dicho proceso, deben añadir a la URL del navegador la extensión _layouts/closeConnection.aspx?loginasanotheruser=true (ver post relacionado).

Esta operación manual retorna al nuevo usuario a la raíz del site collection, donde puede ser que no tenga permisos de acceso, y es bastante engorroso encontrarse con un error de acceso no autorizado tras cada re-login.

Para hacerle la vida más fácil al usuario, y tener una solución permanente de simple uso y acceso, recomiendo fehacientemente añadir el control en el menú de usuario, tal y como se muestra en la siguiente imagen.


La solución es relativamente sencilla, siempre que tengáis acceso a los servidores de SharePoint.

Se trata de añadir en el fichero "\15\TEMPLATE\CONTROLTEMPLATES\Welcome.ascx"  el siguiente código justo antes del control que tiene el ID "ID_RequestAccess" (Editar con Notepad):

  <SharePoint:MenuItemTemplate runat="server" ID="ID_LoginAsDifferentUser" 
    Text="<%$Resources:wss,personalactions_loginasdifferentuser%>" 
    Description="<%$Resources:wss,personalactions_loginasdifferentuserdescription%>"
    MenuGroupId="100" 
    Sequence="100" 
    UseShortId="true" 
    />


El fichero resultante debería tener un aspecto como el siguiente:


Guardamos el resultado y aplicamos lo mismo a todos los servidores frontales (WFE) que tengamos en nuestra granja.

Si no queremos aplicarlo en toda nuestra granja, y tan solo lo necesitamos en un site/site collection específico, siempre podemos añadirlo a nuestra master page, añadiendo un control bajo la etiqueta <div id="suiteBarButtons"> y copiando el siguiente código entre los tags <SharePoint:FeatureMenuTemplate ....> y </SharePoint:FeatureMenuTemplate>


<SharePoint:MenuItemTemplate runat="server" id="MenuItem_SignInAsDifferentUser"
         Text="SignIn As Different User"
         Description="To log in as a different user"
         MenuGroupId="200"
         Sequence="250"
         UseShortId="true"
         ClientOnClickNavigateUrl="~siteLayouts/closeConnection.aspx?loginasanotheruser=true"
         PermissionMode="All"
/>


El resultado será el mismo, pero el ámbito estará limitado a donde aplique dicha .master page.

Con cualquiera de las dos soluciones, el control de "Sign in as different user" debería aparecer en el menú de control de usuario. Es multi-language por defecto y redirige al mismo sitio y página desde la que se efectúa la operación, así que es perfecto para nuestros propósitos.

Al ver los resultados, uno no puede evitar preguntarse: ¿Por qué no está incluido OOB? Pero todos sabemos que a Microsoft les encanta darnos trabajo a los consultores de SharePoint (cosa que, personalmente, debo agradecerles, claro está...).

En fin,  ¡Eso es todo por hoy amigos!