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
}
}
Comments
- Anonymous
April 23, 2014
The comment has been removed