April Fools Day 2015 – What’s in Pandora’s Box

The Idea

So, I’ve seen the Upside-Down-Ternet many times, and I began thinking…How can I leverage this idea on one of my wife’s favorite websites – Pandora.

She listens to Pandora for a good part of the day from our home internet connection… Perfect! I can set up a transparent http proxy, and manipulate requests for Pandora as they come through.

Now, what should I play?   This of course. And may more things.  And maybe What does the spleen do?

The Implementation

Determining an “attack vector”

I fired up Chrome’s developer tools while listening to a pandora stream, and was quite pleasantly surprised: the audio is transferred over HTTP (correct – no encryption), in MP3 format. (And I discovered a little too late that the Pandora ONE Player will play audio/mp3 streams, while the free pandora player will only play audio/mp4 streams – This is important later on!)  How easy this will be!  All I’ll need to do is watch for the  specially crafted URL requesting resources from http://audio-*.pandora.com/ (and *.p-cdn.com) access and respond accordingly – In this case, with an mp3 pre-staged on my intercepting server.

Base Environment

My “host” in this scenario is a VM running on Hyper-V on my Windows 8.1 Desktop.  The VM is running Ubuntu 14 as a guest OS, and has  2 cores with 256 MB ram, and one network adapter.

Phase 1: Configuring Squid3 & iptables

Squid3 is a proxy server that supports something called “transparent mode.”  In conjunction with iptables, squid can be a very effective content filter, caching proxy, or the perfect tool to carry out an April fools prank.

In this scenario, we’ll be setting up our linux machine to “Masquerade” as the machines that will be passing traffic to (through) it. In much the same manner as how your existing home router works: You have one public IP address, and all of the requests from computers within your network (using private IP addresses)  appear to come from that one public IP. This is called NAT.

Since this linux machine will facilitate the transfer of all traffic from the “victim” machines to the internet, It’s in the perfect location to identify (and manipulate) Pandora requests.

OK, OK, enough theory, let’s get some code


  1. Enable ip_forwarding (this is temporary, and will go away after a reboot of the  “host” machine)
    echo 1 > /proc/sys/net/ipv4/ip_forward
  2. Configure iptables to pass traffic (Never configure it this way if you’re actually building an edge device.  Since all of my devices – both “host” and “victim” machines are on the same physical network, I took some liberties with security)
    iptables -F
    iptables -t nat -F
    iptables -P INPUT ACCEPT
    iptables -P OUTPUT ACCEPT
    iptables -P FORWARD ACCEPT
  3. Next, we need to tell iptables to “masquerade,” or that is to “NAT” the traffic that comes from the local subnet, and is destined for the internet.
    iptables -t nat -A POSTROUTING -s -j MASQUERADE
  4. Great, but what about our prank?   Let’s explicitly redirect traffic destined for the IP segment owned by Pandora (you can find this using whois)
    iptables -t nat -A PREROUTING -d -p tcp --dport 80 -j DNAT --to-destination


  1. First, install squid using your favorite packaging tooapt-get install squid3
  2. Configure Squid.  I’ve taken the liberty of trimming down the config file as thin as possible for this scenario.  5 lines!
    redirect_program /home/administrator/pandora.pl
    http_access allow all
    http_port 3128 transparent
    strip_query_terms off
    coredump_dir /var/spool/squid3
  3. Next, we need to write the redirect_program.  Having not actually read the Squid3 documentation, and surmising based on operation – This is loaded at the time the Squid3 service is started, and continually runs in the background.  Squid3 then passes URLs from clients into the script through the pipeline.  The script then passes a URL back to Squid3.  In this circumstance, we use some regex to identify all requests for a Pandora song (http://audio.*?pandora\.com and http://.*\.p-cdn\.com)
    use strict;
    $| = 1;
    while (<>) {
    my @elems = split;
    my $url = $elems[0];
    if ($url =~ m#^http://audio.*?pandora\.com#i) {
    $url = "";
    print "$url\n";
    if ($url =~ m#^http://.*\.p-cdn\.com#i) {
    $url = "";
    print "$url\n";
    print "$url\n";
  4. Restart Squid3
    service squid3 restart


Since we’re actually replacing the song in Pandora with a “payload” track, we need some way of hosting this audio.  Additionally, we need the host to respond with the “payload” track for any and all incoming requests.  Queue: Apache mod_rewrite.

  1. Edit the  /etc/apache2/sites-enabled/000-default.conf file, and add these three lines.  This causes any inbound HTTP requests to return the test.mp4 file (with the correct MIME association, so as not to break “free” Pandora)
    RewriteEngine on
    RewriteRule .* /test.mp4
    AddType audio/mp4 .mp4
  2. Place the test.mp4 file at /var/www/html

Phase 1.5: Test Proof of Concept

  1. Set a host on the LAN to use the afforementioned box as a default gateway.
  2. Launch Pandora
  3. Validate that only the payload song will play.

Phase 2: Deploy to LAN

I have a standard FiOS router as my default gateway, and the device does not give total control over the DHCP server settings.  Of particular interest here is the option routers parameter.  This allows the DHCP server to dictate to the clients what IP address they should use as a default gateway.  Obviously if this prank is going to affect more than my sandbox, I need the other devices on the LAN to pass all of their traffic through the “host”

Configure isc-dhcp-server

  1. Install isc-dhcp-server using your favorite package manager
    apt-get install isc-dhcp-server
  2. modify the lines below in the /etc/dhcp/dhcpd.conf file.  Define some hosts if you’d like to exclude them from the prank.  All hosts with a host block will be issued an IP in the deny unknown clients pool:  this is not; however, what determines their gateway, but rather the options routers clause in the  host  block.   One very important thing here is to set the lease time rather low.  I don’t want this prank to cause some random device to get an IP and hold onto it for the default of 8 days. Bumblebee happens to be my desktop:
    option domain-name "ccrossan.com";
    option domain-name-servers,,;default-lease-time 100;
    max-lease-time 100;
    host bumblebee
    hardware ethernet 00:24:8C:93:7C:EE;
    option routers;
    }subnet netmask
    option routers;
    pool {
    deny unknown clients;
    option routers;
    allow unknown clients;
    option routers;
  3. Re-start the DHCP server
  4. Disable DHCP on the FiOS router.
  5. Watch hilarity ensue as users launch Pandora in their browsers only to hear your specially selected track!

Thanks for reading.  If you stuck with it this far, you’re a trooper.

Please leave any comments or suggestions you may have below!

Pushing Calendar Events with the EWS API

We’ve had a need to populate users’ calendars with data from an internal FileMaker Database, so I dug around in the EWS API, and came up with a script that uses the FileMaker ODBC Connection, and the EWS API to accomplish the task:

First things first, we need to install the EWS Managed API on the machine that will run the script.

After the EWS Managed API is installed, we need to reference it in our PowerShell script:

Add-Type -Path “C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll”

Next, we need to set up a System.Net.NetworkCredential object for the account we’ll use to push these events.  This account must have at least modify permission on the target users’ calendar.

$Credentials = new-object system.net.NetworkCredential(“CalendarAccessAccount”,”SuperStrongPa$$w0Rd!”,”litware”)

Next, we need to Create anMicrosoft.Exchange.WebServices.Data.ExchangeService object:

$version = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
$service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService($version)

We don’t want to use the default credentials, Instead we want to authenticate using the service account specified earlier:

$service.UseDefaultCredentials = $false

And, presuming AutoDiscover is set up correctly in our domain, we want to let EWS figure out the server address, port, etc:


Next, we need to reference the user’s calendar (it’s really just a folder as far as the API is concerned):

$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar, “TargetMailbox@litware.com”)

And finally, we build the appointment object:

$Appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $Service
$appointment.Subject = “Test111”
$appointment.Body = “Test111”
$appointment.Start = $(Get-Date).AddHours(6)
$appointment.End =$(Get-Date).AddHours(9)

Don’t forget to save it:



All in all, we can wrap this up as a function:

Function CreateAppointment($User,$Credentials)
$version = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
$service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService($version)
$service.UseDefaultCredentials = $false

$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar, $mailboxName)

$Appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $Service
$appointment.Subject = “Test Subject”
$appointment.Body = “Test Body”
$appointment.Start = $(Get-Date).AddHours(6)
$appointment.End =$(Get-Date).AddHours(9)



Now we can call the function from, say, with a loop so as to iterate through each user in a CSV:

$users = Import-CSV “Users.csv”

$Credentials = new-object system.net.NetworkCredential(“CalendarAccessAccount”,”SuperStrongPa$$w0Rd!”,”litware”)

Foreach ($User in $Users)


CreateAppointment $User $Credentials



More to come later on the FileMaker ODBC Connection…

FIM Portal No Access for FIM Admin Account

Today’s adventure with Forefront Identity Manager started when I was unable to log into the FIM portal.  Some digging revealed that the accountName attribute for my admin user had been set to null (probably from too much tinkering with sync rules).

I realized that the accountName was probably the issue by two indicators: there was no account name attribute for the FIM Admin object in the FIM Synchronization Service Manager application, and because the query below referencing the ObjectValueString table lacked some attributes. The change-fimadmin.ps1 script helped me determine these SQL sanity check queries.

I had already eliminated the usual suspects for not being able to access the portal (ObjectSID, MPRs, etc), so this stumped me for a little while

Anyway, I needed a way to get back in the portal (and I didn’t want to re-install), so I came up with this script that uses the FIM PowerShell modules to set the accountName attribute of the FIM Admin user (identified by the well-known admin user GUID).

I used the script on How to Use PowerShell to Set the Required Attributes for the FIM Portal Access as a starting point, modifying it to set only the accountName attribute.


If(@(get-pssnapin | where-object {$_.Name -eq “FIMAutomation”} ).count -eq 0) {add-pssnapin FIMAutomation}

Function SetAttribute
PARAM($CurObject, $AttributeName, $AttributeValue)
$ImportChange = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportChange
$ImportChange.Operation = 1
$ImportChange.AttributeName = $AttributeName
$ImportChange.AttributeValue = $AttributeValue
$ImportChange.FullyResolved = 1
$ImportChange.Locale = “Invariant”
If ($CurObject.Changes -eq $null) {$CurObject.Changes = (,$ImportChange)}
Else {$CurObject.Changes += $ImportChange}
$curObject= export-fimconfig -uri $URI –onlyBaseResources -customconfig (“/Person[ObjectID='{7fb2b853-24f0-4498-9534-4e10589723c4}’]”)

$ImportObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject

$ImportObject.ObjectType = $curObject.ResourceManagementObject.ObjectType
$ImportObject.TargetObjectIdentifier = $CurObject.ResourceManagementObject.ObjectIdentifier
$ImportObject.SourceObjectIdentifier = $CurObject.ResourceManagementObject.ObjectIdentifier
$ImportObject.State = 1

SetAttribute -CurObject $ImportObject -AttributeName “AccountName” -AttributeValue $adminAccountName
$ImportObject | Import-FIMConfig -uri $URI -ErrorVariable Err -ErrorAction SilentlyContinue


After running this script, you should be able to log into the FIM portal again.

Helpful places to look also include the FIMService database.  Particularly the ObjectValueString and UserSecurityIdentifiers Tables.


The following query represents the values for the FIM Admin User, and should yield 7 rows(Attribute Keys 1,66,68,70,117,125,132)

SELECT TOP 1000 [AttributeID]
FROM [FIMService].[fim].[ObjectValueString]

where ObjectKey =2340

The following query represents the SID, in HEX form, of the FIM Admin User, and should yield 1 row:

SELECT TOP 1000 [UserObjectKey]
FROM [FIMService].[fim].[UserSecurityIdentifiers]
where UserObjectKey =2340




Stay up to date with RSS

Staying Up-To-Date

I spend spent a lot of time watching various blogs, web pages, and other online sources for updates to the many platforms I’m responsible for supporting.  Windows has a new security patch. Mac OSX needs heart-bleed remediation.  SharePoint has a new Cumulative Update.  There’s a new Linux Kernel out, and 52 commits have occurred for the ROM on my phone.

That’s a lot of moving targets, with many different pages to remember to check on a semi-regular basis.  With probability against me, the time spent loading a page (and possibly googling it if I forgot to bookmark it) and deciphering what’s changed since I last visited generally resulted in a lot of lost time.

My Solution

Recently, a co-worker turned me on to RSS feeds.  They’ve been around forever, and yet, I’ve never really used them.  That is, until I realized how valuable they can be.   Just think: superbookmarks! One “Single Pane of Glass” to view all of the content updates. Feedly is a web based RSS reader.  You can use various authentication methods ( I prefer logging in with my Google Account) to access your list of “Subscribed” RSS feeds.

Whenever new content is posted, it shows up in your “unread” subscriptions.  Just make it your homepage, and enjoy the easy reading!

Subscribing to Content

After you’ve found a content source you’d like to stay current on, You’ll need to:

  1. Identify the RSS Feed URL
    1. Most sites will have an RSS button.  It should look like this: However, some sites do not publish the RSS feed, but still make it available.
    2. The RSS Feed for WordPress sites can be accessed via http://<sitename>/feed or http://<sitename>/?feed=rss2.
    3. Reddit publishes RSS Feeds for subreddits in the form of http://reddit.com/r/<subreddit>/.rss
  2. Point Feedly at the URL
    Click the “Add Content” button in Feedly, and provide the URL you discovered in step 1.

  3. Add the Feed to one of your collections
    Click the green “+”

  4. Choose a Collection

  5. Enjoy!
    New posts from this content source will now automagically show up when you open Feedly!

My Feeds

If you’re curious what I’m following, here’s a list of the RSS feeds I choose to follow.  You could also download, and import my feeds directly into your Feedly!

  • Ars Technica
    • http://feeds.arstechnica.com/arstechnica/index/
  • Michael Niehaus’ Windows and Office deployment ramblings
    • http://blogs.technet.com/mniehaus/rss.xml
  • Reddit /r/sysadmin
    • http://www.reddit.com/r/sysadmin/.rss
  • codeinsecurity
    • http://codeinsecurity.wordpress.com/feed/
  • Krebs on Security
    • http://krebsonsecurity.com/feed/
  • In the Cloud
    • http://blogs.technet.com/b/in_the_cloud/rss.aspx
  • Ask Premier Field Engineering (PFE) Platforms
    • http://blogs.technet.com/b/askpfeplat/rss.aspx
  • Errata Security
    • http://blog.erratasec.com/feeds/posts/default
  • NPR News
    • http://www.npr.org/rss/rss.php?id=1001
  • XKCD
    • http://xkcd.com/rss.xml
  • LifeHacker
    • http://feeds.gawker.com/lifehacker/vip
  • Todd Klindt’s Blog Posts (SharePoint Patches)
    • http://www.toddklindt.com/blog/_layouts/listfeed.aspx?List={56F96349-3BB6-4087-94F4-7F95FF4CA81F}
  • Reddit /r/sharepoint
    • http://www.reddit.com/r/sharepoint/.rss
  • Stefan Goßner (SharePoint)
    • http://blogs.technet.com/b/stefan_gossner/rss.aspx

Cleaning Up Exchange Messages with Search-Mailbox

Like most sysadmins, I receive notifications from end users about SPAM showing up in their inbox.  While not all spam can be avoided, we can deal with it.  I wanted to lessen the impact of already delivered spam and potentially avert a crisis if the same phishing email is sent to all 1500 mailboxes, so I whipped up this script to search out and destroy these messages from my Exchange environment:

$Subject = “About your last transaction”
$StartDate = $(‘1/1/2015’)
$BodyLanguage = “sellam.fr”
$TargetMailbox = “spamdump”
$TargetFolder = “WHD2918”

$Search = [scriptblock]::Create(“Received>=`”$StartDate`” and Subject:`”$Subject`” and `”$BodyLanguage`””)

Get-Mailbox -ResultSize Unlimited | Search-Mailbox -SearchQuery $Search -targetmailbox $TargetMailbox -targetfolder $TargetFolder -loglevel full -logonly

Note the last flag in the last line of the script: “-logonly.”  Be very careful to run the command with this command the first go-round.  This ensures that the query you specify does not grab messages that it shouldn’t (and you wind up deleting everyone’s entire mailbox).  The result of logonly is an excel file in the target mailbox with the headers of the resultant messages.

After reviewing the messages, replace -logonly with -deletecontent.  This will actually move the messages from the users’ mailboxes into the target mailbox.

If you want to modify the query, take a look into how Search-Mailbox actually works.   Search-Mailbox uses KQL, so be sure to brush up on the syntax.  If you’ve beocme accustomed to the powershell boolean operators such as “-and,” You’ll be unpleasantly surprised when you learn that the same operator will evaluate to “not and” in KQL

ForeFront Identity Manager (2010 R2) Synchronization Service Becomes Disabled

I had just installed FIM 2010 R2 in a lab environment – All roles on one server, and noticed that the “Forefront Identity Manager Synchronization Service”  Kept stopping, and being set to “Disabled.”

I had installed all of the latest patches for both FIM (4.1.3613.0) and SharePoint (14.0.7140.5000). I saw nothing in the Windows Event log to indicate there was a problem.  The “Synchronization Service Manager on FIM” application would launch fine while the service was running.  All configured management agents would synchronize no problem.  It’s just that – Every so often, the  “Forefront Identity Manager Synchronization Service” would just up and STOP!

After some research, I found this TechNet Blog Post which suggests that SharePoint is the culprit!

Since SharePoint is installed on this server only for the purpose of providing the FIM Portal, I had no need to set up (or otherwise use) the User Profile Service.   Consequently, SharePoint isn’t expecting the Synchronization Service to be in a running state! So, as part of the “Health Analysis Job (Hourly, Microsoft SharePoint Foundation Timer, All Servers)” SharePoint notices the service is running, and disables it!

I verified this by returning the service to the normal Automatic – Running state, and manually kicking off that Timer Job.

Sure enough, the job was stopped! ULS Viewer shows me this also:

See that? – “The SharePoint Health Analyzer found and fixed the following problem: One or more services have started or stopped unexpectedly..”  No details about which service was “started unexpectedly,” but I presume that the “Forefront Identity Manager Synchronization Service” was the culprit.

To prevent this from happening again, I nagivated to “Review Job Definitions” under “Monitoring” in Central Administration, located the  “Health Analysis Job (Hourly, Microsoft SharePoint Foundation Timer, All Servers)” and disabled it.

All seems well at this point in time…

My set of links for FIM installation tips, tricks, procedures, etc:

  • https://technet.microsoft.com/en-us/library/hh332711(v=ws.10).aspx
  • http://www.harbar.net/articles/fimportal.aspx
  • http://www.toddklindt.com/blog/Lists/Posts/Post.aspx?ID=224
  • http://social.technet.microsoft.com/wiki/contents/articles/2229.fim-2010-build-overview.aspx
  • http://www.fimspecialist.com/fim-portal/installing-fim-2010-r2-sp1-portal-on-sharepoint-foundation-2013/
  • https://social.technet.microsoft.com/Forums/en-US/76bd6012-f619-4636-8401-74cac8436f1f/fim-sync-service-keeps-disabling?forum=ilm2
  • http://www.fimspecialist.com/category/fim-hotixes-service-packs-updates/
  • https://technet.microsoft.com/en-us/library/jj200258(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh322920(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh322863(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/jj134316(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh322877(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh332711(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh332707(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh332708(v=ws.10).aspx
  • https://technet.microsoft.com/en-us/library/hh332710(v=ws.10).aspx
  • https://fim2010techie.wordpress.com/2012/12/10/synchronizing-active-directory-users/
  • http://blogs.msdn.com/b/connector_space/archive/2014/12/30/understanding-the-fim-service-management-agent.aspx
  • http://social.technet.microsoft.com/wiki/contents/articles/3610.fim-2010-wiki-articles.aspx



Hiding Featured Images in WordPress Blog Posts

My wife recently asked me if she could hide the featured images in her blog posts.  She wanted the photos displayed on her home page and post listings, but not on the actual page for the blog post – She wanted to actually insert the image to her post at some point into the post:

I did some Googling, and found that most themes implement a “single.php” file.  In this file is a definition for how the individual blog posts render:

<?php if (is_single()) : ?>
<article id=”post-<?php the_ID(); ?>” <?php post_class(); ?>>
<?php the_post_thumbnail(‘featured’); ?>
<div id=”post-content”>
<?php the_title(‘<h1 id=”post-title”>’, ‘</h1>’); ?>

Of interest to me was the line

<?php the_post_thumbnail(‘featured’); ?>

Which I simply commented out:

<?php #the_post_thumbnail(‘featured’); ?>

And now, the featured image is not displayed at the top of the post, and she is free to insert the image anywhere she wishes:


So, with that, you should check out her blog: Anna’s Alcove


Forgot SharePoint Farm User Account Password

I had recently patched an inherited SharePoint 2010 Farm up to the December 2014 CU.  I’m currently prepping to migrate the farm to SharePoint 2013, but I needed to get it patched in the interim.

I successfully applied SP2, and the the December 2014 CU (14.0.7140.5000 – Much thanks to Todd Klindt’s SharePoint Admin Blog for the easy build number lookup), and all seemed well.

That is, until I had to change an extranet user’s email address.  These users don’t have mail accounts in our Exchange environment, but we do populate the mail attribute in AD with their corporate email address.  I made the change to the attribute in AD, and attempted to run the User Profile Synchronization (Central Administration | Manage Service Applications | User Profile Service Application | Start Profile Synchronization).

This action failed because the User Profile Synchronization Service was not running on the server! (Central Administration | Manage Services on Server).

I attempted to start the service but was prompted for the DOMAIN\SPFarm account! I searched all archives and documents, but found no reference to this password!  UH OH!!!!!

I finally found this post: http://joelblogs.co.uk/2012/09/22/recovering-passwords-for-sharepoint-2010-farm-web-application-and-service-application-accounts/

I had full administrative access to the server on which Central Administration was installed, so all I had to do was run a “one liner” in PowerShell.  Could it really be that easy?!

Here’s how easy it is:

&$env:windir\\system32\\inetsrv\\appcmd.exe list apppool 
 "SharePoint Central Administration v4" /text:ProcessModel.Password

I ran the command in my dev environment first (we always test foreign code outside of production, right?), and got this!

No Way.  That’s my Farm account password….in PLAIN TEXT! WHOA SCARY!

So, If you ever find yourself forgetting any of your IIS Application Pool Account Passwords, you now have the tool to recover it!


Birds in Flight

My wife and I were walking around Old City Philadelphia.  We sat down to eat lunch, and were instantly swarmed with birds turned dogs.  They knew we had food, and they weren’t leaving until it was gone.  So, we obliged their requests, and tossed some sandwich chunks into the air.  After seeing their reaction, I decided to grab my recently acquired Canon EOS Rebel T1i to see what i could capture.  I set it to manual focus (Since there was so much in the background the camera *could* choose to focus on), set the ISO to 6,400.  I set my shutter speed to 1/4000 sec, and an F-Stop of f/5.6.  I snapped quite a few pictures of nothing at all….and then this:

Birds in flight (and some free-falling) - All attempting to get a piece of the sandwich!
Birds in flight (and some free-falling) – All attempting to get a piece of the sandwich!

Collecting User Data in SharePoint 2010 with custom Site Columns

The Task: Build a system to archive paper documents (being scanned from e-mail enabled scanners) and optimize for retrieval

I decided to build an E-Mail enabled library to get the documents into SharePoint.   This allows users to save the email address in their contact list on the copier, and makes scanning in documents very easy.

To gather the metadata for these documents, I used the “Collect  Data From a User” (CUD) Action in SharePoint Designer.  This created a Content Type based on the name of the task – In my case “Student Document Data Collection.”

I then added some of my existing site columns to this content type from SPD – things like first name, last name, and district.  I didn’t want to use the CUD wizard to add these fields to the data collection task because a) all of the fields already exist in the site, and b) some of the fields are multiple choice, and I really don’t want to manage two instances of the same data!

After I modified the content type, I refreshed the workflow and returned to the CUD wizard in SPD, and saw that all of my fields populated! Hoorah!

I proceeded to build the rest of the workflow, referencing the fields collected in the CUD task in the normal manner; however, I was noticing a problem: None of the user entered data was showing up!

How could this be? SharePoint was prompting me for the data, I entered it, and I hit save… It should be there, right?  I wrote entries to the workflow history log to see if maybe the data just wasn’t being applied to the current item.  No dice – It looked like SharePoint just wasn’t storing the collected data.

Thanks to reddit user sbrick89, It looks like fields (Site Columns) created in the CUD action within SPD actually have a distinction from standard Site Columns! It’s not a big difference, but it will mess up your day (or, in my case WEEK)!   These fields are prefixed with “FieldName_”.

I jumped into my SharePoint Management PowerShell and whipped this up in order to create my Site Columns (in a way that they will be usable for data collection):


$Web = Get-SPWeb $SiteURL
$FieldXMLString = ‘<Field Type=”Text”
Description=”Student First Name”
DisplayName=”Student First Name”
Group=”0 Student Columns”

Documentation for the syntax of the $FieldXMLString can be found here: https://msdn.microsoft.com/en-us/library/office/ms437580(v=office.15).aspx

Of note is this “Name: Required Text: The name of a field. This is the internal name of a field and is guaranteed never to change for the lifetime of the field definition. It must be unique with respect to the set of fields in a list. The name is autogenerated based on the user-defined name for a field.

I also wanted to create a multiple choice Site Column for District:

$FieldXMLString = ‘<Field Type=”Choice”
Group=”0 Student Columns”
<Choice>District 1</Choice>
<Choice>District 2</Choice>

After creating the Site Columns with the proper internal name, I was able to add the newly created site column to the CUD Content Type, update my workflow, and collect the user data successfully!   Yes, It does seem that any alterations (including changes to the items in a choice Site Colume) to the CUD Content Type require that the workflow be loaded in SPD, the CUD Step opened, “next through” the wizard, and the workflow re-published in order for the changes to appear in the actual data collection step.