Archivo de la etiqueta: PowerShell

Aumentar el numero de filas del BCS en SharePoint 2010

Después de algún tiempo sin publicar ninguna entrada… he vuelto a sacar un rato para ello. Esta vez, se trata de un error muy común cuando trabajamos con listas externas en SharePoint 2010. Las listas externas están basadas en tipos de contenido externos, los cuales podemos crear a través de BCS (Busines Conectivity Service).

Una vez hemos configurado la nueva cuenta de acceso en el Sercure Storage Service y hemos creado tanto el BCS como la lista basada en el nuevo tipo de contenido externo, accedemos a la lista y vemos el siguiente error:

 

No se puede mostrar este elemento web. Para obtener información sobre
cómo solucionar el problema, abra esta página web en un editor HTML
compatible con Microsoft SharePoint Foundation, como Microsoft SharePoint
Designer. Si el problema persiste, póngase en contacto con el administrador
del servidor web.

Identificador de correlación:9ba64368-5a98-4064-90b8-c9f9681d9e66

Revisando los logs de SharePoint con ese identificador de correlación obtenernos mas información sobre el error:

Error while executing web part: Microsoft.BusinessData.Runtime.ExceededLimitException:
El conector de bases de datos limitó la respuesta. La respuesta de la base de datos
contiene más de '2000' filas. La cantidad máxima de filas que se pueden leer a través
del conector de base de datos es '2000'. El límite puede cambiarse mediante el cmdlet
'Set-SPBusinessDataCatalogThrottleConfig'...

Lo que nos quiere decir este error es que se ha superado el límite de filas por defecto (2000) que se pueden obtener en una consulta, mediante el BCS.

Para solucionar este error, debemos recurrir al PowerShell para aumentar dicho limite…

#Define el Proxy BCS
$bdcAppProxy = Get-SPServiceApplicationProxy | where {$_ -match "BDC_*"}
$throttleDatabaseItems = Get-SPBusinessDataCatalogThrottleConfig -Scope Database -ThrottleType Items -ServiceApplicationProxy $bdcAppProxy
#Muestra los items antes de la modificacion
$throttleDatabaseItems
#Modifica el numero de elementos en base de datos
Set-SPBusinessDataCatalogThrottleConfig -Identity $throttleDatabaseItems -Maximum 1000000 -Default 5000
#Muestra los items despues de la modificacion
$throttleDatabaseItems

 

Script para ver donde se esta usando una caracteristica en SharePoint 2010

Es posible que en algun momento dado neceistes saber, donde se esta utilizando una caracteristica dentro de SharePoint 2010, ya que cuando tienes multiples Web Application con muchas colecciones de sitios, es complicado controlarlo y mas aun, si existen varios administradores de sitio, que pueden activar/descativar caracteristicas (Features) a su gusto…

Si se te ha planteado un situacion similar y quieres disponer de un listado de todos los sitios, donde se esta haciendo uso de una caracteristicas (Features) concreta, puedes usar el siguiente script de PowerShell:

#====================================================================================
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration") > $null
[System.Reflection.Assembly]::LoadWithPartialName("System.Collections.Generic") > $null
#====================================================================================
$ContentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService;
$Farm = [Microsoft.SharePoint.Administration.SPFarm]::Farm.Local;
#====================================================================================
function GetFeatureUsageById([string]$FeatureId)
{
	$FeatureGuid = New-Object System.Guid($FeatureId)
	$FeatureDef=$ContentService.Farm.FeatureDefinitions[$FeatureGuid]
	if($FeatureDef -eq $null)
	{
		Write-Host "WARNING: Característica invalida o desconocida"
		return;
	}
	Write-Host "Ambito de la característica: " $FeatureDef.Scope
	if($FeatureDef.Scope -eq [Microsoft.SharePoint.SPFeatureScope]::Farm)
	{
		Write-Host "WARNING: Característica de granaja no soportada"
		return;
	}
	[Microsoft.SharePoint.Administration.SPWebApplicationCollection] $Applications = $ContentService.WebApplications
	foreach($App in $Applications)
	{
		if($FeatureDef.Scope -ne [Microsoft.SharePoint.SPFeatureScope]::WebApplication)
		{
			foreach($TopLevel in $App.Sites)
			{
				if($FeatureDef.Scope -ne [Microsoft.SharePoint.SPFeatureScope]::Site)
				{
					[Microsoft.SharePoint.SPWebCollection] $AllWebs = $TopLevel.AllWebs
					foreach($Web in $AllWebs)
					{
						  $Feature = $Web.Features[$FeatureId];
						  if($Feature -ne $null)
						  {
								Write-Host $Feature.DisplayName " usado en el sitio: " $Web.Url
						  }
						  $Web.Dispose();
					}
				}
				else
				{
					if($TopLevel.Features[$FeatureId] -ne $null)
					{
						Write-Host "Usado por la Coleccion de Sitio: " $TopLevel.Url
					}
				}
			$TopLevel.Dispose();
			}
		}
		else
		{
			if($App.Features[$FeatureId] -ne $null)
			{
			  Write-Host "Usado por la Aplicacion Web: ",$App.Name
			}
		}
	}
}
#====================================================================================
function GetFeatureUsageByName([string]$FeatureName)
{
	$FeatureDef=$ContentService.Farm.FeatureDefinitions[$FeatureName]
	if($FeatureDef -eq $null)
	{
	   Write-Host "WARNING: Característica invalida o desconocida"
	   return
	}
	$FeatureId=$FeatureDef.Id
	GetFeatureUsageById $FeatureId
}
#====================================================================================
#Llamada a la funcion que devuelve la informacion de la caracteristica
#GetFeatureUsageById "8c0cd022-afa0-4f1b-9bbe-4f128c0cf4b3"
#GetFeatureUsageByName "Document Rating Moderators"

La llamada a este script puedes hacerla de dos forma diferentes:

  • Si dispones del GUID puede llamar al metodo: GetFeatureUsageById “8c0cd022-afa0-4f1b-9bbe-4f128c0cf4b3”
  • Por el contrario si sabes el nombre de la caracteristica puedes usar este otro metodo: GetFeatureUsageByName “Document Rating Moderators”

En el script las llamadas a estos dos metodos estan comentados a modo de ejemplo.

 

Script para habilitar CollectSPRequestAllocationCallStacks en SharePoint 2010

Una tarea que ha de realizar cualquier desarrollador de SharePoint 2010 es la labor de revisar los logs en los diferentes entornos de los que se cuenta…

Revisando los logs de ULS con la aplicación ULS Viewer (verdaderamente útil), me he encontrado con este mensaje de error relacionado con un memory leak (perdida de memoria):

An SPRequest object was not disposed before the end of this thread.
To avoid wasting system resources, dispose of this object or its
parent (such as an SPSite or SPWeb) as soon as you are done using it.
This object will now be disposed.  Allocation Id:
{646667A7-73BC-4DDD-B0FB-6EDFC315CCE7}  To determine where this
object was allocated, set
Microsoft.SharePoint.Administration.SPWebService.ContentService.CollectSPRequestAllocationCallStacks = true.

Este es un mensaje que no nos da mucha información sobre el objeto que esta generando la perdida de memoria al no ser liberado… para obtener mas información lo que debemos hacer es ver la pila de llamadas actual.

Para ello y como se especifica en la descripción del error, lo que debemos hacer es activar la propiedad CollectSPRequestAllocationCallStacks, para ello, lo mas sencillo es usar un script de PowerShell:

$contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
write-host "Actual: " $contentService.CollectSPRequestAllocationCallStacks
$contentService.CollectSPRequestAllocationCallStacks = $true
$contentService.Update()
write-host "Nuevo: " $contentService.CollectSPRequestAllocationCallStacks

Una vez hayamos realizado el cambio podemos volver a revisar los logs de ULS y ahora comprobaremos que nos muestra toda la información de la pila sobre el objeto que no esta siendo liberado.

 

No es posible retirar/eliminar/desplegar una solución Sharepoint 2010

Esto es lo que me ocurrió el día de ayer en uno de mis entornos de SharePoint 2010, al intentar actualizar una versión de una solución (.wsp)… después de intentar retirar la solución con PowerShell, veo que el proceso se queda indefinidamente en “Retracting”.

Intento realizar el mismo proceso desde la Administración Central, pero ocurre lo mismo 🙁

Así que después de un rato esperando… recuerdo que en SharePoint 20007 había un comando que forzaba la ejecución de todos los trabajos (timer jobs) llamado execadmsvcjobs, con lo que desde una consola de PowerShell ejecuto lo siguiente:

stsadm -o execadmsvcjobs

Tras la ejecución del comando, veo que SharePoint comienza a ejecutar todos los trabajos que tenia pendiente (entre ellos el “retract” de mi solución)…

Aquí lo dejo para que mi compañero @Raul Gilabert siempre lo tenga como referencia 🙂

Mas información sobre este comando, aquí.

Scripts para la activación/desactivación de caracteristicas en SharePoint 2010

Una de las muchas cosas que se puede hacer con PowerShell es la activacion/desactivacion de caracteristicas. Me ha ocurrido que hay veces que con el usuario administrador de la granja, no me deja activar caracteristicas desde la Administración Central… y recurro a este tipo de scripts…

Lo primero es la identificación del GUID de la caracteristica que queremos activar/desactivar:

 

#Listado de las caracteristicas de la granaja, ordenado
Get-SPFeature | Sort -Property DisplayName, Id | FT -GroupBy Scope DisplayName,Id

Este seria el resultado de la ejecución del comando Get-SPFeature:

Una vez tenemos el listado de todas las caracteristicas instaladas en la Granaja, solo nos queda localizar y obtener el GUID sobre la que queremos activar/desactivar. A continuacion os indico como se pueden realizar estas acciones a través de script:

#Deshabilita una caracteristica en el sitio: http://url_intranet
Disable-SPFeature –Identity f6924d36-2fa8-4f0b-b16d-06b7250180fa –url http://url_intranet

#Habilita una caracteristica en el sitio: http://url_intranet
Enable-SPFeature –Identity f6924d36-2fa8-4f0b-b16d-06b7250180fa –url http://url_intranet

Puedes consultar mas informacion sobre los comandos: Disable-SPFeature y Enable-SPFeature.

Script para vaciar la papelera de reciclaje secundaria

Un script que nos puede ser de utilidad es el siguiente, ya que muchas veces tenemos mucha informacion que no esta ocupando mucho espacio en base de datos, y que se encuentra en la papelera de reciclaje.

Cuando tu eliminas un contenido en SharePoint, va a la pepelera de reciclaje y si posteriormente lo eliminas de esta pepalera, el contenido, va a una secundaria…

Para ejecutar el script, lo unico que has de modificar el la url del sitio en el que quieres vaciar la papelera de reciclaje secundaria… en este ejemplo he usado “http://url_intranet”, pero deberas sustituirlo por la url de tu sitio…

$mySite = New-Object Microsoft.SharePoint.SPSite("http://url_intranet");
$papeleraQuery = New-Object Microsoft.SharePoint.SPRecycleBinQuery;
$papeleraQuery.ItemState = [Microsoft.SharePoint.SPRecycleBinItemState]::SecondStageRecycleBin;
$papeleraQuery.OrderBy = [Microsoft.SharePoint.SPRecycleBinOrderBy]::Default;
$papeleraElementos = $mySite.GetRecycleBinItems($papeleraQuery);
$Contador = $papeleraElementos.Count;
for($Elemento = 0; $Elemento -lt $Contador; $Elemento++)
{
    $unElemento = New-Object System.Guid($papeleraElementos[$Elemento].ID);
    $papeleraElementos.Delete($unElemento);
}
$mySite.Dispose()

Por ultimo y si te interesa el tema, la clase que posibilita esta funcionalidad es: Microsoft.SharePoint.SPRecycleBinQuery.

 

Script para borrar Colecciones de Sitio sin confirmación

Anteriormente os había habrado de como hacer un backup/restore de una Colección de Sitios en SharePoint 2010 con PowerShell, pues ahora os voy a comentar como borrar cualquier Colección de Sitio.

Este proceso es también muy rápido y sencillo y con una linea puedes llegar a borrar si Sitio que no desees:

#Elimina la Coleccion de Sitio
Remove-SPSite -Identity "http://micoleccionsitio" -GradualDelete -Confirm:$false

Hay que tener en cuenta que no existe una marcha atrás para este proceso a no ser que dispongas de una copia de seguridad.

En cuanto a la ejecución del este script sin confirmación, únicamente se debe al parámetro: -Confirm:$false. Este puede ser usando con mas objetos que implementen el uso de la propiedad -Confirm, para evitar que tengamos que interacturar con los scripts.

Script para la copia de seguridad de Colecciones de Sitio

Hola, hoy quiero mostraros como se puede hacer con PowerShell de una forma rápida y sencilla una copia de seguridad de una Colección de Sitio de SharePoint 2010, con una simple línea de código.

Esta copia lo que hace es generar un archivo fisico en el que se guarda toda la estructura e información del sitio en concreto:

#Backup de la Coleccion de Sitio
Backup-SPSite -Identity http://micoleccionsitio -Path C:\backup_micoleccionsitio.bak

Tan sencillo como la copia es la restauración:

#Restauracion de la Coleccion de Sitio
Restore-SPSite -Identity http://micoleccionsitio_nueva -Path C:\backup_micoleccionsitio.bak

Es importante tener en cuenta que cuando realizamos un backup o copia de seguridad, SharePoint deja en modo lectura la colección de sitios, por lo que no se puede hacer mientras los usuarios estén trabajando, por lo que habrá que programarlo.

Script para controlar el tamaño de los Sitios en SharePoint

Si tienes multiples subsitios dentro de una coleccion de sitios en SharePoint 2010 y quieres saber por cada uno de ellos, cuanto espacio ocupa, en diferentes medidas, aqui os dejo un script de PowerShell muy útil. Además este script, da el tamaño total de la suma de todos.

#====================================================================================
function GetWebSizes ($StartWeb)
{
    $web = Get-SPWeb $StartWeb
    [long]$total = 0
    $total += GetWebSize -Web $web
    $total += GetSubWebSizes -Web $web
    $totalInMb = ($total/1024)/1024
    $totalInMb = "{0:N2}" -f $totalInMb
    $totalInGb = (($total/1024)/1024)/1024
    $totalInGb = "{0:N2}" -f $totalInGb
    write-host "El tamaño de los subsitios bajo:" $StartWeb " es de " $total "Bytes, el cual es " $totalInMb " MB o" $totalInGb "GB"
    $web.Dispose()
}
#====================================================================================
function GetWebSize ($Web)
{
    [long]$subtotal = 0
    foreach ($folder in $Web.Folders)
    {
        $subtotal += GetFolderSize -Folder $folder
    }
    write-host "Sitio:" $Web.Title " tiene " $subtotal "KB"
    return $subtotal
}
#====================================================================================
function GetSubWebSizes ($Web)
{
    [long]$subtotal = 0
    foreach ($subweb in $Web.GetSubwebsForCurrentUser())
    {
        [long]$webtotal = 0
        foreach ($folder in $subweb.Folders)
        {
            $webtotal += GetFolderSize -Folder $folder
        }
        write-host "Sitio:" $subweb.Title " tiene " $webtotal "Bytes"
        $subtotal += $webtotal
        $subtotal += GetSubWebSizes -Web $subweb
    }
    return $subtotal
}
#====================================================================================
function GetFolderSize ($Folder)
{
    [long]$folderSize = 0
    foreach ($file in $Folder.Files)
    {
        $folderSize += $file.Length;
    }
    foreach ($fd in $Folder.SubFolders)
    {
        $folderSize += GetFolderSize -Folder $fd
    }
    return $folderSize
}
#====================================================================================
$siteurl = "http://intranet"
#Llamada a la funcion para devolver el tamaño del la Intranet
GetWebSizes $siteurl

Script para el aprovisionamiento de My Site en SharePoint

Este es uno de los primeros de una serie posts, cuyo objetivo es mostrar como se pueden realizar muchas de las labores de administracion de SharePoint 2010 habituales, con scripts de PowerShell.

Comenzamos con un sencillo script que permite aprovisionar el My Site de un usuario, unicamente hay que llamar a la siguiente funcion:

[Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
Function CreateMySite($siteurl, $loginname)
{
	$site = New-Object Microsoft.SharePoint.SPSite($siteurl)
	$context = [Microsoft.Office.Server.ServerContext]::GetContext($site)
	$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
	if ($upm.UserExists($loginname)) {
		$profile = $upm.GetUserProfile([string]$loginname)
		trap [Microsoft.Office.Server.UserProfiles.PersonalSiteExistsException]
		{
			Write-Host "WARNING: Ya existe el sitio personal del usuario: $loginname" -ForeGroundColor Red
			continue
		}
		write-host "Creando el sitio personal para el usuario: $loginname" -ForeGroundColor Green
		$profile.CreatePersonalSite();
	} else {
		Write-Host "WARNING: No existe el usuario: $loginname" -ForeGroundColor Red
	}
	$site.Dispose()
}

$siteurl = "http://misitio"
$loginname = "DOMINIO\USUARIO"
#Llamada a la funcion para crear el My Site
#CreateMySite $siteurl $loginname

En el caso que quieras provisionar todos los usuarios existentes en el UserProfile, en vez de utilizar la función anterior puedes usar esta otra:

[Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
Function CreateMySite($siteurl)
{
	$site = New-Object Microsoft.SharePoint.SPSite($siteurl)
	$context = [Microsoft.Office.Server.ServerContext]::GetContext($site)
	$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
	foreach ($userobject in $Profiles ) {
		$loginname = $userobject.item("AccountName")
		if ($upm.UserExists($loginname)) {
			$profile = $upm.GetUserProfile([string]$loginname)
			trap [Microsoft.Office.Server.UserProfiles.PersonalSiteExistsException]
			{
				Write-Host "WARNING: Ya existe el sitio personal del usuario: $loginname" -ForeGroundColor Red
				continue
			}
			write-host "Creando el sitio personal para el usuario: $loginname" -ForeGroundColor Green
			$profile.CreatePersonalSite();
			trap
			{
				Write-Host "ERROR: Se ha producido un error al crear el sitio para: $loginname" -ForeGroundColor Red
				continue
			}
		}else{
			Write-Host "WARNING: No existe el usuario: $loginname" -ForeGroundColor Red
		}
	}
	$site.Dispose()
}

$siteurl = "http://misitio"
#Llamada a la funcion para crear el My Site
#CreateMySite $siteurl