PSCredential object used in automatic Full User Profile Synchronization

In category SharePoint | August 30, 2014

As part of governance plan, full user profile synchronization may require to be run automatically weekly in your organization. While there are large number of great articles on the Internet providing you magical scripts to automatically trigger full synchronization process with Windows Server Task Scheduler, they still miss a few things you may not have paid attention to.

See an example below that supports you in full synchronization:

$ups = Get-SPServiceApplication <GUID>
$ups.StartImport($true)

The missing case is if User Profile Synchronization Service is not started, this script doesn’t work. You would need the if-else function to check the status of User Profile Synchronization Service then start it.

$svcPwd = ConvertTo-SecureString -AsPlainText -String "d0ntPutpwdHere-pLease" -Force
$svcAcc = (get-spfarm).defaultserviceaccount
if($syncSvc.Status -eq "Disabled")
{
  Write-Host "Provisioning User Profile Synchronization Service"
  $ups.SetSynchronizationMachine($syncServer, $syncSvc.ID, $svcAcc, $svcPwd)
}
else
{
  Write-host "User Profile Synchronization Service is"$syncSvc.Status
}

Ironically the account you use is Farm account and its password displaying as plain-text format. This is highly risky if the script is accessible to someone (he simply needs to open Task Scheduler to trace location of the script).

To really mask the password, you can implement PSCredential to create SecureString object. First, enter the following command then type your password.

Read-Host “Enter your password:” -AsSecureString | ConvertFrom-SecureString | Set-Content B:pwd.txt 

The password is encrypted to be stored in B:pwd.txt. If you want to see it, use the following command:

Get-Content B:pwd.txt

If you set the variable of your password is encrypted string, User Profile Synchronization service will not accept it once it’s triggered to be run. What we need to do is convert the encrypted password to basic string (BSTR). See the code snippet below:

$svcAcc = “MicrosoftFarm” ## Account to run User Profile Synchronization service
$encryptedPwd = Get-Content C:pw.txt | ConvertTo-SecureString
$svcPwd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($encryptedPwd))

Below is the full code snippet you can use along with Task Scheduler to run Full User Profile Synchronization.

Add-PSSnapIn Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

## Sets variable for User Profile Service Application
$ups = Get-SPServiceApplication |?{$_.displayname -eq "User Profile Service Application"}

## Sets variable for service instance
## If you have multiple sync services are running, specify the ID. Enter the following command to check
## ## $upsID = get-spserviceinstance | ? {$_.Typename -eq "User Profile Synchronization Service"} | Select Status, ID, Server
$syncSvc = Get-SPServiceInstance |?{$_.id -eq "6c905cfd-9808-4e67-93a6-dae3f877bf9a"}

## Sets variables for farm account and password. Password is encrypted to be stored in C:pw.txt
$svcAcc = "Microsoftfarm"
$encryptedPwd = Get-Content C:pw.txt | ConvertTo-SecureString
$svcPwd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($encryptedPwd))

## Sets variable for synchronization server
## If you have multiple server, specify the one you want synchronization service to be started
$syncServer = get-content env:computername

if($syncSvc.Status -eq "Disabled")
{
  Write-Host "Provisioning User Profile Synchronization Service"
  $ups.SetSynchronizationMachine($syncServer, $syncSvc.ID, $svcAcc, $svcPwd)
}
else
{
  Write-host "User Profile Synchronization Service is"$syncSvc.Status
}

while ($syncSvc.Status -eq "Provisioning")
{
    $syncSvc = Get-SPServiceInstance |?{$_.id -eq "6c905cfd-9808-4e67-93a6-dae3f877bf9a"}
    Write-Host $syncSvc.Status
    sleep 3
}
Write-Host $syncSvc.Status

## Start Full Synchronization
$profileApp = @(Get-SPServiceApplication | ? { $_.TypeName -eq "User Profile Service Application" })[0] 

$serviceContext = ([Microsoft.SharePoint.SPServiceContext]::GetContext(
         $profileApp.ServiceApplicationProxyGroup,
         [Microsoft.SharePoint.SPSiteSubscriptionIdentifier]::Default)) 

$configManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileConfigManager($serviceContext)
 if($configManager.IsSynchronizationRunning() -eq $false)
 {
 $configManager.StartSynchronization($true)
    Write-Host "Started Synchronizing"
 }
 else
 {
    Write-Host "Already Synchronizing"
 }

The code below is to check the full synchronization function will not be executed until the User Profile Synchronization service is already started.

while ($syncSvc.Status -eq "Provisioning")
{
    $syncSvc = Get-SPServiceInstance |?{$_.id -eq "6c905cfd-9808-4e67-93a6-dae3f877bf9a"}
    Write-Host $syncSvc.Status
    sleep 3
}

I would like to thank HungT – my great colleague who supported me to make this script.

Reference:

Share

Leave a Reply