Web Service Set User License Office 365 - c#

So basically, I want to set AD's user license (Powershell script) from C# code. Here is the code:
//adminUser & adminPassword from app.config
public static string SetUserLicense(string userPrincipalName, string adminUser, SecureString adminPassword, string licenses)
{
string strReturn = "";
try
{
// Create Initial Session State for runspace.
InitialSessionState initialSession = InitialSessionState.CreateDefault();
initialSession.ImportPSModule(new[] { "MSOnline" });
// Create credential object.
PSCredential credential = new PSCredential(adminUser, adminPassword);
// Create command to connect office 365.
Command connectCommand = new Command("Connect-MsolService");
connectCommand.Parameters.Add((new CommandParameter("Credential", credential)));
Command userCommand = new Command("Set-MsolUser");
userCommand.Parameters.Add((new CommandParameter("UserPrincipalName", userPrincipalName)));
userCommand.Parameters.Add((new CommandParameter("UsageLocation", "ID")));
Command licCommand = new Command("Set-MsolUserLicense");
licCommand.Parameters.Add((new CommandParameter("UserPrincipalName", userPrincipalName)));
licCommand.Parameters.Add((new CommandParameter("AddLicenses", licenses)));
using (Runspace psRunSpace = RunspaceFactory.CreateRunspace(initialSession))
{
// Open runspace.
psRunSpace.Open();
//Iterate through each command and executes it.
foreach (var com in new Command[] { connectCommand, userCommand, licCommand })
{
if (com != null)
{
var pipe = psRunSpace.CreatePipeline();
pipe.Commands.Add(com);
// Execute command and generate results and errors (if any).
Collection<PSObject> results = pipe.Invoke();
var error = pipe.Error.ReadToEnd();
if (error.Count > 0 && com == licCommand)
{
strReturn = error[0].ToString();
}
else if (results.Count >= 0 && com == licCommand)
{
strReturn = "User License update successfully.";
}
}
}
// Close the runspace.
psRunSpace.Close();
}
}
catch (Exception ex)
{
strReturn = ex.Message;
}
return strReturn;
}
However, when I run it, everything works well (unlicensed now become licensed). Then, I published the code so I get the DLLs & Services.asmx which run on the server. After that, I make a service agent and added service reference (web service URL), so periodically, the agent can call SetUserLicense function.
Here is code from service agent which calls the Web Service:
NewWSOffice365.ServicesSoapClient Service = new NewWSOffice365.ServicesSoapClient();
string Result = Service.SetUserLicense("blabla#bns.org");
The problem is when the service agent runs, I get error:
You must call the Connect-MsolService cmdlet before calling any other cmdlets.
The weird thing, I've put Connect-MsolService in my C# code (see above). Everything meets its requirement, here: http://code.msdn.microsoft.com/office/Office-365-Manage-licenses-fb2c6413 and set IIS AppPool UserProfile to true (default: false).

You need to add Powershell session before using "Connect-MsolService"
credential is your above credential.
PSCommand psSession = new PSCommand();
psSession.AddCommand("New-PSSession");
psSession.AddParameter("ConfigurationName", "Microsoft.Exchange");
psSession.AddParameter("ConnectionUri", new Uri("https://outlook.office365.com/powershell-liveid/"));
psSession.AddParameter("Credential", credential);
psSession.AddParameter("Authentication", "Basic");
psSession.AddParameter("AllowRedirection");
powershell.Commands = psSession;
powershell.Invoke();
PSCommand connect = new PSCommand();
connect.AddCommand("Connect-MsolService");
connect.AddParameter("Credential", credential);
powershell.Commands = connect;
powershell.Invoke();

Related

c# Can logged in credentials (non explicit) be used with wsmanconnectioninfo?

I have the function below with multiple threads, which was fine with explicit credentials when I was the only one using it, but I've been asked to put it into a powershell script where it will be plain text to leverage the multithread capability.
Is it possible to use the implied credentials of the account running the script with wsmanconnectioninfo? If not, is there a different way to create the Exchange shell connection without explicit credentials?
private Collection<PSObject> runPowerShellScript(object server)
{
Collection<PSObject> psobjs = new Collection<PSObject>();
string result = "";
string serverName = server.ToString();
string loginPassword = "xxx";
System.Security.SecureString secpassword = new SecureString();
foreach (char c in loginPassword)
{
secpassword.AppendChar(c);
}
PSCredential credential = new PSCredential(#"domain/samaccount", secpassword);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("https://xxxxx/powershell"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
PowerShell powershell = PowerShell.Create();
if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)
{
// do nothing
}
else
{
runspace.Open();
powershell.Runspace = runspace;
}
try
{
PSCommand command = new PSCommand();
command.AddScript($#"get-mailboxdatabase -Server " + server + " -Status");
powershell.Commands = command;
psobjs = powershell.Invoke();
if (powershell.HadErrors == true)
{
result = "Failed - " + powershell.Streams.Error[0].ToString();
result = result.Replace("\"", "*");
}
}
catch (Exception ex)
{
string fail = ex.Message;
}
}
object serverNameO = server;
PSObject serverNameObj = new PSObject(serverNameO);
psobjs.Insert(0, serverNameObj);
return psobjs;
}
This is working
WSManConnectionInfo wmc = new WSManConnectionInfo(new Uri(`"http://xxx/powershell`"));
wmc.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
wmc.ShellUri = `"http://schemas.microsoft.com/powershell/Microsoft.Exchange`";
using (Runspace runspace = RunspaceFactory.CreateRunspace(wmc))
{
}

How to get password policy for Azure Active Directory logged in user

I want to get password expiry date of logged in user in c# using graph api or adal.
With this question, I know how to get the password policy and also the expiry date using PowerShell but not yet sure with C#
Get Azure Active Directory password expiry date in PowerShell
In c# Either I want to Get PasswordExpiry Date or as an Alternative LastPasswordChangedDate.
Using AD Graph API
To get this property of Azure AD user using C#, we can call the PowerShell commands directly. You can refer the code sample below to achieve the goal:
private static void GetPasswordExpiredDate()
{
try
{
var userName = "";
var password = "";
var securePassword = new SecureString();
var domainName = "";
foreach (char c in password)
{
securePassword.AppendChar(c);
}
Collection<PSObject> user = null;
Collection<PSObject> passwordPolicy = null;
// Create Initial Session State for runspace.
InitialSessionState initialSession = InitialSessionState.CreateDefault();
initialSession.ImportPSModule(new[] { "MSOnline" });
// Create credential object.
PSCredential credential = new PSCredential(userName, securePassword);
// Create command to connect office 365.
Command connectCommand = new Command("Connect-MsolService");
connectCommand.Parameters.Add((new CommandParameter("Credential", credential)));
// Create command to get office 365 users.
Command getPasswordPolicy = new Command("Get-MsolPasswordPolicy");
getPasswordPolicy.Parameters.Add(new CommandParameter("DomainName", domainName));
//Command getUserCommand = new Command("$UserPrincipal=Get-MsolUser -UserPrincipalName 'user1#adfei.onmicrosoft.com'");
Command getUserCommand = new Command("Get-MsolUser");
getUserCommand.Parameters.Add(new CommandParameter("UserPrincipalName", "user1#adfei.onmicrosoft.com"));
//Command getPasswordExpiredDate = new Command("$UserPrincipal.LastPasswordChangeTimestamp.AddDays($PasswordPolicy.ValidityPeriod)");
using (Runspace psRunSpace = RunspaceFactory.CreateRunspace(initialSession))
{
// Open runspace.
psRunSpace.Open();
//Iterate through each command and executes it.
foreach (var com in new Command[] { connectCommand, getUserCommand, getPasswordPolicy })
{
var pipe = psRunSpace.CreatePipeline();
pipe.Commands.Add(com);
if (com.Equals(getUserCommand))
user = pipe.Invoke();
else if (com.Equals(getPasswordPolicy))
passwordPolicy = pipe.Invoke();
else
pipe.Invoke();
}
DateTime date =(DateTime) user[0].Properties["LastPasswordChangeTimestamp"].Value;
UInt32 ValidityPeriod = (UInt32)passwordPolicy[0].Properties["ValidityPeriod"].Value;
Console.WriteLine($"The password will be expired at {date.AddDays(ValidityPeriod)}");
// Close the runspace.
psRunSpace.Close();
}
}
catch (Exception)
{
throw;
}
}

How to add/remove elements from collection using Powershell wrapper System.Management.Automation

I'm trying to add collection of aliases to Exchange server. This can be done only via Powershell cmdlets.
As Microsoft have wrapper under powershell and distributed call can be done only in runspace I use System.Management.Automation utilities for this.
Command that adds aliases looks like this one:
Set-Mailbox -Identity john#contoso.com -EmailAddresses #{add=”john#northamerica.contoso.com”}
Where Set-Mailbox is a command, all other fields are parameters and #add shows that we add new element to existing collection.
As Exchange runspace is running in PSLanguageMode.NoLanguage mode than only Command can be executed but not Scripts. With this approach exception is risen:
Command addAliasCommand = new Command("Set-Mailbox -Identity john#contoso.com -EmailAddresses #{add=”john#northamerica.contoso.com”}", true);
Only clear Command with parameters can be executed:
Command addAliasCommand = new Command("Set-Mailbox", true);
addAliasCommand.Parameters.Add("identity", "test#test.onmicrosoft.com");
addAliasCommand.Parameters.Add("EmailAddresses", "testing.alias10#test.onmicrosoft.com, testing.alias11#test.onmicrosoft.com");
But problem with this approach that it’s completely rewrites collection of aliases, when I want to add/remove new ones.
The question is how to add pointer #Add that will show that these values are added to the existing collection of ProxyAddressCollection?
Full code:
System.Security.SecureString secureString = new System.Security.SecureString();
foreach (char c in Password)
secureString.AppendChar(c);
PSCredential credential = new PSCredential(AdminLogin, secureString);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("https://ps.outlook.com/PowerShell"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
connectionInfo.SkipCACheck = true;
connectionInfo.SkipCNCheck = true;
connectionInfo.MaximumConnectionRedirectionCount = 4;
IList<string> gmResults = null;
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runspace.Open();
using (Pipeline plPileLine = runspace.CreatePipeline())
{
try
{
Command addAliasCommand = new Command("Set-Mailbox", true);
addAliasCommand.Parameters.Add("identity", "test#test.onmicrosoft.com");
addAliasCommand.Parameters.Add("EmailAddresses", "testing.alias10#test.onmicrosoft.com, testing.alias11#test.onmicrosoft.com");
var rsResultsresults = plPileLine.Invoke();
if (!string.IsNullOrEmpty(resultObjectName))
{
gmResults =
rsResultsresults.Select(obj => obj.Members[resultObjectName].Value.ToString()).ToList();
}
plPileLine.Stop();
}
catch (Exception e)
{
return null;
}
finally
{
runspace.Close();
runspace.Dispose();
}
}
runspace.Close();
}
The #{ add = "john#northamerica.contoso.com" } is actually a Hashtable which is a #{ key = value } structure, so you could do:
Command addAliasCommand = new Command("Set-Mailbox", true);
addAliasCommand.Parameters.Add("identity", "john#contoso.com");
var addresses = new Hashtable();
addresses.Add("add", "john#northamerica.contoso.com");
addAliasCommand.Parameters.Add("EmailAddresses", addresses);
I add the same problem. I ended up using this:
var pipeline = runspace.CreatePipeline();
string cmdAlias = "Set-Mailbox " + username + "#" + domainName + " -EmailAddresses #{Add='" + username + "#" + domainNameAlias + "'}";
pipeline.Commands.AddScript(cmdAlias);
pipeline.Invoke();

How I can create a User in AD with Powershell in a ASP.NET Webapplication

I have a question to C# and Powershell in a ASP.NET Application.
I want to create a User in our Active Directory and I want/must use a powershell for this. I had built a Webapllication that could add a mailcontact in the Exchange Server one year ago. For this I used the System.Management.Automation Namespace with the Powershell Classes. But I don't know how I can do it for the Active Directory.
the ps command that I must use:
New-ADUser %prefix-%name
-SamAccountName "%name"
-UserPrincipalName "%name#test-company.com"
-GivenName "%text1"
-SurName "%text2"
-displayname "%name"
-enabled $true
-Path '%OU'
-AllowReversiblePasswordEncryption $true
-PasswordNeverExpires $true
-AccountPassword (ConvertTo-Securestring "%name" -asplaintext -Force)
and here my cs code:
public void CreateRemoteConnectionToActiveDirectory(string Username, string password//,...comming)
{
SecureString securePassword = new SecureString();
str_password = password;
str_username = Username;
foreach (char x in str_password)
{
securePassword.AppendChar(x);
}
PSCredential cred = new PSCredential(str_username, securePassword);
// connection?
}
My Old Code for the exchange Server:
public string CreateRemoteConnectionToExchange(string UserName, string Password, string Mailbox)
{
SecureString SecurePassword = new SecureString();
string str_password = Password;
string str_username = UserName;
foreach (char x in str_password)
{
SecurePassword.AppendChar(x);
}
PSCredential cred = new PSCredential(str_username, SecurePassword);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri(ExchangeServer), Schema, cred);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default;
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-MailContact");
command.AddParameter("ExternalEmailAddress", "SMTP:" + Mailbox + MailExtension);
command.AddParameter("Name", Mailbox);
command.AddParameter("Alias", Mailbox);
command.AddParameter("FirstName", Mailbox);
command.AddParameter("Initials", "");
command.AddParameter("LastName", "");
command.AddParameter("OrganizationalUnit", OrganizationalUnit);
command.AddParameter("DomainController", configDC);
powershell.Commands = command;
try
{
runspace.Open();
powershell.Runspace = runspace;
powershell.Invoke();
return "Der Kontakt wurde Erfolgreich erstellt";
}
catch (Exception ex)
{
///...
}
finally
{
runspace.Dispose();
runspace = null;
powershell.Dispose();
powershell = null;
}
}
How I can do this. A Example,tutorial or a tipp would me help.
Looks like your connection just needs to connect to either your AD server or another server that can actually execute the command.

How to create an Exchange mailbox?

I am trying to create an Exchange mailbox in C#. The following code doesn't produce an error, but it also doesn't appear to create a mailbox as I would expect:
private void buttonCreateUser_Click(object sender, EventArgs e)
{
Boolean Success = CreateUser(textBoxFirstName.Text, textBoxLastName.Text,
textBoxAlias.Text, textBoxPassword.Text,
comboBoxDomain.SelectedItem.ToString(),
comboBoxOrganizationalUnit.SelectedItem.ToString());
if (Success)
{
labelStatus.Text = "User Created";
}
else
{
labelStatus.Text = "There Is Some Error";
}
}
public Boolean CreateUser(string FirstName, string LastName, string Alias,
string PassWord, string DomainName, string OrganizationalUnit)
{
string Name = FirstName + " " + LastName;
string PrincipalName = FirstName + "." + LastName + "#" + DomainName;
Boolean success = false;
RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
SecureString spassword = new SecureString();
spassword.Clear();
foreach (char c in PassWord)
{
spassword.AppendChar(c);
}
PSSnapInException snapInException = null;
PSSnapInInfo info = rsConfig.AddPSSnapIn(
"Microsoft.Exchange.Management.PowerShell.E2010", out snapInException);
Runspace myRunSpace = RunspaceFactory.CreateRunspace(rsConfig);
myRunSpace.Open();
Pipeline pipeLine = myRunSpace.CreatePipeline();
Command myCommand = new Command("New-MailBox");
myCommand.Parameters.Add("Name", Name);
myCommand.Parameters.Add("Alias", Alias);
myCommand.Parameters.Add("UserPrincipalName", PrincipalName);
myCommand.Parameters.Add("Confirm", true);
myCommand.Parameters.Add("SamAccountName", Alias);
myCommand.Parameters.Add("FirstName", FirstName);
myCommand.Parameters.Add("LastName", LastName);
myCommand.Parameters.Add("Password", spassword);
myCommand.Parameters.Add("ResetPasswordOnNextLogon", false);
myCommand.Parameters.Add("OrganizationalUnit", OrganizationalUnit);
pipeLine.Commands.Add(myCommand);
pipeLine.Invoke();
myRunSpace.Dispose();
success = true;
return success;
}
I don't get an error, so I don't know what I am doing wrong.
Update
I am using Web Service For this.If I run same code with windows application it works,But not with WebService? should I make any change in Exchange Server? Though I can Get information of MailBox with Get-MailBox but New-MailBox not Creating User.
I've been struggling with this very issue for a few days (I knew nothing about C# as a language before this week). Anyway, for anyone like me, looking to implement this, but struggling, here is an example that works for me:
We use Exchange2010, and I can run this from a machine that doesn't have the exchange tools installed.
using System.Management.Automation;
using System.Management.Automation.Remoting;
using System.Management.Automation.Host;
using System.Collections.ObjectModel;
using Microsoft.PowerShell.Commands;
static string createmailbox(string name, string alias, string email, string database, string UPN)
{
SecureString spassword = new SecureString();
string PassWord = "<set default password here or read in input from form>";
spassword.Clear();
foreach (char c in PassWord)
{
spassword.AppendChar(c);
}
string orgunit = "<define the OU here if you always use the same one, alternatively, add as parameter in function call>";
string dc = "<similarly, add DC here if needed, or call from function>";
PSCredential newCred = (PSCredential)null;
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("<put in CAS server FQDN here>/powershell?serializationLevel=Full"),
"http://schemas.microsoft.com/powershell/Microsoft.Exchange", newCred);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-Mailbox");
command.AddParameter("-Name", name);
command.AddParameter("-Alias", alias);
command.AddParameter("-UserPrincipalName", email);
command.AddParameter("-PrimarySMTPAddress", email);
command.AddParameter("-Password",spassword);
// (ConvertTo-SecureString -AsPlainText "P4ssw0rd" -Force)
command.AddParameter("-Database", database);
command.AddParameter("-OrganizationalUnit", orgunit);
// command.AddParameter("-Email", email);
command.AddParameter("-DomainController", dc);
powershell.Commands = command;
try
{
runspace.Open();
powershell.Runspace = runspace;
Collection<PSObject> results = powershell.Invoke();
return results.ToString();
}
catch (Exception ex)
{
string er = ex.InnerException.ToString();
}
finally
{
runspace.Dispose();
runspace = null;
powershell.Dispose();
powershell = null;
}
}
My use case is via a WPF form, so the parameters are populated from text boxes on the form. I've set things like the password (we have a default password for shared mailboxes and the user account is disabled), the OU and the domain controller as static text, but they could be called via variables just as easily.
I get the solution for this .I change permission leval of inproxy.dll and whooooo its working great ...

Categories