Sorry, i checked the link "Find username from Active Directory using email id" but that's for C# i can't figure that out how to do in Vb.net.
In my gridview when i select the row to get the email id and pass it to AD to find the user name but so far i can't figure that out what command will give that details in VB.net
Protected Sub grdValidate_RowUpdating(sender As Object, e As EventArgs)
Dim strEmail As String = grdValidate.SelectedRow.Cells(2).Text
Dim ctx As New PrincipalContext(ContextType.Domain)
' find a user
Dim user As UserPrincipal = UserPrincipal.FindByIdentity(ctx, strEmail)
End Sub
i saw this property "UserPrincipal.EmailAddress" but VS is not even recognize the command. Obviously i imported
Imports System.DirectoryServices
Imports System.DirectoryServices.AccountManagement
I am trying to find a command to pass the email and match the email id in AD and get the user information.
Thanks in Advance
You need to add .NET references to System.DirectoryServices and System.DirectoryServices.AccountManagement and then...
Using context As New System.DirectoryServices.AccountManagement.PrincipalContext(DirectoryServices.AccountManagement.ContextType.Domain, strDomainName)
Dim yourUser As System.DirectoryServices.AccountManagement.UserPrincipal = System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(context, strEmailAddress)
If yourUser IsNot Nothing Then
strFirstName = yourUser.GivenName
strLastName = yourUser.Surname
End If
End Using
MsgBox(strFirstName & " " & strLastName)
I've used fully qualified names for clarity, but you can tidy things up with Imports System.DirectoryServices.AccountManagement at the beginning of the module
Related
I'm trying to create a vb.net code for a simple query through LDAP but having an issue and can't find where it is.
Dim ldapServerName As String = "xxx.test.intranet.xxx.ca"
Dim oRoot As DirectoryEntry = New DirectoryEntry("LDAP://" & ldapServerName & "/c=ca, DC=xxx,DC=corp,DC=xxx,DC=ca")
oRoot.Username = "ou=Tool,ou=applications,o=xxx,c=ca"
oRoot.Password = "something#2015"
Dim LDAPSearcher As New DirectorySearcher()
LDAPSearcher.Filter = "(&(employeenumber=6012589))"
Dim SearchResult As SearchResult = LDAPSearcher.FindOne()
Dim UserEntry As DirectoryEntry = SearchResult.GetDirectoryEntry()
EDTEST.Text = UserEntry.Properties("employeenumber").Value.ToString
it is giving me an error saying that the object is not valid. The searcher variable is in fact empty so it has to do with my query somehow.
This is my first time with LDAP¨and I have tried some of the solution i could find on the net but nothing is working so far.
Error: Object not set to an instance of an object.
Unless you're adding another attribute to search by, you don't need the AND operator in your filter syntax - a search for simply (employeenumber=6012589) should work just fine.
If do you have another attribute you'd like to search by, the filter syntax would be similiar to what you have now, only with the additional attribute :
(&(employeenumber=6012589)(objectClass=user))
EDIT:
I put together an example using the lower level System.DirectoryServices and System.DirectoryServices.Protocols namespaces. This helps break up the actual login and search functions, and will also provide better context when errors occur. For the example, I've replaced all of my variables with the ones you're using in your question. I tested this against our own Active Directory instance over unsecured port 389 using my creds and a base domain similar to the one you're using.
Imports System.DirectoryServices.Protocols
Imports System.Net
Module Module1
Sub Main()
' setup your creds, domain, and ldap prop array
Dim username As String = "ou=Tool,ou=applications,o=xxx,c=ca"
Dim pwd As String = "something#2015"
Dim domain As String = "DC=xxx,DC=corp,DC=xxx,DC=ca"
Dim propArray() As String = {"employeenumber"}
' setup your ldap connection, and domain component
Dim ldapCon As LdapConnection = New LdapConnection("xxx.test.intranet.xxx.ca:389")
Dim networkCreds As NetworkCredential = New NetworkCredential(username, pwd, domain)
' configure the connection and bind
ldapCon.AuthType = AuthType.Negotiate
ldapCon.Bind(networkCreds)
' if the above succceeded, you should now be able to issue search requests directly against the directory
Dim searchRequest = New SearchRequest(domain, "(employeenumber=6012589)", SearchScope.Subtree, propArray)
' issue the search request, and check the results
Dim searchResult As SearchResponse = ldapCon.SendRequest(searchRequest)
Dim searchResultEntry As SearchResultEntry
If (searchResult.Entries.Count > 0) Then ' we know we've located at least one match from the search
' if you're only expecting to get one entry back, get the first item off the entries list
searchResultEntry = searchResult.Entries.Item(0)
' continue to do whatever processing you wish against the returned SearchResultEntry
End If
End Sub
End Module
So this is what I've got -
Public Shared Function GetDirectoryEntry() As DirectoryEntry
Try
Dim entryRoot As New DirectoryEntry("LDAP://RootDSE")
Dim Domain As String = DirectCast(entryRoot.Properties("defaultNamingContext")(0), String)
Dim de As New DirectoryEntry()
de.Path = "LDAP://" & Domain
de.AuthenticationType = AuthenticationTypes.Secure
Return de
Catch
Return Nothing
End Try
End Function
Protected Sub rbAddUser_Click(sender As Object, e As EventArgs) Handles rbAddUser.Click
AddMemberToGroup("LDAP://DOMAIN.local/CN=" & !DISTRIBUTIONNAME! & ",CN=Users,DC=DOMAIN,DC=local", "/CN=" & !SELECTEDUSER! & ",CN=Users,DC=DOMAIN,DC=local")
End Sub
Private Sub AddMemberToGroup(ByVal bindString As String, ByVal newMember As String)
Dim ent As DirectoryEntry = GetDirectoryEntry()
ent.Properties("member").Add(newMember)
ent.CommitChanges()
End Sub
I hope this is easy enough for people to read, anyway the group and user are selected by the users in a table and when they click the add button I want the selected users to be adding to the selected distribution list.
when it gets to the CommitChanges() I get this error
An exception of type 'System.DirectoryServices.DirectoryServicesCOMException' occurred in System.DirectoryServices.dll but was not handled in user code Additional information: An operations error occurred.Error -2147016672
This is a common issue with the Process Model application pool configuration, from the official documentation:
By using the <processModel> element, you can configure many of the security, performance, health, and reliability features of application pools on IIS 7 and later.
This issue exists as CommitChanges() requires elevated privileges, and can be fixed by setting your web-application to run under NetworkManager; this can be done in two ways:
Directly in your code, place the problem code inside this Using statement:
Using HostingEnvironment.Impersonate()
'Problem code goes here.
End Using
Via IIS Manager:
Navigate to your website's application pool;
Navigate to Advanced Settings;
Scroll down to the Process Model group;
Change Identity to NetworkService
I solved the error by passing through my user credentials
Private Sub AddMemberToGroup(ByVal bindString As String, ByVal newMember As String)
Dim ent As New GetDirectoryEntry(bindString)
ent.Properties("member").Add(newMember)
ent.Username = "DOMAIN\USERNAME"
ent.Password = "PASSWORD"
ent.CommitChanges()
End Sub
However my code still doesn't work, I just get no errors.
I have an automation app I am developing for an isolated environment. One of its features will be to automate clearing a Windows user profile from the registry path HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\
The trouble I am having is in how to determine I am removing the correct subkey, as each subkey under this path is cryptic. I can identify the correct subkey visually in regedit by opening each subkey and inspecting for the String Value I am looking for (ProfileImagePath = C:\Users\USERANME).
Example: Subkey = S1-5-21-420551719-245851362-9522986-177556
Contains String Value = ProfileImagePath = C:\Users\n9000988
I already have a function that seeks and finds all available usernames, then a user control to select which username to work with.
So in this example, n9000988 is defined and selected.
So now I just need the ability to define what subkey the stringvalue resides in. Once I have that, I can then call to remove the subkey as that is the end goal of this sub.
What I've tried so far:
For Each subKeyName As String In My.Computer.Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows NT\CurrentVersion\ProfileList").GetSubKeyNames()
For Each profPath As String In My.Computer.Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & subKeyName).GetValue("ProfileImagePath")
MsgBox(profPath)
Next
Next
But this returns a MsgBox for each and every character in ProfileImagePath for all subkeys that contain the string ProfileImagePath.
I almost feel like my logic in this sub is trying to go too far forward before it can determine how to get the name of the subkey.
This one is making my brain hurt. Any help would be appreciated.
UPDATE:
That was perfect and so clean!!!
End result -
Public Class Dialog3
Private Function Username_To_SID(ByVal Username As String) As String
Return New Security.Principal.NTAccount(Username).Translate(GetType(Security.Principal.SecurityIdentifier)).Value
End Function
Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
' Kill SearchIndexer to release locked files
Try
Process.GetProcessesByName("SearchIndexer")(0).Kill()
Catch ex As Exception
End Try
Dim userID As String = Dialog1.ListBox1.SelectedItem
Dim userPath As String = "C:\users\" & userID
' Rename user folder
Try
My.Computer.FileSystem.RenameDirectory(userPath, userID & ".BAK")
Catch ex As Exception
MsgBox("Failed to rename user folders path")
End Try
Try
My.Computer.Registry.LocalMachine.DeleteSubKey("Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & (Username_To_SID(Dialog1.ListBox1.SelectedItem)))
Catch ex As Exception
MsgBox("Failed to remove registry entry in ProfileList")
End Try
Me.DialogResult = System.Windows.Forms.DialogResult.OK
Dialog1.Close()
Me.Close()
End Sub
I want to suggest you to stop using/searching/parsing registry techniques while you are programming in .NET, you can do it all using pure .NET code.
If I understanded good what you want is to know the equivalent SID of an Username, then you could use this:
' [ Username To SID ]
'
' // By Elektro H#cker
'
' Usage Examples:
' MsgBox(Username_To_SID("Administrator")) ' Result like: S-1-5-21-250596608-219436059-1115792336-500
''' <summary>
''' Returns the SecurityIdentifier of an existing Username.
''' </summary>
''' <param name="Username">Indicates the username to retrieve the SID.</param>
Private Function Username_To_SID(ByVal Username As String) As String
Return New Security.Principal.NTAccount(Username).
Translate(GetType(Security.Principal.SecurityIdentifier)).Value
End Function
Hey guys before I was just hiding the parent form, but now when I try to read from the parent file it says it can't because it's already running in a process. I followed some tutorial and it said to go to the project properties and have the application stop running when all the forms are closed.
But now since I did that it says the directory can't be found probably because I am reading the input from the parent form. Anyways here is my code
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" + frmLogin.txtUser.Text))
How should I go about doing this?
Edit:
Private Sub btnHunter_Click(sender As System.Object, e As System.EventArgs) Handles btnHunter.Click
selection = "Hunter"
writeData.classSelection()
End Sub
This is what I have when the button is clicked.
Here is the classSelection sub:
Public Sub classSelection()
If frmClass.selection = "Hunter" Then
writeFile1.WriteLine(frmClass.selection)
End If
If frmClass.selection = "Gatherer" Then
writeFile1.WriteLine(frmClass.selection)
End If
If frmClass.selection = "Farmer" Then
writeFile1.WriteLine(frmClass.selection)
End If
writeFile1.Close()
End Sub
The error points to this line:
If frmClass.selection = "Hunter" Then
Saying part of the file path cannot be found.
If you want to read input textbox in closed parent form, you have to declare public var
Make a new module in your project .. and add this
public sLogin as String
And before you hide or close frmLogin .. add this
sLogin = txtUser.Text
So, you could change your code with
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & sLogin))
matzone has given you a good hint. And to check exactly what your path is, just add a MessageBox using variables :
Dim writePath1 As String
Dim writeFile1 As StreamWriter
writePath1 = "C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & sLogin
If MessageBox.Show(writePath1, "Continue ?", MessageBoxButtons.YesNo) = DialogResult.Yes Then
writeFile1 = New StreamWriter(File.OpenWrite(writePath1))
' ...
writeFile1.Close() ' Very important ! Adrian pointed it out.
End If
^^ and if it works, you can discard the Dialog test or replace it by some test code like If File.Exists(...)
However, I don't understand wether you want to close the parent Form or hide it. It's different !
Closing the parent Form will discard any access to parent Form members, including txtUser.Text.
If you want to close the parent Form, the ChildForm should not be a child of that parent you are trying to close, or you must just hide the parent Form :
frmLogin.Hide() ' Not frmLogin.Close()
If you close frmLogin, frmLogin.txtUser won't be accessible, or use sLogin provided by matzone instead. Alternatively, you should pass frmLogin.txtUser.Text value to a custom property of ChildForm.
Imports System.IO
Public Partial Class ChildForm1
' Inherits System.Windows.Form
' ...
Private _txtUserFile As String
Public WriteOnly Property TxtUserFile() As String
Set(ByVal NewFileName As String)
_txtUserFile = NewFileName
End Set
End Property
Public Sub LoadFile()
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & txtUserFile))
' ...
writeFile1.Close()
End sub
' ...
End Class
Then use this in parent Form :
MyChildForm.TxtUserFile = Me.txtUser.Text
' Me.Close() ' This will definately KILL Form1 (the parent one)
Me.Hide() ' Always use Hide() until you'll terminate your Application
MyChildForm.Show()
MyChildForm.LoadFile()
^^ but this is not a good code either ! Your problem remains unclear (at least for me)
"Still saying it can't find part of the path", then check the path..
Does the file actually exists ?
Does the path contains glitch ? (use the provided MessageBox test)
Does your account can access that directory ? (Windows configuration and account levels)
Well !
In fact, the problem could be somewhere else.
For example, I was able to reproduce your exception by providing an empty string [""] as the value of, either :
frmLogin.txtUser.Text ' = ""
' or
sLogin ' = ""
' or
txtUserFile ' = ""
In fact, I get the "Could not find a part of the path..." exception because the StreamWriter couldn'd read/write to a File, as I didn't provided a valid FileName for that file. As the filename parameter was an empty string "", the provided path for StreamWriter was just representing a directory instead of a file and an exception was raised.
Now, you should check wether you have a valid path before building a new instance of StreamWriter to get sure you are actually pointing to a File ?
Dim writeFile1 As StreamWriter
Dim MyEntirePath As String = "C:\Users\...\Accounts\" + frmLogin.txtUser.Text
MessageBox.Show(MyEntirePath) ' would be enough to be sure your path is correct
' Some test code here...
If everythingOK then ' create the StreamWriter...
writeFile1 = New StreamWriter(MyEntirePath)
' ...
' ...
Also, it's not a good idea to create your streamwriter, and use it in another part/method of your code. You never known if one day, you'll change your code, and forget to make the link between
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" + frmLogin.txtUser.Text))
' plus
Private Sub btnHunter_Click(sender As System.Object, e As System.EventArgs)
...
End Sub
' plus
Public Sub classSelection()
...
writeFile1.Close()
End Sub
^^ too much "here and there"...
You'll obviously also get an exception if you try to click btnHunter twice.. I don't know what is the purpose of your code nor how it works, it looks like a game.. But I would use File.Exist(..) checks, create the file before, if none, and put that in a Try/Catch to check if I eventually don't have administrator rights to write to that directory. Otherwise, make a code that allow user to read/write files to a custom folder. Andalso, you have :
Application.StartupPath
^^ Very usefull, like :
Dim MyFilePath As String = Application.StartupPath + "\Datas\MyText.txt"
After two weeks of coding, I usually forget where I put those "C:\blabla.." or "D:\gnagna\" or what classes actually uses those absolute reference paths. I've dropped this way of getting directories long ago since the day I moved to Win7 on another computer and all such applications I developped using that approach was doomed...
I am using designing a Windows Form application using VB.net. I trying to have the application return the number of rows in a specific SharePoint List. Everything works perfectly when I I remove the ndQuery.InnerXml code; however, I want to filter the list before I get the count. The two columns I want to filter are "Assigned Employee" and "status." I looked at many different posts here on Stack(SharePoint SoapServerException calling GetListItems web service), but my Exception is relating to the Query. The detail of the soapserverException is: "One or more field types are not installed properly. Go to the list settings page to delete these fields: 0x81020014."
I tried going to the relationship page, but I could not browse to it:
(url)/Relationships%20List/allitems.aspx
Can any one see a problem with the Query code?
Imports System
Imports System.IO
Imports System.Net
Imports System.Xml
Imports <xmlns="rs">
Public Class Form1
Dim i As Integer
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim listService As New getListItems.Lists
listService.Credentials = CredentialCache.DefaultCredentials
listService.Url = "http://(servername)/_vti_bin/Lists.asmx"
Dim xmlDoc = New System.Xml.XmlDocument()
Dim ndQuery As XmlNode =
xmlDoc.CreateNode(XmlNodeType.Element, "Query", "")
Dim ndViewFields As XmlNode =
xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "")
Dim ndQueryOptions As XmlNode =
xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "")
ndQueryOptions.InnerXml =
"<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>"
ndViewFields.InnerXml = "<FieldRef Name='Assigned Employee'/><FieldRef Name='Status'/>"
ndQuery.InnerXml = "<Where><And><Contains><FieldRef Name ='Assigned Employee'/><Value Type='Text'>Engineer</Value></Contains><Contains><FieldRef Name='Status'/><Value Type='Text'>New</Value></Contains></And></Where>"
Try
Dim ndListItems As XmlNode =
listService.GetListItems("Requests", Nothing, ndQuery, _
ndViewFields, Nothing, ndQueryOptions, Nothing)
Dim n1 As XmlNode = ndListItems.Item("rs:data")
Dim a As String = n1.Attributes("ItemCount").InnerText
'Attempted For each loop, but not needed:
'Dim listItemCount As String
'Dim innerXML = New System.Xml.XmlDocument
'innerXML.LoadXml(ndListItems.InnerXml)
'Dim rows As XmlNodeList = innerXML.GetElementsByTagName("rs:data")
'For Each (XmlNode Attribute In rows)
'Next
Label1.Text = a
Catch ex As System.Web.Services.Protocols.SoapException
Label1.Text = ("Message:" + ControlChars.Lf + ex.Message +
ControlChars.Lf +
"Detail:" + ControlChars.Lf + ex.Detail.InnerText +
ControlChars.Lf +
"StackTrace:" + ControlChars.Lf + ex.StackTrace)
End Try
End Sub
End Class
You may need to replace the spaces in the field names with _x0020_ e.g.
<FieldRef Name='Assigned_x0020_Employee'/>
The Name attribute takes the field's internal name so double check that's what you're using.
When I have encountered the fun "one or more field types are not installed properly" error in the past it has usually been due to my CAML WHERE criteria indicating a field is of a certain type when it is not (e.g. I indicate Value type="Text" when it is actually a lookup).
If you go and get CAML Query Builder (free) from U2U, you can point it at your site (using the built in web services of SharePoint) and build your CAML query using their drag and drop designer. Once you have the query working there just click on the Edit tab and it will show you the exact CAML that SharePoint expects. My guess is you will find a field type incorrectly set. Whole process should take about 10 minutes after you install it.
I discovered the problem when breaking apart the query statement into two parts:
'ndQuery.InnerXml = "<Where><Eq><FieldRef Name ='Assigned_x0020_Employee'/><Value Type='Text'>Engineer</Value></Eq></Where>"
'ndQuery.InnerXml = "<Where><Eq><FieldRef Name ='Status'/><Value Type='Text'>New</Value></Eq></Where>"
I figured out that although one of the Columns in the SP list was named "Assigned Employee," the actual FieldRef Name was just employee. When I modified the code to include that, the error went away. I was spending all my time changing the Value Type, instead of looking at the FieldRef Name
Final Conclusion:
The "one or more field types are not installed properly" error not only gets returned if the "Value Type" is incorrect, but also when the "FieldRef Name" contains the wrong label.
Final working code line:
ndQuery.InnerXml = "<Where><And><Eq><FieldRef Name ='Employee'/><Value Type='Text'>Engineer</Value></Eq><Eq><FieldRef Name='Request_x0020_Status'/><Value Type ='Text'>New</Value></Eq></And></Where>"