I am trying to check if a user is an admin on a particular machine.
I have the following code that works fine when the computer is on the same domain:
public bool CheckAdmins(string computerName)
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
string branchnumber = computerName.Substring(0, 3);
bool admin = false;
if (logonUser.authenticate())
{
using (DirectoryEntry machine = new DirectoryEntry("WinNT://" + logonUser.Domain + "/" + computerName,logonUser.Domain + "\\" + logonUser.UserID,logonUser.Password))
{
//get local admin group
using (DirectoryEntry group = machine.Children.Find("Administrators","group"))
{
//get all members of local admin group
object members = group.Invoke("Members", null);
foreach (object member in (IEnumerable)members)
{
//get account name
string accountName = new DirectoryEntry(member).Name;
bool isAdmin = principal.IsInRole(accountName);
if (isAdmin == true) { admin = true; }
}
}
}
}
return admin;
}
However, across domain, this simply comes back with 'network path not found'.
I have been experimenting with LDAP but not getting too far. I have tried a number of methods and ideally need an example. This is what I am using currently:
String strPath = "LDAP://172.24.242.51/CN=258TP520,OU=258,DC=net,DC=test,DC=co,DC=uk";
DirectoryEntry myDE = new DirectoryEntry(strPath, "testdom\user", "password");
List<string> memberof = new List<string>();
foreach (object oMember in myDE.Properties["memberOf"])
{
memberof.Add(oMember.ToString());
}
However myDE.properties doesn't seem to contain anything. All help appreciated!
Thanks
I needed to append the FQDN to the computername, like so
using (DirectoryEntry machine = new DirectoryEntry("WinNT://" + computerName + ".net.test.co.uk",logonUser.Domain + "\\" + logonUser.UserID,logonUser.Password))
This fixed my issue.
Related
I see so many people struggling to copy or moving files around in SharePoint online, that I decided to write a small demo console app to show how to do it.
We will be using the CreateCopyJobs method, available on CSOM to copy a folder from one site collection to another. This method can be used to copy or move files between site collections or even on the same SC, betwen different libraries or folders inside a library.
The method works exactly as the UI, when you try to copy or move something in a library.
1 - Create new .NET console app. We will be using PnP, so go to your project NuGet manager and add SharePointPnPCoreOnline
2 - add to the usings of your class the following:
using Microsoft.SharePoint.Client;
using Newtonsoft.Json;
using OfficeDevPnP.Core;
3 - Define the following class to receive the status of the job that we will be checking.
class CopyJobProgress
{
public string Event;
public string JobId;
public string CorrelationId;
}
4 - Now add this sample main method:
static void Main(string[] args)
{
var siteUrl = "https://...-admin.sharepoint.com";
var userName = "admin#...";
var password = "....";
AuthenticationManager authManager = new AuthenticationManager();
using (var ctx = authManager.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, password))
{
var web = ctx.Web;
ctx.Load(web);
ctx.ExecuteQuery();
string sourceFile = "https://....sharepoint.com/sites/<site>/<library>/<file or folder>";
string destinationPath = "https://....sharepoint.com/sites/<site>/<destination library>";
var createJobInfo = ctx.Site.CreateCopyJobs(new string[] { sourceFile }, destinationPath,
new CopyMigrationOptions() { IsMoveMode = false, IgnoreVersionHistory = true,
AllowSchemaMismatch = true, NameConflictBehavior = MigrationNameConflictBehavior.Replace });
ctx.ExecuteQueryRetry();
Dictionary<string, CopyJobProgress> eventsFound = new Dictionary<string, CopyJobProgress>();
bool jobEndFound = false;
while (!jobEndFound)
{
var progress = ctx.Site.GetCopyJobProgress(createJobInfo[0]);
ctx.ExecuteQuery();
foreach (string log in progress.Value.Logs)
{
CopyJobProgress progressRes = (CopyJobProgress)JsonConvert.DeserializeObject(log, typeof(CopyJobProgress));
if (!eventsFound.ContainsKey(progressRes.Event))
{
Console.WriteLine(DateTime.Now + " - " + progressRes.Event + " - CorrelationId: " + progressRes.CorrelationId);
eventsFound[progressRes.Event] = progressRes;
}
if (progressRes.Event == "JobEnd")
{
jobEndFound = true;
}
}
if (!jobEndFound)
System.Threading.Thread.Sleep(2000);
}
Console.WriteLine("Done!");
}
}
In my project I am supposed to get data from openweathermap.org and put that in a collection in my DocumentDB database in Azure.
The code below works locally on my development machine, but when i upload the project, it runs and succeed (says the dashboard) but no documents are created. I can only create the documents if I run from local machine.
Why is that?
Here is my code:
public static void Main()
{
JobHost host = new JobHost();
// The following code ensures that the WebJob will be running continuously
host.Call(typeof(Program).GetMethod("saveWeatherDataToAzureDocumentDB"));
}
[NoAutomaticTrigger]
public static async void saveWeatherDataToAzureDocumentDB()
{
string endpointUrl = ConfigurationManager.AppSettings["EndPointUrl"];
string authorizationKey = ConfigurationManager.AppSettings["AuthorizationKey"];
string url = "http://api.openweathermap.org/data/2.5/weather?q=hanstholm,dk&appid=44db6a862fba0b067b1930da0d769e98";
var request = WebRequest.Create(url);
string text;
var response = (HttpWebResponse)request.GetResponse();
using (var sr = new StreamReader(response.GetResponseStream()))
{
text = sr.ReadToEnd();
}
// Create a new instance of the DocumentClient
var client = new DocumentClient(new Uri(endpointUrl), authorizationKey);
// Check to verify a database with the id=FamilyRegistry does not exist
Database database = client.CreateDatabaseQuery().Where(db => db.Id == "weatherdata").AsEnumerable().FirstOrDefault();
// If the database does not exist, create a new database
if (database == null)
{
database = await client.CreateDatabaseAsync(
new Database
{
Id = "weatherdata"
});
}
// Check to verify a document collection with the id=FamilyCollection does not exist
DocumentCollection documentCollection = client.CreateDocumentCollectionQuery(database.SelfLink).Where(c => c.Id == "weathercollection").AsEnumerable().FirstOrDefault();
// If the document collection does not exist, create a new collection
if (documentCollection == null)
{
documentCollection = await client.CreateDocumentCollectionAsync("dbs/" + database.Id,
new DocumentCollection
{
Id = "weathercollection"
});
}
//Deserialiser til et dynamisk object
if (text == "")
{
mark m = new mark() { name = "Something" };
await client.CreateDocumentAsync(documentCollection.DocumentsLink, m);
}
else
{
var json = JsonConvert.DeserializeObject<dynamic>(text);
json["id"] = json["name"] + "_" + DateTime.Now;
await client.CreateDocumentAsync(documentCollection.DocumentsLink, json);
}
}
public sealed class mark
{
public string name { get; set; }
}
UPDATE - This is what I have in my App.config
<appSettings>
<!-- Replace the value with the value you copied from the Azure management portal -->
<add key="EndPointUrl" value="https://<My account>.documents.azure.com:443/"/>
<!-- Replace the value with the value you copied from the Azure management portal -->
<add key="AuthorizationKey" value="The secret code from Azure"/>
Also, At DocumentDB Account i find the Connection string like this. AccountEndpoint=https://knoerregaard.documents.azure.com:443/;AccountKey=my secret password
How should I apply this to the WebJob?
Appriciate your help!
I have scenerio to create new groups in Active Directory using LDAP and C#.
Please provide the suggestions
This article on CodeProject is a really good starting point:
Howto: (Almost) Everything In Active Directory via C#
To create a group, you need to:
bind to a container where you want to create the group inside of
create the group and define some properties
Code:
public void Create(string ouPath, string name)
{
if (!DirectoryEntry.Exists("LDAP://CN=" + name + "," + ouPath))
{
try
{
// bind to the container, e.g. LDAP://cn=Users,dc=...
DirectoryEntry entry = new DirectoryEntry("LDAP://" + ouPath);
// create group entry
DirectoryEntry group = entry.Children.Add("CN=" + name, "group");
// set properties
group.Properties["sAmAccountName"].Value = name;
// save group
group.CommitChanges();
}
catch (Exception e)
{
Console.WriteLine(e.Message.ToString());
}
}
else { Console.WriteLine(path + " already exists"); }
}
Some addition info on setting the Group Scope and Group Type, the enums are:
public enum GroupType : uint
{
GLOBAL = 0x2,
DOMAIN_LOCAL = 0x4,
UNIVERSAL = 0x8,
SECURITY = 0x80000000
}
SECURITY ( Shortened from ADS_GROUP_TYPE_SECURITY_ENABLED ) is combined with the first 3 enums to give you the 6 possible options, without it a group will be a Distribution group.
The values are set as an int, which with the security flag goes into negatives, so unchecked() needs to be used.
Alternatively you could create an enum for the combined values.
GLOBAL | SECURITY = 0x80000002 = -2147483646
DOMAIN_LOCAL | SECURITY = 0x80000004 = -2147483644
UNIVERSAL | SECURITY = 0x80000008 = -2147483640
The value is stored in the 'groupType' property:
var groupType = unchecked((int)(GroupType.UNIVERSAL | GroupType.SECURITY));
group.Properties["groupType"].Value = groupType;
group.CommitChanges();
Take a look at this link: http://msdn.microsoft.com/en-us/library/ms180903(v=vs.80).aspx
I think you might be looking for this part of the code:
// Bind to the domain that this user is currently connected to.
DirectoryEntry dom = new DirectoryEntry();
// Find the container (in this case, the Consulting organizational unit) that you
// wish to add the new group to.
DirectoryEntry ou = dom.Children.Find("OU=Consulting");
// Add the new group Practice Managers.
DirectoryEntry group = ou.Children.Add("CN=Practice Managers", "group");
// Set the samAccountName for the new group.
group.Properties["samAccountName"].Value = "pracmans";
// Commit the new group to the directory.
group.CommitChanges();
I just got through solving this problem for a .NET Core 2.0 app - here is an updated solution for those using .NET Core 2.0+.
This utilizes the NuGet package System.DirectoryServices.Protocols:
try
{
string adminUsername = "myAdminUser";
string namingContext = "CN=Test123,DC=MyCompany,DC=com";
string hostNameAndSSLPort = "192.168.123.123:636";
string adminuser = $"CN={adminUsername},{namingContext}";
string adminpass = "password";
using (LdapConnection connection = new LdapConnection(hostNameAndSSLPort))
{
LdapSessionOptions options = connection.SessionOptions;
options.ProtocolVersion = 3;
options.SecureSocketLayer = true;
connection.AuthType = AuthType.Basic;
NetworkCredential credential = new NetworkCredential(adminuser, adminpass);
connection.Credential = credential;
connection.Bind();
string rolesContext = $"CN=Roles,{namingContext}";
string nameOfNewGroup = "MyGroup";
string groupDN = $"CN={nameOfNewGroup},{rolesContext}";
string dirClassType = "group";
AddRequest addRequest = new AddRequest(groupDN, dirClassType);
AddResponse addResponse = (AddResponse)connection.SendRequest(addRequest);
Console.WriteLine($"A {dirClassType} with a dn of\n {groupDN} was added successfully. The server response was {addResponse.ResultCode}");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Also there are a lot of great code examples in this sample project provided by Microsoft.
I am trying to remove the user accounts which are inactive from last 30 days.
I tried fetching User Information List. Checked all of it's properties and fields but coudn't find anything related to last login time.
You can do something like this
public DateTime Get(string attr, string UserName)
{
DomainConfiguration domainConfig = new DomainConfiguration();
using (new SPMonitoredScope("AD Properties"))
{
using (DirectoryEntry domain = new DirectoryEntry("LDAP://" + domainConfig.DomainName, domainConfig.UserName, domainConfig.Password))
{
//DirectorySearcher searcher = new DirectorySearcher(domain, "(|(objectClass=organizationalUnit)(objectClass=container)(objectClass=builtinDomain)(objectClass=domainDNS))");
DirectorySearcher searcher = new DirectorySearcher(domain);
searcher.PageSize = 1000;
searcher.Filter = "(SAMAccountName='" + UserName + "')";
//searcher.Filter = "(|(objectCategory=group)(objectCategory=person))";
searcher.Filter = "(&(objectClass=user) (cn=" + UserName + "))";
var user = searcher.FindOne();
DateTime LastLogon = DateTime.FromFileTime((Int64)user.Properties["lastLogon"].Value);
return LastLogon;
}
}
}
Hope this Helps you.
I do not know why it does gives me the some older dates than i expected.
but at least it will compile and run.
using System.DirectoryServices.AccountManagement;
private static DateTime? GetUserIdFromDisplayName(string displayName)
{
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find user by display name
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, displayName);
if (user != null)
{
return user.LastLogon;
}
else
{
return null;
}
}
}
I have a problem with user permission of users which are programmatically added to Sharepoint 2013 group using Client Object Model. The web application allows anonymous, but I also have a document library "Teacher Documents" with contribute permission only to a certain group (let's say "Teachers"), and I have added the user to the site's default member too (let's say "School Members"). The code works fine and the user was successfully added to both groups.
While it did look OK and the username was listed as the member of the groups, they still cannot contribute. When I checked, they do have the anonymous access on the document library but not the Contribute permission. Here's my code:
public static string AddUserToGroup(string siteURL, string groupName, string userName, string name, string email, NetworkCredential impersonateCredential)
{
try
{
ClientContext context = new ClientContext(siteURL);
context.Credentials = impersonateCredential;
Group oGroup = null;
oGroup = context.Web.SiteGroups.GetByName(groupName);
context.Load(oGroup);
bool groupExists = false;
try
{
context.ExecuteQuery();
groupExists = true;
}
catch { }
if (groupExists)
{
UserCreationInformation userCreationInfo = new UserCreationInformation();
userCreationInfo.Email = email;
userCreationInfo.LoginName = userName;
userCreationInfo.Title = name;
bool userExists = false;
try
{
User checkUser = oGroup.Users.GetByLoginName(userName);
context.Load(checkUser);
context.ExecuteQuery();
userExists = true;
}
catch { }
if (!userExists)
{
User oUser = oGroup.Users.Add(userCreationInfo);
context.ExecuteQuery();
}
}
else
{
return "No associated group assigned";
}
return "Member " + userName + " has been added to group.";
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
And here's how I call it:
string siteURL = "http://spfe01.gilang.com/";
string username = "spfe01\\budi.utomo";
string name = "Budi Utomo";
string email = "budi.utomo#spfe01.gilang.com";
NetworkCredential impersonateCredential = new NetworkCredential("username", "password", "spfe01");
AddUserToGroup(siteURL, "Teachers", username, name, email, impersonateCredential));
(You can test it on a console application)
It worked, the user was added to "Teachers", but no permission on "Teacher Documents" document library. Adding the user to the admin group "School Owners" with full control on the site did not work either.
EDIT:
In my case, I have added the group manually to the document library, and users that are added manually to the group are granted permissions and allowed to contribute. By manually I mean using the standard "Permissions" function of the Sharepoint on the web browser.
Actually, did you break the inheritance?
Most probably, the folder and file inherit the permission of the main folder
Here is my code:
caml = new Microsoft.SharePoint.Client.CamlQuery();
caml.ViewXml = #"Caml to get the file";
items = objList.GetItems(caml);
clientContext.Load(items);
clientContext.Credentials = new NetworkCredential("LoginID", "LoginPW", "LoginDomain");
clientContext.ExecuteQuery();
item = items[0];
item.BreakRoleInheritance(true, true);
clientContext.ExecuteQuery();