Project Server 2010 – Waiting For Resources

I ran into this interesting state in project server last week and was able to resolve it this morning.  You may find that the timer job never executes itself..why?  Have no clue!  Especially since we already ran it three times previously and it always worked!

So I figured a way to successfully fire it manually from PowerShell:

$job = get-sptimerjob -id 4d9b0bd6-2919-4256-b030-c9d50c168e57
$wa = get-spwebapplication https://projects.contoso.com
$job.Execute($wa.id)

Keep in mind that rather execute in the owstimer process it will run as the current PowerShell user.  That user must have access to the database server to apply security and create databases.

Enjoy!
Chris

Project Server 2010 – Moving Project Sites and deleting the old PWA causes issues

Recently we had to deconstruct the entire Project Server environment and rebuild it.  This involved moving the sharepoint sites related to the projects and then re-attaching the old project server databases to a new PWA (ie, the old PWA was http://projects.contoso.com, the new PWA is http://projects.contoso.com/PWA).  Then we had to relink the PWA projects to their old but moved sites urls.

This all went fine until the moment we had to view or edit the properties of the documents in the team sites.  We would get a lovely correlation error when trying to view or edit.  The generic error was:

05/30/2012 10:36:10.02  w3wp.exe (0x207C)                        0x1D80 Project Server                 General                        g7ls Exception  System.ServiceModel.FaultException: The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.    Server stack trace:      at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)     at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)     at System.S… 22df46a2-3f76-4c8c-b317-d2076882b490
05/30/2012 10:36:10.02* w3wp.exe (0x207C)                        0x1D80 Project Server                 General                        g7ls Exception …erviceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)     at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)     at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)    Exception rethrown at [0]:      at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)     at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)     at Microsoft.Office.Project.Server.Interfaces.IAuthentication.GetUserByName(String username)     at Microsoft.Office.Project.Server.AuthenticationHelper.AuthenticateUserByName(String userName, Guid … 22df46a2-3f76-4c8c-b317-d2076882b490
05/30/2012 10:36:10.02* w3wp.exe (0x207C)                        0x1D80 Project Server                 General                        g7ls Exception …siteId) 22df46a2-3f76-4c8c-b317-d2076882b490

Changing the includeExceptionDetailInFaults property of the D:Program FilesMicrosoft Office Servers14.0WebServicesSharedProjectServerPSIweb.config file to "True", we get a more meaningful error:

05/30/2012 10:36:12.68  w3wp.exe (0x207C)                        0x282C Project Server                 General                        g7ls Exception  System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: No site found (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is: System.InvalidOperationException: No site found    at Microsoft.Office.Project.Server.DataAccessLayer.DAL.GetConnectionStrings(PlatformContext context)     at Microsoft.Office.Project.Server.DataAccessLayer.DAL..ctor(PlatformContext context)     at Microsoft.Office.Project.Server.Base.PlatformContext.get_Dal()     at Microsoft.Office.Project.Server.Base.PlatformContext.InitSqlCommandTimeout(CachedContextProperties cachedProperties)     at Microsoft.Office.Project.Server.Base.PlatformContext.PreInitialize(Guid trackingId, Guid siteId, SPUrlZone urlZone, CultureInfo languageCulture, Cultu… a73494b6-2bff-4b2f-9faf-67ad55d9f7d9
05/30/2012 10:36:12.68* w3wp.exe (0x207C)                        0x282C Project Server                 General                        g7ls Exception …reInfo localeCulture)     at Microsoft.Office.Project.Server.Base.PlatformContext..ctor(Boolean isWindowsUser, String username, Guid userId, Guid trackingId, Guid siteId, SPUrlZone urlZone, CultureInfo languageCulture, CultureInfo localeCulture, Guid delegateUid, String delegateName)     at Microsoft.Office.Project.Server.Base.Platform…). a73494b6-2bff-4b2f-9faf-67ad55d9f7d9

After reviewing the possibilites of what could cause this, I found a few things:

  • Project sites have special content types (Project Site Document)
  • The Project Site Document has a special field type (Microsoft.Office.Project.PWA.CustomFieldTypes.SPFieldPWALink)
  • Project site lists have event receivers (Microsoft.Office.Project.PWA.WSSEventReceivers.PSDBUpdater)

I tried several different things before I found the one item that was really causing the issues with viewing and editing.  They included:

  • Trying to remove the content type and set them to "Document" – Didn't work
  • Trying to remove the event receivers (removing them was successful, but it didn't fix the problem)
  • Removing the "Links" column values from all the items (the values removed, but it didn't fix the problem)
  • Removing the "Links" field from the list – this was the answer

Turns out that the custom field type had recorded the old PWA url and when the display forms were trying to render, the call to the PWA authentication service would fail because it couldn't find the old PWA url. After removing the "Links" field from the "Content Type/List" and changing the content types to "Document", we were able to viewedit the properties of the items once again:

$f = $list.fields["Links"]
$f.delete()

foreach ($li in $list.items)
{
if ($li["Content Type"] -eq "Project Site Document")
{
$li.file.checkout()
$li["Content Type"] = "Document"
$li.update()
$li.file.checkin("")
}
}

Enjoy!
Chris

Follow me on twitter: @givenscj

Check out the previous blog post:
http://blogs.architectingconnectedsystems.com/blogs/cjg/archive/2012/05/30/SharePoint-Farm-Full-Password-Reset.aspx

Project Server PSI WCF bug – WSEC_CAT_UID and WSEC_GRP_UID

At one of my customers we are automating the project and project site creation for Project Server 2010.  As part of that, we wanted the proper permissions to be setup for each resource/user.  This includes making them in the "Project Manager" group and the "My Projects" and "My Resources" categories.  The code wasn't very straight forward, but I got most of it working (creating the resource and making a resource a user).  The part that doesn't work is the group and categories assignment.  Here is the code:

SvcSecurity.SecurityGroupsDataSet sgDataSet = new SvcSecurity.SecurityGroupsDataSet();
//Get the security group
SvcSecurity.SecurityGroupsDataSet sglist = securityClient.ReadGroupList();
SvcSecurity.
SecurityGroupsDataSet.SecurityGroupsRow groupDs = null;
foreach (SvcSecurity.SecurityGroupsDataSet.SecurityGroupsRow sg in sglist.SecurityGroups)
{
if (sg.WSEC_GRP_NAME == groupName)
{
groupDs = sg;|
}
}

SvcSecurity.SecurityGroupsDataSet ds = new SvcSecurity.SecurityGroupsDataSet();
// Specify which users belong to the new group.

SvcSecurity.SecurityGroupsDataSet ds = new SvcSecurity.SecurityGroupsDataSet();
// Specify which users belong to the new group.

SvcSecurity.SecurityGroupsDataSet.GroupMembersRow groupMembersRow = ds.GroupMembers.NewGroupMembersRow();
groupMembersRow.WSEC_GRP_UID = groupDs.WSEC_GRP_UID;
// Add the GUID of the resource to the group.
groupMembersRow.RES_UID = NewResGuid;
ds.GroupMembers.AddGroupMembersRow(groupMembersRow);
securityClient.SetGroups(ds);

SecurityGroupsDataSet.GroupMembersRow groupMembersRow = ds.GroupMembers.NewGroupMembersRow();
groupMembersRow.WSEC_GRP_UID = groupDs.WSEC_GRP_UID;
// Add the GUID of the resource to the group.
groupMembersRow.RES_UID = NewResGuid;
ds.GroupMembers.AddGroupMembersRow(groupMembersRow);
securityClient.SetGroups(ds);

The problem lies in the finding of the group.  The DataSet that is returned returns the WSEC_GRP_UID.  This particular column is NOT what the following AddGroupMembersRow call wants!  It actually is looking for a second GUID in the database called WSEC_GRP_GUID.  This is not returned in the PSI call and therefore, you have ZERO chance of successfully going through the PSI apis to get the id.  You end up having to query the database directly…yuk.

Anyone that develops PSI out there?  You really need to fix this…

Chris