How to get Build Id from tfs during the build in C# - c#

To get a log link i need the id of current build, I tried to use this in my C# code, but it didn't return Build Id:
var envVars;
envVars = Environment.GetEnvironmentVariables();

To get the Build.Id during the build with C# you can sue this line:
string buildId = Environment.GetEnvironmentVariable("Build_BuildId",Environment.VariableTarget.Process);

You can get the build Id from this variable
$(Build.BuildId)
Pass it as parameter(exactly as it written here) to the tool(console app?) that you are building.
You can check other variables from this link
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml

The solution is to put this var in txt file via PowerShell script, and than get it by C#
PS:
if(!(Test-Path -Path C:\BuildVariables)){
New-Item -ItemType directory -Path C:\BuildVariables
}
Out-File -FilePath C:\BuildVariables\buildId.txt -Force -InputObject $(Build.Buildid)
C#:
public static string ShowEnvironmentVariables()
{
string var = File.ReadAllText("C:\\BuildVariables\\buildId.txt");
return var;
}

Related

Cannot Associate Test Case in Visual Studio

I have a standard MSTest unit test in a unit test C# project file. The project is running .NET Framework 4.7.2, and has version 1.3.2 of the MSTest adapter and framework installed. I am running Visual Studio 2017 Enterprise 15.7.6, and have a VSTS workspace with some random manually-created test cases in it.
When I right-click on my unit test in the Test Explorer, and select "Associate to Test Case", I am able to enter the test case ID, add the association, and click "Save". Upon save, I get an error message, below.
I have tried to save the association using different versions of MSTest, and different .NET Framework versions for the project file, neither of which solved the issue. I also tried running Visual Studio as an administrator, which did not work. Has anyone else had this issue, or know of any workarounds?
I test it in my side using two VS2017 versions, they all works well.
For example, I add a simple test case manually in one test plan in VSTS, and then I create a simple unit test project with .net 4.7.2 in my side using VS2017 15.7.6, I could a associate to Test Case in my side.
If possible, you could test it in your side with the following steps:
(1) Test it with other VS machines(The same VS version but not in the same machine if you have).
(2) Clean the VSTS cache. Clean and rebuild your test project in solution explorer window, test it again.
(3) Tools->Options->Work Items, select "Visual Studio(Compatibility mode)" there.
(4) If still no help, add a new test simple unit test project in your VS, uremove the nuget packages: MSTest.TestAdapter and MSTest.TestFramework, and then add a local reference to Microsoft.VisualStudio.QualityTools.UnitTestFramework, view the result again.
Update:
I update my VS2017 to the 15.8.1 version, I got the same issue, that option was disable in default. It would be a real feedback.
https://developercommunity.visualstudio.com/content/problem/309413/cannot-associate-test-case-in-visual-studio.html?childToView=311392#comment-311392
Other members who get the same issue could vote it.
A work around I put together and now use exclusively instead of manual association is to supply the test case id in the test method name and automatically update the case in TFS via the rest API by adding the following PowerShell script to run on a successful build in TFS.
A GUID for each test is generated using the full namespace for the test method and needs to be added to "/fields/Microsoft.VSTS.TCM.AutomatedTestId"
This would need adjusted to your own TFS authentication methods and possibly TFS version (I'm using 2017.2) along with the type of tests you need to read in. This is supporting Coded UI and xUnit. The LoadFrom at the top can be removed if you are not using Coded UI at all.
param (
[string]$Dll = $(throw "-path to test Dll is required.")
)
Write-Warning "$Dll will be locked until this powershell session closes"
#Load for CodedUi Support
[Reflection.Assembly]::LoadFrom(("C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.TestTools.UITesting.dll"))
[Reflection.Assembly]::LoadFrom(("C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll"))
try {
$tests = ([Reflection.Assembly]::LoadFrom(($Dll)).GetTypes().GetMethods() | Where-Object { $_.GetCustomAttributes($false) | Where-Object {$_.TypeId.Name -icontains 'TestMethodAttribute' -or $_.TypeId.Name -icontains 'FactAttribute' -or $_.TypeId.Name -icontains 'SkippableFactAttribute' -or $_.TypeId.Name -icontains 'TheoryAttribute'}} | ForEach-Object { #{ Class = $_.DeclaringType.Name; Name = $_.Name; FullName = $_.DeclaringType.FullName + "." + $_.Name; }})
}
catch {
Write-Error "Could not load or read $dll" -ErrorAction Stop
}
foreach ($test in $tests)
{
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider;
$nameHash = $sha1.ComputeHash([System.Text.Encoding]::Unicode.GetBytes($test.FullName));
[byte[]]$toGuid = [System.Byte[]]::CreateInstance([System.Byte],16);
[System.Array]::Copy($nameHash, $toGuid, 16);
$guid = [guid]::new($toGuid);
$id = ([Regex]::Match($test.Name, "(\d+)(?!.*\d)").Value)
try {
if ($psversiontable.PSVersion.Major -lt 6) {
$currentGUID = (Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Get -UseBasicParsing -UseDefaultCredentials).Fields.'Microsoft.VSTS.TCM.AutomatedTestId'
}
else {
$currentGUID = (Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Get -UseBasicParsing -UseDefaultCredentials -AllowUnencryptedAuthentication).Fields.'Microsoft.VSTS.TCM.AutomatedTestId'
}
}
catch {
$currentGUID = $null;
}
if($currentGUID -ne $guid)
{
Write-Host "Updating $id."
[array]$hash = #{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomatedTestName";
from = $null;
value = $test.FullName;
},#{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomatedTestStorage";
from = $null;
value = (Split-Path $DLL -leaf);
},#{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomatedTestId";
from = $null;
value = $guid;
},#{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomationStatus";
from = $null;
value = "Automated";
},#{
op = "add";
path = "/fields/System.Reason";
from = $null;
value = "Completed";
},#{
op = "add";
path = "/fields/System.State";
from = $null;
value = "Ready";
}
$patch = Convertto-json $hash -Compress
write-host $test.Name
write-host "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview"
if ($psversiontable.PSVersion.Major -lt 6) {
$result = Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Patch -UseBasicParsing -UseDefaultCredentials -Body $patch -ContentType "application/json-patch+json"
}
else {
$result = Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Patch -UseBasicParsing -UseDefaultCredentials -Body $patch -ContentType "application/json-patch+json" -AllowUnencryptedAuthentication
}
}
else {
Write-Host "No changes to $id."
}
}

Using powershell with .NET returning null

I am using .NET with powershell trying to retrieve result of Get-Acl command of specific AD object. Unfortunately when I run the code from C# code I get 0 result. Also the ThrowIfError is not throwing any error.
Command test01 = new Command("import-module");
test01.Parameters.Add("name", "activedirectory");
session.Commands.AddCommand(test01);
Command test0 = new Command("Set-Location");
test0.Parameters.Add("Path", "AD:");
session.Commands.AddCommand(test0);
Command test1 = new Command("Get-Acl");
test1.Parameters.Add("Path", identity);
session.Commands.AddCommand(test1);
session.AddCommand("select-object");
session.AddParameter("Property", "Access");
var tempResults1 = session.Invoke();
ThrowIfError();
private void ThrowIfError()
{
var errors = session.Streams.Error;
if (errors.Count > 0)
{
var ex = errors[0].Exception;
session.Streams.ClearStreams();
// Never close session to dispose already running scripts.
throw ex;
}
}
This code running on server in powershell is working correctly:
PS AD:\> Import-Module -Name activedirectory
PS AD:\> set-location ad:
PS AD:\> get-acl -path <distinguishedNameOfADObject>
Question
How to get the same result like I get from Powershell? I should get atleast something not a zero result.
Little background:
I am trying to get Send-As rights not using Get-ADPermission cmdlet because its taking too long time when I need to search for rights within thousands of mailboxes. Using this article link I am trying another approach to get the rights. I have already the slower version working using C# code:
Command command = new Command("Get-ADPermission");
command.Parameters.Add("Identity", identity);
session.Commands.AddCommand(command);
session.AddCommand("where-object");
ScriptBlock filter = ScriptBlock.Create("$_.ExtendedRights -eq 'send-as'");
session.AddParameter("FilterScript", filter);
session.AddCommand("select-object");
session.AddParameter("Property", "User");
tempResults = session.Invoke();
The better way is to define a powershell-script instead of multiple commands to get the values you need. Example with your powershell-code:
using System.Collections.ObjectModel;
using System.DirectoryServices;
using System.Management.Automation;
namespace GetAclPowershellTest
{
class Program
{
static void Main(string[] args)
{
/****Create Powershell-Environment****/
PowerShell PSI = PowerShell.Create();
/****Insert PowershellScript****/
string Content = "param($object); Import-Module ActiveDirectory; Set-Location AD:; Get-ACL -Path $object"; //Add Scrip
PSI.AddScript(Content);
PSI.AddParameter("object", "<distinguishedNameOfADObject>");
/****Run your Script with PSI.Invoke()***/
Collection<PSObject> PSIResults = PSI.Invoke();
/****All Errors****/
Collection<ErrorRecord> Errors = PSI.Streams.Error.ReadAll();
/****needed, because garbagecollector ignores PSI otherwise****/
PSI.Dispose();
/**** Your ACL-Object ****/
ActiveDirectorySecurity MyACL = (ActiveDirectorySecurity)PSIResults[0].BaseObject;
/*insert your code here*/
}
}
}
This example works for me.
You have to set a reference to the Powershell-Assembly (Usually you can find it at "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll")
Benefit of this solution is, you could read a .ps1-File you got from someone, fill the parameters with the objects you have and the script runs like in a standard powershell-session. The only requirement to set parameters is the param-part in the Script.
More Infos about param: https://technet.microsoft.com/en-us/library/jj554301.aspx
Hope, this helps...
Greetings, Ronny
Update:
string Content = "param($object); Import-Module ActiveDirectory; Set-Location AD:; (Get-ACL -Path $object).Access | Where-Object{($_.ActiveDirectoryRights -eq 'ExtendedRight') -and ($_.objectType -eq 'ab721a54-1e2f-11d0-9819-00aa0040529b')}";
And the loop at the end looks like this now:
foreach (PSObject o in PSIResults)
{
ActiveDirectoryAccessRule AccessRule = (ActiveDirectoryAccessRule)o.BaseObject;
/**do something with the AccessRule here**/
}

Accessing Sharepoint document library list using Windows PowerShell script

Task: I need to loop thru all files on Sharepoint site and download them to local folder.
Script:
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$s = Get-SPSite “https://abc.abctools.consumer.abc.net/sites/rtc/report/SitePages/Forms/AllPages.aspx”
$files = $s.RootWeb.GetFolder("Shared Documents").Files
foreach ($file in $files) {
Write-host $file.Name
$b = $file.OpenBinary()
$fs = New-Object System.IO.FileStream(("C:\SP Document Library files\"+$file.Name), [System.IO.FileMode]::Create)
$bw = New-Object System.IO.BinaryWriter($fs)
$bw.Write($b)
$bw.Close()
}
Errors: I get when i try to run/execute above script.
1. "You cannot call a method on a null-valued expression."
New-Object: Exception calling ".ctor" with "2" agrument(s): "Could not find a part of the path 'C:\SP Document Library files\'
New-Object: Constructor not found. Cannot find an appropriate constructor for the type system.IO.BinaryWrite.
The term 'Get-SPSite' is not recognized as a cmdlet, function, operable program or script file. verify the term and try again.
Response on Error #2: I have created the folder & named "SP Document Library files" so that path is correct C:\SP Document Library files not sure why i see that msg.
Library files (.csv,.xls) exists in a folder.
Folder name : 2014-01-31.
1. What to do to in order resolve above error message(s).
2. I'm not sure if i need to use whole sharepoint url or part of it.Educate me on that.
Thanks!!
Try by giving ReadWrite FileAccess.
And you can get the root web directly if you know the Url instead of using SPSite.
Here's my script I use and has always worked
$siteUrl = '“https://abc.abctools.consumer.abc.net/sites/rtc”'
$listUrl = '“https://abc.abctools.consumer.abc.net/sites/rtc/Shared Documents”'
$folderPath = 'C:\\....'
$web = Get-SPWeb -Identity $siteUrl
$list = $web.GetList($listUrl)
$items = $list.Items
ForEach ($item in $items)
{
$binary = $item.File.OpenBinary();
$folderPathToSave = $folderPath + "\\" + $item.Name;
if ($binary -ne $null)
{
$stream = New-Object System.IO.FileStream($folderPathToSave,[System.IO.FileMode]::Create,[System.IO.FileAccess]::ReadWrite);
$writer = New-Object System.IO.BinaryWriter($stream);
$writer.Write($binary);
$writer.Close();
}
}
$web.Dispose()
The original post:
http://naimmurati.wordpress.com/2012/06/07/backup-documents-from-document-library-with-powershell-script/

Call WinRT Async method from Powershell to set account picture in win8

I'm trying to put something together that will use the AD Thumbnail photo to set a user's account picture on Windows 8. It seems like I should be able to use the API from WinRT to do this. I've pieced something together from various sources about calling the API from powershell, but I can't get it working. Here's an example of what I've tried to do:
$photo = ([ADSISEARCHER]“samaccountname=$($username)”).findone().properties.thumbnailphoto
$path = "C:\temp\Photo.jpg"
$photo | set-content $path -encoding byte
[Windows.System.UserProfile.UserInformation,Windows.System.UserProfile,ContentType=WindowsRuntime] > $null
[Windows.System.UserProfile.UserInformation]::SetAccountPictureAsync($photo)
I've tried a couple of other variations, but no matter what I do, I end up with an error like this:
Cannot convert argument "image", with value: "System.Object[]", for "setAccountPictureAsync" to type "Windows.Storage.IStorageFile" . . .
Is there something simple that I'm missing here to make this work?
I found this blog post by Keith Hill which seems like it might be helpful, but I am not sure if it directly translates to the issue I'm having.
Thanks!
Aurock
https://fleexlab.blogspot.com/2018/02/using-winrts-iasyncoperation-in.html has a pure-PowerShell solution.
Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
function Await($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$netTask = $asTask.Invoke($null, #($WinRtTask))
$netTask.Wait(-1) | Out-Null
$netTask.Result
}
This could then be used as:
$photoPath = "$home\Pictures\Photo.jpg"
$file = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($photoPath)) ([Windows.Storage.StorageFile])
$result = Await ([Windows.System.UserProfile.UserInformation]::SetAccountPictureAsync($file)) ([Windows.System.UserProfile.SetAccountPictureResult])
SetAccountPicture expects an object implementing IStorageFile and not a byte array. I would save the picture to your Pictures folder then load that into a StorageFile as shown below. You should be able to pass that object into the SetAccountPicture() method e.g.
$photoPath = "$home\Pictures\Photo.jpg"
$asyncOp = [Windows.Storage.StorageFile]::GetFileFromPathAsync($photoPath)
$typeName = 'PoshWinRT.AsyncOperationWrapper[Windows.Storage.StorageFile]'
$wrapper = new-object $typeName -Arg $asyncOp
$file = $wrapper.AwaitResult()
$asyncOp = [Windows.System.UserProfile.UserInformation]::SetAccountPictureAsync($file)
$typeName = 'PoshWinRT.AsyncOperationWrapper[Windows.System.UserProfile.SetAccountPictureResult]'
$wrapper = new-object $typeName -Arg $asyncOp
$result = $wrapper.AwaitResult()
$wrapper.Dispose()

specify build action of content - Nuget

What is the simplest way to tell Nuget package to add all css files as an embedded resource (ie build action is embedded resource).
I am trying to do it through install.ps1 in the tools folder but still cant get anywhere
Note: I am creating the package from the directory structure(tools\content\lib)
This is my install.ps1 which does not work.
param($installPath, $toolsPath, $package, $project)
$MsbNS = #{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'}
function EmbeddContent($ProjectLink, [string]$XPath)
{
$nodes = #(Select-Xml $XPath $ProjectLink -Namespace $MsbNS | Foreach {$_.Node})
foreach ($node in $nodes)
{
if($node.Include.StartsWith("Content\css"))
{
$cet = $node.ownerdocument.CreateElement("EmbeddedResource")
$cet.setAttribute("Include", $node.Include)
$parent = $node.ParentNode
[void]$parent.RemoveChild($node)
[void]$parent.Appendchild($cet)
}
}
}
$project.Save()
$fileLocation = $project.FileName
$dte.ExecuteCommand("Project.UnloadProject");
$proj = [xml](gc $fileLocation)
Embeddcontent $fileLocation '//msb:Project/msb:ItemGroup/msb:Content'
$proj.Save($fileLocation)
Help Please ..
You can use DTE instead of messing with xml to change the BuildAction. From http://nuget.codeplex.com/discussions/227696:
$item = $project.ProjectItems | where-object {$_.Name -eq "ReleaseNotes.txt"}
$item.Properties.Item("BuildAction").Value = [int]3
This link shows the enumeration values:
http://msdn.microsoft.com/en-us/library/aa983962(VS.71).aspx

Categories