lunes, 23 de septiembre de 2013

Sincroniza las propiedades de usuario desde user profile service a la lista de información de usuario

#----------------------------------------------------------------------------- 

# Name:               Sync-SPUserInfoList.ps1   v2

# Description:        This script will update all of the properties in the User

#                     Information List with from the UPS

# Usage:              Make sure the UPS is connected to the Central Admin WebApp 

# By:                 Ivan Josipovic, Softlanding.ca  

#----------------------------------------------------------------------------- 

Add-PSSnapin Microsoft.SharePoint.PowerShell -ea 0;

$ErrorActionPreference = "SilentlyContinue";

  

$PropertyMap=@("Title,PreferredName,Display Name",

"EMail,WorkEmail,EMail",

"MobilePhone,CellPhone,Mobile Phone",

"Notes,AboutMe,About Me",

"SipAddress,WorkEmail,Sip Address",

"Picture,PictureURL,Picture URL",

"Department,Department,Department",

"JobTitle,SPS-JobTitle,Job Title",

"FirstName,FirstName,First Name",

"LastName,LastName,Last Name",

"WorkPhone,WorkPhone,Work Phone",

"UserName,UserName,UserName",

"WebSite,WebSite,WebSite",

"SPSResponsibility,SPS-Responsibility,Ask About Me",

"Office,Office,Office");

 

$Context = Get-SPServiceContext $(Get-SPWebApplication -IncludeCentralAdministration | ? {$_.IsAdministrationWebApplication}).Url;

$ProfileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($Context);

 

if($ProfileManager){

    foreach ($Site in $(Get-SPSite -Limit All | ? {!$_.Url.Contains("Office_Viewing_Service_Cache")})){

        $RootWeb = $Site.RootWeb;

        Write-Host $($Site.Url);

 

        foreach ($User in $($RootWeb.SiteUsers)){

            if ($ProfileManager.UserExists($($User.UserLogin))){

                $UPUser = $ProfileManager.GetUserProfile($($User.UserLogin));

                $UserList = $RootWeb.SiteUserInfoList;

 

                $Query = New-Object Microsoft.SharePoint.SPQuery;

                $Query.Query = "<Where><Eq><FieldRef Name='Name' /><Value Type='Text'>$($User.UserLogin)</Value></Eq></Where>";

                $UserItem = $UserList.GetItems($Query)[0];

 

                ForEach ($Map in $PropertyMap){

                    $PropName = $Map.Split(',')[0];

                    $SiteProp = $UserItem[$PropName];

                    $UPSProp = $UPUser[$($Map.Split(',')[1])].Value;

                    $DisplayName = $Map.Split(',')[2];

  

                    if($PropName -eq "Notes"){

                        #Write-Host "$DisplayName Updated: $SiteProp - $($UPSProp[0].Replace("&nbsp;"," "))";

                        $UserItem[$PropName] = $($UPSProp[0].Replace("&nbsp;"," "));

                    }elseif($PropName -eq "Picture"){

                        #Write-Host "$DisplayName Updated: $($SiteProp.Split(",")[0]) - $($UPSProp[0])";

                        $UserItem[$PropName] = $UPSProp[0];

                    }elseif($PropName -eq "SPSResponsibility"){

                        #Write-Host "$DisplayName Updated: $SiteProp - $($UPSProp -join ', ')";

                        $UserItem[$PropName] = $($UPSProp -join ', ');

                    }else{

                        #Write-Host "$DisplayName Updated: $SiteProp - $UPSProp";

                        $UserItem[$PropName] = $UPSProp;

                    }

                }

                #Write-Host "Saving: $($User.UserLogin)";

                $UserItem.SystemUpdate();

                #Write-Host "";

            }

        }

        $RootWeb.Dispose();

        #Write-Host "";

    } 

}else{

    Write-Host -foreground red "Cant connect to the User Profile Service. Please make sure that the UPS is connected to the Central Administration Web Application. Also make sure that you have Administrator Rights to the User Profile Service";

}

Display Name in SharePoint is out of synch

In some SharePoint installations there is often a problem with display names of users. As an example: The display name of a user in an organization consists of his firstname surname and orginizational unit like:
  • Betty Looser (RD/F)
If Betty gets married and changes her unit, SharePoint should show her new name and unit
  • Betty Winner (FR/I)
but it displays still the old one. More worse in some sitecollections the name is displayed correctly whereas in others not.

Why is this happening ?

This happens because SharePoint stores all user, which were ever logged in a site collection in a special database table "UserInfo Table". This information is stored for every site collection.
The contents of this table are displayed by a hidden SharePoint list called "User Information List". If you are a SharePoint admin, you can display the list information by typing the following url:
  • http://{sitecollection url}/_catalogs/users/simple.apx
When you first visit a SharePoint site collection, your user info is stored in the database table.

But there is a property in the user info table named "tp_IsActive". This property is set when a user in a site collection gets active. "Active" means (from msdn)

"A user is considered "active" if he or she created or modified any data in the site collection."

This property is used by the SharePoint timer jobs, to synch the user information with the profile store. A user information with tp_IsActive = 0 is therefore never updated within a site collection.

That means all user, that have only read rights or have never changed content in a site collection will have the problem with not updated user display names. This problem is also often caused when you grant "All autheticated users" read rights to a site.

Solution

The solution for this problem is to create a PowerShell script and a Windows Task Schedule.

The PowerShell Script

Create a file and name it "UpdateDisplayName.ps1". The script loops throught all user within all sitecollections and checks if their user display name is different that in profile store. If so the user display name is updated. You can change this script easily to change also other properties.


#
# Author: I.B.Bikmaz
#

# Loading Microsoft.SharePoint.PowerShell
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin -eq $null) {  
  Add-PSSnapin "Microsoft.SharePoint.Powershell"
}

# Loading Needed Assemblies
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") | out-null
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server") | out-null
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles") | out-null


<# --------------------------------
  These values can be changed
-------------------------------- #>
# -- Format of the date for the log file
# --
$date = Get-Date -uformat "%Y_%m_%d_%H_%M"

# -- Name of the log file
# -- Create Folder if not exists
$log = "E:\Appl\SP2010\Scripts\UserDisplayNameUpdate_$date.log" 

# -- Url of the web application
# --
$webapp = Get-SPWebApplication "http://sharepoint/"

# -----------END CHANGE-----------
  
  
# Logging!! 
Start-Transcript -path $log 

# Write Starting Date
$processDate = Get-Date
Write-Host "Starting Profile Info Update:" $processDate

# Create the stopwatch
[System.Diagnostics.Stopwatch] $sw;
$sw = New-Object System.Diagnostics.StopWatch
$sw.Start()

<# --------------------------------
  GET ProfilService
-------------------------------- #>
$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager( [Microsoft.Office.Server.ServerContext]::Default )
if ($upm -eq $null){
  Write-Host "Could not find User Profile Manager!"
  exit
}

<# --------------------------------
  Looping through all sites 
  to check if stored user info 
  has changed.
-------------------------------- #>
try {  
  foreach($site in $webapp.Sites) {
    $web = $site.RootWeb
    $siteCollUsers = $web.SiteUsers
    
    Write-Host "> SiteCollection: " $site.Url
    
    foreach( $user in $siteCollUsers ) {  
      $login = $user.LoginName                    
      $dispname = $user.Name
      
      if ($upm.UserExists($login)){
        $profile = $upm.GetUserProfile($login);
        $profilename = $profile["PreferredName"].ToString();
        if ($dispname -ne $profilename){
          Write-Host "  >> Changing '" $dispname "' >> '" $profilename "'"
          $user.Name = $profilename
          $user.Update()
        }          
      }
      
    }
    $web.Dispose()
    $site.Dispose()
  }
}
catch [System.Exception] {
  $_.Exception.ToString();
  Write-Host "Error while updating user info tables."
  Stop-Transcript
  exit
} 
  
$sw.Stop()
Write-Host "Time Elapsed: " $sw.Elapsed.ToString()
Write-Host "User Display Names successfully updated !"
Stop-Transcript


The Windows Task Scheduler

Check the script manually before creating a task schedule. Run the script as SharePoint Farm Account or the account which has admin rights on the user profile service. If you use another user the script will fail.

Open the Task Scheduler in Windows 2008 and create a new task. I think that it will be enough to trigger the task once a week (depens on how many user your company has). Run the task as SharePoint Farm Admin or the account which has rights to use the user profile service.

In the Actions tab choose "Start a program" as Action. Program/script is "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
and argument is:
-command "C:\Scripts\UpdateDisplayName.ps1"

As the script writes a log file you can check if the script runned successfully. The place for the log file can be changed in the script.

viernes, 20 de septiembre de 2013

Explorar soluciones WSP en Windows Explorer

Para poder explorar archivos de soluciones SharePoint .wsp, podermos hacerlo directamente con el explorador de Windows. Para ello debemos introducir unas lineas al registro de Windows.
  1. Creamos el archivo wspfiletype.reg
  2. Click derecho del mouse - Edit:
    Edit the created .reg file
  3. Pegamos el siguiente contenido:
    Windows Registry Editor Version 5.00
    
    [HKEY_CLASSES_ROOT\.wsp]
    @="CLSID\\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}"
    "InfoTip"="Contains compressed files"
    
    [HKEY_CLASSES_ROOT\.wsp\PersistentHandler]
    @="{098f2470-bae0-11cd-b579-08002b30bfeb}"
    
    Paste the registry snippet
  4. Guardamos los cambios.
  5. Doble click sobre el archivo .reg para importar los cambios al registro de Windows.
  6. Reiniciamos explorer.exe
  7. Ahora tomamos la solucion SharePoint (el archivo .wsp), le agregamos la extensión .cab y ya podemos explorar la solución:
    Exploring WSP file as a regular CAB file