Display operatingsystem property in a message box - vb.net

I am having trouble getting the operatingsystem property for computers in Active Directory(AD). Here is the code I am having trouble with and the function that gets the property from AD. The hostname works perfectly but the OS_Name displays a blank message box.
Alternatively, I would also like help formatting the filter to make things easier down the road. My goal is to check the operating system and only process the Windows 10 Enterprise and Windows 7 Enterprise operating systems but I can't even display the operating system in a message box. Please help.
Dim enTry As DirectoryEntry = New
DirectoryEntry("GC://my.work.com/DC=AB27,DC=my,DC=work,DC=com")
Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
mySearcher.Filter = ("(objectClass=computer)")
mySearcher.PropertiesToLoad.Add("dNSHostName")
mySearcher.PropertiesToLoad.Add("operatingSystem")
Dim ds As SearchResult
For Each ds In mySearcher.FindAll()
Dim OS_Name As String = GetProperty(ds, "operatingSystem")
Dim hostName As String = GetProperty(ds, "dNSHostName")
MessageBox.Show(hostName)
MessageBox.Show(OS_Name)
Next
Function GetProperty(ByVal searchResult As SearchResult, ByVal
PropertyName As String)
If searchResult.Properties.Contains(PropertyName) Then
Return searchResult.Properties(PropertyName)(0).ToString()
Else
Return String.Empty
End If
End Function
I expect the message for the operating system to display the operating system property. Instead it displays a blank message box.
When I use debug.writeline instead of a message box it leaves a blank line between each hostname as if it reads the OS but just adds a line to hold the space.

Not sure what is in your DirectoryEntry nor if why you have structured your filter is causing a problem but the following shows me my hostname and operating system...
Dim enTry As DirectoryEntry = New DirectoryEntry
Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
mySearcher.PropertiesToLoad.Add("dNSHostName")
mySearcher.PropertiesToLoad.Add("operatingSystem")
mySearcher.PropertiesToLoad.Add("operatingSystemVersion")
mySearcher.Filter = "(&(objectClass=computer)(operatingSystem=*server*))"
Dim resEnt As SearchResult
For Each resEnt In mySearcher.FindAll()
Dim OS_Name As String
Dim hostName As String
hostName = GetProperty(resEnt, "dNSHostName")
OS_Name = GetProperty(resEnt, "operatingSystem")
Next

Related

LDAP Vb.net simple query

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

Need help getting Registry.GetValue to work correctly

I have a simple setup project that is no longer working and it seems like a windows update is the cause. I am using Visual Studio 2010 on Windows 7. The project is 64bit. It still works on some computers but it does not work on any computers that have had updates recently.
Here is the original code:
Dim appPath As String = Registry.GetValue("HKEY_CURRENT_USER\SOFTWARE\Our Company Inc.\SoftwareName.exe", "Path", "Not Found")
appPath &= "Colorbar.col"
Dim sid : sid = "S-1-1-0"
Dim objWMI : objWMI = GetObject("winmgmts://./root\cimv2")
Dim objSID : objSID = objWMI.Get("Win32_SID='" & sid & "'")
Dim userAccount As String = objSID.AccountName
Dim fileInfo As IO.FileInfo = New IO.FileInfo(appPath)
Dim fileAcl As New FileSecurity
fileAcl.AddAccessRule(New FileSystemAccessRule(userAccount, FileSystemRights.FullControl, AccessControlType.Allow))
fileInfo.SetAccessControl(fileAcl)
I have put the key value pair of "Path" and "[TARGETDIR]" in the registry editor and have the output from this installer class (the code above) in the Install and Commit custom actions.
This code that used to work now returns "Exception has been thrown by the target of an invocation -> C:\Windows\SYSWOW64\Colorbar.col"
I have checked the registry when this message appears and the path is correct so I don't know where SYSWOW64 is coming from.
I have tried to change getting the appPath using this code:
Dim regKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64)
regKey = regKey.OpenSubKey("SOFTWARE\Our Company Inc.\SoftwareName.exe")
Dim appPath As String = regKey.GetValue("Path").ToString
This returns an "Object reference not set to an instance of an object" error.
I have made a test Windows Form application and put both versions of code in a button event. Everything works as expected. Any ideas why the code does not work in a setup project anymore and what I can do to get it working again?
Thanks in advance.
Finally have it working again. I got around using the registry by using the custom action's CustomActionData and setting it to:
/name="[TARGETDIR]\"
I was then able to access it in my installer class by using this line of code:
Dim appPath As String = Context.Parameters.Item("name")
Once the path was set, everything else worked as expected. The final code looks like this:
Public Overrides Sub Commit(ByVal stateSaver As System.Collections.IDictionary)
MyBase.Commit(stateSaver)
Dim appPath As String = Context.Parameters.Item("name")
appPath = appPath.Remove(appPath.Length - 1)
appPath &= "Colorbar.col"
Dim sid : sid = "S-1-1-0"
Dim objWMI : objWMI = GetObject("winmgmts://./root\cimv2")
Dim objSID : objSID = objWMI.Get("Win32_SID='" & sid & "'")
Dim userAccount As String = objSID.AccountName
Dim fileInfo As IO.FileInfo = New IO.FileInfo(appPath)
Dim fileAcl As New FileSecurity
fileAcl.AddAccessRule(New FileSystemAccessRule(userAccount, FileSystemRights.FullControl, AccessControlType.Allow))
fileInfo.SetAccessControl(fileAcl)
End Sub

Disabling a checkbox by getting its name from a server

It is quite a bit hard to explain what I have in mind but I will try my best...
I have an installer with a ton of checkboxes. Each checkbox is mod (modification for a game). At times mods interfere with a game and cause the game to crash. So I have to update the installer with either updated mod(s) or I have to temporarily disable the mod or mods that are causing the crashing.
What it will do is connect to a server that checks if a file contains "true or false" if it contains "true" it will execute code that does this:
Connects to a different server, gets the name of a checkbox, and does something like this:
NameOfCheckBox.Enabled = False
The thing is... I know how to do this, except the very last part.
How do I tell my program that the text it gets from the server is a name of checkbox that is located on the form?
This is my code:
Try
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create("https://docs.google.com/document/d/1G3R0CoRG-LCXy-8jm-LcCJZJ9B0whsOJ64efjL0btc8/edit?usp=sharing")
Dim response As System.Net.HttpWebResponse = request.GetResponse()
Dim sr As System.IO.StreamReader = New System.IO.StreamReader(response.GetResponseStream())
Dim status As String = sr.ReadToEnd()
Dim request2 As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create("https://docs.google.com/document/d/1cYkhGTDEpxqltOvCSSD0Kw9J_1DG1dyJSV2qQ1Xekto/edit?usp=sharing")
Dim response2 As System.Net.HttpWebResponse = request2.GetResponse()
Dim sr2 As System.IO.StreamReader = New System.IO.StreamReader(response2.GetResponseStream())
Dim checkboxtodisable As String = sr2.ReadToEnd()
If status.Contains("True") Then
Dim chk As CheckBox
chk.Name = checkboxtodisable
chk.Enabled = False
Else
End If
Catch ex As Exception
MessageBox.Show("Unable to connect to server!")
MessageBox.Show(ex.Message)
End Try
The error I get is:
Object reference not set to an instance of an object
The error is located on this line of code:
chk.Name = checkboxtodisable
You can retrieve a control by name like this:
Dim MyCheckBox As Checkbox = Me.Controls("checkbox1")
So your code would look like this:
If status.Contains("True") Then
Dim chk as checkbox = Me.Controls(checkboxtodisable)
chk.Enabled = False
End If

Using DirectoryEntry.Invoke("SetPassword", ...) to set initial AD account password, I get "RPC server is unavailable" error

The company I'm working in has a web service that can create new Active Directory accounts based on information that is typed in e.g. username, firstname, lastname, OU1, OU2, etc.
This web service has been working fine on Windows Server 2003. Now I'm working on moving the web service to 2008 R2 servers. However a certain functionality doesn't work anymore, which is when it tries to set a random initial password to the newly created account.
The exception that is thrown is a TargetInvocationException containing an inner exception of COMException with a message of "The RPC Server is unavailable".
Imports System.DirectoryServices
Dim ldapPath As String = "..." 'assume valid LDAP path
Dim objContainer As DirectoryEntry = New DirectoryEntry(ldapPath, vbNullString, vbNullString, AuthenticationTypes.Secure)
objUser = objContainer.Children.Add("cn=" & Username.Trim, "user")
'sets objUser.Properties e.g. givenName, displayName, userPrincipalName, samAccountName, etc. Not important...
objUser.CommitChanges()
strPassword = RandomPassword() 'function that generates random password
objUser.Invoke("SetPassword", New Object() {strPassword})
objUser.Properties("useraccountcontrol").Value = "512" ' set as normal account
objUser.CommitChanges()
'and so on...
The error happens on the line that says:
objUser.Invoke("SetPassword", New Object() {strPassword})
Strangely the account creation itself works and I can see the new user from Active Directory Users and Computers.
I have consulted a few different people who manage the security of the DCs and the web servers, they don't really know why...
In the end I figured out a different way of setting the password, which is using the System.DirectoryServices.AccountManagement library.
So the code becomes something like this:
Imports System.DirectoryServices
Imports System.DirectoryServices.AccountManagement
Dim ldapPath As String = "..." 'assume valid LDAP path
Dim objContainer As DirectoryEntry = New DirectoryEntry(ldapPath, vbNullString, vbNullString, AuthenticationTypes.Secure)
Dim objUser As DirectoryEntry = objContainer.Children.Add("cn=" & Username.Trim, "user")
'sets objUser.Properties e.g. givenName, displayName, userPrincipalName, samAccountName, etc. Not important...
objUser.CommitChanges()
Dim domainContext As PrincipalContext = New PrincipalContext(ContextType.Domain, ...)
Dim user As UserPrincipal = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, Trim(Username))
strPassword = RandomPassword() 'function that generates random password
user.SetPassword(strPassword)
user.Enabled = True 'setting these two properties
user.PasswordNotRequired = False 'result in useraccountcontrol value = 512 (normal account)
user.Save()
'and so on...
I'm mixing old code with new code in this one, but it appears to be working really well on the new servers. One thing to note is that sometimes the UserPrincipal.FindByIdentity call initially returns Nothing, I believe due to delay in the account creation or with the replication. So I have to make sure that the user object is not Nothing by trying FindByIdentity multiple times until I get the object.
Despite finding a solution (more like a way around) to the problem, still I'm confused as to why the old code does not work on the new servers, but the new one does. The error is very generic and searching the internet for clues have resulted in nothing but more confusion.
Would really appreciate if experts out there can shed some lights or even comment on the way my new code looks, any problems?
Thanks in advance.

VB.NET Remove user from active directory

Hi I am trying to create a VB.NET application which will (hopefully) reduce some time spent on some of my departments helpdesk calls. The part that I am stuck with is how to use VB.NET to remove a user from a group. The following is code that I have been playing with:
Public Shared Sub RemoveUserFromGroup(ByVal deUser As String, ByVal GroupName As String)
Dim entry As DirectoryEntry = ADEntry()
Dim mySearcher As DirectorySearcher = New DirectorySearcher(entry)
mySearcher.Filter = "(&(ObjectClass=Group)(CN=" & GroupName & "))"
mySearcher.PropertiesToLoad.Add("OrganizationalUnit")
mySearcher.PropertiesToLoad.Add("DistinguishedName")
mySearcher.PropertiesToLoad.Add("sAMAccountName")
Dim searchResults As SearchResultCollection = mySearcher.FindAll()
If searchResults.Count > 0 Then
Dim group As New DirectoryEntry(searchResults(0).Path)
Dim members As Object = group.Invoke("Members", Nothing)
For Each member As Object In CType(members, IEnumerable)
Dim x As DirectoryEntry = New DirectoryEntry(member)
MessageBox.Show(x.Properties("sAMAccountName").Value)
If x.Properties("sAMAccountName").Value = deUser Then
MessageBox.Show(searchResults.Item(0).Path.ToString)
MessageBox.Show(x.Properties("sAMAccountName").Value)
'group.Invoke("Remove", New Object() {x.Properties("OrganizationalUnit").Value})
group.Properties("member").Remove(x.Properties("OrganizationalUnit").Value)
End If
Next
End If
When I run the program, I recevie a COMException was unhandled, unspecified error at the group.properties line. When using group.invoke I receive the error TargetInvocationException was unhandled.
My aim is to pass as a string the username (sAMAccountName) and the groupname (sAMAccountName) to the function which will locate the user and remove them from the group.
I am new to VB.NET and would appreciate any assistance people can provide.
I am coding in .NET 2.0 as I am unsure if the server it will live on will have 3.5 installed.
Well the error message 0x80004005 E_FAIL Unspecified failure is not very helpful. I often get frustrated when working with Active Directory.
Try changing line:
group.Properties("member").Remove(x.Properties("OrganizationalUnit").Value)
to
group.Invoke("Remove", New Object() {x.Path.ToString()})
If you need more reference take a look at this article on VB.net Heaven by Erika Ehrli. The article covers various use cases with Active Directory.
I hope that helps.