Tuesday, May 31, 2016

Upgrade MySite to SharePoint 2013 but the photos are not linking back

So I didn't want to follow the Microsoft recommended directions to upgrade mysite for upgrading the service applications for Metadata and the user profile service.   Which  was fine for the metadata service since they weren't using anything on it.   But the user profile service does present one issue, the photo, which is stored in the user profiles.  


But I do have all the pictures on the mysite since it is stored at the root web under the User Photos library.  


here is the script to update the user photos with powershell,   replace the TODO with your information:




[Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
$siteurl = "TODO fill in mysite url"
$site = New-Object Microsoft.SharePoint.SPSite($siteurl)
$context = [Microsoft.Office.Server.ServerContext]::GetContext($site)
write-host $site.RootWeb.Lists["User Photos"]
#Get list of photos
$list = $site.RootWeb.Lists["User Photos"]
$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
Write-host $list.Items.Count
foreach($listitem in $list.Items)
{
    if($listitem["Name"].ToString().Contains("LThumb") )
    {
      #  Write-host $listitem["Name"].ToString()
        $user = $listitem["Name"].ToString().Replace("_", "\").Substring(0, $listitem["Name"].ToString().LastIndexOf("_"))
    #    write-host $user
        $fullphotourl = $siteurl + "User%20Photos/Profile%20Pictures/" + $listitem["Name"].ToString();
        write-host $fullphotourl
        if ($upm.UserExists($user))
        {
            $profile = $upm.GetUserProfile($user)
            $profile["PictureURL"].Value = $fullphotourl;
            $profile.Commit();
        }
   
    }
}
$site.Dispose()

Infopath template update does not complete apply when the document has digital signature

Encountered a strange issue where the form library template does not get fully applied with the changes when the document is signed using the browser.   If you open the form using the client, the templates gets applied and everything is kosher.


So tried all the basic things to get the browser form to upgrade or relink the form with the update template but no go.


Only one thing would work so, I had to write a little powershell script to open the forms with the InfoPath filler and submit it so that the form is saved with the template updates.




if the file is bigger than 50 MBs, you have to change the setting on the client machine.  it is defaulted to 50MB but you have files that are bigger so the registry setting has to be changed to increase the FileSizeLimitInBytes value located at [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\WebClient\Parameters]

find the TODO and replace with your own value
--------------------------------------------------------

Import-Module "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -AssemblyName Microsoft.Office.Interop.InfoPath
#url
$site = "TODO:  url of the site"
#user name
$admin = "TODO: account name with domain.  I used user@domain"
#Get Password as secure String
$password = Read-Host "Enter Password" -AsSecureString
#Get the Client Context and Bind the Site Collection
$context = New-Object Microsoft.SharePoint.Client.ClientContext($site)
#Authenticate
$credentials = New-Object System.Net.NetworkCredential($admin , $password)
$context.Credentials = $credentials
write-host "authenicated"
$web = $context.Web
$context.Load($web)
$context.ExecuteQuery()
write-host $web.Title

$list = $context.Web.Lists.GetByTitle("TODO: ListName to be filled in")


#write-host $list.Title
$context.Load($list)
$context.ExecuteQuery()
write-host $list.Title
write-host $list.

$query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(1000, "Title");
$items = $list.GetItems($query);
$context.Load($items);
$context.ExecuteQuery();

 #$context.Url
write-host $items.Count
$iApp = New-Object  Microsoft.Office.Interop.InfoPath.ApplicationClass
#$sdoc = New-Objct Microsoft.Office.Interop.InfoPath.XDocumentClass
$versionMode = New-Object Microsoft.Office.Interop.InfoPath.XdDocumentVersionMode
foreach($li in $items)
{
    #write-host  $li["Title"].ToString()
   
    $url = "TODO: Url of the list" + $li["Title"].ToString()
  
   #write-host $url
   try
   {
    $xdoc = $iApp.XDocuments.Open($url) #, $versionMode.xdCanTransformSigned)
        $xdoc.Save()
            $xdoc.CloseDocument()
             write-host  "Done 1:  "  $li["Title"].ToString()
    }
    catch
    {
        try
        {
            $xdoc = $iApp.XDocuments.Open($url, 18)  # 16 for $versionMode.xdCanTransformSigned + 2 for xdUseExistingVersion)
             $xdoc.Save()
            $xdoc.CloseDocument()
             write-host  "Done 2:  "  $li["Title"].ToString()
        }
        catch {
            $ErrorMessage = $_.Exception.Message
          
             write-host  "ERROR:  " $ErrorMessage " ::: " $li["Title"].ToString()
        }
    }
   
   
}

$context.Dispose()

Tuesday, April 26, 2016

Upgrade from SharePoint 2013 to SharePoint 2016 issues

I created a new 2016 farm in another domain (development) so that i can test the upgrade from a 2013 farm.  The content upgrade is nice and simple as stated in all the blogs and documentation from microsoft.

Here is the big issue:   Workflow farm!

The 2010 workflows work fine since it is included with the content database but with the workflow farm introduced in 2013, there are multiple parts that needs to be there for it to work like the Application management service which gives the permissions for the workflow by the realms.  

Since the upgrade for 2016 service applications does not include the Application management, i'm stuck.  Here are the things i tried so far

  • follow the disaster recovery instructions with minor tweeks for WF pointing to the correct service bus, no go.
  • try to copy the activities to the new farm, no go.
  • try to re-publish the 2013 workflow in a new workflow farm, no go.  
  • possible thoughts but this will not work either due to the app management service, which was to share or use the same workflow farm from the 2013 sharepoint farm and the 2016 sharepoint farm.   


Here is another issue to consider, while doing the 2010 farm to 2013 upgrade, i could upgrade one web application at a time with no issues.   But with the 2013 to 2016 upgrade, i can not do this since the workflow farm holds all the 2013 farms web applications workflows in the same database (WFResourceManagementDB).  This causes some issues since if there is a simple fix for the first issue above then all the web applications need to be upgraded or the 2013 farm needs to point to the 2016 workflow farm.

Will update as i find the solution(s) to the issues found so far.   

Tuesday, April 5, 2016

Powershell script to generate powershell script to toggle publish feature

Add-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$url = {your url here}
$site = get-spsite $url
$feature = $site.features.Item('f6924d36-2fa8-4f0b-b16d-06b7250180fa')
        
    if($feature -ne $null)
       {
            $ConfirmPreference = 'None'
       #     $feature
       #     Write-Host Disable-SPFeature -Identity $feature.DefinitionId -Url $site.Url -Force  -WarningAction SilentlyContinue
            Write-Host enable-SPFeature  -Identity $feature.DefinitionId -Url $site.Url  -Force   -WarningAction SilentlyContinue
      
       }
foreach($w in $site.AllWebs)
{
  #  Write-Host '#--------------------------------------------------------------------------------------'
  #  $w.Url
    $feature = $w.features.Item('94c94ca6-b32f-4da9-a9e3-1f3d343d7ecb')
        
    if($feature -ne $null)
       {
       $ConfirmPreference = 'None'
         #   $feature
         #  Write-Host  Disable-SPFeature -Identity $feature.DefinitionId -Url $w.Url -Force  -WarningAction SilentlyContinue
            Write-Host enable-SPFeature  -Identity $feature.DefinitionId -Url $w.Url  -Force   -WarningAction SilentlyContinue
      
       }

}

Friday, February 19, 2016

SharePoint 2013 workflow can't terminate using UI: Terminate using powershell

Had a strange situation where the workflow instance will not terminate using the UI.   When I click on the status, it just gave an error so after tracking down what the error was in the uls which didn't give too much information but that something was a null where a value was expected: 


Getting Error Message for Exception System.Web.HttpUnhandledException (0x80004005): Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.ArgumentNullException: Value cannot be null.


at Microsoft.SharePoint.Workflow.SPWorkflow.retrieveSchema(Schema schemaIndex)


at Microsoft.SharePoint.Workflow.SPWorkflow.retrieveSchemaGuid(Schema schemaIndex)


at Microsoft.SharePoint.Workflow.SPWorkflow.get_AssociationId()


at Microsoft.SharePoint.Workflow.SPWorkflow.GetReadOnlyParentAssociation()


at Microsoft.SharePoint.Workflow.SPWorkflow.get_ParentAssociation()
.......




Here is the powershell to terminate the workflow instance that is suspended.  a slightly modified script from http://social.technet.microsoft.com/wiki/contents/articles/23850.sharepoint-2013-workflow-management-starting-a-workflow-using-powershell.aspx






Add-PSSnapin *sharepoint* -ErrorAction SilentlyContinue


$sourceWebURL = '<url to your web>'
$sourceListName = '<list name>'
$TargetWorkflow = '<workflow name>'
$itemId = <Id of the item the workflow you want to stop>


$spSourceWeb = Get-SPWeb $sourceWebURL
$spSourceList = $spSourceWeb.Lists[$sourceListName]

#-- Getting a Workflow manager object to work with.
$wfm = New-object Microsoft.SharePoint.WorkflowServices.WorkflowServicesManager($spSourceweb)
#-- Getting a Workflow instance in order to perform my commands.
$wfis=$wfm.GetWorkflowInstanceService()


$wfinstances = $wfis.EnumerateInstancesForListItem($spSourceList.ID, $itemId)
foreach($wfi in $wfinstances)
{
    if($wfi.Status -eq "Suspended")
    {
        $wfi
        $wfis.TerminateWorkflow($wfi)
    }
}

Tuesday, February 2, 2016

SharePoint 2013 Usage service trouble shooting

Recently my farm encountered an issue with the Usage statistics not showing up in my reports but the data was still getting captured in the database.  


first thing to check are some status for your service application


$app = Get-SPServiceApplication -Identity '{Your usage service app guid}'


the get the usageapplication for some properties and status:


$ua = Get-SPUsageApplication -Identity $app


$ua.Status




if everything looks good, then make sure your usage definitions have Receivers:


$aud = Get-SPUsageDefinition | where {$_.Name -like "Analytics*"}


$aud | fl


$prud = Get-SPUsageDefinition | where {$_.Name -like "Page Requests"}


$prud | fl




Look at your results to make sure you have the following
-------------
EnableReceivers : True

Receivers : {Microsoft.Office.Server.Search.Analytics.Internal.AnalyticsCustomRequestUsageReceiver}





EnableReceivers : True

Receivers : {Microsoft.Office.Server.Search.Analytics.Internal.ViewRequestUsageReceiver}






finally if that's all good then unprovision your usage app and then go provision using Central admin:


first to unprovision:


$app = Get-SPServiceApplication -Identity '{Your usage service app guid}'
$app.Unprovision()


then in Central Admin, Monitoring, Configure usage and health data collection
-enable
-check items you want collected
-database name
-windows auth
-Ok


-----------------------------------------------------------------------------------------------------------------
Some very helpful links:


http://blogs.msdn.com/b/sharepoint_strategery/archive/2015/04/15/sp2013-search-index-health-reports-for-monitoring-and-troubleshooting.aspx




https://gallery.technet.microsoft.com/scriptcenter/Builds-SP-Search-2013-10d72a25


https://gallery.technet.microsoft.com/scriptcenter/Get-SPSearchTopologyState-b7452c6a



Thursday, January 14, 2016

Create an Identity or incremental field based on Fiscal Year with a workflow in SharePoint

So I got a request from a customer who uses SharePoint 2013 that they need to create an identifier that looks something like this:  FY15 XXXX  


the XXXX is the identity number that starts from 1 at the new Fiscal year (the client's fiscal year starts in October).


This is an interesting problem that everyone encounters.  So I gave it a thought and came up with a solution that removes the concurrency concerns and other factors that could cause issues.


Here is the solution that's been tested and is working:


first create the column called: 
  • FiscalYear
    • number
    • Default: 
      • calculated value: =IF(MONTH(Today)>=10,YEAR(Today),YEAR(Today)-1)
      • This calculation is based on the fiscal year starting in October
  • IdentifierID
    • string or number:  I used String so that it is easier to append to my real id
    • Please note that the images have been modified so if you see UniqueID or UniqueID0, that was the original name of the field IdentifierID.


ok.  now the fun part of the exercise.  Creating a workflow on the list.


I created two stages:  Main and Sleep.  
  • Main:  does all the work, like call web service and calculate the ID
  • Sleep:  pauses for a minute for other items created previous to the current item to get their IdentifierID


Main:
  • variable to sleep = No
  • build the requestheader dictionary
  • call web service
    • https://MySharePointSite/_api/web/lists/getbytitle('NameOfList')/items?$top=1&$select=IdentifierID&$filter=(ID lt [%Current Item:ID%] and FiscalYear eq [%Current Item:FiscalYear%])&$orderby=ID desc
    • the key is here:
      • get the top 1 item
      • filter by ID less than currentItemID and FiscalYear equals CurrentItemFiscalYear
      • Order by ID desc
  • get results into listitems dictionary
  • get count of items in listitems dictionary
    • this is so that I know if it is the first item in the new Fiscal Year
  • then get the IdentifierID
  • Process the IdentifierID



  • go to End of Workflow


Sleep:
  • Pause for a minute for other workflow instances on previous items to complete
  • go back to main