Share via


Finding Event Subscriptions in TFS 2012 Using PowerShell

Update: Changed script to use System.Collections.ArrayList for increased performance

Update: You can use the ArrayList but a better approach is to not use it and just pipeline each object out, so I updated the script to reflect that

Well, I'm going thru some PowerShell training at the moment and thought I could continue to apply that into my ALM needs. In this case, I came across a client that had several warning messages about the notification event failing for some email deliveries. This was detected on the Best Practices Analyzer tool found on Team Foundation Power Tools for 2012.

Their TFS setup is fairly large and contains several team projects with around 250 users, with some degree of turnover. I needed some way to list all subscriptions in the system in a format they could then query.

The script below will create a function that will connect to a TFS collection and then list all existing subscriptions. The subscriptions will be listed in an array of PSObjects, that can be piped into a Where-Object for additional filtering. The created object is a "flatter" version of the original object and it's easier to query. In addition to that, I added some code to resolve the identity of the subscriber. 

I also added code that, instead of using a custom PSObject, it uses the original .Net and I add the subscriber identity as an extended property. Either way works, so you can pick which one you like best.

Once you find the subscriptions that are invalid, you can delete them using the BISSUBSCRIBE.EXE tool and passing the subscription id.

 

The PowerShell script will create the following output (this example uses the collectionurl parameter, but if you don't specify it a dialog will pop up for you to select the collection):

 

Here's the script:

#TFS Powershell function to list all event subscriptions in TFS 

#for all team projects (or a specific team project) in a given collection

#

#Author: Marcelo Silva (marcelo.silva@microsoft.com)

#

#Copyright 2013

#

function Get-TFSEventSubscriptions

{

    Param([string] $CollectionUrlParam,

          [string[]] $Projects)

 

 

    # load the required dlls

    # Below is correct syntax for v3

    Add-Type -AssemblyName "Microsoft.TeamFoundation.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

 

    #This syntax is deprecated, however it loads whatever version you have of Team Explorer, :-)

    #[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")

 

    $tfs

 

    if ($CollectionUrlParam)

    {

        #if collection is passed then get tfs collection obj

        $tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($CollectionUrlParam)  

    }

    else

    {

        #if no collection specified, open project picker to select it via gui

        $picker = New-Object Microsoft.TeamFoundation.Client.TeamProjectPicker([Microsoft.TeamFoundation.Client.TeamProjectPickerMode]::NoProject, $false)

        $dialogResult = $picker.ShowDialog()

        if ($dialogResult -ne "OK")

        {

            exit

        }

 

        $tfs = $picker.SelectedTeamProjectCollection

    }

 

    # Authenticate current user

    try

    {

        $tfs.EnsureAuthenticated()

    }

    catch

    {

        Write-Error "Error occurred trying to connect to project collection: $_ "

        exit 1

    }

 

    #TFS Services to be used

    $eventService = $tfs.GetService("Microsoft.TeamFoundation.Framework.Client.IEventService")

    $identityService = $tfs.GetService("Microsoft.TeamFoundation.Framework.Client.IIdentityManagementService")

 

    foreach ($sub in $eventService.GetAllEventSubscriptions())

    {

        #First resolve the subscriber ID

        $tfsId = $identityService.ReadIdentity([Microsoft.TeamFoundation.Framework.Common.IdentitySearchFactor]::Identifier,

                                               $sub.Subscriber,

                                               [Microsoft.TeamFoundation.Framework.Common.MembershipQuery]::None,

                                               [Microsoft.TeamFoundation.Framework.Common.ReadIdentityOptions]::None )

        if ($tfsId.UniqueName)

        {

            $subscriberId = $tfsId.UniqueName

        }

        else

        {

            $subscriberId = $tfsId.DisplayName

        }

 

        #then create custom PSObject

        $subPSObj = New-Object PSObject -Property @{

                        ID = $sub.ID

                        Device = $sub.Device

                        Condition = $sub.ConditionString

                        EventType = $sub.EventType

                        Address = $sub.DeliveryPreference.Address

                        Schedule = $sub.DeliveryPreference.Schedule

                        DeliveryType = $sub.DeliveryPreference.Type

                        SubscriberName = $subscriberId

                        Tag = $sub.Tag

                        }

 

        #Send object to the pipeline. You could store it on an Arraylist, but that just

        #consumes more memory

        $subPSObj

 

        ##This is another variation where we just add a property to the existing Subscription object

        ##this might be desirable since it will keep the other members

        #Add-Member -InputObject $sub -NotePropertyName SubscriberName -NotePropertyValue $subscriberId

 

    }

}