Tuesday, February 18, 2014

Very high opening/viewing numbers in audit log

I recently had an issue where I was seeing crazy numbers of downloads from a document library in the site collection audit logs - 20k downloads from one user across a two day period when the library only contained 300 documents. The culprit? Outlook. Any client that allows a user to sync the contents of a document library, will write entries into the audit log every time a sync occurs. Outlook is one application that most users have that will allow syncing offline. This is initiated via a button in the Ribbon of the document library:

image

 

 

 

Fortunately there’s a workaround. In the Advanced Settings of the document library, there’s an option to prevent offline clients from syncing content from the library:

image

If you make this change to a library:

  • New connections to the library can still be created by clicking “Connect to Outlook” but the sync will never succeed
  • Existing connections will still exist in Outlook but attempts to sync will fail:image
    • This message only briefly appears on-screen when you manually do a “Send / Receive”
    • When “Send / Receive” is done in the background, the user is not warned with the above message
    • There is also no visual indication that the syncing of a library no longer occurs which may or may not be a good thing

I also tested this with Colligo Email Manager, and unfortunately changing the “Offline Client Availability” has no effect – Colligo could still sync the contents of the library offline.

Monday, June 17, 2013

Posting multiple parameters to a Web API project using jQuery

Ok this one had me stumped.  I was trying to pass multiple parameters to a Web API method using jQuery but no data would bind to my data transfer object when the method executed.

*Note that this is a good example of how to pass multiple parameters to a Web API method when you take the issue discussed into consideration

The Controller

public class UserDTO
{
   public int userID;
   public string username;
}

[HttpPost]
public string Post([FromBody]UserDTO userDTO)
{
   return userDTO.userID.ToString() + " " + userDTO.username;
}

The Web API route config

config.Routes.MapHttpRoute(
   name: "DefaultApi",
   routeTemplate: "api/{controller}/{id}",
   defaults: new { id = RouteParameter.Optional }
);

The jQuery

var apiUrl = "http://localhost:55051/api/User";
var userDTO = {
   userID: 5,
   username: "testuser"
};

$.ajax({
   type: "POST",
   url: apiUrl,
   data: JSON.stringify(userDTO),
   datatype: "json",
   contenttype: "application/json; charset=utf-8"
)};

Fiddler Output

Fiddler shows correctly passed JSON variables and in the Raw view I can see:
{"userID":5,"username":"testuser"}

On Execution

userID = 0
username = null

The Issue?

Case sensitivity on the .ajax jQuery call:
  • datatype should be dataType
  • contenttype should be contentType
Thanks to those at StackOverflow for assistance with this one!

Wednesday, December 15, 2010

Moving a Records Center: Bad Idea

Moving a SharePoint 2010 records center will cause several issues of varying significance.

Document Management Implications:

  • If you have a custom Send To location allowing users to submit documents to the record center, this URL will need to be updated
    • A simple change
  • If your Send To location leaves a reference to the file in the original location, this will be broken:image
    • When clicking on the file reference you will see an error message “File not found”
    • This is irreversible

Records Center Implications:

  • All content organizer rules will have incorrect URL’s to the destination library, so these all need to be updated
    • A time consuming change if you have a lot of rules
  • Any document library/records library with retention schedules will be irreversibly broken in that you can no longer manage the schedule.  All libraries will need to be re-created, content migrated, and retention schedules added
    • The symptoms of this are detailed below in section “Broken Records Library Symptoms”
    • I have found no way to get around this other than recreating all libraries!!!
    • A very time consuming change if you have a lot of libraries, content, or complex retention schedules
    • Note: to delete record libraries you need to remove all records, then run the "Hold Processing and Reporting" timer job in Central Administration.  When this is complete, you can delete the records library.  Thanks to Michal Pisarek on MSDN for this one.

Broken Records Library Symptoms

When trying to manage the retention settings on the records library I see the error:

1. Click on Change source or configure library schedule:

manage the retention schedule

2. An error occurs:

error

3. And in the logs (nothing very helpful):

Exception Thrown: StartIndex cannot be less than zero.

Parameter name: startIndex Inner Exception: StartIndex cannot be less than zero.

Parameter name: startIndex

Recommendation

If you are using a single records center for managing retention, putting the records center in it’s own site collection is a good idea.  This also adds isolates the content from a security perspective.  You can always manually add links to the record center where necessary for people that need to access it from the main application.

Plan the Information Architecture up front – this one needs a good home from that start.

Tuesday, December 14, 2010

Delete document library option missing on settings page

You can’t delete a document library if it contains records.  This is a sensible feature considering that documents declared as records would logically have some retention requirement…

To delete:

  1. Undeclare your records or move them to another location
    1. If you’re working with a large document library with many folders etc. you could create a “Records View”, by filtering out any documents where the “Declared Record” field is not blank:
    2. image
    3. When all are deleted/moved, the delete option appears again in the settings page
  2. Delete the document library

Monday, November 15, 2010

PowerShell: file renaming en-masse

You may have come across the following error message when uploading files in SharePoint:
The file name is invalid or the file is empty. A file name cannot contain any of the following characters: \ / : * ? " < > | # { } % ~ &
But what if you have hundreds or thousands of files that DO include one or more symbols, and you need to move them onto SharePoint?
The following PowerShell script will replace a string in a filename with another string you provide.  It doesn’t alter file extensions or folders.  The script can be executed with command line parameters, however if they are not provided, it will prompt you for input.  The following parameters are used:
  • The directory e.g. “C:\test”
  • The text to find e.g. “&”
  • The replacement text e.g “and”
  • An optional switch that specifies whether to recurse through subfolders: –recurse
An example of how to use this script would be:
  • fileRenamer.ps1 “C:\test” “&” “and” –recurse
If you execute the script with no parameters, it will ask you to enter the directory, find, and replacement values in turn, but it won’t ask for whether you’d like to recurse.  It will default to non recursive.

Error Handling

The only issue this script handles is when the provisional new file name for a file already exists e.g. you are changing Q&A.doc to QandA.doc, and this filename is already in use.  In this instance, the script will notify the user that the rename operation has been cancelled and summary information is added to the end of the script.

Script Output

The script prints its progress to the console, and also provides some summary information at the end:
image

Disclaimer

Use at your own risk. I will not be held responsible for any actions and/or results this script may cause.  If you choose to use this script; test it first, and only run on directories/files with backups as the implications of renaming large numbers of files are serious and the operation cannot be undone.

The Code

Paste this into a new file and save it as “fileRenamer.ps1” or similar.
param(
    [switch]$recurse,
    [string]$directory = $(read-host "Please enter a directory"),
    [string]$find = $(read-host "Please enter a string to find"),
    [string]$replace = $(read-host "Please enter a replacement string")
)

# Startup text
echo "This script will replace words in files of any type.  It will not modify file extensions."
echo ""
echo "WARNING: This action cannot be undone; use at your own risk!"
echo ""

# Setup variables
$modifiedcounter = 0
$counter = 0
$exceptioncounter = 0
$exceptionfilenames = ""
$files = ""

echo "Replacing text '$find' with '$replace' in all filenames..."
echo ""

if ($recurse)
{
    # Grab all files recurse
    $files = get-childitem $directory -include *.* -recurse
}
else
{
    $files = get-childitem $directory *.*
}

foreach ($file in $files) {
    $filename = $file.Name
   
    # Only run if this is a file
    if ($filename.IndexOf('.') -gt 0)
    {
        $name_noextension = $filename.SubString(0, $filename.LastIndexOf('.'))
        $extension = $filename.SubString($filename.LastIndexOf('.'), $filename.Length-$filename.LastIndexOf('.'))

        echo ("Filename:          " + $file.FullName)
        #echo "Extension removed: $name_noextension"
        #echo "Extension:         $extension"
       
        # If there is a match then attempt to rename the file
        if ([regex]::IsMatch($name_noextension, ".*$find.*")) {
            # Change the filename
            $name_noextension = $name_noextension.Replace($find, $replace);
            $newname = $name_noextension += $extension
           
            #echo "New name:          $newname"

            # Test to see whether a file already exists
            if (Test-Path ($file.DirectoryName + "\" + $newname))
            {
                # A file already exists with that filename
                echo ("Action:            A file exists with the name " + ($file.DirectoryName + "\" + $newname) + " so this action has been cancelled.")
                $exceptioncounter++
                $exceptionfilenames += ($file.DirectoryName + "\" + $newname)
            }
            else
            {
                # Rename the file                
                rename-item $file.FullName -newname $newname
                echo "Action:            Filename modified from $filename to $newname."
                $modifiedcounter++
            }
        }
        else
        {
            echo "Action:            None";
        }   

        $counter++
    }
}

# Output the results
echo ""
echo "$modifiedcounter of $counter filenames modified."
echo "Exception count: $exceptioncounter"

# If there were exceptions then output that as well
if ($exceptioncounter -gt 0)
{
    echo ""
    echo "The following files were not modified as files already existed with their provisional new names:"
    echo $exceptionfilenames
}

Read-host "Press enter to quit"

Feedback

Please let me know if you spot any errors in this script or ways in which it could be improved!

Monday, November 8, 2010

SharePoint 2010: RSS settings missing in list settings page

When you view the list settings in the ribbon of a library or list, you may notice that the RSS Feed button is disabled:

image

You’re first port of call may be the List/Library settings page, where you would find the RSS settings link under the Communications area:

image

However, if this is missing, it’s likely that RSS is disabled at the site or site collection level.  Moving up the chain, if you view the site settings you might find an RSS link under Site Administration:

image

If this link is missing, try looking up at the site collection level, where there is another settings page allowing you to enable RSS for the whole site collection:

image

Enable this, then double check your site RSS settings, then you should have an enabled RSS button on your lists and libraries!

image

Wednesday, November 3, 2010

SharePoint 2010 Label Error: The Policy Label Configuration is Invalid

I’ve recently been working a lot around Information Management policies including Labels.  A Label Information Management policy allows you to add force Office users to add a label into a document such as Word or Excel. 
A label is composed of text and fields from your associated content type.  The requirement was to have the following format on the label:
  • {Protection Level} {Caveat}
After saving this policy, I opened a document of my content type in Word and was presented with the following message":
The Policy Label configuration is invalid.  Contact your Policy Administrator
image
Well it turns out you can’t format your label with two content type fields on the same line with only blank space characters in between – hopefully this will be improved in the next update…
The following does work as alternatives:
  • {Protection Level} – {Caveat} (a character in-between the two fields)
  • {Protection Level} \n {Caveat} (note this places the Caveat field on a new line)

Update

Well it turns out you can use the ASCII tab escape character "\t":
  • {Protection Level} \t {Caveat}