Main menu

  • Unit testing for SharePoint 2010 development

    Tags: SharePoint, Testing

    When developing for SharePoint 2010 Unit testing is often overlooked and it shouldn’t be.  It’s true that SharePoint is a product and we don’t need to test that, but the code we write to extend is the same as all other code and needs testing.

    Being able to test it though does require a little thought (and potentially a change) to way to you structure your code.  Getting away from running operations against SharePoint inside “CreateChildControls” for example.  You could unit test this method, but personally I think of a web part like a view (or an asp.net code behind file), it’s for presentation logic, not manipulating data or running CAML queries.

    The purists amongst you will probably say that this is Integration tests and not Unit tests, and I guess you are correct, I should probably interface out the SharePoint OM etc etc … you are right, but for SharePoint dev, I think this is the best way forward taking time and effort into account – “Is the juice worth the squeeze?” – for me….NO!

    I know we don’t need to test the SharePoint OM, but we do need to test our CAML queries – that needs to be ran against a SharePoint implementation, and probably one provisioned with the required lists etc.

    Unfortunately getting going with Unit testing in Visual Studio 2010 for SharePoint is not as easy as it should be.  The problems are: SharePoint 2010 is .net 3.5 and 64bit. 

    • MSTest in Visual Studio cannot run tests in 64bit mode.
    • Visual Studio unit test framework is .net 4 only.
    • My favourite (and I think the best free) testing framework MBUnit doesn’t seem to play well with 64 bit in .net 3.5.  The behaviour I see is changing the project type to .net 3.5 simply prompts VS to upgrade the project.  I’ve not looked into this a great deal, but would certainly rather it worked!

     

    The solution that seems to be most popular is NUnit.  I only use NUnit for this, that’s a choice thing – its just looks dated to me!  I like Icarus test runner for MBUnit – a lot!

    NUnit doesn’t have great integration with Visual Studio, the few bits I found in the Extension gallery were again, .net 4 only.

    I recommend you download TestDriven.net – I’ve blogged about this before – I’m a fan!  It makes is super easy to debug and run tests in VS.  Add an External Tool link in VS specifically for NUnit – more on that in a bit.

    Creating your tests

    Once you’ve installed NUnit from here, and TestDriven.net you’re ready to go..

    In Visual Studio, create a class library project and add a reference to NUnit.framework (and probably Microsoft.SharePoint).

    Make sure the project is targeting the .net 3.5 framework and the platform target is x64.

    Consider you have this simple little helper method just to get you the URL of an item

    public class Class1 : IDisposable
    {
        SPWeb _web;
    
        /// <summary>
        /// Inject SPWeb
        /// </summary>
        public Class1(SPWeb web)
        {
            _web = web;
        }
    
        /// <summary>
        /// Simple example of running a CAML query
        /// </summary>
        public int GetItemIDByTitle(string itemTitle)
        {
            if (String.IsNullOrEmpty(itemTitle))
                throw new ArgumentNullException("itemTitle", "cannot be null or empty");
    
            try
            {
                SPList configList = _web.Lists["Some List"];
                SPQuery query = new SPQuery();
                query.Query = "<Where><Eq><FieldRef Name='Title' /><Value Type='Text'>" + itemTitle + "</Value></Eq></Where>";
    
                //Should only be 1!
                SPListItemCollection items = configList.GetItems(query);
                if (items.Count > 0)
                {
                    return items[0].ID;
                }
            }
            catch (Exception)
            {
                throw;
            }
            return 0;
        }
    
        /// <summary>
        /// Cleanup
        /// </summary>
        public void Dispose()
        {
            if (_web != null)
            {
                _web.Dispose();
            }
        }
    }
    

     

    You can see I am injecting an SPWeb into the class through the constructor.  The method is running a little bit of CAML.

    Not the most useful of code snippet I agree!!

    Write this little test…

    public class DummyTests
    {
        Class1 _provider;
        SPSite _site;
    
        [TestFixtureSetUp]
        public void Setup()
        {
            _site = new SPSite("http://sp2010");
            _provider = new Class1(_site.RootWeb);
        }
    
        [TestFixtureTearDown]
        public void TearDown()
        {
            _site.Dispose();
            _provider.Dispose();
        }
    
        [Test]
        public void Get_Item_URL_By_Title_Test()
        {
            string itemTitle = "Some Title";
            int expectedId = 1;
    
            var item = _provider.GetItemIDByTitle(itemTitle);
    
            Assert.AreEqual(expectedId, item);
        }
    }
    

     

    As mentioned before you have a couple of options for running the tests (there are more, you could buy ReFactor which has some nice stuff – but I haven’t got and can’t afford that!)  I recommend you do both, TestDriven is great for quickly running and debugging a test and the NUnit test runner is great to see all the green ticks when running all your tests!  Even if it is an old, ugly interface with more “80’s grey” than anyone should have to deal with!

    Once you have TestDriven.net installed, you can simple right click on the test to debug it…

    image

    For NUnit, create add a new External Tool entry in VS.  Tools –> External Tools…

    image

    In the command – be sure to target the 64bit version, actually its just nuit.exe, so I should say be sure NOT to target the x86 version!!

    In the arguments text box, use the helper to get the placeholders for BinDir and TargetName, adding the “/run” argument will run the tests automatically when the nuit runner opens.

    You’ll then get a new entry on the Tools menu – hit that and your tests should run….

    image

    Lovely!

    More / Resources:

    more...

  • Call a PowerShell script from SharePoint feature reciever

    Tags: SharePoint, PowerShell

     

    This is not likely to be something you use on a day to day basis, and I can see how some people might disagree with this method – preferring to use other techniques e.g. SharePoint project types etc in VS.

    I just see this as another way to skin the same cat!  A very handy tool to have in your box.

    I have used this for different things, but provisioning lists and adding some content to those lists a common thing.  It’s much easier to use PowerShell to do certain things, deploying a solution every time is just a pain and not overly good use of time waiting for VS to do its thing and recycle app pools left right and centre – so I work with PowerShell on my dev box.

    This then comes in when deploying to stage or production (yes, at this point you could create the artefacts perfectly in your VS solution, but time is money people…spending hours working and essentially still be at the same point I am now, just doesn’t interest me in the slightest – I have no interest in writing code just for the sake of writing code, it much achieve something).

    However, if my project/solution were to be sold for mass reuse on farms that were totally out of my control – I would not use this method.

    You need to add a reference to System.Management.Automation

    I created a simple class called PowerShellProxy that has a couple of helper methods, but this being the important one!

    public static void RunFromFile(string filePath, bool addSharePointSnapIn)
    {
        #region Arg Validation
    
        if (String.IsNullOrEmpty(filePath))
        {
            throw new ArgumentNullException("filePath", "Cannot be null or empty");
        }
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException("File not found", filePath);
        }
    
        #endregion
    
        try
        {
            PowerShell ps = PowerShell.Create();
            if (addSharePointSnapIn)
            {
                ps.AddScript("Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction Continue");
            }
    
            string script = ReadFileContent(filePath);
            ps.AddScript(script);
            var result = ps.Invoke();
    
    

     

    You can then just pass in the file path of your ps1 file and you’re away.  Personally I have created a folder within the Layouts folder in my VS solution – that way it’s nice and neat and easy for source control.

     

    More:

    more...

  • Mobile theme for Orchard

    Tags: Orchard, mobile, CSS, Metro

    I have created a mobile specific theme for my blog! If you are on a mobile device this is not news to you!!

    I came across this post by Betrand Le Roy (the father of Orchard!) the other day whilst looking into this and it exactly what I needed for dynamically changing the theme in my blog.  Combine that will how much I like it when you go to a site on a phone and it’s layout is changed to make it easier to read/use.  And I’ve not seen many better than the blogspot/blogger theme by this guy, if you’ve got a few minutes, take a look at the site – his designs and artwork are pretty special.  You can see a demo of the mobile theme I am on about here on some Europe news blog.

    Now, I should manage expectations, my theme was created in a few hours and isn’t as good as that one…it has swipe events and everything!! Something I might look to do in the future!  I found a jGestures project on codeplex that should help.

    I could use something like jQuery mobile (which I’ve looked at before – apparently v1 is out now) or IUI, but they look very iPhoney and i think my iPhoney days are behind me, but anyway…I don’t want an iPhone look-a-likey, I think they generally look average and don’t work as well as a native app, so don’t make it look like one.

    I just want a simple theme that works well on a mobile device.  And this is what I come up with!!

    image

    I have tried on my Windows Phone 7, but that doesn’t do screen shots…which is something I just found out!!  Trust me…it looked equally magnificent!!!

    Kept with my Metro theme – which for me means square and blue Smile

    Made the whole abstract and title area clickable so its easier for fingers.

    Search box is nice and big (I have hidden the search box when you are on a single blog page – keeping the focus on the content).

    Generally made buttons/text and stuff a bit chunky!

    imageimage

    I based it on the SafeMode theme that you get with Orchard, so really starting from the bare bones, which is good – kept the project nice and trim!

    I have overridden numerous views to get this far…

    image

    Couple of problems with it:

    Navigation: I don’t have a menu, I don’t really want the same items as the main site and with the standard Orchard menu module, I don’t think its possible to have different menus.  Sure I could hack in something!

    Zones: I haven’t shown most zones, mainly because I want to keep it trim, but I would like to at least have the tags, I like using tag clouds on sites if nothing else it gives me a feel on what content I can expect to find here or where the author’s interests/expertise lies, but because I’ve got my tag cloud in the same zone as the twitter widget and I certainly don’t want that.  The solution is to probably put the tag cloud in a zone I don’t use on the main site as well as the one I do and render the respective zone in each theme!

    Bit bloaty: I’ve got a few js libraries like Syntax highlighter which give it a bit of bloat – I’m should run some tests to see how performance is!

    Moving around: Basically there is no way to move around, the theme mentioned above has back and next etc, I’m not sure this functionality is even available easily in Orchard, but currently you either need to hit the back button or scroll back up to hit the header once you’ve read something…making the wild assumption that anyone even makes it to the bottom!!

    Swipey stuff: Need to get some swipe actions happening!

    Theme switcher: I have put the code for the switching in my main theme, obviously means there is a dependency on having the mobile theme, not a problem.  However unless I set the Mobile theme as the current theme and then set it back to the main one again, the mobile theme is not loaded.  I don’t get an error, but none of the styles are loaded for the Mobile theme…i simply get “SafeMode”.

    Blog and only blog: This is specifically targeting at blog sites – it will need more work to handle pages etc.

    I’m going to hopefully work on some of those over coming weeks and release it to the Orchard Theme Gallery.

    Resources:

    more...

  • Migrate GeeksWithBlogs to Orchard CMS

    Tags: Orchard, GeeksWithBlogs, Migration, Metro, BlogML

    As you can see I have migrated my blog to the Orchard CMS platform.

    I’ve used Orchard for a few projects and having gone through the pain enjoyment of learning Orchard, it was really the only platform I was going to choose for my blog!

    The theme I created myself, based on the Metro blog engine theme and the Mango Orchard theme.  I used Metro Studio to create the icons you see in the top left!

    This, as expected was not going to be a simple export and import job, GeeksWithBlogs don’t enable the export to BlogML feature that SubText has, as they told me it was too buggy!

    Orchard has a format all of it’s own so some serious Googling was the only plan.

    Seems I was not alone in my quest to migrate from GeeksWithBlogs, I don’t have any issue with them or the platform really, yes the themes are quite ugly and its quite dated, I just wanted more control.  MrHinsh has a codeplex project for this, but as I wasn’t going to WordPress I kept looking.

    I found this solution on codeplex, to export from MetaWebBlog to BlogML and this to import from BlogML into Orchard.

    The export ran and worked fine, except it didn’t include the tags (categories) into the post and it didn’t add any of the comments.  So I played with the code, found out that GeeksWithBlogs doesn’t support the MetaBlog method (GetComments).  With MetaBlog all comments have their own RSS url, so I wrote a little method to take the blog post ID go away and get the XML for the comments, parse that and build it into the BlogML output file.

    IEnumerable<BlogMLComment> GetCommentsForPost(Post post) {
        string commentsUrl = _blogUrl + "/Comments/commentRss/" + post.postid.ToString() + ".aspx";
    
        XNamespace dc = "http://purl.org/dc/elements/1.1/";
        XDocument doc = XDocument.Load(commentsUrl);
    
        var comments = from d in doc.Descendants("item")
                       select new BlogMLComment {
                           DateCreated = DateTime.Parse(d.Element("pubDate").Value),
                           UserName = d.Element(dc + "creator").Value,
                           Title = d.Element("title").Value,
                           Content = new BlogMLContent { Text = d.Element("description").Value }
                       };
    
        return comments ?? null;
    }
    

     

    That worked great (I’m not really sure if the comments RSS URL format is specific for GeeksWithBlogs or is a MetaWebBlog thing). 

    The full code I am happy to share, I did get in touch with the author of the original project requesting to be added as a developer so I could check in my enhancements.  I’ve heard nothing yet, the last checkin from them was in 2008 so perhaps it’s a gone and forgotten project!  I might create my own project or submit a patch to the work item.

    So I have my content all ready to go!

    With the import I immediately came across a problem which i raise here, the Orchard module is not working in v 1.4.  This was swiftly sorted by the author and I’m very grateful!  Well there are a few of us in the discussion that are!!

    There were still a few little things to work around with the import, it didn’t import into the selected blog for example, it created a new one…the way round this was to put in a slug!

    So that’s it, the journey is complete!  From GeeksWithBlogs to Orchard in only 4000 steps!

    Not quite…images, ahhhhh, images!!!  The source url on all image elements are still pointing to GWB.  I haven’t sorted this and not sure I ever will!   Now it’ll be a job to spin through the Orchard content to update them all, something I would like to do, but finding the time and inclination will be challenge all in itself!

    With regard to the Metro theme, I haven’t published that to the Theme Gallery, it’s really in no state to do so!  I am overriding many views to make little changes here and there.  The way the navigation works is a little hacky as well, because I wanted to keep the standard navigation functionality in the admin section (don’t know why now!) I have overridden the view to stick in my own CSS class based on the title of the navigation item.  Then in CSS i set the image.  If I don’t want to use an image I suffix the title with /t!  hmmmm. 

    image

    The tag cloud, if you are wondering is taken from here.  It does actually seem a little flakey…it sometimes doesn’t load – I may go back to the standard way!  It’s also a bugger to use on an iPad!

    I do want to create a mobile specific theme (it doesn’t work great on my phone!) – not sure how I go about switching themes on the fly in Orchard based on the browser, but I’m sure it’s possible.  One of the beauties of Orchard is it flexibility and extensibility!

    more...

  • PowerShell script to find where in a site collection a specific feature is enabled.

    Tags: PowerShell, SharePoint

    It's not an uncommon task to want to find out in what webs you have a specific feature enabled.  This little script does just that, taking 2 params (site collection url, feature name) and simple output the SharePoint web url.  Nothing fancy, but certainly a useful script to have in your toolbox!

    A good example of this is where you are using content publishing going from an Enterprise internal farm to a Foundation external farm, certain feature won’t be in the Foundation farm and will cause the Content Publisher to fail, it will be so kind as to tell you what feature is causing the problem, but not where it is!  Someone somewhere has enabled a feature they shouldn’t have!!!

    I’m sure some “one line wizards” could optimise this script – but that’s not my bag – I’m interested in getting the job done for our clients and providing a useful script we can use again and again.

    You could of course add in Disable-SPFeature command if you wanted to do that at the same time…

    #Powershell script to identify where in a site collection a specific feature is enabled
    #Version: 1.0
    #Author: Steve Clements | Perspicuity Ltd
    #Params:
    #$siteCollectionUrl - url of the site collection
    #$featureName - name of the feature you want to find
     
     
    param ([string] $siteCollectionUrl, [string] $featureName)
     
    if(!$siteCollectionUrl-or!$featureName) {
        Write-Host-ForegroundColorRed"You must provide a site collection url and feature name to find!"
        break
    }
     
    Write-Host-BackgroundColorDarkGreen"Feature '"$featureName"' exists in these sites"
     
    Get-SPSite$siteCollectionUrl | ForEach-Object {
        Get-SPWeb-Site$_ | ForEach-Object {
          $f=Get-SPFeature-Web$_ | Where {$_.DisplayName -eq$featureName}
      if($f) {
              Write-Host$_.Url
          }
        }
    }
     
    Write-Host-BackgroundColorDarkGreen"Done"
    

    more...

  • Gotcha: 403 and 401 errors in SharePoint using Anonymous access

    Tags: SharePoint

    Recently I came up against a problem where I was getting 401 Unauthorized and 403 Forbidden errors in SharePoint on an extended anonymous only site.

    It worked perfectly when using windows authentication, for any level of user.

    In the end I tracked the problem down to accessing SPContext.Current

    I found this article which states you should use SPSecurity.RunWithElevatedPrivileges when using the current context and it worked!!

    A little surprising, but not unexpected the SharePoint logs showed nothing about this problem.

    Check out the link above which gives a perfect little code snippet of how to resolve the problem.

    more...

  • Enable Publishing Approval workflow on all SP Web(s) in an Site collection with Powershell

    Tags: PowerShell, SharePoint

    What you need / What you've got?

    1. Pretty obvious, when a user edits/changes a page, you need someone to check its all good before it goes live! Aka Publishing Approval
    2. You can use the "Publishing site with workflow" template or enable it manually or set it up in your custom site definition.
    3. BUT...you've got an entire site collection full of web sites and you need to do it "en-mass" … step up Powershell.
      1. A common scenario could be you were working in Stage or Pre-go live and having Approval workflow just isn't practical or required. Now its live...you need and want it.

    What you need to do to SharePoint...

    1. Enable Moderation on the library (that is Content Approval in UI)
    2. Enable Minor Versions (that’s is 1.1, 1.2 etc)
    3. Create the Workflow History list and enable the Workflow History feature (hiding this list is optional, but I think its best, showing the list offers nothing to the user, you can access the same history looking at the workflow status screen, which is far more usefully presented)
    4. Create the Workflow Tasks list
    5. Associate the "Publishing Approval" workflow to the library
    6. Set the properties on the WorkFlow association
      1. This is your choice, but I have set AllowManual to true, AutoStartCreate and Change to false
    7. Add the association
    8. You would be forgiven in thinking that’s it, job done...but you will find that the even though the workflow is there, it doesn't the "major check-in" property enabled so the experience for the user is different i.e they have to choose the non-default option to fire the workflow.
    9. You need to set the property DefaultContentApprovalWorkflowId to the id of the Workflow association object, what tricked me up...even though in the UI the property is in the workflow with the other workflow properties, but this property is on the library.
    10. Still not done...now, the workflow is firing great, but every status is "Rejected". Why? Because you need to Update the workflow association data.
    11. For this I cheated and setup 1 workflow on the pages library, with the correct actions and Approvers group, then went into SharePoint Manager and grabbed the xml from there.
    12. Also I set the Enabled property to true and call WorkflowAssociations.Update(myAssociation) to set both new properties…
    13. Yes, that’s it...you are actually done now!!!

    The Magic

    This script is 99% influenced by this post http://bit.ly/AcOa2s, I’ve butchered it and added the extra stuff required… FYI: http://get-spscripts.com is a great resource for SharePoint PowerShell scripts...the scripts published are always of high quality, well commented and explained - bookmark it if you don't like thrashing.

    The crazy colours and rather OTT output is my fault!

    I’ve also put the params at the top – not overly user friendly, but this is perfect for my requirements…you can easily change that!

    $url="<site collection URL>"
    $list="Pages"
    $workFlowName="Publishing Approval"
    $wfassname="Page Approval"
     
     
     
    functionAddWorkflowToLibraries ($SiteCollection, $ListName, $WfName, $WfAssociationName)
    {
       #Get site object and create blank guid to store workflow template ID
        $site=Get-SPSite$SiteCollection
       [Guid]$wfTemplateId=New-ObjectGuid
        
        # Get every sub web
        Get-SPWeb-Site$site | ForEach-Object {
      Write-Host-ForegroundColorWhite-BackgroundColorDarkMagenta"WEB: "$_.Title$_.Url
            
            #Do the following if a list exists with the name specified by the user - e.g., Pages
            if ($_.Lists[$ListName]) {
                Write-Host"PROCESS:"$listName"list"
                
                #
                # Get list and set version properties
                #
                $list=$_.Lists[$ListName]
                $list.EnableModeration =$true
                $list.EnableMinorVersions =$true
                $list.Update()
                
               #Go through each workflow installed in the site to find the correct ID            
                foreach ($wfTemplatein$_.WorkflowTemplates) {
                    if ($wfTemplate.Name -eq$WfName) {
                       $wfTemplateId=$wfTemplate.Id
                   }
               }
                
                #
                #SETUP WORKFLOW HISTORY LIST
                #
                $wfTemplate=$_.WorkflowTemplates[$wfTemplateId]
                if($wfTemplate-eq$null) {
                    Write-Host"ERROR: Workflow '"$WfName"' with ID '"$wfTemplateId"' NOT found"-BackgroundColorRed-ForegroundColorWhite
                }
                else {
                    #Check if the site already has a workflow history list - if not, create it
                if(!$_.Lists["Workflow History"])
                    {
                        Write-Host"CREATE: Workflow History list"-ForegroundColorBlue
                        
                    $_.Lists.Add("Workflow History", "A system library used to store workflow history information that is created in this site.  It is created by the Publishing feature.",
                        "WorkflowHistory", "00BFEA71-4EA5-48D4-A4AD-305CF7030140", 140, "100")
                        
                        if (!$_.Features["00BFEA71-4EA5-48D4-A4AD-305CF7030140"]) {
                            Enable-SPFeature-IdentityWorkflowHistoryList-Url$_.Url
                    }
                        $wfHistory=$_.Lists["Workflow History"]
                        $wfHistory.Hidden =$true
                    $wfHistory.Update()
                    }
                    else
                {
                        Write-Host"FOUND: Workflow History list"-ForegroundColorgreen
                    $wfHistory=$_.Lists["Workflow History"]
                    }
                    
                    #
                    #Check if the site already has a workflow tasks list - if not, create it
                    #
                if(!$_.Lists["Workflow Tasks"]) {
                        $_.Lists.Add("Workflow Tasks", "This system library was created by the Publishing feature to store workflow tasks that are created in this site.", "WorkflowTasks", "BF611337-1591-49f4-BF42-CE7BE53852D8", 107, "100")
                        Write-Host"CREATE: Workflow Tasks list"-ForegroundColorBlue
                }
                    else {
                        Write-Host"FOUND: Workflow Tasks list"-ForegroundColorgreen
                    }
                $wfTasks=$_.Lists["Workflow Tasks"]
                    
                    #
                    #new up workflow association (extra associated data can be added if you have it)
                    #
                $wfAssociation= [Microsoft.SharePoint.Workflow.SPWorkflowAssociation]::CreateListAssociation($wfTemplate, $WfAssociationName, $wfTasks, $wfhistory)
                    $wfAssociation.AllowManual =$true
                    #$wfAssociation.AllowAsyncManualStart = $true
                    $wfAssociation.AutoStartChange =$false
                    $wfAssociation.AutoStartCreate =$false
                    
                    #
                    #Check to see if the association has already been added to the list
                    #
                [guid]$wfId=New-ObjectGuid
                [bool]$wfFound=$false
                    
                    foreach ($wfin$list.WorkflowAssociations) {
                        if ($wf.Name -eq$wfAssociation.Name) {
                            $wfId=$wf.Id
                            write-host"FOUND: Workflow"$wf.Name"already exists on"$list.Title"list in site"$_.Title-ForegroundColorgreen
                        $wfFound=$true
                    }
                    }
                    #If association is already there, ignore the add (and optionally delete it)
                if ($wfFound-eq$true) {
                        #Command to remove existing workflow from list before adding new one, if required
                    #$list.WorkflowAssociations.Remove($wfId)
                    write-host"REMOVE: Workflow"$wfAssociation.Name"from"$list.Title"in site"$_.Title-ForegroundColorMagenta
                }
                    #else, add it to the workflow association to the list
                else
                {
                        #Create the association
                    $list.WorkflowAssociations.Add($wfAssociation) | Out-Null
                        
                        #Set the association data (for approvers and approval steps
                        $wfAssociation.AssociationData =Get-AssociationData
                        #enable is not available until its associated.
                        $wfAssociation.Enabled =$true
                        
                        $list.WorkflowAssociations.Update($wfAssociation)
                        
                        $list.DefaultContentApprovalWorkflowId =$wfAssociation.Id
                        $list.Update()
                        write-host"CREATE: Workflow"$wfAssociation.Name"to"$list.Title"in site"$_.Title-BackgroundColorCyan-ForegroundColorRed
                }
                }
            }
            else {
                Write-Host-BackgroundColorDarkRed-ForegroundColorWhite"No"$listName" list found"
            }
        }
        
       #Dispose of Site object
        $site.Dispose()
    }
    functionGet-AssociationData() {
        return"<dfs:myFields xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`" xmlns:dms=`"http://schemas.microsoft.com/office/2009/documentManagement/types`" xmlns:dfs=`"http://schemas.microsoft.com/office/infopath/2003/dataFormSolution`" xmlns:q=`"http://schemas.microsoft.com/office/infopath/2009/WSSList/queryFields`" xmlns:d=`"http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields`" xmlns:ma=`"http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes`" xmlns:pc=`"http://schemas.microsoft.com/office/infopath/2007/PartnerControls`" xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`"><dfs:queryFields /><dfs:dataFields><d:SharePointListItem_RW><d:Approvers><d:Assignment><d:Assignee><pc:Person><pc:DisplayName>Approvers</pc:DisplayName><pc:AccountId>Approvers</pc:AccountId><pc:AccountType>SharePointGroup</pc:AccountType></pc:Person></d:Assignee><d:Stage xsi:nil=`"true`" /><d:AssignmentType>Serial</d:AssignmentType></d:Assignment></d:Approvers><d:ExpandGroups>false</d:ExpandGroups><d:NotificationMessage /><d:DueDateforAllTasks xsi:nil=`"true`" /><d:DurationforSerialTasks xsi:nil=`"true`" /><d:DurationUnits>Day</d:DurationUnits><d:CC /><d:CancelonRejection>true</d:CancelonRejection><d:CancelonChange>true</d:CancelonChange><d:EnableContentApproval>true</d:EnableContentApproval></d:SharePointListItem_RW></dfs:dataFields></dfs:myFields>"
    }
     
    AddWorkflowToLibraries$url$list$workFlowName$wfassname
    

    more...