Using Studio 2013 VB.
I am attempting to retrieve group members from our Lotus Notes Domino directory - but I cannot get past this error: "A protocol error occurred. Failed, invalid authentication method specified." I was assuming (maybe incorrectly) that this could be done using DirectorySearcher as we do for our Active Directory.
I have tried retrieving various data with the same results. My research seems to indicate a problem with the ldapsettings but I am using the same alias and specific ldapsettings used by other in-house scripts (albeit written in perl). So the ldapsettings still might be the problem.
The line of code that fails is:
Dim result As SearchResult = searcher.FindOne
The value of searcher.Filter is (&(objectclass=dominoGroup)(cn=mydominogroup))
So this looks like it is build right.
Any help with errors in my code - or even suggestions to accomplish this task a better way are appreciated.
Here is my code:
dim grp as String = "mydominogroup"
Using dEntry As New DirectoryEntry("LDAP://mycompanyldapsettings")
dEntry.Username = myadminaccount
dEntry.Password = myadminpassword
Using searcher As New DirectorySearcher(dEntry)
searcher.Filter = String.Format("(&(objectclass=dominoGroup)(cn={0}))", grp)
Dim result As SearchResult = searcher.FindOne <--fails here
If result Is Nothing Then
"report group not found"
Else
Dim members As Object = result.GetDirectoryEntry.Invoke("Members", Nothing)
If members Is Nothing Then
"report no members found in group"
Else
For Each member As Object In CType(members, IEnumerable)
Dim currentMember As New DirectoryEntry(member)
If currentMember.SchemaClassName.ToLower = "user" Then
Dim props As PropertyCollection = currentMember.Properties
"get and list the user pros("someattribute").Value)"
End If
Next
End If
End If
End Using
End Using
Decided to call an external Process to solve this.
Related
I am using the QuickBooks QBFC12 SDK, and specifically, I am attempting to delete a "data extension" on an invoice in QB.
Some of the time the following VB.NET code will work, but many times it doesn't:
Dim objRequest As IMsgSetRequest
Dim objDatExtAdder As IDataExtAdd
Dim objResponse As IMsgSetResponse
Dim objOurResponse As IResponse
Dim objInvoiceQuery As IInvoiceQuery
Dim objInvoiceRetList As IInvoiceRetList
Dim objInvoiceRet As IInvoiceRet
Dim szInvoiceTxnID As String = ""
Dim objDataExtDel As IDataExtDel
' Check to see if the invoice is already on file.
objInvoiceQuery = objRequest.AppendInvoiceQueryRq
objInvoiceQuery.ORInvoiceQuery.InvoiceFilter.MaxReturned.SetValue(1)
objInvoiceQuery.IncludeLineItems.SetValue(True)
objInvoiceQuery.IncludeLinkedTxns.SetValue(True)
objInvoiceQuery.ORInvoiceQuery.InvoiceFilter.ORRefNumberFilter.RefNumberFilter.MatchCriterion.SetValue(ENMatchCriterion.mcEndsWith)
objInvoiceQuery.ORInvoiceQuery.InvoiceFilter.ORRefNumberFilter.RefNumberFilter.RefNumber.SetValue(szQBInvoiceNumber)
objResponse = objSessionManager.DoRequests(objRequest)
objOurResponse = objResponse.ResponseList.GetAt(0)
If objOurResponse.StatusCode = 0 Then
' Lock onto the invoice.
objInvoiceRetList = objOurResponse.Detail
If objInvoiceRetList.Count > 0 Then
' The invoice already exists.
objInvoiceRet = objInvoiceRetList.GetAt(0)
szInvoiceTxnID = objInvoiceRet.TxnID.GetValue
End If
End If
objRequest.ClearRequests()
' Remove any previous value.
objRequest = objSessionManager.CreateMsgSetRequest("US", 11, 0)
objRequest.Attributes.OnError = ENRqOnError.roeStop
objDataExtDel = objRequest.AppendDataExtDelRq()
objDataExtDel.OwnerID.SetValue("0")
objDataExtDel.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetInvoice)
objDataExtDel.ORListTxn.TxnDataExt.TxnID.SetValue(szInvoiceTxnID)
objDataExtDel.DataExtName.SetValue(szDataExtensionName)
objResponse = objSessionManager.DoRequests(objRequest)
objOurResponse = objResponse.ResponseList.GetAt(0)
If objOurResponse.StatusCode = 0 Then
Debug.Print("Worked")
Else
Debug.Print("Didn't work")
End If
On the occasions where it reports "Didn't Work," objourresponse.StatusMessage returns:
The necessary QuickBooks object access flag was not set in the attribute definition for an attribute. QuickBooks error message: Unknown Error
I have tried to understand what the "Object Access Flag" is and where it can be found, and I have searched on Google and the Intuit developer's site for more information, but I can't find anything.
Can someone help with understanding what this is, how I can get past this issue, and how I can consistently delete this data extension whenever necessary?
After a LOT of trial and error, I believe I have struck on a solution.
The particular extension was part of a drop-down selector that I have displayed on the invoice. Some of the valid values are "Printed" or "Shipped". Formerly, when I went to change the value in the extension, I was first deleting the extension using AppendDataExtDelRq, then adding it back in with the new value using AppendDataExtAddRq.
I was able to get the value to change if, instead of using the delete/add combination, I used AppendDataExtModRq and simply changed the value.
I still think there is a bug in the SDK like #InteXX suspects, but I also noticed that IF I set the extension to a pre-defined value in the drop-down, then all is good. BUT, if I try to set the extension to a value that isn't pre-defined in QB for that extension/drop-down, then I get the exact same error:
The necessary QuickBooks object access flag was not set in the attribute definition for an attribute. QuickBooks error message: Unknown Error
So the upshot is that it is working now by using the MOD and not the DELETE/ADD approach, but make sure you set the value to a pre-defined value.
I was asked to write an app at work that grabs an Employee list from our Sharepoint online site for eventual auto updating. The part I am stuck on is retrieving all of the fields of my employee list.
I would think that my query would simply bring back all of the fields that I see on my sharepoint list. But I admit that at this point that I do not have the best understanding of CAML.
So, I start to loop through each item in my Allitems object to create a datarow for each row of info so I can have a nice little data-table to display to the user. When the line of code runs to find item.("First Name") , I get the message that it is not in the list and that I may need to explicitly query it. Same with all of the other fields with a space. My AllItems object is bringing back all columns with the names that do not have a space (ie. Department, Title, Location, Email) which is strange to me.
Apparently, I do not understand Sharepoint enough and what the fields are called with a space.
I also see some C# examples with another method for the query object : query.ViewFields . I do not have this option for my query object. Also, can someone recommend another Sharepoint imports that would be beneficial here besides the ones that I am using?
Any help and advice would be greatly appreciated. Even an entirely different way of getting this data would be appreciated.
Also, I left only 4 of the datarow fields in the below code since it is failing on "First Name" to keep the code uncluttered. Since that would be the same reason for all of the other fields that are not comming back in my query.
Chris
Imports Microsoft.SharePoint
Imports Microsoft.SharePoint.Client
Try
Dim cred = New SharePointOnlineCredentials(txtUserName.Text, secureString)
Dim ctx = New Microsoft.SharePoint.Client.ClientContext(siteUrl)
ctx.Credentials = cred
Dim web As Web = ctx.Web
Dim list As List = web.Lists.GetByTitle(siteList)
ctx.Load(list)
ctx.ExecuteQuery()
Dim query As CamlQuery = CamlQuery.CreateAllItemsQuery()
query.ViewXml = "<View Scope='RecursiveAll'><Query><ViewFields><FieldRef Name='First Name'/><FieldRef Name='Last Name'/><FieldRef Name='Office Phone'/><FieldRef Name='Email'/><FieldRef Name='Cell Phone'/><FieldRef Name='Department'/><FieldRef Name='Location'/></ViewFields></Query></View>"
Dim AllItems As ListItemCollection = list.GetItems(query)
ctx.Load(AllItems)
ctx.ExecuteQuery()
If AllItems.Count > 0 Then
Dim dt As New DataTable
Dim dRow As DataRow
Dim dcID As New DataColumn("Id")
dcID.DataType = Type.GetType("System.String")
Dim dcFName As New DataColumn("First Name")
dcFName.DataType = Type.GetType("System.String")
Dim dcLName As New DataColumn("Last Name")
dcLName.DataType = Type.GetType("System.String")
Dim dcTitle As New DataColumn("Title")
dcTitle.DataType = Type.GetType("System.String")
dt.Columns.Add(dcID)
dt.Columns.Add(dcFName)
dt.Columns.Add(dcLName)
dt.Columns.Add(dcTitle)
For Each item As ListItem In AllItems
dRow = dt.NewRow()
dRow("Id") = item.Id
dRow("First Name") = item("First Name")
dRow("Last Name") = item("Last Name")
dRow("Title") = item("Title")
dt.Rows.Add(dRow)
Next
DGVList.DataSource = dt
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
Ok, it seems that the CAML was correct. I just did not know the internal names on the Sharepoint site. Once I obtained a list of the internal field names (not the display ones like I naively thought), I no longer ran into any errors. The answer was not so hard once I realized that I was querying fields that did not exist. It makes perfect sense that Visual Studio would yell at me for it.
For better or worse we are launching an Access db from Sharepoint. Note that this db is not PUBLISHED to SP, people just double-click the link and open the db on their desktops.
So now we need to begin imposing the equivalent of some roles-based edit restrictions. I know there is a VBA CurrentWebUser function and a CurrentWebUserGroups which provides some basic data about who's accessing an Office file from Sharepoint. However my reading and limited experimenting with this stuff leads me to suspect that, for Access at least, these will only work with published dbs, and not ones that are just being launched and run locally, like we're doing.
Is there anything I can get from SP in a case like this? Web user and user group would be useful, so would whichever site/page the link is being clicked on. Is any of this available?
Thanks.
rabbit
Well, not in any simple way.
As you've already determined, Application.CurrentWebUser just returns Null.
However, there are several ways to query the user information from SharePoint.
The recommended way (also by me) if you're going to work with SharePoint extensively, is to use the CSOM api, which requires a .Net language, so you'll have to create a COM module, authenticate it separately, and that's all a lot of work.
However, if you're only using simple GET requests, you can also use the REST API and re-use the authentication MS Access uses itself (since MS Access uses MSXML2 to submit web requests to SharePoint, we can create our own MSXML2.XMLHTTP object and it will re-use the cookies Access uses).
The following code uses the JSONInterpreter object I've shared here on GitHub. You could convert it to use XML and MSXML if you don't want that dependency, though.
To execute a request, I use the following code, that assumes the Access application is authenticated, but if it isn't, it connects to the SharePoint site using ADO.
(For this code, MySiteName is a global variable containing the URL of your SharePoint site, without a trailing slash)
Public Function SPRestGetJSON(Site As String, Request As String) As String
Dim tries As Long
Dim Success As Boolean
Do
'Try to execute request
tries = tries + 1
Dim xmlHttpReq As Object 'MSXML2.XMLHTTP60
Set xmlHttpReq = CreateObject("Msxml2.XMLHTTP.6.0") 'New MSXML2.XMLHTTP60
xmlHttpReq.Open "GET", Site & Request, False
xmlHttpReq.setRequestHeader "Content-Type", "application/json"
xmlHttpReq.setRequestHeader "Accept", "application/json;odata=nometadata"
xmlHttpReq.send
Dim root As JSONInterpreter
Set root = New JSONInterpreter
root.JSON = xmlHttpReq.responseText
If Not root.Exists("odata.error") Then
Success = True
End If
If Not Success And tries = 1 Then
'Connect to SharePoint using WSS + ADO to create auth cookies inside MSXML
Dim conn As Object 'ADODB.Connection
Set conn = CreateObject("ADODB.Connection") 'New ADODB.Connection
conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;WSS;DATABASE=" & Site
On Error Resume Next
conn.Execute "SELECT 1 From SomeTable" 'Execute to non-existent table but connect to sharepoint
On Error GoTo 0
conn.Close
End If
Loop While tries < 2 And Success = False
SPRestGetJSON = xmlHttpReq.responseText
End Function
Then, we can use that in a simple function:
Public Function GetSPUsername() As String
Dim jsi As New JSONInterpreter
jsi.JSON = SPRestGetJSON(MySiteName, "/_api/Web/CurrentUser")
GetSPUsername = jsi.item("LoginName").VBAVariant
End Function
Getting groups is also available. This code returns an array of dictionary objects, you can view the available keys in the locals window:
Public Function GetSPGroups() As Variant 'Array of dictionaries
Dim jsi As New JSONInterpreter
jsi.JSON = SPRestGetJSON(SiteName, "/_api/Web/CurrentUser/Groups")
GetSPGroups = jsi.item("value").VBAVariant
End Function
Then, to get the title of the first group the current user is a member of in the immediate window, we can use:
?GetSPGroups(0)!Title
I'm trying to fetch the files inside a folder ordered by LastWriteTime.
The code is running very fast when accessing to a local path (C:\MyFolder), but is hanging when accessing to a remote path (\\MyServer\MyFolder)
Dim myOrderedList As List(Of String) = (From item In IO.Directory.GetFiles(strFolderSource) _
Let file = New IO.FileInfo(item) _
Order By file.LastWriteTime _
Select item).ToList()
Should this code work? Is not allowed this method to get files from a remote folder?
Which alternative code could I use to get the same result without hanging?
EDITED (2019-01-18 16:32):
Sorry guys, I've tried the proposed solution from Rango, and still the same hang. Finally I created a small logging system to catch the step that caused the problem, and realized that all is a credential problem.
Just before the code I posted I do a NET USE to grant access to the remote computer, and the net use is executed, but for any reason, the GetFiles() fails because of Logon failure: unknown user name or bad password.
So, Could I ensure the credentials with the net use before call the GetFiles()?
Maybe using a pause or something like this?
FULL CODE:
Dim processInfo As New System.Diagnostics.ProcessStartInfo()
processInfo.FileName = "C:\WINDOWS\system32\net"
processInfo.Arguments = "net use \\MyServer\IPC$ ""password"" /USER:Username"
System.Diagnostics.Process.Start(processInfo)
Dim myOrderedList As List(Of String) = (From item In IO.Directory.GetFiles("\\MyServer\g$\MyFolder") _
Let file = New IO.FileInfo(item) _
Order By file.LastWriteTime _
Select item).ToList()
You could try to use DirectoryInfo.EnumerateFiles instead wich has two advantages:
No consecutive security handshakes from the remote server necessary
Streaming the files instead of loading all into memory before you start ordering them
Dim di = new DirectoryInfo(strFolderSource)
Dim files = From fi In di.EnumerateFiles() Order By fi.LastWriteTime Select fi.FullName
Dim myOrderedList As List(Of String) = files.ToList()
Finally solved including a sleep of 5 seconds after the net use and before the GetFiles():
System.Threading.Thread.Sleep(5000)
Thanks for your time, and hope this helps anybody with a similar problem.
I am starting to work with the QuickBooks SDK, and so far I am able to query Employees no problem, like so:
_sessionManager.OpenConnection("", "<software>")
_sessionManager.BeginSession("", ENOpenMode.omDontCare)
Dim requestSet As IMsgSetRequest = GetLatestMsgSetRequest(_sessionManager)
' Initialize the message set request object
requestSet.Attributes.OnError = ENRqOnError.roeStop
Dim empQuery As IEmployeeQuery = requestSet.AppendEmployeeQueryRq()
' Do the request and get the response message set object
Dim responseSet As IMsgSetResponse = _sessionManager.DoRequests(requestSet)
Dim response As IResponse = responseSet.ResponseList.GetAt(0)
Dim empRetList As IEmployeeRetList = response.Detail
....
_sessionManager.EndSession()
_sessionManager.CloseConnection()
Which will give me a list of employees which I can iterate through. This works well for the basic employee data, such as name, date of birth, etc. but there is a EmployeePayrollInfo property that does not seem to be returned with the IEmployeeQuery.
I see that there is an interface IEmployeePayrollInfo but I have not as yet been able to figure out if there is a way to query it. I see that there are report related payroll info queries, but I am trying to query the EmployeePayrollInfo directly, to retrieve the vacation information. Is this something that can be done with QBFC?
EDIT
I was able to get this working, see accepted answer below.
Open Quickbooks.
Go to the Edit menu and click Preferences.
In the Preferences window, click Integrated Applications in the list on the left.
Click the Company Preferences tab.
Select the application with which you are connecting to QuickBooks.
Click Properties.
Check "Allow this application to access Social Security Numbers, customer credit card information, and other personal data"
The employee data should now include EmployeePayrollInfo. Please comment if this does not work.
For anyone searching for the same functionality, the only information I was able to find seems to indicate that Intuit has specifically excluded this functionality from the QuickBooks SDK for security reasons. What we ended up doing to solve our problem is create a custom report in QuickBooks that included all of the information that we needed, exported it as a CSV file, and then import it accordingly in our software. Same end result, but a couple more steps than we were originally hoping for. Hopefully Intuit will change their mind about excluding this from the SDK.
UPDATE
I have finally been able to query the EmployeePayrollInfo, what was needed was adding "EmployeePayrollInfo" to the query itself like so:
empQuery.IncludeRetElementList.Add("EmployeePayrollInfo")
So now the code looks like this:
Dim sessionManager As New QBSessionManager
sessionManager.OpenConnection2("", "<software>", ENConnectionType.ctLocalQBD)
sessionManager.BeginSession("", ENOpenMode.omDontCare)
Dim requestSet As IMsgSetRequest = sessionManager.CreateMsgSetRequest("US", 12, 0)
requestSet.Attributes.OnError = ENRqOnError.roeStop
Dim empQuery As IEmployeeQuery = requestSet.AppendEmployeeQueryRq()
empQuery.IncludeRetElementList.Add("EmployeePayrollInfo") ' this line did the trick!
Dim responseSet As IMsgSetResponse = sessionManager.DoRequests(requestSet)
Dim response As IResponse = responseSet.ResponseList.GetAt(0)
Dim empRetList As IEmployeeRetList = response.Detail
If empRetList.Count > 0 Then
For i As Integer = 0 To empRetList.Count - 1
Dim emp As IEmployeeRet = empRetList.GetAt(i)
If emp IsNot Nothing Then
' do something with the queried data
End If
Next
End If
sessionManager.EndSession()
sessionManager.CloseConnection()