I'm trying to add new object to existing organisational unit in Active Directory. Following code is used to do this.
It runs without errors. But new object is not created after this. Please advise what I'm doing wrong here.
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
namespace TestAdObjectCreation
{
class Program
{
static void Main(string[] args)
{
DirectoryEntry root = new DirectoryEntry("LDAP://servername/OU=Services,OU=PCX,DC=q2q,DC=xenyq,DC=com", "Administrator", "pass");
DirectoryEntry newItem = root.Children.Add("test_node", "valid_schema_class_name");
root.CommitChanges();
root.Close();
root.Dispose();
}
}
}
What kind of object are you trying to create??
First of all, all LDAP object always have a prefix, DC= for domain component, OU= for organizational unit, CN= for common name.
Also, many LDAP objects have minimal requirements for what they need to be considered valid; e.g. a user or a group must have a unique samAccountName.
So again - what are you trying to create??
If you wrap your creation code into a try..catch - do you get any exceptions? If so - what are they??
static void Main(string[] args)
{
DirectoryEntry root = new DirectoryEntry("LDAP://servername/OU=Services,OU=PCX,DC=q2q,DC=xenyq,DC=com", "Administrator", "pass");
try
{
DirectoryEntry newItem = root.Children.Add("CN=test_node", "valid_schema_class_name");
root.CommitChanges();
}
catch(Exception exc)
{
string error = exc.GetType().FullName + ": " + exc.Message;
}
}
Related
I am studying gremlin. I need to connect gremlin to .net and below is my code:
internal class Program
{
private const string Host = "localhost";
private const int Port = 8182;
private const string NameTraversalSource = "gmodern";
[Obsolete]
private static void Main(string[] args)
{
Console.WriteLine("Start");
Graph graph = new Graph();
var client = new GremlinClient(new GremlinServer(Host, Port));
var g = graph.Traversal().WithRemote(new DriverRemoteConnection(client));
g.AddV("person").Property("name", "marko");
var re = g.V().HasLabel("person").Values<string>("name").ToList();
foreach (var c in re)
{
Console.WriteLine(c);
}
Console.WriteLine("End");
Console.ReadKey();
}
}
I don't know why it doesn't answer the desired result. I added vertex and name property with value of "marko". I need to print it out. But it doesn't print. Why? Help me.
I voted to close this as I thought more details were required, but I think I realize the problem. In many ways the question could be closed as more of a "duplicate" as many Gremlin oriented questions tend to have this answer: You need to iterate your traversal.
The following line does nothing:
g.AddV("person").Property("name", "marko");
All it does is create a traversal (i.e. an Iterator). It does not execute it. To execute you must iterate it with some form of terminal step. Since you are aren't doing anything with the result you should probably use iterate() like:
g.AddV("person").Property("name", "marko").iterate();
I write a very sample test program and run it as local system account in a domain machine. Here is the code look like:
static void Main(string[] args)
{
try
{
System.Console.Out.WriteLine("Test Start");
List<string> temp = new List<string>();
temp.Add(Environment.UserDomainName);
temp.Add("test");
temp.Add("test.com");
temp.Add("dc.test.com");
temp.Add("gc.test.com");
foreach (var i in temp)
{
using (HostingEnvironment.Impersonate())
{
System.Console.WriteLine("LDAP://{0}", i);
DirectoryEntry entry = new DirectoryEntry("LDAP://" + i);
try
{
entry.RefreshCache();
string nativeGuid = entry.NativeGuid;
string path = entry.Path;
string server = entry.Options.GetCurrentServerName();
System.Console.WriteLine("{0} success!", i);
}
catch (Exception e)
{
System.Console.WriteLine("{0}\n {1}", i, e);
}
}
}
System.Console.Out.WriteLine("Test End");
}
catch (Exception e)
{
System.Console.Out.WriteLine("e:Main{0}", e.Message);
}
System.Console.In.ReadLine();
}
The NetBIOS name for the domain is "test", full domain name is "test.com". "dc.test.com" is the DC FQDN and "gc.test.com" is the GC FQDN.
It works fine for "test.com", "dc.test.com"" and "gc.test.com", but it throws DirectoryServicesCOMException (0x80072020) for "test" and "Environment.UserDomainName".
The detail running result is:
Test Start
LDAP://TEST
TEST
System.DirectoryServices.DirectoryServicesCOMException (0x80072020): An operati
ons error occurred.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.RefreshCache()
at ConsoleApplication1.Program.Main(String[] args)
LDAP://test
test
System.DirectoryServices.DirectoryServicesCOMException (0x80072020): An operati
ons error occurred.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.RefreshCache()
at ConsoleApplication1.Program.Main(String[] args)
LDAP://test.com
test.com success!
LDAP://dc.test.com
dc.test.com success!
LDAP://gc.test.com
gc.test.com success!
Test End
It works all fine if I run it as domian admin account. Any idea what cause this? Thanks a lots!
What are you actually trying to do? If you're on a machine joined to the domain, you should just do new DirectoryEntry().
As for your error, when you log on to Windows with a local account, the UserDomainName environment variable is set to the local computer name. If that machine's name is the same as the domain's NetBIOS name, then I wouldn't be surprised if Windows gets confused.
I currently have a couple methods here:
public ADHelper()
{
connection = InitializeConnection();
}
private DirectoryEntry InitializeConnection()
{
DirectoryEntry ldapConnection = new DirectoryEntry("LDAP://servername.domain.com:389/DC=domain,DC=com");
ldapConnection.Username = "user"
ldapConnection.Password = "password";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
return ldapConnection;
}
I'd like to create another method to check and see if an object exists within that domain. I'm currently doing that with the following:
public bool Exists(string objectPath)
{
bool found = DirectoryEntry.Exists("LDAP://" + objectPath);
return found;
}
But that forces me to specify an entire LDAP string. I'd like to simply extend the initial ldapConnection with an OU and maybe CN parameter within the Exists() method. Is there any way to make this happen without making the Initialize() method public?
Thanks so much!
Maybe something like this:
public bool AccountExists(string userEmail)
{
using (var root = GetLdapRoot())
{
using (var searcher = new DirectorySearcher(root))
{
searcher.Filter = string.Format("(&(objectClass=User)(mail={0}))", userEmail);
searcher.PropertiesToLoad.Add("email");
var result = searcher.FindAll();
return result.Count > 0;
}
}
}
private static DirectoryEntry GetLdapRoot()
{
return new DirectoryEntry("LDAP://DC=com"); //or whatever your root domain is. Set credentials if you need to
}
by setting a filter and being specific about what properties to load in, the search will be more efficient. By using the root as your LDAP:// string, you should be searching the entire directory.
I've had this code working for at least a year and today it threw an exception that i haven't been able to figure out why its happening. Its a Forms.WebBrowser that hits a generic site first and then a secondary site.
'first site
wbr.ScriptErrorsSuppressed = False
wbr.Navigate("http://www.bing.com/?rb=0")
Do
Application.DoEvents()
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
'second site
wbr.ScriptErrorsSuppressed = True
Dim start As DateTime = DateTime.Now
Dim loopTimeout As TimeSpan = TimeSpan.FromSeconds(timeout)
wbr.Navigate("http://www.FlightAware.com")
Do
Application.DoEvents()
'loop timer
If DateTime.Now.Subtract(start) > loopTimeout Then
'stop browser
wbr.Stop()
'throw exception
Dim eExpTme As Exception = New Exception("A loop timeout occurred in the web request.")
Throw eExpTme
End If
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
The error happens on the second site access and it shows that it errors on the very last line with
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Windows.Forms.UnsafeNativeMethods.IHTMLLocation.GetHref()
at System.Windows.Forms.WebBrowser.get_Document()
at System.Windows.Forms.WebBrowser.get_ReadyState()
I just don't get why its errorring on the second site and not the first and what exactly that error message means. I've looked at some help forums but nothing concrete that i can use to troubleshoot.
AGP
The web site has a frame on ad.doubleclick.net, by default cross-domain frame access is disabled for the internet zone, so you get a security exception.
Catch the exception and move on. There isn't much you need to care about in the frame, doubleclick is an ad service.
You can implement IInternetSecurityManager and let IE to believe ad.doubleclick.net and FlightAware.com are the same web site, but this can cause security problem if you extend the trust to arbitrary web sites.
Here is a little hack in C# which you can convert in Vb.net:
public class CrossFrameIE
{
// Returns null in case of failure.
public static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow)
{
if (htmlWindow == null)
{
return null;
}
// First try the usual way to get the document.
try
{
IHTMLDocument2 doc = htmlWindow.document;
return doc;
}
catch (COMException comEx)
{
// I think COMException won't be ever fired but just to be sure ...
if (comEx.ErrorCode != E_ACCESSDENIED)
{
return null;
}
}
catch (System.UnauthorizedAccessException)
{
}
catch
{
// Any other error.
return null;
}
// At this point the error was E_ACCESSDENIED because the frame contains a document from another domain.
// IE tries to prevent a cross frame scripting security issue.
try
{
// Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider.
IServiceProvider sp = (IServiceProvider)htmlWindow;
// Use IServiceProvider.QueryService to get IWebBrowser2 object.
Object brws = null;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws);
// Get the document from IWebBrowser2.
IWebBrowser2 browser = (IWebBrowser2)(brws);
return (IHTMLDocument2)browser.Document;
}
catch
{
}
return null;
}
private const int E_ACCESSDENIED = unchecked((int)0x80070005L);
private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
}
// This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}
Whats the best way to save variables like userid that is stored and reachable from different pages in WP7.
There's the querystring method, but can be kind of a pain to implement.
When navigating, pass the parameter like a HTTP querystring.
Then, on the otherside, check if the key exists, and extract the value. The downside of this is if you need to do more than 1, you need to type it in yourself, and it only supports strings.
So to pass an integer, you'd need to convert it. (And to pass a complex object, you need to take all the pieces you need to recompile it on the other side)
NavigationService.Navigate(new Uri("/PanoramaPage1.xaml?selected=item2", UriKind.Relative));
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
string selected = String.Empty;
//check to see if the selected parameter was passed.
if (NavigationContext.QueryString.ContainsKey("selected"))
{
//get the selected parameter off the query string from MainPage.
selected = NavigationContext.QueryString["selected"];
}
//did the querystring indicate we should go to item2 instead of item1?
if (selected == "item2")
{
//item2 is the second item, but 0 indexed.
myPanorama.DefaultItem = myPanorama.Items[1];
}
base.OnNavigatedTo(e);
}
Here's a sample app that uses a querystring.
http://dl.dropbox.com/u/129101/Panorama_querystring.zip
A easier (and better) idea is to define a variable globally, or use a static class. In App.xaml.cs, define
using System.Collections.Generic;
public static Dictionary<string,object> PageContext = new Dictionary<string,object>;
Then, on the first page, simply do
MyComplexObject obj;
int four = 4;
...
App.PageContext.Add("mycomplexobj",obj);
App.PageContext.Add("four",four);
Then, on the new page, simply do
MyComplexObj obj = App.PageContext["mycomplexobj"] as MyComplexObj;
int four = (int)App.PageContext["four"];
To be safe, you should probably check if the object exists:
if (App.PageContext.ContainsKey("four"))
int four = (int)App.PageContext["four"];
You may use an App level variable (defined in App.xaml.cs) and access it from anywhere within your app. If you want to persist, shove it into Isolated Storage and read it on App launch/activate. There are helpers available to JSon serialize/deserialize your reads/writes from the Isolated Storage.
Check out Jeff's post (here) on tips to use Isolated Storage.
Hope this helps!
Well "best" is always subjective, however, I think an application service is a good candidate for this sort of thing:-
public interface IPhoneApplicationService : IApplicationService
{
string Name {get; set;}
object Deactivating();
void Activating(object state);
}
public class AuthenticationService : IPhoneApplicationService
{
public static AuthenticationService Current {get; private set; }
public void StartService(ApplicationServiceContext context)
{
Current = this;
}
public void StopService()
{
Current = null;
}
public string Name {get; set;}
public object Deactivating()
{
// Return an serialisable object such as a Dictionary if necessary.
return UserID;
}
public void Activating(object state)
{
UserID = (int)state;
}
public int UserID { get; private set; }
public void Logon(string username, string password)
{
// Code here that eventually assigns to UserID.
}
}
You place an instance of this in your App.xaml:-
<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
<shell:PhoneApplicationService
Launching="Application_Launching" Closing="Application_Closing"
Activated="Application_Activated" Deactivated="Application_Deactivated"/>
<local:AuthenticationService Name="AuthServ" />
</Application.ApplicationLifetimeObjects>
Now you do need to tweak the App.xaml.cs:-
private void Application_Activated(object sender, ActivatedEventArgs e)
{
var state = PhoneApplicationService.Current.State;
foreach (var service in ApplicationLifetimeObjects.OfType<IPhoneApplicationService>())
{
if (state.ContainsKey(service.Name))
{
service.Activating(state[service.Name]);
}
}
}
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
var state = PhoneApplicationService.Current.State;
foreach (var service in ApplicationLifetimeObjects.OfType<IPhoneApplicationService>())
{
if (state.ContainsKey(service.Name))
{
state[service.Name] = service.Deactivating();
}
else
{
state.Add(service.Name, service.Deactivating());
}
}
}
You can now access you UserID anywhere in your app with:-
AuthenticationService.Current.UserID
This general pattern can be used to maintain seperation of key application wide services (you don't load a whole bunch of incohesive properties into your App class). It also provides the hooks for maintaining state between activations which is essential.