Filtering out lists that are not SharePoint libraries

The best way to filter out SharePoint lists when iterating the collection of lists is by Template ID.  However it’s not that easy to get the template ID.  Interestingly, GUIDs are somewhat less than random when generated by Microsoft for their internal products. For example, the Feature ID GUID’s last 3 digits is actually the Template ID:

$GUID = $list.TemplateFeatureId.ToString()
$TemplateID = $GUID.substring($guid.length-3)
if ($TemplateID -ne "101")
{
write-host "skipping non-DocLib List $($list.title)"
continue;
}

Granting myself site collection admin access

Sometimes one needs to grant themselves site collection admin access, here’s two kinds of site collection admin status assignments:

$meStr = "domain\administrator";
$w = get-spweb "http ://subdomain.domain.com/sites/Projects"
$me = $w.ensureuser($meStr)
$me.issiteadmin
$me.issiteadmin=$true
$me.update()

Or set Primary or secondary:

Get-SPSite -Limit All | ?{$_.url -notlike "*/Departments/"} | %{Set-SPSite $_ -OwnerAlias "" -SecondaryOwnerAlias ""}

Don’t forget to pipe your SPContentDatabases and even all SPDatabases into an AddSPShellAdmin CmdLet to ensure DB access for yourself is granted.

Uploading pictures into ActiveDirectory remotely via PowerShell

One can upload pictures into PowerShell remotely. A few requirements:
1. Install RSAT; ; that’s adding the Feature in Computer Management
2. Have remote web services running on AD
3. Have sufficient access; you must be member of either the Organization Management or Recipient Management role groups to upload the pictures.
4. Have a set of photos, preferably named with the user accounts, JPGs, 96×96 and less than 10kb

Here’s what’s needed in PowerShell to get started using AD CmdLets:

Import-module ActiveDirectory
if ((Get-PSSnapin -Name ActiveDirectory -ErrorAction SilentlyContinue) -eq $null ){
            import-module ActiveDirectory
}

here’s how to see the existing picture for a given user:

$user = Get-ADUser [user] -Properties thumbnailphoto
$user.thumbnailphoto.length
$user.thumbnailphoto | Set-Content "C:tempJtest3a.jpg" -Encoding byte -Force

Testing in Outlook: Pictures are cached in Outlook for the duration of the session. To check whether the picture is available, one has to totally exit Outlook.

$LocalFiles = get-childitem -Path $WorkingPath -filter $TypeFilter | where {!$_.PSIsContainer}

To upload the picture, get the user:

$User = Get-ADUser -Filter {SamAccountName -eq $Name}

Let’s get the photo after resizing to 96×96 ensuring it is less than 10k

$Photo = [byte[]](Get-Content "$WorkingPath$File" -Encoding byte)
Set-ADUser $Name -Replace @{thumbnailPhoto=$Photo}

Creating Fields and Content Types cleanly in SharePoint

when creating Content Types in SharePoint, it’s nice to script the process, for planning and repeatability. Here’s a nifty routine that allows a single line creation of Site Columns and Content Types.

First, here’s the routine to create Site Columns. The here-string XML is replaced with placeholders filled by parameters. Note the convenient parameters:

function tryAdd-TextField ([Microsoft.SharePoint.SPWeb] $web, [string] $DisplayName, [string] $InternalName, [string] $Group, [Boolean] $Hidden, 
[Boolean] $Required, [Boolean] $ShowInDisplayForm, [Boolean] $ShowInEditForm, [Boolean] $ShowInNewForm )
{
$fields = $web.fields;
try
{
    $q=$fields.getFieldByInternalName($InternalName); 
} catch
{
    $q=$null;
}
 
if ($q -ne $null)
{
Write-Host "$($InternalName) already exists!, no action taken to create this site column"
}
else
{
$fieldXMLString = '
 '
 
 $FieldXMLString = $FieldXMLString.Replace("@InternalName",$InternalName.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@DisplayName",$DisplayName.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@Group",$Group.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@Hidden",$Hidden.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@Required",$Required.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@ShowInDisplayForm",$ShowInDisplayForm.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@ShowInEditForm",$ShowInEditForm.tostring())
 $FieldXMLString = $FieldXMLString.Replace("@ShowInNewForm",$ShowInNewForm.tostring())
 
 $web.Fields.AddFieldAsXml($fieldXMLString)
 }
 }
function tryAdd-CT ([Microsoft.SharePoint.SPWeb] $web, [string] $Field, [string] $Group, [string] $Parent, [string] $Name, [string] $Description )
{
    try
    {
        $ctypeParent = $web.availablecontenttypes[$Parent]
 
    }
    catch
    {
        $ctypeParent = $null;
    }
 
    if ($ctypeParent -eq $null)
    {
        write-host "Content Type $($Name) not created because there was a problem finding the Parent Content Type $($Parent)"
    }
    else
    {
    $ctype = new-object Microsoft.SharePoint.SPContentType($ctypeParent, $web.contenttypes, $Name)
    $ctype.Description = $Description
    $ctype.group = $Group
 
    if (![string]::IsNullOrEmpty($field))
    {
    foreach ($fld in $field.split("|"))
     {
        $f=$web.fields.getFieldByInternalName($fld)  
        $link = new-object Microsoft.SharePoint.SPFieldLink $f
        $ctype.FieldLinks.Add($link)
     }
    }
 
    try
    {
        $ctype = $web.contenttypes.add($ctype)
    }
    catch
    {
        write-host "Content Type $($Name) already exists"
    }
    }
}

Let’s now create some site columns:

tryAdd-TextField -web $Web -DisplayName "Year"    -InternalName "YearACT"    -Group "Actuarial" -Hidden $False -Required $False -ShowInDisplayForm $True -ShowInEditForm $False -ShowInNewForm $False
tryAdd-TextField -web $Web -DisplayName "Quarter" -InternalName "QuarterACT" -Group "Actuarial" -Hidden $False -Required $False -ShowInDisplayForm $True -ShowInEditForm $False -ShowInNewForm $False
tryAdd-TextField -web $Web -DisplayName "Month"   -InternalName "MonthACT"   -Group "Actuarial" -Hidden $False -Required $False -ShowInDisplayForm $True -ShowInEditForm $False -ShowInNewForm $False
tryAdd-TextField -web $Web -DisplayName "LOB"     -InternalName "LOBACT"     -Group "Actuarial" -Hidden $False -Required $False -ShowInDisplayForm $True -ShowInEditForm $False -ShowInNewForm $False

Here’s how to create a Content Type with one field:

tryAdd-CT -web $Web -Field $null -Group "Actuarial"  -Parent (select-parent)  -Name "My Core ACT" -Description "Core Actuarial Document"

Note in the comment below, the fields can be passed in pipe-delimited

tryAdd-CT -web $Web -Field "YearACT|QuarterACT|MonthACT|LOBACT" -Group "Actuarial"  -Parent "My Core ACT" -Name "General (ACT)" -Description "General Actuarial Document"

Folder, File size and timestamp analysis using PowerShell

In just a few lines, one can generate a CSV of all files and their attributes including size and timestamp. I prefer to use TSV (tab delimited) to ensure embedded characters like quotes or commas don’t disrupt the CSV layout.

$q = Get-ChildItem "\serverReserve" -Recurse
#$q | ConvertTo-Csv -NoTypeInformation | out-file "D:DivActAnalyticsACTRDriveFoldersFiles.csv" 
$q2 = $q | select PSPath,PSChildName,   PSIsContainer,BaseName,Length,Name,FullName,Extension,CreationTime,LastAccessTime,LastWriteTime 
 
foreach ($qItem in $q2)
{
   $qItem.PSPath = $qItem.PSPath.replace("Microsoft.PowerShell.CoreFileSystem::","")
}
 
$q2 | ConvertTo-Csv -NoTypeInformation -delimiter "`t" | out-file "D:myFolderReport.csv"

Encoding and Decoding URLs in PowerShell

URLs in SharePoint are often filled with “%20” in place of blanks, and other substitutions.

However, there are times when the original clean URL is desired. The “%20” references are known as “encoded” URls. URL encoding replaces unsafe ASCII characters with a “%” followed by two hexadecimal digits.

URLs can only be sent over the Internet using the ASCII character set. However for emailing or auditing URLs, sometimes the decoded URL is desired.

Here’s how to Encode and Decode an URL in PowerShell:

$EncodedURL = [System.Web.HttpUtility]::UrlEncode($URL)
$DecodedURL = [System.Web.HttpUtility]::UrlDecode($URL)

Industry-standard encoding is described in detail at: http://www.w3schools.com/tags/ref_urlencode.asp

PowerShell Scripting Services can greatly enhance automation processes. When working with SharePoint, having a reliable Sharepoint development company is crucial for efficient collaboration and data management.

For More, Contact reach Reality Tech a trusted provider of SharePoint online development services to explore your options further

 

Fixing taxonomy terms after a Metalogix Migration

When migrating from SharePoint 2010 to 2013 using the Metalogix Content Matrix 7.0.0.1 migration tool, a taxonomy issue was encountered. The individual term from the SP2010 source was not applied to the SP2013 destination and associated with the correct term set and term.

The destination taxonomy field appeared empty in every sense. It was not displayed when viewing the Item, nor in the list view.

However one remnant of the term did appear in a surprising place. Within the read-only property bag of the item (item.XML) there was a field with what appears to be a GUID devoid of dashes as property name, with a value that seems somewhat usable.

Additional Read

How to Choose the Right SharePoint Migration Tool and Service Partner?

The property value in this case was “a466a2acd62b498291c78829c2bb5fe3”.
item.GetFormattedValue(“a466a2acd62b498291c78829c2bb5fe3”) gets the value, as does item[“a466a2acd62b498291c78829c2bb5fe3”]
This is the GUID of the target field associated with the termset.
To make this more generic, I set the targetField to the field name we are looking for, and derive the GUID generically this way.

[Microsoft.SharePoint.Taxonomy.TaxonomyField]$taxonomyField = $item.Fields.GetField($targetField)

Then stripped off the dashes, to get it into the format that appears in the property bag:

$FieldGUID = $taxonomyField.id.Guid.tostring().replace("-","")

Then I derive the value for the property:

$FQterm = $item[$fieldGUID]

The value appears in the internal format, so I strip off any text appearing after a pipe:

$fqTerm = $FQterm.Substring(0,$FQterm.IndexOf("|"))

To match to the appropriate term, we need to handle the situation where a text value can appear under multiple parents. So we walk the hierarchy to find the single correct match. First we split the term into colon delimited segments:

$termHierarchy = $FQterm.Split(":")

Then check parent term matching to narrow to one appropriate matching term. This assumes checking two levels finds the match. It can be extended to match 7 levels deep if needed:

if ( $TC.count -gt 1)
{
  $termIdx=-1;
  if ($termHierarchy.count -ge 2)
  {
     $ParentTerm = $termHierarchy[$termHierarchy.count-2];
  }
  else
  {
    $ParentTerm = $null;
  }
 
  for ($ti=0; $ti -lt $TC.count; $ti++) #loop to ensure parent is right one
  {
     if ($TC[$ti].parent.getdefaultlabel(1033) -eq $parentTerm)
     {
       $termIdx = $ti;
     }
  }
}

Start Your SharePoint Online Migration Project In A Click

Our technology and wide delivery footprint have created billions of dollars in value for clients globally and are widely recognized by industry professionals and analysts.

SharePoint 2013 issues with IE11

Working with IE11, Web Part pages could not be edited in the browser. Web parts could not be selected during creating the page, and the web part properties could not be presented for editing. The problem seems to be specific to IE11. It works great in IE10.

The solution is to set the hostname for the web part to run in Compatibility Mode.

To get it to work, here’s what I did:
1.Press ALT + T when viewing the SharePoint page
2.Click Compatibility View Settings in the menu
3.Click Add to add the current SharePoint site to the list of compatibility view pages
4.Click Close

That’s it. Not only does the page work, but other aspects of the page come back to life.

Happy browsing!

Changing URL Style Within VBA

I recently encountered an issue when a user within a file-select popup navigated to SharePoint via an http: reference, causing the code to fail. It turns out, the code worked great with UNC notation.

The routine below prompts for Excel files, and changes any reference to http: and corrects the / orientation to and then saves it into the active cell:

Sub browseWorkbooks()
Dim FileSpec As String
 
FileSpec = Application.GetOpenFilename("All Excel Files (*.xl*;*.xlsx;*.xlsm;*.xlsb;*.xlam;*.xltx;*.xltm;*.xls;*.xla;*.xlt;*.xlm;*.xlw),*.xl*;*.xlsx;*.xlsm;*.xlsb;*.xlam;*.xltx;*.xltm;*.xls;*.xla;*.xlt;*.xlm;*.xlw", , "Select source workbook")
     If FileSpec <> "False" Then
        'Change to UNC
        FileSpec = Replace(FileSpec, "http:", "")
        FileSpec = Replace(FileSpec, "/", "")
        ActiveCell = FileSpec           
     End If

PowerGUI vs. PowerShell ISE

Boy, have I become dependent on PowerGUI for PowerShell scripting?  I’ve recently been compelled to use the ISE that comes with Windows, and the differences manifest directly in reduced productivity.

Here are some issues encountered with ISE:

– No concurrent separately threaded sessions
– No object explorer pane
– no split pane
– weak top icon actions
– No auto-shading of matching braces
– adds carriage return to console window for each step in debugging
– No way to directly see $error output
– Weak Auto-indenting
– No way to just “Pause” execution
– Can’t add tabs into code
– Shortcuts don’t work, like shift-ctrl-C for commenting code
– poor coloring of breakpoint highlighting
– Icons don’t work for stop/start debugging