I am trying to automate a process that gets and sets mailbox permissions using remote powershell via an automated exchange pipeline. The AccessRights property of the Get-MailboxPermission command output is of type Microsoft.Exchange.RecipientTasks.MailboxRights []. I cannot find this namespace anywhere on nuget and it does not appear to be part of the EWS api, as far as I can tell. Does anyone know where this namespace can be found so I can reference it in my project, or if there is a way to cast the output as a standard object type?
Thank you
In Remote Powershell you have deserialized types https://blogs.msdn.microsoft.com/powershell/2010/01/07/how-objects-are-sent-to-and-from-remote-sessions/ so the server side types aren't what you should be using at that point. All you need to do is something like
Command getmbPerms = new Command("Get-MailboxPermission");
getmbPerms.Parameters.Add("Identity", Mailbox);
Pipeline plPileLine = Runspace.CreatePipeline();
plPileLine.Commands.Add(getmbPerms);
Collection<PSObject> RsResultsresults = plPileLine.Invoke();
foreach (PSObject obj in RsResultsresults)
{
Console.WriteLine(obj.Properties["User"].Value.ToString());
PSObject AccessRights = (PSObject)obj.Properties["AccessRights"].Value;
System.Collections.ArrayList AccessRightsCol = (System.Collections.ArrayList)AccessRights.BaseObject;
foreach (String Permission in AccessRightsCol)
{
Console.WriteLine(Permission);
}
}
plPileLine.Stop();
and then just parse the Enums out of the String. When you Set rights for a user the AccessRights parameter is just a string that matches the server side enums.
Command AddPermissions = new Command("Add-MailboxPermission");
AddPermissions.Parameters.Add("Identity", Mailbox);
AddPermissions.Parameters.Add("User", UserName);
AddPermissions.Parameters.Add("AccessRights", "FullAccess");
AddPermissions.Parameters.Add("AutoMapping", false);
Related
I'm trying to assign a value to the custom Active Directory attribute msExchRecipientTypeDetails for a user account as below, but it's resulting in an "unspecified error" COM exception. I'm not seeing this problem with other custom attributes (including others related to MS Exchange), nor with small values (e.g., 1) on the right side of the assignment. It doesn't seem to be security-related. How do I resolve this?
using (DirectoryEntry userEntry = result.GetDirectoryEntry())
{
userEntry.Properties["msExchRecipientTypeDetails"].Value = 2147483648;
userEntry.CommitChanges();
}
The msExchRecipientTypeDetails attribute is of type IADsLargeInteger, which is AD's way of storing long (64-bit) integers. The number must be converted to IADsLargeInteger before being assigned.
This does the conversion:
using ActiveDs;
private IADsLargeInteger LongToAdLong(long inputValue)
{
IADsLargeInteger outputValue = new LargeInteger(); // 64-bit
outputValue.HighPart = (int)(inputValue >> 32); // 32-bit
outputValue.LowPart = (int)(inputValue & 0xFFFFFFFF); // 32-bit
return outputValue;
}
Using that, you can now assign the value to the attribute:
using (DirectoryEntry userEntry = result.GetDirectoryEntry())
{
var mailboxTypeValue = LongToAdLong(2147483648);
userEntry.Properties["msExchRecipientTypeDetails"].Value = mailboxTypeValue;
userEntry.CommitChanges();
}
As an aside, if you are directly assigning values to AD Exchange attributes as part of a process to provision mailboxes for new users, don't do this as it is unsupported and will result in email issues, some of which may not be obvious. A better way would be to use the PowerShell API to call into an appropriate PowerShell command, such as Enable-RemoteMailbox.
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 am creating a new EventLog EventSource, and I use my own custom set of categories.
I currently do this in C# code with the following:
var eventSourceData = new EventSourceCreationData(sourceName, logName)
{
CategoryCount = AllCategories.Count(),
CategoryResourceFile = resourceFilePath,
ParameterResourceFile = resourceFilePath,
MessageResourceFile = resourceFilePath
};
EventLog.CreateEventSource(eventSourceData);
I have now converted this to a powershell script like this:
New-eventlog -logname $Log -ComputerName $ComputerName -Source $Source -CategoryResourceFile $categoryDllPath -MessageResourceFile $categoryDllPath -ErrorVariable Err -CategoryCount 20
Notr -CategoryCount 20 at the end, my script fails on this argument saying it is not a valid parameter. (Which it seems not to be)
So my question is, using Powershell how can I provide the CategoryCount so that the logging works correctly?
Thanks so much.
The error message is A parameter cannot be found that matches parameter name 'CategoryCount'.
As far as I can see, New-EventLog doesn't support CategoryCount.
But you can still use .NET classes directly in Powershell, so something like this should work:
$eventSourceData = new-object System.Diagnostics.EventSourceCreationData("$SourceName", "$logName")
$eventSourceData.CategoryCount = 20
$eventSourceData.CategoryResourceFile = $CategoryDllPath
$eventSourceData.MessageResourceFile = $CategoryDllPath
If (![System.Diagnostics.EventLog]::SourceExists($eventSourceData.Source))
{
[System.Diagnostics.EventLog]::CreateEventSource($eventSourceData)
}
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 have 2 powershell scripts that I execute from c# which I'm using to first list message using an IMAP cmdlet and the 2nd script performs a view on a specific message. Both execute successfully from powershell, the 2nd one I am trying to retrieve an attachment and I see a bunch of data output to the console like so...
Sent from my iPhone
------=_NextPart_000_0027_01CCDAA7.399EBE00
Content-Type: image/jpeg; name="photo.JPG"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="photo.JPG"
/9j/4QH6RXhpZgAATU0AKgAAAAgACgEPAAIAAAAGAAAAhgEQAAIAAAAHAAAAjAESAAMAAAABAAYA
AAEaAAUAAAABAAAAlAEbAAUAAAABAAAAnAEoAAMAAAABAAIAAAEyAAIAAAAUAAAApAITAAMAAAAB
AAEAAIdpAAQAAAABAAAAuIglAAQAAAABAAABZgAAAABBcHBsZQBpUGhvbmUAAAAAAEgAAAABAAAA
SAAAAAEyMDA5OjA5OjIwIDE1OjEwOjU1AAAKgp0ABQAAAAEAAAE2kAAABwAAAAQwMjIxkAMAAgAA
ABQAAAE+kAQAAgAAABQAAAFSkQEABwAAAAQBAgMAoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIA
BAAAAAEAAAZAoAMABAAAAAEAAASwpAYAAwAAAAEAAAAAAAAAAAAAAA4AAAAFMjAwOTowOToyMCAx
so it appears everything is fine so far - except there is I believe a difference in the function result as possible a stream/pipe from powershell?
The first one returns a collection of PSObjects which is called like so
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();
foreach (PSObject result in ps.Invoke())
{
dynamic val = result.BaseObject;
}
The 2nd script executes without error using Invoke() however trying to retrieve data via for each or
dynamic xx = ps2.Invoke();
xx is empty;
I thought maybe I need to use BeginInvoke and call asynchronously so I tried
static dynamic GotMail(dynamic o)
{
return o;
}
delegate dynamic SomeDelegate(dynamic o);
and attempted to use like so..
SomeDelegate sd = GotMail;
IAsyncResult ar = ps2.BeginInvoke();
dynamic val2 = sd.EndInvoke(ar);
and I recieve "The async result object is null or of an unexpected type." I'm not even passing parameters into the powershell scripts..everything is hardcoded - the script I run from powershell successfully is exactly what I execute from .NET
Any suggestions for this much appreciated.
Thanks
You're invoking the script twice by calling Invoke() twice. Remove the first call to invoke e.g.:
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
//ps.Invoke();
foreach (PSObject result in ps.Invoke()) {
dynamic val = result.BaseObject;
}