Setting AutoCleanupDays With PowerShell in SharePoint 2010

The Problem

In it’s default configuration, SharePoint (2007 and 2010) will delete workflow associations after 60 days (e.g. the information found on the Workflow Status page). There are times when you may want to alter this functionality and retain the association for a longer period of time.

In SharePoint 2007, the recommendation from Microsoft (per TechNet), is to disable the Workflow Auto Cleanup timer job. The Workflow Auto Cleanup timer job is a web application scoped timer job. As such, disabling the job is often not the optimal solution; as disabling the job will ensure that cleanup is not occurring for all of the site collections within the web application for which the timer job was disabled.

The Solution

Thankfully, there is a property (SPWorkflowAssociation.AutoCleanupDays) that is exposed with the workflows associated with a given list/content type. And once again, PowerShell comes to the rescue, giving us the ability to manipulate the cleanup days at a more granular level. This ensures that we do not disable the timer job for an entire web application.

Presented as two functions, we can manipulate the workflow association settings for either the workflows associated with a list or the workflows associated with a content type attached to a list.

Set-SPListWorkflowAssocationCleanup

The following function allows us to set the AutoCleanupDays for all of the workflows associated with a given list.

Set-SPListWorkflowAssocationCleanup -WebUrl "http://intranet" -ListName "Shared Documents" -CleanupDays 365 -ReportOnly:$false
function Set-SPListWorkflowAssocationCleanup {
    param (
        [string] $WebUrl = $(Read-Host -prompt "Enter a Url"),
        [string] $ListName = $(Read-Host -prompt "Enter a List Name"),
        [int32] $CleanupDays = $(Read-Host -prompt "Enter the number of Cleanup Days"),
        [switch] $ReportOnly = $true
        )        

    $web = Get-SPWeb $WebUrl;
    if ($web -eq $null) {
        Write-Error -message "Error: Web Not Found" -category InvalidArgument
    } else {
        $list = $web.Lists[$ListName];
        if ($list -eq $null) {
            Write-Error -message "Error: List Not Found" -category InvalidArgument
        } else {
            [Microsoft.SharePoint.Workflow.SPWorkflowAssociation[]] $wfaMods = @();
            foreach ($wfa in $list.WorkflowAssociations) {
                $message = "Found Workflow Association for " + $wfa.Name + " with AutoCleanupDays set to " + $wfa.AutoCleanupDays
                Write-Verbose -message $message -verbose

                if ($ReportOnly -eq $false) {
                    $wfa.AutoCleanupDays = $CleanupDays;
                    $wfaMods = $wfaMods + $wfa;
                }
            }

            if ($ReportOnly -eq $false) {
                foreach ($wfa in $wfaMods) {
                    $message = "Setting AutoCleanupDays for " + $wfa.Name + " to " + $CleanupDays
                    Write-Verbose -message $message -verbose
                    $list.WorkflowAssociations.Update($wfa);
                }
            }
        }
    }
}

Set-SPListContentTypeWorkflowAssocationCleanup

The following function allows us to set the AutoCleanupDays for all of the workflows associated with content type for a given list.

Set-SPListContentTypeWorkflowAssocationCleanup -WebUrl "http://intranet" -ListName "Shared Documents" -ContentTypeName "Document Content Type" -CleanupDays 365 -ReportOnly:$false
function Set-SPListContentTypeWorkflowAssocationCleanup {
    param (
        [string] $WebUrl = $(Read-Host -prompt "Enter a Url"),
        [string] $ListName = $(Read-Host -prompt "Enter a List Name"),
        [string] $ContentTypeName = $(Read-Host -prompt "Enter a Content Type Name"),
        [int32] $CleanupDays = $(Read-Host -prompt "Enter the number of Cleanup Days"),
        [switch] $ReportOnly = $true
        )        

    $web = Get-SPWeb $WebUrl;
    if ($web -eq $null) {
        Write-Error -message "Error: Web Not Found" -category InvalidArgument
    } else {
        $list = $web.Lists[$ListName];
        if ($list -eq $null) {
            Write-Error -message "Error: List Not Found" -category InvalidArgument
        } else {
            $ct = $list.ContentTypes[$ContentTypeName];
            if ($ct -eq $null) {
                Write-Error -message "Error: Content Type Not Found" - category InvalidArgument
            } else {
                [Microsoft.SharePoint.Workflow.SPWorkflowAssociation[]] $wfaMods = @();
                foreach ($wfa in $ct.WorkflowAssociations) {
                    $message = "Found Workflow Association for " + $wfa.Name + " with AutoCleanupDays set to " + $wfa.AutoCleanupDays
                    Write-Verbose -message $message -verbose

                    if ($ReportOnly -eq $false) {
                        $wfa.AutoCleanupDays = $CleanupDays;
                        $wfaMods = $wfaMods + $wfa;
                    }
                }

                if ($ReportOnly -eq $false) {
                    foreach ($wfa in $wfaMods) {
                        $message = "Setting AutoCleanupDays for " + $wfa.Name + " to " + $CleanupDays
                        Write-Verbose -message $message -verbose
                        $ct.WorkflowAssociations.Update($wfa);
                    }
                }
            }
        }
    }
}

Conclusion

By manipulating the workflow associations for a list at the list/content type level the default configuration of a SharePoint farm can be retained (e.g. Workflow associations removed after 60 days) and in those cases where there is a business need, the workflow associations can be maintained for a longer period of time.

Reference

SharePoint 2010 Downloadable Content

Microsoft provides a number of free resources for “getting to know” SharePoint 2010. Note that the most of the CHMs are updated monthly.

Downloadable Books

Downloadable CHM

UserProfileServiceUserStatisticsWebPart:LoadControl failed

If you’re experiencing any kind of LoadControl failed errors after provisioning a User Profile Service Application when attempting to manage the service application, you may have forgotten to perform an iisreset.

04/06/2011 11:17:40.48	w3wp.exe (0x18B8)	0x1BEC	SharePoint Portal Server	User Profiles	et8j	High	UserProfileServiceUserStatisticsWebPart:LoadControl failed, Exception: System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceStatisticsWebPartBase.LoadControl(Object sender, EventArgs e)	59a0ca16-b035-420c-a6d4-c62ec550fc0c
04/06/2011 11:17:40.49	w3wp.exe (0x18B8)	0x1BEC	SharePoint Portal Server	User Profiles	et8j	High	UserProfileServiceAudienceStatisticsWebPart:LoadControl failed, Exception: System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceStatisticsWebPartBase.LoadControl(Object sender, EventArgs e)	59a0ca16-b035-420c-a6d4-c62ec550fc0c
04/06/2011 11:17:40.49	w3wp.exe (0x18B8)	0x1BEC	SharePoint Portal Server	User Profiles	et8j	High	UserProfileServiceImportStatisticsWebPart:LoadControl failed, Exception: System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceStatisticsWebPartBase.LoadControl(Object sender, EventArgs e)	59a0ca16-b035-420c-a6d4-c62ec550fc0c
04/06/2011 11:18:22.48	w3wp.exe (0x18B8)	0x1C98	SharePoint Portal Server	User Profiles	et8j	High	UserProfileServiceUserStatisticsWebPart:LoadControl failed, Exception: System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceStatisticsWebPartBase.LoadControl(Object sender, EventArgs e)	5e9291a6-c7ee-4f1d-91d2-f0689697e9da
04/06/2011 11:18:22.49	w3wp.exe (0x18B8)	0x1C98	SharePoint Portal Server	User Profiles	et8j	High	UserProfileServiceAudienceStatisticsWebPart:LoadControl failed, Exception: System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceStatisticsWebPartBase.LoadControl(Object sender, EventArgs e)	5e9291a6-c7ee-4f1d-91d2-f0689697e9da
04/06/2011 11:18:22.49	w3wp.exe (0x18B8)	0x1C98	SharePoint Portal Server	User Profiles	et8j	High	UserProfileServiceImportStatisticsWebPart:LoadControl failed, Exception: System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceStatisticsWebPartBase.LoadControl(Object sender, EventArgs e)	5e9291a6-c7ee-4f1d-91d2-f0689697e9da

Reference

SharePoint 2010: System.Security.SecurityException when you try to start the User Profile Synchronization Service

System.Security.SecurityException: There are currently no logon servers available to service the logon request with a KerbS4ULogon exception? Kerberos strikes again.

The Error

UserProfileApplication.SynchronizeMIIS: Failed to configure ILM, will attempt during next rerun. Exception: System.Security.SecurityException: There are currently no logon servers available to service the logon request.
at System.Security.Principal.WindowsIdentity.KerbS4ULogon(String upn)
at System.Security.Principal.WindowsIdentity..ctor(String sUserPrincipalName, String type)
at System.Security.Principal.WindowsIdentity..ctor(String sUserPrincipalName)
at Microsoft.IdentityManagement.SetupUtils.IlmWSSetup.GetDomainAccountSIDHexString(String domainName, String accountName)
at Microsoft.IdentityManagement.SetupUtils.IlmWSSetup.GrantSQLRightsToServiceAccount()
at Microsoft.IdentityManagement.SetupUtils.IlmWSSetup.IlmBuildDatabase()
at Microsoft.Office.Server.UserProfiles.Synchronization.ILMPostSetupConfiguration.ConfigureIlmWebService(Boolean existingDatabase)
at Microsoft.Office.Server.Administration.UserProfileApplication.SetupSynchronizationService(ProfileSynchronizationServiceInstance profileSyncInstance) The Zone of the assembly that failed was: MyComputer.

Root Cause

A security feature introduced in Windows Server 2003 prevents the KDC from distributing a service ticket (TGS) for an account that does not have a Service Principle Name (SPN) defined. As the SPTimerV4 account is unable to obtain a valid service ticket, the above exception is thrown. At the end of the day, without properly set SPNs, Kerberos authentication is not possible.

The Fix

As stated on Yvan Duhamel’s blog, setting a temporary SPN on the account running the SPTimerV4 (OWSTIMER) service will allow you to start the service.

setspn –a NONE/NONE OWSTimerAccount

The SPN can be removed after the service is provisioned and the FIM services will continue to start properly after restarts. However, if the User Profile Synchronization Service ever needs to be restarted through Central Administration, the SPN will need to be in place. That being said, it is most likely best to keep the SPN on the account.

Reference

Performance Optimization WordPress Plugins by W3 EDGE