Tuesday, April 8, 2014

Enumerating TFS Permissions for items within the TPC for audit and logging

Below is a powershell cmdlet that I threw together to enumerate data out of our TFS instance.  This is used to keep track of permissions in the event we need to re-create them and to allow us to audit it to make sure things don't change.

This can also be used to keep a pre-production environment's permissions in sync with Production.

In 2014 I was 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

Wednesday, March 26, 2014

A new pediatric oncology camp in Chicago

I have been working with a new pediatric oncology camp that is getting started in Chicago that will be at the Ritz Carlton Hotel, Chicago called Camp Kids are Kids.

How cool is it that there will be a pediatric oncology camp in a hotel in the city.

Take a look at their website at http://www.campkidsarekids.org.  They are getting ready for the camp to start in Aug 2014. 

10 Years from last post

 Well world!   After the last almost 10 years I have been up to a few things in life and work.  Most recently I was working at Microsoft on ...