How to set ManagedBy property for Security Group via C# - c#

I am having issues updating the ManagedBy property for Security Groups (works fine for Distribution Groups). I receive the following error: '{"You don't have sufficient permissions. This operation can only be performed by a manager of the group."}'
I am running with an account that has full access. The command works when running via PowerShell just not via C#. Here is the command I am running.
Command cmdCreateDR = new Command("Set-DistributionGroup");
cmdCreateDR.Parameters.Add("Identity", "GroupName");
cmdCreateDR.Parameters.Add(new CommandParameter("BypassSecurityGroupManagerCheck"));
Collection<PSObject> manByUsers = new Collection<PSObject>();
manByUsers.Add(new PSObject("domain\\UserName1"));
manByUsers.Add(new PSObject("domain\\UserName2"));
cmdCreateDR.Parameters.Add("ManagedBy", manByUsers);
Collection<PSObject> resultsEx = RunPowerShellCommand(cmdCreateDR);

BypassSecuirtyGroupManagerCheck is a switch and the way your using it your passing it in a bool set to false which won't achieve your desired results. You should be doing something like
SwitchParameter switchpara = new SwitchParameter(true);
cmdCreateDR.Parameters.Add("BypassSecurityGroupManagerCheck", switchpara);
Cheers
Glen

Related

Run C# script through scheduled task

I've developed a small script in c# that is querying SQL Server and add computer objects to some Active Directory groups based on certain criteria. The script is working fine when I run it using the account which has the necessary rights to add/remove objects from Active Directory Group.
When I try to schedule the job, so it runs automatically from server using the "SYSTEM" account it does not work, I get "Access denied" I've updated the bind account to use the credentials from an account that works but I still have the same issue.
> Error Message:
> *2020-01-13 18:32:30,984 [1] ERROR TestAD.clsActiveDirectory - Error occured when trying to add computerobject abcdefg-a10 to group. Error
> message: Access is denied.*
The only way to make it work is using the actual account as account to run the scheduled task, however, problem is that our company policy does not allow us to store passwords, so I need to have the account logged-on to run this script.
code snippet
de.Username = "testing#test.com";
de.Password = "xxxxxxxxx";
de.AuthenticationType = AuthenticationTypes.Secure;
de.AuthenticationType = AuthenticationTypes.Sealing;
de.AuthenticationType = AuthenticationTypes.Delegation;
de.Properties.Count.ToString();
ds.SearchRoot = de;
ds.Filter = "(&(objectClass=computer)(name=" + _myComputerName.ToString() + `"))";`
ds.PropertiesToLoad.Add("memberof");
ds.PropertiesToLoad.Add("distinguishedname");
ds.SizeLimit = 10;
ds.PageSize = 0;
ds.SearchScope = System.DirectoryServices.SearchScope.Subtree;
I've tried adding some "AuthenticationTypes" to see if that made difference but still same
any help would be appreciated
Thx.
Have you tried using SQL Server Agents? My company uses them as opposed to Scheduled Tasks. They may be less elegant, but it may be a good alternative to your situation.
Create a SQL Server Agent that calls the executable with or without parameters.
If you cannot call the executable from the hosting OS, you can call an SSIS package on the network to call the executable for you.
Please let me know if you need more details.
I found the issue, and in the end pretty straight forward.
The Active Directory flow is following
- Bind to active directory with my special account and search for the computer object and
validate if it needs to be added to Active Directory Group
- if it needs to be added do 2nd bind to the Active Directory group and add computer
object. ==> This piece failed when using scheduled task or run under "SYSTEM" context
Reason for failure: When I bind 2nd time I did not specify any credentials so it was
using default credentials (SYSTEM) if I run the script my account which has enough
rights to add computer objects to groups.
I updated code for 2nd bind to include binding credentials and now it's working as
expected.
I hope this will be helpful for somebody else who has to troubleshoot similar issues.
old code
try
{
DirectoryEntry ent = new DirectoryEntry(bindString);
ent.Properties["member"].Add(newMember);
ent.CommitChanges();
}
New code
try
{
DirectoryEntry ent = new DirectoryEntry(bindString);
ent.AuthenticationType = AuthenticationTypes.Secure;
ent.AuthenticationType = AuthenticationTypes.Sealing;
ent.AuthenticationType = AuthenticationTypes.Delegation;
ent.Username = "test123#test.com";
ent.Password = "test123";
ent.Properties["member"].Add(newMember);
ent.CommitChanges();
}

Create test run with state property in Azure DevOps .NET SDK

I'm using the Azure DevOps .NET SDK (v16.530.0-preview) and when I try to create a test run using CreateTestRunAsync (in TestManagementHttpClient) and use the RunCreateModel object as a parameter, it looks like the RunCreateModel's State property is read-only. The docs also confirm this.
TestApi.RunCreateModel run = new TestApi.RunCreateModel
{
Name = testRun.Name
//State = testRun.State (is read-only)
};
https://learn.microsoft.com/en-us/dotnet/api/microsoft.teamfoundation.testmanagement.webapi.runcreatemodel.state?view=azure-devops-dotnet-preview#Microsoft_TeamFoundation_TestManagement_WebApi_RunCreateModel_State
But the weirdness is that when creating the run, the UI shows In Progress then it shows the test run running for {x hours, minutes, sec}.
Is there a way I can avoid this and set the state as NotStarted?
You can define the state in the constructor:
var testRun = new RunCreateModel(name: "API Test Run", state: "NotStarted");
var results = testApi.CreateTestAsync(testRun, "Project").Result;
I succeeded to create a test run with "Not Started" state with the above code.

Slow PowerShell execution of Microsoft Exchange 2013 commands from c#

I have the following code that executes an exchange cmdlet. It works fast with command that return some output but work slow if command has no output.
for example
Invoke("Get-Mailbox")
print following output:
Begin execution at 11:44:43
Finish execution at 11:44:51
Output :
Administrator
Discovery Search Mailbox
Artem Romanchik
Execution time was about 8 second(6 second for loading exchange snappin + 2 seconds for command execution)
Slow example is Invoke("Set-Mailbox -identity tema -MaxSendSize 10MB")
Begin execution at 11:53:34
Finish execution at 11:54:36
Output :
Now it was 62 seconds(2 seconds for command and 60 seconds of waiting for something)
How can I reduce execution time of second example?
Invoke method code:
public void Invoke(string command)
{
var config = RunspaceConfiguration.Create();
PSSnapInException warning;
config.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Snapin", out warning);
using(var runspace = RunspaceFactory.CreateRunspace(config))
{
runspace.Open();
using(var _psInstance = new RunspaceInvoke(runspace))
{
var psCommand = new PSCommand();
Console.WriteLine(String.Format("Begin execution at {0}", DateTime.Now.ToLongTimeString()));
var result = _psInstance.Invoke(command);
Console.WriteLine(String.Format("Finish execution at {0}", DateTime.Now.ToLongTimeString()));
var output = "";
foreach (var line in result)
{
if (line == null)
continue;
output += "\n" + line.BaseObject.ToString();
}
Console.WriteLine(String.Format("Output: {0}", output));
runspace.Close();
}
}
}
Set-Mailbox will accept multiple identity parameters
From Get-Help Set-Mailbox:
Identity:
The Identity parameter specifies the mailbox.
This parameter accepts the following values:
•Alias
Example: JPhillips
•Canonical DN
Example: Atlanta.Corp.Contoso.Com/Users/JPhillips
•Display Name
Example: Jeff Phillips
•Distinguished Name (DN)
Example: CN=JPhillips,CN=Users,DC=Atlanta,DC=Corp,DC=contoso,DC=com
•Domain\Account
Example: Atlanta\JPhillips
•GUID
Example: fb456636-fe7d-4d58-9d15-5af57d0354c2
•Immutable ID
Example: fb456636-fe7d-4d58-9d15-5af57d0354c2#contoso.com
•Legacy Exchange DN
Example: /o=Contoso/ou=AdministrativeGroup/cn=Recipients/cn=JPhillips
•SMTP Address
Example: Jeff.Phillips#contoso.com
•User Principal Name
Example: JPhillips#contoso.com
It's taking so long because it's having to search all the mailboxes looking for any of those properties in every mailbox that match the identity string you've given it.
You can speed that up by first doing a Get-Mailbox using a filter that specifies exactly which property you're using for identity. If it doesn't find the mailbox, don't try to do the set.
Beyond that, I think you'd be much better off switching to using implicit remoting instead of loading the snap in. It's much faster to set up a PS Session connection to one of the management sessions on the Exchange server and then use Invoke-Command to run the Exchange cmdlets in that session. It also eliminates the need to have the Exchange management tools installed where you're running the script and keep them updated every time you add a service pack or RU to your Exchange servers.

Powershell Pipe and Foreach-Object in c#

I am invoking a get-msoluser cmdlet of office365 and i use the following cmdlet in powershell
Get-MsolUser -UserPrincipalName user#organization.onmicrosoft.com | ForEach-Object{ $_.licenses}
The output is a collection of licenses and i wanted the same script to be run in c#. so i have written the code as follows
private void displayLicenses(){
Command cmd = new Command("Get-MsolUser");
cmd.Parameters.Add("UserPrincipalName","user#organization.onmicrosoft.com");
Command cmd2 = new Command("ForEach-Object");
cmd2.Parameters.Add("$_.licenses.AccountSku");
Pipeline pipe = Office365Runspace.CreatePipeline();
pipe.Commands.Add(cmd);
pipe.Commands.Add(cmd2);
Console.WriteLine("Before invoking the pipe");
ICollection<PSObject> result = pipe.Invoke();
CheckForErrors(pipe);
Console.WriteLine("Executed command {0} + {1} with no error", cmd.CommandText, cmd2.CommandText);
foreach(PSObject obj in result){
foreach(PSPropertyInfo propInfo in obj.Properties){
Console.WriteLine(propInfo.Name+": "+propInfo.Value+" "+propInfo.MemberType);
}
}
}
But i still get an error on executing this function saying
Unhandled Exception:
System.Management.Automation.CommandNotFoundException: The term
'ForEach-Object' is not recognized as the name of a cmdlet, function,
scrip t file, or operable program. Check the spelling of the name, or
if a path was in cluded, verify that the path is correct and try
again.
I checked that my project has a reference to System.management.Automation.dll file that contains the ForEach-Object cmdlet.
I found the dll using this cmd in powershell
(Get-Command ForEach-Object).dll
Thanks,
Satya
I figured out the problem causing for the issue. It is due to the misconfigured runspace i created.
InitialSessionState initalState = InitialSessionState.Create();
initalState.ImportPSModule(new String[] { "msonline" });
//initalState.LanguageMode = PSLanguageMode.FullLanguage;
Office365Runspace = RunspaceFactory.CreateRunspace(initalState);
Office365Runspace.Open();
i was creating the initalstate with empty one,When i changed it to default one it worked fine.On creating the default one it includes all the modules that were obtained by default.
InitialSessionState initalState = InitialSessionState.CreateDefault();
it worked fine.
Thanks,
Satya
It sounds like your're trying to run that in the remote session at the Exchange server. Those are NoLanguage constrained sessions, meaning that you can only run the Exchange cmdlets in those sessions. If you want to use PowerShell core language cmdlets (like foreach-object), you have to do that in a local session and either use Import-PSSession to import the Exchange functions into your local session (implicit remoting) , or use Invoke-Command and point it at the remote session on the Exchange server.

How to obtain DefragAnalysis using C#

I am currently developing an application in C# (.NET 4.0) that should have as a part of its functionality the ability to determine the percentage of fragmentation on a particular volume. All the other features have been tested and are working fine but I’ve hit a snag trying to access this data. I would ideally prefer to use WMI as this matches the format I’m using for the other features but at this point I’m willing to use anything that can be efficiently integrated into the application, even if I have to use RegEx to filter the data. I am currently doing the development on a Windows 7 Professional (x64) machine. I have tested the following Powershell snippet using Administrator rights and it works flawlessly.
$drive = Get-WmiObject -Class Win32_Volume -Namespace root\CIMV2 -ComputerName . | Where-Object { $_.DriveLetter -eq 'D:' }
$drive.DefragAnalysis().DefragAnalysis
This is the method I’m using in C# to accomplish the same thing, but the InvokeMethod keeps returning 11 (0xB).
public static Fragmentation GetVolumeFragmentationAnalysis(string drive)
{
//Fragmenation object initialization removed for simplicity
try
{
ConnectionOptions mgmtConnOptions = new ConnectionOptions { EnablePrivileges = true };
ManagementScope scope = new ManagementScope(new ManagementPath(string.Format(#"\\{0}\root\CIMV2", Environment.MachineName)), mgmtConnOptions);
ObjectQuery query = new ObjectQuery(string.Format(#"SELECT * FROM Win32_Volume WHERE Name = '{0}\\'", drive));
scope.Connect();
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
object[] outputArgs = new object[2];
foreach (ManagementObject moVolume in searcher.Get())
{
// Execution stops at this line as the result is always 11
UInt32 result = (UInt32)moVolume.InvokeMethod("DefragAnalysis", outputArgs);
if (result == 0)
{
Console.WriteLine("Defrag Needed: = {0}\n", outputArgs[0]);
ManagementBaseObject mboDefragAnalysis = outputArgs[1] as ManagementBaseObject;
if (null != mboDefragAnalysis)
{
Console.WriteLine(mboDefragAnalysis["TotalPercentFragmentation"].ToString());
}
}
else
{
Console.WriteLine("Return Code: = {0}", result);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Could not acquire fragmentation data.\n" + ex);
}
return result;
}
I have even added the following line to the app.manifest but still nothing.
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Could somebody please tell me what I’m overlooking? Failure is not an option for me on this, so if it cannot be done using C# I don’t mind creating a DLL in another language (even if I have to learn it), that will give me the results I need. Ideally the application should be able work on any OS from XP upwards and must be totally transparent to the user.
These are the resources I have already used. I wanted to add the jeffrey_wall blog on msdn as well but as a new user I can only add 2 hyperlinks at a time. Thanks again.
http://www.codeproject.com/Messages/2901324/Re-the-result-of-DefragAnalysis-method-in-csharp.aspx
http://social.technet.microsoft.com/Forums/vi-VN/winserverfiles/thread/9d56bfad-dcf5-4258-90cf-4ba9247200da
Try building your application targeting 'Any CPU' - on the Build tab of the project properties. I suspect you're using a target of x86. I get the same error code on my Win7 x64 machine if I do that.
In fact, running your PowerShell snippet in the x86 version of PowerShell gives an empty set of results, too.
You get the same error if you run either piece of code without full Administrator privileges, as you've found, so also ensure your app.manifest is correct. A UAC prompt is a handy hint that it's taking effect!
No idea why this WMI query doesn't like running under WoW64, I'm afraid, but hopefully this will give you a head-start.
You could simply call the PowerShell command you mentioned in your post, since you said the PowerShell code works. From C# you would want to follow this workflow:
Instantiate a PowerShell RunSpace
Open the RunSpace
Add a script to the Commands property
Invoke the command list
Here is an example of how to achieve this, and process the resulting object output.
http://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C
For Windows XP and Windows Vista, you would have to ensure that PowerShell was installed on each of the systems you want to run your program on. Not a bad prerequisite to have, but something to keep in mind as a dependency.
Hope this helps.
The 32-bit WMI provider for Win32_Volume doesn't seem to be able to start the defragsvc for whatever reason. You can force the 64-bit WMI provider even in a 32-bit client running under WOW64 by changing your code to add an additional WMI connection option:
ConnectionOptions mgmtConnOptions = new ConnectionOptions {
EnablePrivileges = true,
Context = new ManagementNamedValueCollection() {
{ "__ProviderArchitecture", 64 }
}
};

Categories