We are working on TFS databases (TFS_Warehouse, TFS_FabrikamFibreCollection) to create some report related to TFS activities. We need to generate reports based on Team Name.
TFS maintained
following hierarchies for projects:
ProjectCollection
Project
Team
We are able to map ProjectCollections and Projects in the TFS_Warehouse database, they are in DimTeamProject.
But ee are not able to map Team Name in TFS_Warehouse / TFS_FabrikamFibreCollection database.
If you have any idea about Team Name mappings with DB tables please let me know.
This is the closest solution I found for your question:
SELECT map.[TeamId]
,map.[ProjectId]
,proj.[ProjectNodeName] AS [Team Project Name]
,ado.[SamAccountName] AS [Team Name]
FROM [Tfs_FabrikamFibreCollection].[dbo].[tbl_TempTeamProjectMapping] map
JOIN [Tfs_Warehouse].[dbo].[DimTeamProject] proj ON map.[ProjectId] = proj.[ProjectNodeGUID]
JOIN [Tfs_FabrikamFibreCollection].[dbo].[ADObjects] ado ON map.[TeamId] = ado.[TeamFoundationId]
For some reason, the [tbl_TempTeamProjectMapping] table includes the default security groups (Readers, Contributors, Project Administrators, etc.) but these can easily be filtered out of the results.
We don't suggest handle database directly. You can create Excel reports instead. Usually, when we create a Team, we'll create an area path with the name of the team. So you can try to select Area Path in the field:
I'd recommend staying away from the SQL and use the TFS API. The following PowerShell invokes the TFS client namespace and brings back the collections and projects.
#region Get-TfsSummary
function Get-TfsSummary{
param(
[parameter(Position=0,HelpMessage=' Full server name. e.g. tfsServer.domain.net',Mandatory)]
[string]
$serverFQDN, # eg 'tfsServer.domain.net'
[parameter(Position=1,HelpMessage=' port used to access the TFS server e.g. 8080')]
[string]
$serverPort, # eg '8080'
[parameter(Position=2,HelpMessage=' The root virtual directory for TFS. Default is tfs e.g. tfs ')]
[string]
$tfsRootNode # eg 'tfs'
)
Add-Type -AssemblyName "Microsoft.TeamFoundation.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
$tfsUri = 'http://' + $serverFQDN + ':' + $serverPort +'/' + $tfsRootNode + '/'
$tfsConfigurationServer = [Microsoft.TeamFoundation.Client.TfsConfigurationServerFactory]::GetConfigurationServer($tfsUri)
$tpcService = $tfsConfigurationServer.GetService("Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService")
$sortedCollections = $tpcService.GetCollections() | Sort-Object -Property Name
$numberOfProjects = 0
$numberOfStoppedCollections = 0
$numberOfStartedProjects = 0
$numberOfStoppedProjects = 0
$isStopped = ''
foreach($collection in $sortedCollections) {
$collectionUri = $tfsUri + "/" + $collection.Name
$tfsTeamProject = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($collectionUri)
try {
$cssService = $tfsTeamProject.GetService("Microsoft.TeamFoundation.Server.ICommonStructureService4")
}catch{}
$sortedProjects = $cssService.ListProjects() | Sort-Object -Property Name
if($collection.State -eq 'Stopped'){
$isStopped = ' but is stopped'
$numberOfStoppedCollections++
$numberOfStoppedProjects += $sortedProjects.Count
}
Write-Host "`n" $collection.Name "(" $collection.Id ")- contains" $sortedProjects.Count "project(s)$isStopped"
$isStopped = ''
foreach($project in $sortedProjects)
{
$numberOfProjects++
Write-Host (" - " + $project.Name + " (" + $project.Uri + ")")
}
}
$numberOfStartedProjects = $numberOfProjects - $numberOfStoppedProjects
Write-Host
Write-Host "Number of stopped collections " $numberOfStoppedCollections
Write-Host "Total number of project collections " $sortedCollections.Count
Write-Host "Online projects " $numberOfStartedProjects
Write-Host "Total number of projects " $numberOfProjects
}
#endregion Get-TfsSummary
Related
We are using Azure DevOps 2019 on-prem in our firm, and I would like to create an option box field in our Bug work item, and I want it to be a combo-box where the values are builds from all the build definitions under the project.
From checking the documentation of the system, I did not find any option to how to do it, and ether if it would be better to query the System through the API, or Query the DB.
I don't think there is a built-in feature like this.
What you can do, is to create a string field that takes the values from the gloabllist, in the globallist create in the first time a globallist with the project name, for example:
<GLOBALLIST name="MyProject-builds">
</GLOBALLIST>
Now you can use PowerShell to get the build definitions for this project, and update this globallist with the values:
Param(
[string]$collection = "http://tfs-server:8080/tfs/collection",
[string]$project = "MyProject",
[string]$filePath = "C:\Globallist.xml"
)
$url = "$collection/$project/_apis/build/definitions?api-version=4.0"
$builds = (Invoke-RestMethod -Uri $url -Method Get -UseDefaultCredentials -ContentType application/json).value.name
witadmin exportgloballist /collection:$collection /f:$filePath
[xml]$gloabllist = Get-Content $filePath
$gloabllist.GLOBALLISTS.GLOBALLIST.Where({ $_.name -eq "$project-builds" }).LISTITEM | %{ $_.ParentNode.RemoveChild($_) | Out-Null }
$node = $gloabllist.GLOBALLISTS.GLOBALLIST.Where({ $_.name -eq "$project-builds" })
$builds.ForEach({
$child = $gloabllist.CreateElement("LISTITEM")
$att = $gloabllist.CreateAttribute("value")
$child.Attributes.Append($att)
$child.value = "$_"
$node.AppendChild($child)
})
$gloabllist.Save($filePath)
witadmin importgloballist /collection:$collection /f:$filePath
You can set a scheduled build that tun this script each day to be updated all the time.
You can also improve the script to get all the projects, itreate them, get the build definitions names and update the globallist file.
The Company I work for uses Jira to support the requirement capture & test phases of a project. We assign stories (i.e. requirements) to a release. As a Test Engineer, I raise bugs which I then reference in the story as "Is Blocked By".
I need to create a report which lists each of the releases and the stories associated with that release. As I raise bugs, I need the report to also be populated by the bugs (or actually any other issue raised).
I cannot see a way of doing this within Jira directly but I have found a Jira module for Python... I've got the following working but now I'm stuck;
from jira import JIRA
server = {"server" : "https://jira.pxr5.hw"}
login = ('bob', 'dave')
jira = JIRA (options = server, basic_auth = login)
myProject = jira.project ("QSC")
for eachVersion in myProject.versions:
print eachVersion.name + " - " + eachVersion.id
This produces the expected output;
Release 0 - 10518
Release 0.1 - 10602
Release 0.2 - 10603
Release 1.0 - 10519
Release 2.0 - 10520
Release 3.0 - 10521
closed - 10616
work complete - 10617
From the documentation I've found, I cannot see how to return anything further by which I mean the stories under each Version and (where they exist) the bugs I've raised.
Please can you help? Thanks for your attention.
I got there in the end... Kind of... Here's a solution I found by unpicking the "raw" property...
from jira import JIRA
import sys
userName = "Dave"
userPassword = "Bob"
server = {"server" : "https://jira.pxr5.hw"}
login = (userName, userPassword)
# Open a link to Jira
jira = JIRA (options = server, basic_auth = login)
# Return an object comprising the project we're working on
myProject = jira.project ("quark")
# Get a list of the releases in the project. Notice that the version
# has to be surrounded by single quotes as it may have spaces in it
for eachVersion in myProject.versions:
jqlStatement = "project=quark AND fixVersion='" + eachVersion.name + "'"
print eachVersion.name
# Get a list of stories accociated with each release of the project
theStories = jira.search_issues (jqlStatement)
# Go through each story in the current release
for eachStory in theStories:
# The story is indented one tab with it's ID and summary name
print "\t" + eachStory.raw["key"] + " " + eachStory.raw["fields"]["summary"]
# Now get a list of issue links and go through each one
issueLinks = eachStory.raw["fields"]["issuelinks"]
for eachLink in issueLinks:
print "\t\t" + eachLink["inwardIssue"]["key"] + " " + \
eachLink["inwardIssue"]["fields"]["summary"]
I have a requirement to export Windows Event logs to CSV from our production environment periodically.
I have a simple XML Config file containing a list of machines I need the events from, and a list of Event Ids that I need to retrieve.
From here I'm looping through each machine name in turn, and then each event Id to retrieve the logs and then export to CSV. I'd like one CSV per machine per execution.
Once I've worked out all my variables the PS Command is quite simple to retrieve the log for one Event Id
foreach ($machine in $config.Configuration.Machines.Machine)
{
$csvname=$outputlocation + $machine.Value + "_" + $datestring + ".csv"
foreach ($eventid in $config.Configuration.EventIds.EventId)
{
Get-WinEvent -ComputerName $machine.Value -ErrorAction SilentlyContinue -FilterHashTable #{Logname='Security';ID=$eventid.Value} | where {$_.TimeCreated -gt $lastexecutiondate} | export-csv -NoClobber -append $csvname
}
}
Execpt I'm unable to append to a CSV each time, PS 2.0 apparently does not support this. I've tried extracting all Event Ids at once but this seems to be a bit long winded and may now allow use of a config file, but I'm fairly new to PowerShell so I haven't had much luck.
I also need to specify multiple LogNames (System, Security and Application), and would prefer to run one statement as opposed to the same statement 3 times and appe but I'm unsure of how to do this.
Unfortunately at this point Google has me running in circles.
The following is something I culled together to allow me to export the prior 24 hours of events for select event logs - I'm going to create a scheduled task out of it so it pulls a daily.
Hope this helps someone else...
$eventLogNames = "Application", "Security", "System", "Windows PowerShell"
$startDate = Get-Date
$startDate = $startDate.addDays(-1).addMinutes(-15)
function GetMilliseconds($date)
{
$ts = New-TimeSpan -Start $date -End (Get-Date)
[math]::Round($ts.TotalMilliseconds)
}
$serverName = get-content env:computername
$serverIP = gwmi Win32_NetworkAdapterConfiguration |
Where { $_.IPAddress } | # filter the objects where an address actually exists
Select -Expand IPAddress | # retrieve only the property *value*
Where { $_ -notlike '*:*' }
$fileNameDate = Get-Date -format yyyyMMddhhmm
$endDate = Get-Date
$startTime = GetMilliseconds($startDate)
$endTime = GetMilliseconds($endDate)
foreach ($eventLogName in $eventLogNames)
{
Write-Host "Processing Log: " $eventLogName
<# - Remove comment to create csv version of log files
$csvFile = $fileNameDate + "_" + $serverIP +"_" + $eventLogName + ".csv"
Write-Host "Creating CSV Log: " $csvFile
Get-EventLog -LogName $eventLogName -ComputerName $serverName -After $startDate -ErrorAction SilentlyContinue | Sort MachineName, TimeWritten | Select MachineName, Source, TimeWritten, EventID, EntryType, Message | Export-CSV $csvFile #ConvertTo-CSV #Format-Table -Wrap -Property Source, TimeWritten, EventID, EntryType, Message -Autosize -NoTypeInformation
#>
$evtxFile = $fileNameDate + "_" + $serverIP + "_" + $eventLogName + ".evtx"
Write-Host "Creating EVTX Log: " $evtxFile
wevtutil epl $eventLogName $evtxFile /q:"*[System[TimeCreated[timediff(#SystemTime) >= $endTime] and TimeCreated[timediff(#SystemTime) <= $startTime]]]"
}
Why do I get Failed to export log Security. The specified query is invalid. I get this for each type of event log (system, application etc). This happens only to evtx export. I get the csv file tho`....
I needed to change a work item field from PlainText -> String.
As I could not change the type on the Work Item, creating a new field and updating it's value from the other field is my approach.
I have tried the "Bulk Edit Selected Work Items.." from TFS/Web but I'm not sure if you may reference another field value in that template.
How may I set [Work Item].[FieldNew].Value = [Work Item].[FieldOriginal].Value ??
Is this even possible without having to use the TFD API?
The reason why I need to change the item field type from PlainText to String is that I want to have a query with a column operator to test if the field has value or not.
For a plainText field the only allowed operator is Contains/Does Not Contain. May I override this to allow a ">" ?
KMoraz's solution does not work for me either, because the HTML field becomes read-only when exported to Excel. Therefore, I used a Powershell script to copy the value of one field into another (just replace the "$wiFieldNewValue" variable with the source field you are copying)
Code reference: Bulk update TFS work items using Powershell
Link to code
Embedded code:
#This script sets a specific field to a specified value for all work items in a specific project
Function LoadTfsAssemblies() {
Add-Type –AssemblyName "Microsoft.TeamFoundation.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-Type -AssemblyName "Microsoft.TeamFoundation.WorkItemTracking.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
}
##### SETTINGS
#The TFS Team Project Collection to connect to
$tfsUri = "http://tfsserver:8080/tfs/DefaultCollection"
#The TFS Team Project from which to select the work items
$tfsProject = "Test Project"
#The work item type of the work items to update
$wiType = "Test Case"
#The reference name of the field to update
$wiFieldRefName = "Microsoft.VSTS.Common.Priority"
#The value to set the field to
$wiFieldNewValue = "1"
##### END SETTINGS
LoadTfsAssemblies
$tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tfsUri)
$tfs.EnsureAuthenticated()
if($tfs.HasAuthenticated)
{
Write-Output "Successfully authenticated to TFS server [$tfsUri]"
$workItemStore = $tfs.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore])
$query = "SELECT [System.Id], [System.Title] FROM WorkItems WHERE [System.TeamProject] = '{0}' AND [System.WorkItemType] = '{1}'" -f $tfsProject, $wiType
Write-Output("Using query [$query]")
$workItems = $workItemStore.Query($query)
Write-Output("Going to update [{0}] work items" -f $workItems.Count)
$successCount = 0
$failureCount = 0
ForEach($wi in $workItems) {
Write-Output("Updating work item [{0}]" -f $wi.Title)
try {
$wi.Open()
$wi.Fields[$wiFieldRefName].Value = $wiFieldNewValue
Write-Output("Set field [{0}] to [{1}]" -f $wiFieldRefName, $wiFieldNewValue)
$validationMessages = $wi.Validate()
if($wi.IsValid() -eq $true)
{
$wi.Save()
Write-Output("Successfully updated work item [{0}]" -f $wi.Title)
$successCount++
} else {
Write-Error("Work item is not valid!")
ForEach($validationMessage in $validationMessages)
{
Write-Error("Error: {0}" -f $validationMessage)
}
$failureCount++
}
} catch {
Write-Error("Couldn't set field [{0}] to [{1}] for work item [{2}]" -f $wiFieldRefName,$wiFieldNewValue,$wi.Title)
Write-Error $_
$failureCount++
}
}
Write-Output("Finished!")
Write-Output("Successfully updated: {0}" -f $successCount)
Write-Output("Failed to update: {0}" -f $failureCount)
} else {
Write-Error("Couldn't authenticate to TFS server [$tfsUri]")
}
I'ts possible via Excel.
Create a query with both old and new field columns visible.
Export the query to Excel.
Copy and paste the data from old field column to the new field.
In Excel, from the Team menu click Publish to update the changes in TFS.
I have few workitems which contain custom field called "Reference ID"
is it possible to query using wiql on this custom field.
Currently I am using the following approach:
//foreach project in TFS
//form the wiql
WorkItemCollection workItemCollection = workItemStore.Query(
" SELECT [System.Id], [System.WorkItemType]," +
" [System.State], [System.AssignedTo], [System.Title] " +
" FROM WorkItems " +
" WHERE [System.TeamProject] = '" + tfsProject.Name +
"' ORDER BY [System.WorkItemType], [System.Id]");
//run a loop against the result set
//if workitem.Fields["Reference ID"]=required value
//do some tasks on this workitem
this approach is taking quite sometime since there are more than 1000 results.
my question:
is it possible to add custom field also as a filter condition in the above query
Yes. You use the field name that's associated with the item. You can get this using the Process Explorer (TFS Power Tools) and opening the WorkItemType.
Here's an example we use today
Select Id from WorkItems where ([xxx.Ticket.OriginalTicketID] = '12345');
If you do not have access to TFS Power Tools or the ability to install it, then you can also use the DisplayForm property of the Work Item Object.
myItem = Workitem.GetWorkItem("12345")
myItem.DisplayForm
DisplayForm returns an XML containing all the Field Names and Properties. You could look up the XML by label and get the corresponding Control FieldName.
myItem.Fields.Item("Custom.FieldName")
Sure, just add the name of the custom field.