Get working directory of TFS XAML Build Agents using Powershell - c#

My goal is to come up with a Powershell script to clean the working directory of XAML build agents.
To get the working directory of build agents I could use below C# code, which works fine.
I would like to implement the same in Powershell.
static void Main(string[] args)
{
var TPC = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("CollectionURI"));
IBuildServer buildServer = TPC.GetService<IBuildServer>();
\\ {Microsoft.TeamFoundation.Build.Client.BuildServer}
var buildController = buildServer.GetBuildController("ControllerName");
var buildAgent = buildController.Agents;
var workingFolder = string.Empty;
List<string> list = new List<string>();
foreach (IBuildAgent agent in buildAgent)
{
list.Add(agent.BuildDirectory);
}
}
If it is not possible to find the Powershell equivalent I will have to consume the C# in Powershell through an exe or dll.

It is similar with your C# code:
$url = "http://xxxx:8080/tfs/CollectionName/";
$tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($url);
$buildservice = $tfs.GetService("Microsoft.TeamFoundation.Build.Client.IBuildServer");
$buildcontroller = $buildservice.GetBuildController("ControllerName");
$buildagents = $buildcontroller.Agents;
foreach($buildagent in $buildagents)
{
Write-Host $buildagent.BuildDirectory;
}

Related

File Enumeration performance between .net core and powershell

I currently need to scan a folder within a c# application for files that match a pattern such as RecordId*.*
The folder currently has several hundred thousand files in it and we cannot change that, at least at the moment.
Doing this:
var folderPath = #"\\server\folder\";
var options = new EnumerationOptions()
{
BufferSize = 64000,
RecurseSubdirectories = false,
MatchType = MatchType.Simple,
MatchCasing = MatchCasing.CaseInsensitive
};
var searchPattern = $"{request.RecordId}*.*";
var isMediaFileInFolder = _fileSystem.Directory
.EnumerateFiles(folderPath, searchPattern, options);
Would take about 10 minutes to return the list of found files.
However, we can run this within PowerShell ISE and it runs in less than a second.
$Directory = "\\server\folder\"
$Filter = "REC1234*.*"
Get-ChildItem -Path $Directory -Filter $Filter
I tried running the powershell within c# through something like this:
public static List<string> PSFiles(string path, string pattern)
{
try
{
ICollection<PSObject> collection = null;
List<string> returnStrings = new List<string>();
script = "Get-ChildItem -Path " + path + " -Filter" + pattern;
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript(script);
collection = powerShell.Invoke();
}
foreach (PSObject obj in collection)
{
if (!String.IsNullOrEmpty(obj.ToString()))
{
foreach(var i in Regex.Split(obj.ImmediateBaseObject.ToString().Trim(), "\r\n"))
{
returnStrings.Add(i.Trim());
}
}
}
return returnStrings;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
And it took longer to run than the enumerate files attempt with nearly all of the time spent on the powerShell.Invoice(); step.
After testing in Powershell Core, that is also taking over 10 minutes. Further, using the Directory.EnumerateFiles() on .NET took less than a second.
So the question is, is there a way to mirror the performance of file enumeration within .NET when running on .NET Core?

.NET Core - Download or read a Json file contents from Azure Ubuntu VM

I have a node.js script on my Ubuntu VM, which produces a Json file once it finishes execution. So far I am able to execute this script from a .NET Core console app (using Visual Studio 2019) with the following code:
string subscriptionId = "mySubscriptionId";
string clientId = "myclientId";
string tenantId = "myTenantId";
string clientSecret = "myClientSecret";
var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud);
var azure = Azure.Configure().Authenticate(credentials).WithSubscription(subscriptionId);
var vm = await azure.VirtualMachines.GetByResourceGroupAsync("MyAzureRg", "MyUbuntuVm");
string cmd1 = "#!/bin/bash";
string cmd2 = "cd /home/Username/myapp/";
string cmd3 = "xvfb-run nodejs myNodeScript.js";
List<string> commands = new List<string>{cmd1,cmd2,cmd3};
Console.WriteLine("Executing shell script");
await vm.RunShellScriptAsync(commands, null);
Console.WriteLine("Script executed!");
I then use PuTTY and SSH to the Ubuntu VM, and can confirm that the Json is properly created in path /home/Username/myapp/. However, my question is how do I get the contents from it back (either read or download) to .NET Core app?
The easiest way to get the json file value in this scenario should be using RunShellScriptAsync() again, pls try the code below :
List<string> commands = new List<string> { "cat <your json file path>" };
var result = vm.RunShellScriptAsync(commands, null).GetAwaiter().GetResult();
var message = result.Value[0].Message;
Console.WriteLine(result.Value[0].DisplayStatus);
var stdout = message.Substring(message.IndexOf("[stdout]") + 9).Replace("[stderr]","").Trim();
Console.WriteLine(stdout);
Result on my side :
Hope it helps .

Running .NUnit files programmatically

.nunit files are not running when using NUNIT in C#
I have tried running below code, but the error returned is that the file is not supported. All the examples on the internet use .dll as the path for a testpackage, not .unit.
According to below sites, it is possible to run .unit files:
https://github.com/nunit/docs/wiki/Writing-Engine-Extensions and
https://github.com/nunit/nunit-project-loader/tree/master/src/extension
var path = #"path to nunit file";
var package = new TestPackage(path);
var engine = TestEngineActivator.CreateInstance();
using (var runner = engine.GetRunner(package))
{
var result = runner.Run(this, TestFilter.Empty);
}
}
I have tried the following by referencing nunitprojectloader dll:
var path = #"C:\Users\Administrator\Desktop\nunit-project-loader-master\nunit-project-loader-master\ConsoleApplication1\bin\Debug\DEV.nunit";
NUnitProjectLoader pl = new NUnitProjectLoader();
pl.LoadFrom(path);
var package = pl.GetTestPackage(path);
var engine = TestEngineActivator.CreateInstance();
using (var runner = engine.GetRunner(package))
{
// execute the tests
var result = runner.Run(this, TestFilter.Empty);
}
There is a new error by doing this:
It tries running NBi.NUnit.Runtime.dll which is referenced in the nunit file.
Everythings works fine using the console.

How do I log the Console output of a hosted scriptcs execution?

I am using scriptcs.net to host dynamic scripts, and I would like to capture the output from Console.WriteLine() into my log as information, and Console.Error.WriteLine() as errors. Same as the way Octopus Deploy custom script logging.
The reason I would like to capture the Console.WriteLine() output is to make it easy for script writers to log information using a familiar tool.
Here is my script hosting function:
public static dynamic RunScript()
{
var logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
var scriptServicesBuilder = new ScriptServicesBuilder(new ScriptConsole(), logger).
LogLevel(LogLevel.Info).Cache(false).Repl(false).ScriptEngine<RoslynScriptEngine>();
var scriptcs = scriptServicesBuilder.Build();
scriptcs.Executor.Initialize(new[] { "System.Web" }, Enumerable.Empty<IScriptPack>());
scriptcs.Executor.AddReferences(Assembly.GetExecutingAssembly());
var result = scriptcs.Executor.Execute("Hello.csx");
scriptcs.Executor.Terminate();
if (result.CompileExceptionInfo != null)
return new { error = result.CompileExceptionInfo.SourceException.Message };
if (result.ExecuteExceptionInfo != null)
return new { error = result.ExecuteExceptionInfo.SourceException.Message };
return result.ReturnValue;
}
The contents of my Hello.csx file:
Console.WriteLine("This output is lost forever");
So my question is how can I capture the text written to Console.WriteLine() and save it?

TFS / File Checkout from C#

I don't have a great deal of experience with TFS, other than using it for source control. I am working on a C# application that will need to modify files that are being controlled by TFS. From within my C# application, how can I check out a file that is controlled via TFS?
Thanks - Randy
You can use PendEdit to make your files writables, make your changes to it, then you add it to the pending changes, and finally check it in.
Here is some code where a folder structure is created and then checked in (Very similar to what you will need).
private static void CreateNodes(ItemCollection nodes)
{
using (var tfs = TeamFoundationServerFactory.GetServer("http://tfsserver:8080"))
{
var versionControlServer = tfs.GetService(typeof (VersionControlServer)) as VersionControlServer;
versionControlServer.NonFatalError += OnNonFatalError;
// Create a new workspace for the currently authenticated user.
var workspace = versionControlServer.CreateWorkspace("Temporary Workspace", versionControlServer.AuthenticatedUser);
try
{
// Check if a mapping already exists.
var workingFolder = new WorkingFolder("$/testagile", #"c:\tempFolder");
// Create the mapping (if it exists already, it just overides it, that is fine).
workspace.CreateMapping(workingFolder);
// Go through the folder structure defined and create it locally, then check in the changes.
CreateFolderStructure(workspace, nodes, workingFolder.LocalItem);
// Check in the changes made.
workspace.CheckIn(workspace.GetPendingChanges(), "This is my comment");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
// Cleanup the workspace.
workspace.Delete();
// Remove the temp folder used.
Directory.Delete("tempFolder", true);
}
}
}
private static void CreateFolderStructure(Workspace workspace, ItemCollection nodes, string initialPath)
{
foreach (RadTreeViewItem node in nodes)
{
var newFolderPath = initialPath + #"\" + node.Header;
Directory.CreateDirectory(newFolderPath);
workspace.PendAdd(newFolderPath);
if (node.HasItems)
{
CreateFolderStructure(workspace, node.Items, newFolderPath);
}
}
}
Using the other solution gave me permission problems.
Here's an alternative way to checkout your files using tf.exe:
//Checkout file
Process proc = new Process();
proc.StartInfo =
new ProcessStartInfo(
#"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe",
string.Format("checkout \"{0}\"", fileLocation)
);
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit();
For those looking to use the first solution and resolve the permission issue you can use the following code to use the current credentials, this replaces the "TeamFoundationServerFactory.GetServer" call then use the TfsTeamProjectCollection (tmPrjColl) to get the VersionControlServer:
using Microsoft.TeamFoundation.Client;
using MTVC = Microsoft.TeamFoundation.VersionControl.Client;
using MVSC = Microsoft.VisualStudio.Services.Common;
MVSC.VssCredentials creds = new MVSC.VssCredentials(new MVSC.WindowsCredential(true));
using (TfsTeamProjectCollection tmPrjColl = new TfsTeamProjectCollection(new Uri("<source control URL>"), creds))
{
MTVC.VersionControlServer verCtrlSvr = tmPrjColl.GetService<MTVC.VersionControlServer>();
...
}

Categories