Datasheet View for Picture Library

I love metadata, so it’s always annoying when I am suddenly not able to bulk update items in SharePoint. The Picture Library doesn’t come with a datasheet view option. How to get around this?

This URL: htps://SHAREPOINT/sites/SiteCollection/Images/Forms/BatchEdit.aspx?ShowInGrid=True&View=%7BDCBF7E0E%2D60C2%2D4555%2D91C2%2DB086EE2F9FA1%7D&InitialTabId=
Ribbon%2EList&VisibilityContext=WSSTabPersistence

Well almost. Keep this part. Change this part.

First create a view in your picture library that doesn’t have any thumbnails, but does have the columns you want to edit. Put the URL for that view in the part before the “?”

Find the guid for your view. I do that by opening the view in SharePoint Designer, clicking on the WebPartPages web part, and finding the ViewGuid. (If you have an easier way to do this, please share!)

Your guid will look something like this: {DCBF7E0E-60C2-4555-91C2-B086EE2F9FA1}

Replace: { with %7B    – with %2D    and } with %7D

The guid should now look like this: %7BDCBF7E0E%2D60C2%2D4555%2D91C2%2DB086EE2F9FA1%7D and will replace this part of the URL:

htps://SHAREPOINT/sites/SiteCollection/Images/Forms/BatchEdit.aspx?ShowInGrid=True&View=
%7BDCBF7E0E%2D60C2%2D4555%2D91C2%2DB086EE2F9FA1%7D
&InitialTabId=Ribbon%2EList&VisibilityContext=WSSTabPersistence.

You’ll now be able to use this URL to access the picture library in datasheet view.

Checking User Group Membership in Nintex Workflow

I don’t do much with Nintex yet. If I’m able to do my processing with the SharePoint Designer Workflow I will. Unfortunately one thing that can’t be done in SharePoint Designer (OTB) is check if a user belongs to a SharePoint Group. It’s not that straight-forward in Nintex either. Tom O’Connor at CUBE4 wrote a great post instucting exactly how to do it: Nintex: Checking if a user is a member of a SharePoint group.

Create New List Item with Lookup Fields in Workflow

List A and List B both have a lookup field against List C. You’d like to have a workflow so that an entry in List A will generate an entry in List B setting the value of the lookup field from one to the other. However you’re getting the error: “Coercion Failed: Unable to transform the input lookup data into the requested type.”

 

The key is to get the ID of the field from the lookup table. Even though the field you use in the lookup table is the Title, or something else, the value you’re using to set it with will be the ID from the table.

 

SharePoint 2010 Groups Display Item Limit

How to increase the view limit of SharePoint groups from 30. Thanks to Strausy’s SharePoint KB for the answer.

 

  1. Browse to “http://your site collection/_catalogs/users/AllGroups.aspx”
  2. Site Actions > Edit Page.
  3. Modify the List View web part.
  4. Under Selected View click the “Edit the current view” link.
  5. Go to the Item Limit section and choose the radio button for “Display items in batches of the specified size” and Click OK

 

You can now edit the view settings and change the paging value, like other SharePoint list.

Specify Scope in Search Box Web Part

How to specify the scope to be used in the Search Box Web Part and hide the drop down.

Put the search scope into its own Display Group.

In order to specify the scope, you have to select the “Show scopes dropdown”. To hide the dropdown, fix the dropdown width to 1 pixel.

To set the scope, in the Miscellaneous group, set the Scope display group to the group created.

Scheduled Crawls Don’t Execute

Issue:

SharePoint 2010 search crawls not executing when scheduled. Crawls are able to be executed manually, but don’t execute when their next scheduled time arrives.

Resolution:

Clear the time cache. The cache is located on the Search Server at C:\ProgramData\Microsoft\SharePoint\Config\GUID. Delete all of the files EXCEPT the cache.ini file.

Order of steps:

  1. Stop the timer service
  2. Copy the GUID folder to another location as a backup.
  3. Delete all of the files except the cache.ini file.
  4. Open the cache.ini file in notepad and change the numbers just a value of 1. Save the file.
  5. Restart the timer service.

Security Trimming SharePoint 2010 InfoPath Form Fields

UPDATED for SharePoint 2013

Sources:
Security Trimming InfoPath fields with SharePoint 2010 InfoPath Forms Services Based on SharePoint User Groups & Claims-Based Authentication
Infopath List Form – hide/disable fields based on SharePoint group membership
InfoPath: Displaying SharePoint Group List Using “GetGroupCollectionFromUser” method

Additional info required for 2013:
SharePoint 2013, InfoPath and Claims – GetUserProfileByName
http://blogs.technet.com/b/rajbugga/archive/2013/08/07/infopath-over-claims-authentication-sharepoint-2010-amp-2013.aspx

All of the above sources had most of details, but some steps seemed to be missing when I attempted to follow them. However, I would not have been able to figure it out without them.

For 2013, you’ll need to create a Secure Store Service connection. See the information listed under “Additional info required for 2013” on how to do this.

Create the Data Connection

On a form that has been created and published back to SharePoint, create the data connection. Create a new connection to receive data from a SOAP Web Service.

Connect to https://WEBAPP/sites/SITECOLLECTION/_vti_bin/usergroup.asmx.

The operation we need is GetGroupCollectionFromUser.

Set the sample value for the user login name; this is an actual login – probably yours. The web application in my example has Claims Based Authentication, so instead of just domain\username, I needed to enter “i:0#.w|domain\username”.

Save and publish the form.

Modify the Schema

The schema, as it is now, can’t be used. We need to modify it to add in the data fields.

Export the source files.

It’s helpful to make a new folder for just this form (we’ll delete it later.)

CLOSE INFOPATH AND OPEN THE FOLDER JUST CREATED. The file we need to modify should be called GetGroupCollectionFromUser1.xsd. Open it with notepad.

After the line:

<s:import namespace="http://www.w3.org/2001/XMLSchema"></s:import> 

Add the following:

<s:complexType name="GetGroupCollectionFromUserType">
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string"/>
      <s:element minOccurs="0" maxOccurs="1" name="Groups">
        <s:complexType>
          <s:sequence>
            <s:element maxOccurs="unbounded" name="Group" >
              <s:complexType>
                <s:attribute name="ID" type="s:unsignedShort"></s:attribute>
                <s:attribute name="Name" type="s:string"></s:attribute>
                <s:attribute name="Description" type="s:string"></s:attribute>
                <s:attribute name="OwnerID" type="s:unsignedByte"></s:attribute>
                <s:attribute name="OwnerIsUser" type="s:string"></s:attribute>
              </s:complexType>
            </s:element>
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:sequence>
  </s:complexType>

Find this:

<s:element name="GetGroupCollectionFromUser">
   <s:complexType>
     <s:sequence>
       <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string">
         </s:element>
    </s:sequence>
  </s:complexType>
</s:element>

And replace it with this:

<s:element name="GetGroupCollectionFromUser" type="tns:GetGroupCollectionFromUserType">
</s:element>

Save and close the xsd file.

Finish the form design

In the folder with the modified schema, right-click manifest.xsf and design.

*If you don’t use a data connection library, you can skip this step. File name in the DataConnection library would be GetGroupCollectionFromUser.udcx.

** UPDATE for 2013 – You’ll HAVE to use a data connection file and update the file to use the secure store service: <udc:Authentication><udc:SSO AppId=’InfoPathWebService’ CredentialType=’NTLM’ /></udc:Authentication>

Be sure to change the approval status of the connection file to approved.

Form Load Rule

Create a new rule to execute on Form Load.

Add action “Set a field’s value”. Set the field, userLoginName, in GetGroupCollectionFromUser to userName()

** UPDATE for 2013 – Contrary to the above articles, setting the query field to substring-after(userName(), “0#.w|”) did NOT work for me. I had to set it back to userName() – but you may have to try it either way.

Add the action “Query for data”.

Data connection will be GetGroupCollectionFromUser.

Field Rule

Select the field to be secured. Add a new formatting rule.

The condition is where All occurrences of Name (these are the groups the user interacting with the form belongs to) are not equal to the SharePoint Group with permissions.

Save and publish the form.

Update: I had a scenario where we were showing a field (warning you don’t have rights to do this) only if the user was not member of the contributors group. In that case the condition was where “Any occurrence of Name” is equal to “SharePoint Group” than hide control.

2014-11-21_11-55-33

Retrieving Credentials from the Secure Store Service

I hate that once you set the credentials in a Secure Store Service, you can’t see what they are in the GUI. So this script from Bob Guidinger is a fabulous solution. Thanks Bob! (I would have left a comment on your site, but it wouldn’t let me for some reason 😦 )

$context = Get-SPServiceContext -Site HTTPS://WEBAPP1

$provider = New-Object Microsoft.Office.SecureStoreService.Server.SecureStoreProvider
$provider.Context = $context

$marshal = [System.Runtime.InteropServices.Marshal]

try
{
    $apps = $provider.GetTargetApplications()
    foreach ($app in $apps)
    {
       Write-Output "`n$($app.Name)"
        Write-Output "$('-'*80)"
        try
        {
            $creds = $provider.GetCredentials($app.Name)
            foreach ($cred in $creds)
            {
                $ptr = $marshal::SecureStringToBSTR($cred.Credential)
                $str = $marshal::PtrToStringBSTR($ptr)

                Write-Output "$($cred.CredentialType): $($str)"
            }
        }
        catch
        {
            Write-Output "Error getting credentials!"
        }
        Write-Output "$('-'*80)"
    }
}
catch
{
    Write-Output "Error getting Target Applications."
}

$marshal::ZeroFreeBSTR($ptr)

Replace-RequestAccessEmail

Retrieve and update/change access request on all the sites/webs inside a web application that has my email as the access request. Some sites have a branch site managers email group that need to be used as well. Sourced from PowerShell script to update Access Request Email Address for multiple sites and webs and Windows PowerShell: Build a Better Function.

function Replace-RequestAccessEmail {
<#
.SYNOPSIS
Update Access Request containing Specified Email
.DESCRIPTION
Find all the Access Request Settings that have a specified email and replace it with either another account, another account and the Branch Site Managers email, or remove from string
.EXAMPLE
Replace the email address with a new address and the Branch Site Managers email
Replace-RequestAccessEmail -webapp "https://WEBAPP1" -email "Joe.Cool@email" -replace "SPADMIN@email" -SPSiteMgrs
.EXAMPLE
Removes the email address from the string
Replace-RequestAccessEmail -webapp "https://WEBAPP1" -email "Joe.Cool@email"
.PARAMETER webapp
Web Application to cycle through.
.PARAMETER email
Email in Access Request Setting to locate
.PARAMETER replace
(OPTIONAL) Email to use as replacement - leave off to have email removed from string.
.PARAMETER SPSiteMgrs
(OPTIONAL) Include to replace using Site Managers email based on Site Collection
#>
[CmdletBinding()]
param
(
[Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]$webapp,
[string]$email,
[string]$replace,
[switch]$SPSiteMgrs
)
process {
$webapplication = Get-SPWebApplication -Identity $webapp
[string]$trimSites = $webapplication.URL
$trimSites = $trimSites + "sites/"
foreach($site in $webapplication.Sites)
{
foreach($web in $site.AllWebs)
{
if ($web.HasUniquePerm -and $web.RequestAccessEnabled)
{
if ($web.RequestAccessEmail -like "*$email*")
{
$siteCollection = $web.Site | %{$_.URL}
$siteCollection = $siteCollection.TrimStart($trimSites)
Write-Host "Site Collection: " $siteCollection
Write-Host "On Web" $web.Title ", URL" $web.URL
Write-Host "`tAccess requests go to :" $web.RequestAccessEmail
If($SPSiteMgrs.IsPresent)
{
If(!$replace.IsPresent)
{
#Default with Admin Account
$replace = "SPADMIN@EMAIL"
}
switch ($siteCollection)
{
"BRANCH_A" {$requestAccessEmail = "$replace; BRANCH_A.SPSiteMgr@EMAIL"}
"BRANCH_B" {$requestAccessEmail = "$replace; BRANCH_B.SPSiteMgr@EMAIL"}
"BRANCH_C" {$requestAccessEmail = "$replace; BRANCH_C.SPSiteMgr@EMAIL"}
default {$requestAccessEmail = "$replace"}
}
} else
{
$requestAccessEmail = $web.RequestAccessEmail
$reqeustAccessEmail = $requestAccessEmail.ToLower()
$email = $email.ToLower()
$requestAccessEmail = $requestAccessEmail.Replace($email,$replace)
}
# If the Request Access Email would be blank, set to SharePoint Admins Email
If ($requestAccessEmail -eq "")
{
$requestAccessEmail = "SPADMIN@EMAIL"
}
Write-Host "`t***Will Update Request Access Email to: "$requestAccessEmail "***"
$web.RequestAccessEmail = $requestAccessEmail
$web.Update()
}
}
} #end ForEachWeb
#Dispose of the site object
$site.Dispose()
} #end ForEachSite
} #end Process
} #endFunction