I need to try retrieve a list of changesets that are linked to certain work items and display info on them in the program. But I'm having a lot of trouble figuring it out.
I have been searching the internet extensively for 4 days and have come up empty handed. Is doing this even possible?
I have already tried using wiql http client but it seems to only be able to return work item information.
Use Get Work Item with $expand=relations. In this case, you receive all relations including changesets. Example:
You can reference bellow sample to do that programmatically.
C# sample for your reference to retrieve a list of changesets that are linked to a specific work item.
using System;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Uri accountUri = new Uri("https://dev.azure.com/{organization}");
String personalAccessToken = "PAT-Here";
int workItemId = 227; // ID of a work item
// Create a connection to the account
VssConnection connection = new VssConnection(accountUri, new VssBasicCredential(string.Empty, personalAccessToken));
// Get an instance of the work item tracking client
WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
WorkItemTrackingHttpClient workItemTrackingClient = connection.GetClient<WorkItemTrackingHttpClient>();
WorkItem workitem = workItemTrackingClient.GetWorkItemAsync(workItemId, expand: WorkItemExpand.Relations).Result;
Console.WriteLine(workitem.Id);
Console.WriteLine("Relations with changesets associated:");
foreach (var relation in workitem.Relations)
{
if (relation.Rel == "ArtifactLink")
{
Console.WriteLine(relation.Url);
}
}
Console.ReadLine();
}
}
}
PowerShell script calling the Get Work Item REST API to retrieve a list of changesets that are linked to a specific work item.
Param(
[string]$orgurl = "https://dev.azure.com/{organization}",
[string]$project = "ProjectName",
[string]$workitemid = "227",
[string]$user = "",
[string]$token = "PAT-Here"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#Get workitem relateions
$baseUrl = "$orgurl/$project/_apis/wit/workitems/$($workitemid)?"+"$"+"expand=all"
$response = Invoke-RestMethod -Uri $baseUrl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
#Get changesets
$changesets = $response.relations | where {$_.rel -eq 'ArtifactLink' -and $_.attributes.name -eq "Fixed in Changeset"}
if($changesets){
$changesets | select #{N="ChangesetID";E={$_.attributes.comment}}, #{N="CreatedDat";E={$_.attributes.resourceCreatedDate}}, url
}
else {
Write-Host "No changeset associated to work item $workitemid ."
}
Related
I am trying to get informations about MFA in my C# application. I already achieved to get satisfying results in Powershell but i'm struggling to make the same thing in C#.
My code in Powershell :
Get-MsolUser -SearchString c.test#mytenant.com |
Where-Object {$_.StrongAuthenticationRequirements -like “*”} |
Select-Object UserPrincipalName, DisplayName, #{n='MFA';e=
{$_.StrongAuthenticationRequirements.State}}, #{n='Methods'; e=
{($_.StrongAuthenticationMethods).MethodType}}, #{n='Default Method'; e=
{($_.StrongAuthenticationMethods).IsDefault}}
UserPrincipalName : c.test#mytenant.com
DisplayName : Cyril test
MFA : Enforced
Methods : {OneWaySMS, TwoWayVoiceMobile, PhoneAppOTP,
PhoneAppNotification}
Default Method : {False, False, False, True}
As you can see, i get the MFA status and methods used.
Now, i want to do the same in C#.
My function :
public static List<string> GetMFA(Runspace runspace, string nom)
{
List<string> listResult = new List<string>();
try
{
Command getLicenseCommand = new Command("Get-MsolUser");
getLicenseCommand.Parameters.Add(new CommandParameter("SearchString", nom));
var pipe = runspace.CreatePipeline();
pipe.Commands.Add(getLicenseCommand);
var props = new string[] { "displayname", "userprincipalname", "StrongAuthenticationRequirements" };
Command CommandSelect = new Command("Select-Object");
CommandSelect.Parameters.Add("Property", props);
pipe.Commands.Add(CommandSelect);
// Execute command and generate results and errors (if any).
Collection<PSObject> results = pipe.Invoke();
if (results.Count != 0)
{
var error = pipe.Error.ReadToEnd();
if (error.Count > 0)
{
throw new Exception(error[0].ToString());
}
foreach (PSObject resultat in results)
{
string dn = resultat.Properties["displayname"].Value.ToString();
string upn = resultat.Properties["userprincipalname"].Value.ToString();
string mfa = resultat.Properties["StrongAuthenticationRequirements"].Value.ToString();
string res = dn + '/' + upn + '/' + mfa;
listResult.Add(res);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return listResult;
}
The "StrongAuthenticationRequirements" property isn't returning something like "Enforced" but
System.Collections.Generic.List`1[Microsoft.Online.Administration.StrongAuthenticationRequirement]
What am i missing here ?
I'm guessing the OP doesn't care any more, but for the next person who struggled with this like I have for the last few hours, I'm posting an answer.
In order to call these items, you must include the Microsoft.Online.Administration references which are included as DLLs within the MSOL PowerShell module package.
In Visual Studio:
Right Click References
Select "Add Reference"
Open the "Browse.."
Navigate to the installation location of the MSOL module. This may vary depending on if it was installed on the user/machine scope.
I added Microsoft.Online.Administration.PSModule
You will now be able to parse the results in c#.
Note: It was my experience that I needed to explicitly cast the items into a variable before I could use them.
Edit:
I removed the unnecessary reference to the resources.dll after further testing.
I'm using the .NET client libraries for VSTS/TFS (https://learn.microsoft.com/en-us/vsts/integrate/concepts/dotnet-client-libraries?view=vsts) to retrieve a list of tasks for all Build Definitions for all Team Projects. I'm using the v16.139.0-preview version of the NuGet package Microsoft.TeamFoundation.ExtendedClient (I need to because I need to retrieve Release Definition workflow as well for which you need Microsoft.VisualStudio.Services.Release.Client which has a dependency requirement for the ExtendedClient). The server (on-prem) is a TFS 2017.2. In no way I'm able to retrieve the tasks/phases/process. This is my code:
VssConnection connection = new VssConnection(new Uri("http://tfsserver:8080/tfs/defaultcollection"), new VssClientCredentials());
ProjectHttpClient projectClient = connection.GetClient<ProjectHttpClient>();
IEnumerable<TeamProjectReference> projects = projectClient.GetProjects().Result;
BuildHttpClient buildClient = connection.GetClient<BuildHttpClient>();
foreach (var project in projects)
{
IPagedList<BuildDefinition> buildDefinitions = buildClient.GetFullDefinitionsAsync2(project: project.Name, name: null).Result;
foreach (BuildDefinition buildDefinition in buildDefinitions)
{
// get the tasks
}
}
I have tried to re-retrieve the Build Definition using buildClient.GetDefinitionAsync without additional effect
The "Steps" property (which is going to be deprecated) is always null
The "Process" property is empty
There is no "phases" property available (which seems logical looking at the options to have multiple phases in a Build Definition
There is a contract available for BuildDefinitionStep: https://learn.microsoft.com/en-us/vsts/extend/reference/client/api/tfs/build/contracts/builddefinitionstep?view=vsts
The REST API documentation doesn't have a property called "Step": https://learn.microsoft.com/en-us/rest/api/vsts/build/definitions/get?view=vsts-rest-4.1#builddefinition
Does anyone have an idea on how to solve this?
Just try below C# sample using .NET client libraries, test on TFS 2017.3 and VSTS, both work. (No TFS 2017.2 on my side, If I remember correctly, TFS 2017.2 has the similar build process with TFS 2015, It has no the "Process" and "phases" attribute. )
using System;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
namespace RetrieveTaskList
{
class Program
{
static void Main(string[] args)
{
//For TFS :
var tfsUrl = "http://ws-tfs2017:8080/tfs/DefaultCollection";
var buildClient = new BuildHttpClient(new Uri(tfsUrl), new VssAadCredential());
//For VSTS:
//var tfsUrl = "https://{account}.visualstudio.com";
//var buildClient = new BuildHttpClient(new Uri(tfsUrl), new VssBasicCredential(string.Empty, "PAT here"));
var definitions = buildClient.GetFullDefinitionsAsync(project: "ScrumProject");
foreach (var definition in definitions.Result)
{
Console.WriteLine(string.Format("\n {0} - {1}:", definition.Id, definition.Name));
// Get BuildDefinitionStep to array, each of which has a task property that contains things like the name of the task and the inputs.
var tasks = definition.Steps.ToArray();
//Get each step/task from the array
foreach (var task in tasks)
{
Console.WriteLine(task.DisplayName);
}
}
Console.ReadLine();
}
}
}
You can also use the REST API to retrieve the list of tasks from a build definition.
PowerShell for example:
Param(
[string]$baseurl = "http://server:8080/tfs/DefaultCollection",
[string]$projectName = "ProjectName",
[string]$buildDefinitionID = "26",
[string]$user = "domain\user",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uri = "$baseurl/$($projectName)/_apis/build/definitions/$buildDefinitionID"
Write-Host $uri
$result = (Invoke-RestMethod -Uri $uri -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
$tasks = $result.process.phases.steps.displayName
foreach ($task in $tasks)
{
write-host $task
}
You can also try the REST Client, please reference this thread : Retrieve VSTS/TFS Build task name list
A bit late to the party, but if you're wanting to iterate over the Build tasks using the AzDO .NET Client library you need to cast the Process to a DesignerProcess/DockerProcess/YamlProcess.
var buildDefinitions = await _buildClient.GetFullDefinitionsAsync(project.Id);
foreach (var buildDefinition in buildDefinitions)
{
if (buildDefinition.Process != null && buildDefinition.Process is Microsoft.TeamFoundation.Build.WebApi.DesignerProcess designerProcess)
{
foreach (var phase in designerProcess.Phases)
foreach (var step in phase.Steps)
Console.WriteLine($"taskname={step.DisplayName}");
break;//lets exit the loop early
}
}
Demo repo, https://github.com/f2calv/azdo-api-net-client-issue
With the help of #Andy I was able to solve the problem. I used Fiddler call the REST Api (http://server:8080/tfs/DefaultCollection/MyProject/_apis/build/definitions/1) and read the JSON response. I discovered that the "build" property contains the collection of tasks. I fixed the PowerShell script provided by #Andy:
Param(
[string]$baseurl = "http://server:8080/tfs/DefaultCollection",
[string]$projectName = "MyProject",
[string]$buildDefinitionID = "530",
[string]$user = "domain\user",
[string]$token = "PersonalAccessToken"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uri = "$baseurl/$($projectName)/_apis/build/definitions/$buildDefinitionID"
Write-Host $uri
$result = (Invoke-RestMethod -Uri $uri -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
foreach ($task in $result.build)
{
Write-Host $task.displayName
}
I try to create a contact folder in an other mailbox. Since Powershell can't do this I downloaded a c# sample over this MSDN site:
https://code.msdn.microsoft.com/exchange/Exchange-2013-Create-35e4948c/view/Discussions#content
Then I modified the createFolder_CS.cs to this:
class Ex15_CreateFolder_CS
{
static ExchangeService service = Service.ConnectToService(UserDataFromConsole.GetUserData(), new TraceListener());
static void Main(string[] args)
{
CreateFolder(service, "Test", WellKnownFolderName.MsgFolderRoot);
Console.WriteLine("\r\n");
Console.WriteLine("Press or select Enter...");
Console.Read();
}
static void CreateFolder(ExchangeService service, string DisplayName, WellKnownFolderName DestinationFolder)
{
// Instantiate the Folder object.
Folder folder = new ContactsFolder(service);
// Specify the name of the new folder.
folder.DisplayName = DisplayName;
// Create the new folder in the specified destination folder.
folder.Save(DestinationFolder);
Console.WriteLine("Folder created:" + folder.DisplayName);
}
}
After the change I started the program. I entered my e-mail and the password and it created the contact folder in my mailbox. But when I use a different e-mail address the program did not work.
I compiled it and started the exe-file as (other user) domain/exchange-admin but it still did not work for another mailbox.
So I read something about a ImpersonatedUserId but this is already included in the program.
Maybe you can give me some tipps how to make this working since I am a starter at c#?
The problem with your code is you not telling it what Mailbox you want to save the new folder in. You need to use the FolderId overload to specify this or its always going to save it to the Mailbox of the credentials its running under eg modify you sub like
static void CreateFolder(ExchangeService service, string DisplayName, WellKnownFolderName DestinationFolder,String TargetMailboxSMTPAddress)
{
// Instantiate the Folder object.
Folder folder = new ContactsFolder(service);
// Specify the name of the new folder.
folder.DisplayName = DisplayName;
FolderId ParentFolder = new FolderId(DestinationFolder,TargetMailboxSMTPAddress);
// Create the new folder in the specified destination folder.
folder.Save(ParentFolder);
Console.WriteLine("Folder created:" + folder.DisplayName);
}
If you want to use Impersonation then you just need to add One more line in the code
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,TargetMailboxSMTPAddress);
You will need to be assigned the ApplicationImpersonation RBAC role to use this https://msdn.microsoft.com/en-us/library/office/bb204095(v=exchg.140).aspx
If your creating a console app to run in poweshell I would suggest you just use the Managed API in Powershell eg here a script module that will create Folders in Mailbox using the Managed API
function Connect-Exchange{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [PSCredential]$Credentials
)
Begin
{
Load-EWSManagedAPI
## Set Exchange Version
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
## Create Exchange Service Object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials
#Credentials Option 1 using UPN for the windows Account
#$psCred = Get-Credential
$creds = New-Object System.Net.NetworkCredential($Credentials.UserName.ToString(),$Credentials.GetNetworkCredential().password.ToString())
$service.Credentials = $creds
#Credentials Option 2
#service.UseDefaultCredentials = $true
#$service.TraceEnabled = $true
## Choose to ignore any SSL Warning issues caused by Self Signed Certificates
Handle-SSL
## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
#CAS URL Option 1 Autodiscover
$service.AutodiscoverUrl($MailboxName,{$true})
Write-host ("Using CAS Server : " + $Service.url)
#CAS URL Option 2 Hardcoded
#$uri=[system.URI] "https://casservername/ews/exchange.asmx"
#$service.Url = $uri
## Optional section for Exchange Impersonation
#$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
if(!$service.URL){
throw "Error connecting to EWS"
}
else
{
return $service
}
}
}
function Load-EWSManagedAPI{
param(
)
Begin
{
## Load Managed API dll
###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
$EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
if (Test-Path $EWSDLL)
{
Import-Module $EWSDLL
}
else
{
"$(get-date -format yyyyMMddHHmmss):"
"This script requires the EWS Managed API 1.2 or later."
"Please download and install the current version of the EWS Managed API from"
"http://go.microsoft.com/fwlink/?LinkId=255472"
""
"Exiting Script."
exit
}
}
}
function Handle-SSL{
param(
)
Begin
{
## Code From http://poshcode.org/624
## Create a compilation environment
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
$TASource=#'
namespace Local.ToolkitExtensions.Net.CertificatePolicy{
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() {
}
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'#
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
## end code from http://poshcode.org/624
}
}
function Get-FolderFromPath{
param (
[Parameter(Position=0, Mandatory=$true)] [string]$FolderPath,
[Parameter(Position=1, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=2, Mandatory=$true)] [Microsoft.Exchange.WebServices.Data.ExchangeService]$service,
[Parameter(Position=3, Mandatory=$false)] [Microsoft.Exchange.WebServices.Data.PropertySet]$PropertySet
)
process{
## Find and Bind to Folder based on Path
#Define the path to search should be seperated with \
#Bind to the MSGFolder Root
$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)
$tfTargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
#Split the Search path into an array
$fldArray = $FolderPath.Split("\")
#Loop through the Split Array and do a Search for each level of folder
for ($lint = 1; $lint -lt $fldArray.Length; $lint++) {
#Perform search based on the displayname of each folder level
$fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1)
if(![string]::IsNullOrEmpty($PropertySet)){
$fvFolderView.PropertySet = $PropertySet
}
$SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$fldArray[$lint])
$findFolderResults = $service.FindFolders($tfTargetFolder.Id,$SfSearchFilter,$fvFolderView)
if ($findFolderResults.TotalCount -gt 0){
foreach($folder in $findFolderResults.Folders){
$tfTargetFolder = $folder
}
}
else{
Write-host ("Error Folder Not Found check path and try again")
$tfTargetFolder = $null
break
}
}
if($tfTargetFolder -ne $null){
return [Microsoft.Exchange.WebServices.Data.Folder]$tfTargetFolder
}
else{
throw ("Folder Not found")
}
}
}
#######################
<#
.SYNOPSIS
Creates a Folder in a Mailbox using the Exchange Web Services API
.DESCRIPTION
Creates a Folder in a Mailbox using the Exchange Web Services API
Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951
.EXAMPLE
Example 1 To create a Folder named test in the Root of the Mailbox
Create-Folder -Mailboxname mailbox#domain.com -NewFolderName test
Example 2 To create a Folder as a SubFolder of the Inbox
Create-Folder -Mailboxname mailbox#domain.com -NewFolderName test -ParentFolder '\Inbox'
Example 3 To create a new Folder Contacts SubFolder of the Contacts Folder
Create-Folder -Mailboxname mailbox#domain.com -NewFolderName test -ParentFolder '\Contacts' -FolderClass IPF.Contact
#>
########################
function Create-Folder{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [PSCredential]$Credentials,
[Parameter(Position=2, Mandatory=$true)] [String]$NewFolderName,
[Parameter(Position=3, Mandatory=$false)] [String]$ParentFolder,
[Parameter(Position=4, Mandatory=$false)] [String]$FolderClass
)
Begin
{
$service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials
$NewFolder = new-object Microsoft.Exchange.WebServices.Data.Folder($service)
$NewFolder.DisplayName = $NewFolderName
if(([string]::IsNullOrEmpty($folderClass))){
$NewFolder.FolderClass = "IPF.Note"
}
else{
$NewFolder.FolderClass = $folderClass
}
$EWSParentFolder = $null
if(([string]::IsNullOrEmpty($ParentFolder))){
# Bind to the MsgFolderRoot folder
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)
$EWSParentFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
}
else{
$EWSParentFolder = Get-FolderFromPath -MailboxName $MailboxName -service $service -FolderPath $ParentFolder
}
#Define Folder Veiw Really only want to return one object
$fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1)
#Define a Search folder that is going to do a search based on the DisplayName of the folder
$SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$NewFolderName)
#Do the Search
$findFolderResults = $service.FindFolders($EWSParentFolder.Id,$SfSearchFilter,$fvFolderView)
if ($findFolderResults.TotalCount -eq 0){
Write-host ("Folder Doesn't Exist")
$NewFolder.Save($EWSParentFolder.Id)
Write-host ("Folder Created")
}
else{
Write-error ("Folder already Exist with that Name")
}
}
}
I have recently began using C# to invoke powershell scripts, with some success :)
$spWeb = Get-SPWeb -Identity http://127.0.0.1
$listTemplate = [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary
$spWeb.Lists.Add($args, "", $listTemplate) > $myDirectory
$spWeb.Lists.Add returns a SharePoint GUID.
Question:
I simply wish to pass in the directory/filename in which the GUID will
be written. How could that be done?
I have posted on the MSDN forums here: http://goo.gl/5p0oz but have continued my search on stackoverflow due to a seemingly dead end thread. This post is a cumulative gathering of the information found through MSDN responses.
You can try using the Set-Content cmdlet instead, like this. You need to pass the $myFile as a string and Set-Content will do the rest for you -
Inside your script i.e. MyScript.ps1 here, you will have this piece of code -
param([string]$parameter, [string]$myFile)
try
{
$spWeb = Get-SPWeb -Identity http://127.0.0.1
$listTemplate = [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary
$guid = $spWeb.Lists.Add($parameter, "", $listTemplate)
$guid | Set-Content $myFile
}
catch
{
throw ("Failed. The error was: '{0}'." -f $_ )
}
How to Run:
Open Powershell Prompt and type this
.\MyScript.ps1 "someparam1" "D:\Output.txt"
C# Bit -
private PowerShell _ps;
_ps = PowerShell.Create();
var parameter = new List<string>
{
parameter,
myFile
};
var sr = new StreamReader(#"C:\MyScript.ps1");
_ps.AddScript(sr.ReadToEnd()).AddParameters(parameter);
_ps.Invoke();
I'm attempting to pull the latest version of source code out of TFS programmatically using the SDK, and what I've done somehow does not work:
string workspaceName = "MyWorkspace";
string projectPath = "/TestApp";
string workingDirectory = "C:\Projects\Test\TestApp";
VersionControlServer sourceControl; // actually instantiated before this method...
Workspace[] workspaces = sourceControl.QueryWorkspaces(workspaceName, sourceControl.AuthenticatedUser, Workstation.Current.Name);
if (workspaces.Length > 0)
{
sourceControl.DeleteWorkspace(workspaceName, sourceControl.AuthenticatedUser);
}
Workspace workspace = sourceControl.CreateWorkspace(workspaceName, sourceControl.AuthenticatedUser, "Temporary Workspace");
try
{
workspace.Map(projectPath, workingDirectory);
GetRequest request = new GetRequest(new ItemSpec(projectPath, RecursionType.Full), VersionSpec.Latest);
GetStatus status = workspace.Get(request, GetOptions.GetAll | GetOptions.Overwrite); // this line doesn't do anything - no failures or errors
}
finally
{
if (workspace != null)
{
workspace.Delete();
}
}
The approach is basically creating a temporary workspace, using the Get() method to grab all the items for this project, and then removing the workspace. Is this the correct way to do this? Any examples would be helpful.
I ended up using a different approach that seems to work, mainly taking advantage of the Item.DownloadFile() method:
VersionControlServer sourceControl; // actually instantiated...
ItemSet items = sourceControl.GetItems(sourcePath, VersionSpec.Latest, RecursionType.Full);
foreach (Item item in items.Items)
{
// build relative path
string relativePath = BuildRelativePath(sourcePath, item.ServerItem);
switch (item.ItemType)
{
case ItemType.Any:
throw new ArgumentOutOfRangeException("ItemType returned was Any; expected File or Folder.");
case ItemType.File:
item.DownloadFile(Path.Combine(targetPath, relativePath));
break;
case ItemType.Folder:
Directory.CreateDirectory(Path.Combine(targetPath, relativePath));
break;
}
}
I completed and implemented the code into a button as web asp.net solution.
For the project to work in the references should be added the Microsoft.TeamFoundation.Client and Microsoft.TeamFoundation.VersionControl.Client references and in the code the statements using Microsoft.TeamFoundation.Client; and using Microsoft.TeamFoundation.VersionControl.Client;
protected void Button1_Click(object sender, EventArgs e)
{
string workspaceName = "MyWorkspace";
string projectPath = #"$/TeamProject"; // the container Project (like a tabel in sql/ or like a folder) containing the projects sources in a collection (like a database in sql/ or also like a folder) from TFS
string workingDirectory = #"D:\New1"; // local folder where to save projects sources
TeamFoundationServer tfs = new TeamFoundationServer("http://test-server:8080/tfs/CollectionName", System.Net.CredentialCache.DefaultCredentials);
// tfs server url including the Collection Name -- CollectionName as the existing name of the collection from the tfs server
tfs.EnsureAuthenticated();
VersionControlServer sourceControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
Workspace[] workspaces = sourceControl.QueryWorkspaces(workspaceName, sourceControl.AuthenticatedUser, Workstation.Current.Name);
if (workspaces.Length > 0)
{
sourceControl.DeleteWorkspace(workspaceName, sourceControl.AuthenticatedUser);
}
Workspace workspace = sourceControl.CreateWorkspace(workspaceName, sourceControl.AuthenticatedUser, "Temporary Workspace");
try
{
workspace.Map(projectPath, workingDirectory);
GetRequest request = new GetRequest(new ItemSpec(projectPath, RecursionType.Full), VersionSpec.Latest);
GetStatus status = workspace.Get(request, GetOptions.GetAll | GetOptions.Overwrite); // this line doesn't do anything - no failures or errors
}
finally
{
if (workspace != null)
{
workspace.Delete();
Label1.Text = "The Projects have been brought into the Folder " + workingDirectory;
}
}
}
Your approach is valid.
Your error is in your project path. Use something like this instead:
string projectPath = "$/PathToApp/TestApp";
I agree with Joerage that your server path is probably the culprit. To get more insight into what's happening, you need to wire up some events on the VersionControlServer object. At minimum you'll want Getting, NonFatalError, and Conflict.
Complete list: http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver_events(VS.80).aspx
I had a similar situation where I needed to download contents of 'a' folder from tfs into an existing workspace, without creating a new workspace. With help from the above answers, I was able to put something together that works fine for me as of now. There is however a limitation. This works for contents of 'a' folder with just files and not another folder inside it -I have not tried that out. Maybe that would involve some minor updates. Sharing code, just in case someone is searching for this. I really like the fact that this approach does not deal with workspace [-create and delete], since that is not desired.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Client;
using System.IO;
namespace DownloadFolder
{
class Program
{
static void Main(string[] args)
{
string teamProjectCollectionUrl = "http://<YourTFSUrl>:8080/tfs/DefaultCollection"; // Get the version control server
TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(teamProjectCollectionUrl));
VersionControlServer vcs = teamProjectCollection.GetService<VersionControlServer>();
String Sourcepath = args[0]; // The folder path in TFS - "$/<TeamProject>/<FirstLevelFolder>/<SecondLevelFolder>"
String DestinationPath = args[1]; //The folder in local machine - "C:\MyTempFolder"
ItemSet items = vcs.GetItems(Sourcepath, VersionSpec.Latest, RecursionType.Full);
String FolderName = null;
foreach (Item item in items.Items)
{
String ItemName = Path.GetFileName(item.ServerItem);
switch (item.ItemType)
{
case ItemType.File:
item.DownloadFile(Path.Combine(DestinationPath, FolderName, ItemName));
break;
case ItemType.Folder:
FolderName = Path.GetFileName(item.ServerItem);
Directory.CreateDirectory(Path.Combine(DestinationPath, ItemName));
break;
}
}
}
}
}
While running this from the command prompt copy all the supporting dlls along with exe
cmd>> DownloadFolder.exe "$/<TeamProject>/<FirstLevelFolder>/<SecondLevelFolder>" "C:\MyTempFolder"