PowerShell & SharePoint: Using New-WebServiceProxy to Post New Completed Tasks Automatically

Recently, I was asked to help automate a friend's super boring daily duty of logging repetitive activities to a SharePoint Task list. Even though I'm no longer regularly working with SharePoint (yay!), I accepted the challenge.

Below is the script I created, which can be scheduled (and mixed up, even using $a = Get-Random -minimum 15 -maximum 1250; Start-Sleep -s $a within the function) to fill in the form and post new completed Tasks automatically.

Function Submit-SPForm ($Title, $Description) { # SharePoint list name $listName = 'Tasks'

# Get the WSDL pages of the site.
# Note! The $service object below uses this $uri. Use the top-level
# lists.asmx or you'll encounter an exception when getting your $list
$uri = 'https://sharepoint2010/\_vti\_bin/lists.asmx?wsdl'
$peopleuri = "https://sharepoint2010/\_vti\_bin/people.asmx?wsdl"

# Get the userID of the user running the script
# in order to add it to AssignedTo
$useraccount = "$env:userdomain\\$env:username"
$client = New-WebServiceProxy -Uri $peopleuri -UseDefaultCredential
$person = $client.ResolvePrincipals(@("$useraccount"), 'User', $true)
$userid = $person.userInfoID

# Create xml query to retrieve list.
$xmlDoc = new-object System.Xml.XmlDocument
$query = $xmlDoc.CreateElement("Query")
$viewFields = $xmlDoc.CreateElement("ViewFields")
$queryOptions = $xmlDoc.CreateElement("QueryOptions")
$query.set\_InnerXml("FieldRef Name='Full Name'")

# Since we're just adding a record, retrieve as few records as possible
# Note: "0" gets all records
$rowLimit = "1"

# Create the services
$service = New-WebServiceProxy -Uri $uri  -Namespace SpWs  -UseDefaultCredential
$list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, "")

# Get name attribute values (guids) for list and view
$ndlistview = $service.getlistandview($listname, "")
$strlistid = $ndlistview.childnodes.item(0).name
$strviewid = $ndlistview.childnodes.item(1).name

# Create an xmldocument object and construct a batch element and its attributes.
$xmldoc = new-object system.xml.xmldocument

# Note that an empty viewname parameter causes the method to use the default view
$batchelement = $xmldoc.createelement("Batch")
$batchelement.setattribute("onerror", "continue")
$batchelement.setattribute("listversion", "1")
$batchelement.setattribute("viewname", $strviewid)
$todaysdate = get-date -format "yyyy-MM-dd"

# Body = Description
$xml = "" +
		"New" +
		"$title" +
		"$description" +
		"Completed" +
		"$userid" +
		"$todaysdate" +

# Set the xml content
$batchelement.innerxml = $xml

# Add the record
$ndreturn = $service.updatelistitems($listName, $batchelement)


$title = "Tested File Transfer" $description = "Checked to ensure all files were ready
" $description += "Other

Submit-SPForm -Title $title -Description $description

Here are a few interesting things while creating this script:

  • Invoke-WebRequest is not the appropriate cmdlet for this task. SharePoint's form field naming scheme was complex and ultimately, Invoke-WebRequest was unable to successfully submit the task. It seemed like it worked, but the new items never appeared.
  • New-WebServiceProxy works with 2007, 2010 and SharePoint 2013 (as well as PowerShell 2.0 and 3.0) but beware xml's case sensitivity.
  • Lists.UpdateListItems is used to add new tasks, not just update tasks
  • Fields with spaces or renamed columns could present issues. Makes sure you use the FieldInternalName for the column name. This can be found in the source code of the New page.
  • A people/group picker field only requires the user id of the user in SharePoint. You can get this ID by deciphering the user's URL or just use ResolvePrincipals as seen in this script. The format should look like this: 32
  • Dates require this format: YYYY-MM-DD
  • The default Description field is actually called the Body field and must be referenced as such.
  • Lookup fields work, but the code below doesn't automatically resolve the lookup fields. I just went get the ID (by looking at the URL of the item) and manually input it.

Special thanks goes out to the PowerShell team for the jump start.