This can also be used to keep a pre-production environment's permissions in sync with Production.
I'm not the best at Powershell but it works :)
param ($serverName = $(throw 'please specify a TFS server name')) function GetGroupMembership { [CmdletBinding()] [OutputType([System.Data.Datatable])] PARAM ( [Parameter(Mandatory=$true, Position = 0)] [Microsoft.TeamFoundation.Framework.Client.TeamFoundationIdentity] $TFIdentity ) $tabName = $TFIdentity.DisplayName + "Membership" $table = New-Object system.Data.DataTable “$tabName” $col1 = New-Object system.Data.DataColumn GroupName,([string]) $col2 = New-Object system.Data.DataColumn DisplayName,([string]) $col3 = New-Object system.Data.DataColumn UniqueName,([string]) #Add the Columns $table.columns.add($col1) $table.columns.add($col2) $table.columns.add($col3) #Membership $GroupIdentity = $ims.ReadIdentity($TFIdentity.Descriptor,[Microsoft.TeamFoundation.Framework.Common.MembershipQuery]::Direct,[Microsoft.TeamFoundation.Framework.Common.ReadIdentityOptions]::TrueSid) $members = $ims.ReadIdentities($GroupIdentity.Members,[Microsoft.TeamFoundation.Framework.Common.MembershipQuery]::Direct,[Microsoft.TeamFoundation.Framework.Common.ReadIdentityOptions]::TrueSid) foreach($member in $members) { $row = $table.NewRow() #Enter data in the row $row.GroupName = $TFIdentity.DisplayName $row.DisplayName = $member.DisplayName $row.UniqueName = $member.UniqueName #Add the row to the table $table.Rows.Add($row) } return @(,$table ) } function GetPermissions { [CmdletBinding()] [OutputType([System.Data.Datatable])] PARAM ( [Parameter(Mandatory=$true, Position = 0)] $QueryName, [Parameter(Mandatory=$true, Position = 1)] [Microsoft.TeamFoundation.Framework.Client.AccessControlList] $acl, [Parameter(Mandatory=$true, Position = 2)] $namespace, [Parameter(Mandatory=$true, Position = 3)] $objectType, [Parameter(Mandatory=$true, Position = 4)] $objectPath ) $PermissionstabName = $QueryName $table = New-Object system.Data.DataTable “$PermissionstabName” $col1 = New-Object system.Data.DataColumn ObjectPath,([string]) $col2 = New-Object system.Data.DataColumn ObjectType,([string]) $col3 = New-Object system.Data.DataColumn Name,([string]) $col4 = New-Object system.Data.DataColumn Permission,([string]) $col5 = New-Object system.Data.DataColumn Value,([string]) #Add the Columns $table.columns.add($col1) $table.columns.add($col2) $table.columns.add($col3) $table.columns.add($col4) $table.columns.add($col5) foreach ($ace in $acl.AccessControlEntries) { if ($ace.IsEmpty) { continue } $haspermission = $false $DenyPermissions = @{} $CalculatedPermissions = @{} $AllowPermissions = @{} foreach ($action in $namespace.description.Actions) { $allowed = ($action.bit -band $ace.Allow) $denied = ($action.bit -band $ace.Deny) if (-not $allowed -and -not $denied) { continue } $haspermission =$true if ($allowed) { $CalculatedPermissions.Add($action.Name,"Allow") $AllowPermissions.Add($action.Name,$action.Name) } else { $CalculatedPermissions.Add($action.Name,"Deny") $DenyPermissions.Add($action.Name,$action.Name) } } if ($haspermission) { $identity = $ims.ReadIdentity($ace.Descriptor,[Microsoft.TeamFoundation.Framework.Common.MembershipQuery]::None,[Microsoft.TeamFoundation.Framework.Common.ReadIdentityOptions]::IncludeReadFromSource) $name = $identity.DisplayName Foreach($permission in $CalculatedPermissions.GetEnumerator()) { $row = $table.NewRow() #Enter data in the row $row.ObjectPath = $objectPath $row.ObjectType = $objectType $row.Name = $name $row.Permission = $permission.Name $row.Value = $permission.value #Add the row to the table $table.Rows.Add($row) } } } return @(,$table ) } [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Client') [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.VersionControl.Client') [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.WorkItemTracking.Client') [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Build.Client') [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Build.Common') [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation') $tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($serverName) $css = $tfs.GetService([Microsoft.TeamFoundation.Server.ICommonStructureService]) $auth = $tfs.GetService([Microsoft.TeamFoundation.Server.IAuthorizationService]) $gss = $tfs.GetService([Microsoft.TeamFoundation.Server.IGroupSecurityService]) $ss = $tfs.GetService([Microsoft.TeamFoundation.Framework.Client.ISecurityService]) $vcs = $tfs.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer]) $ims = $tfs.GetService([Microsoft.TeamFoundation.Framework.Client.IIdentityManagementService]) $wis = $tfs.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]) $cssNamespace = $ss.GetSecurityNamespace([Microsoft.TeamFoundation.Server.AuthorizationSecurityConstants]::CommonStructureNodeSecurityGuid) $membershipds = New-Object System.Data.DataSet $permissiondt = New-Object System.Data.DataSet $Objectpermissiondt = New-Object System.Data.DataSet #get all TPC Groups $tpcGroups = $IMS.ListApplicationGroups($null, [Microsoft.TeamFoundation.Framework.Common.ReadIdentityOptions]::None) foreach ($tpcgroup in $tpcGroups) { $members = GetGroupMembership $tpcgroup if ($members.rows.count -gt 0) { $membershipds.Tables.Add($members) } } $Namespaces = $ss.GetSecurityNamespaces() #Get all the permissions for top level NameSpaces foreach($namespace in $Namespaces) { $NameSpaceToken = "" switch ($namespace.Description.DisplayName) { "Server" { $NameSpaceToken = [Microsoft.TeamFoundation.Framework.Common.FrameworkSecurity]::FrameworkNamespaceToken} "Build" { $NameSpaceToken = [Microsoft.TeamFoundation.Build.Common.BuildSecurity]::PrivilegesToken} "BuildAdministration" { $NameSpaceToken = [Microsoft.TeamFoundation.Build.Common.BuildSecurity]::PrivilegesToken} "Workspaces" { $NameSpaceToken = [Microsoft.TeamFoundation.VersionControl.Common.SecurityConstants]::GlobalSecurityResource} "Collection" {}#Namespace: "WorkItemTrackingAdministration" {} # "CSS" { } "Iteration" {} "VersionControlPrivileges" {$NameSpaceToken = [Microsoft.TeamFoundation.VersionControl.Common.SecurityConstants]::GlobalSecurityResource} "WorkItemQueryFolders" {} "Project" { $NameSpaceToken = [Microsoft.TeamFoundation.PermissionNamespaces]::Project} default { continue } } try { $groupAcl = $namespace.QueryAccessControlList($NameSpaceToken,$null,$false) $table = GetPermissions $namespace.Discription.Name $groupAcl $namespace "Group" $namespace.Discription.Name $permissiondt.Tables.Add($table) } Catch { } } foreach ($project in $css.ListProjects()) { $projectGroups = $IMS.ListApplicationGroups($project.Uri,[Microsoft.TeamFoundation.Framework.Common.ReadIdentityOptions]::TrueSid) foreach($group in $projectGroups) { #only get the groups we care about if ($group.DisplayName -eq "[$($project.Name)]\Build Administrators" -or $group.DisplayName -eq "[$($project.Name)]\Project Administrators" -or $group.DisplayName -eq "[$($project.Name)]\Contributors" -or $group.DisplayName -eq "[$($project.Name)]\Readers") { } else { continue; } $members = GetGroupMembership $group if ($members.rows.count -gt 0) { $membershipds.Tables.Add($members) } $projectsecNameSpace = $ss.GetSecurityNamespace([Microsoft.TeamFoundation.Server.AuthorizationSecurityConstants]::ProjectSecurityGuid) #Get Project Permissions $ProjectSecurityToken = [Microsoft.TeamFoundation.Server.AuthorizationSecurityConstants]::ProjectSecurityPrefix + $project.Uri $groupacl = $projectsecNameSpace.QueryAccessControlList($ProjectSecurityToken, [Microsoft.TeamFoundation.Framework.Client.IdentityDescriptor[]]@($group.descriptor), $false) $table = GetPermissions $group.DisplayName $groupAcl $projectsecNameSpace "Project" $project.Name $permissiondt.Tables.Add($table) #Get Top Level Build Permissions for the Project $BuildsecNameSpace = $ss.GetSecurityNamespace([Microsoft.TeamFoundation.Build.Common.BuildSecurity]::BuildNamespaceId) $teamProjectGuid = [Microsoft.TeamFoundation.LinkingUtilities]::DecodeUri($project.Uri).ToolSpecificId $groupacl = $BuildsecNameSpace.QueryAccessControlList($teamProjectGuid, $null, $false) $tablename = $group.DisplayName + "Build Permissions" $table = GetPermissions $tablename $groupAcl $BuildsecNameSpace "Build" $project.Name $permissiondt.Tables.Add($table) } #Get Root Area Path Permissions $rootAreaNodeACL = $cssNamespace.QueryAccessControlList($wis.Projects[$project.Name].AreaRootNodeUri,$null,$false) $table = GetPermissions "$($project.Name) Root AreaPath Permissions" $rootAreaNodeACL $cssNamespace "Area Path" $wis.Projects[$project.Name].Name $Objectpermissiondt.Tables.Add($table) #Get Child Area Path Permissions foreach ($area in $wis.Projects[$project.Name].AreaRootNodes) { $areapath = $area.Path $areaseclist = $cssNamespace.QueryAccessControlList($area.uri, $null, $true) $table = GetPermissions "$areapath AreaPath Permissions" $areaseclist $cssNamespace "Area Path" $areapath $Objectpermissiondt.Tables.Add($table) } try { $vcproject = $vcs.TryGetTeamProject($project.Name) } catch { continue } #Get Version Control permissions on all VC objects $vcAcls = $vcs.GetPermissions(@($vcproject.ServerItem), [Microsoft.TeamFoundation.VersionControl.Client.RecursionType]::Full) $table = New-Object system.Data.DataTable "$($project.Name)VCPermissions" $col1 = New-Object system.Data.DataColumn ObjectPath,([string]) $col2 = New-Object system.Data.DataColumn ObjectType,([string]) $col3 = New-Object system.Data.DataColumn Name,([string]) $col4 = New-Object system.Data.DataColumn Permission,([string]) $col5 = New-Object system.Data.DataColumn Value,([string]) #Add the Columns $table.columns.add($col1) $table.columns.add($col2) $table.columns.add($col3) $table.columns.add($col4) $table.columns.add($col5) foreach($perm in $vcAcls) { foreach($entry in $perm.Entries) { foreach($allow in $entry.Allow) { $row = $table.NewRow() $row.ObjectPath = $perm.ServerItem $row.ObjectType = "VC" $row.Name = $entry.IdentityName $row.Permission = $allow $row.Value = "allow" #Add the row to the table $table.Rows.Add($row) } foreach($deny in $entry.Deny) { $row = $table.NewRow() $row.ObjectPath = $perm.ServerItem $row.ObjectType = "VC" $row.Name = $entry.IdentityName $row.Permission = $deny $row.Value = "deny" #Add the row to the table $table.Rows.Add($row) } } } $Objectpermissiondt.Tables.Add($table) } $membershipds.Tables | Format-Table -AutoSize $permissiondt.Tables | Format-Table -AutoSize $Objectpermissiondt.Tables | Format-Table -AutoSize