VBScript: Reading through a dictionary in a Session variable - asp-classic

I'm trying to store a list of table items in a Session variable to keep track of the last state (CHECKED or UNCHECKED) of the item's checkbox.
I start out by setting all values to UNCHECKED the first time the users loads the page. This part of the code seems to work:
model = Request.querystring("model")
If IsEmpty(Session(model)) Then
Set dicX = CreateObject("Scripting.Dictionary")
sqlStr = "SELECT DISTINCT level FROM IFPDB WHERE IFPDB.model='"
sqlStr = sqlStr & model
sqlStr = sqlStr & "'"
Set objRS = objConn.Execute(sqlStr)
' For each unique level get all of that levels menu names
Do While (Not objRS.EOF)
level = objRS("level")
dicX.Add level, CreateObject("Scripting.Dictionary")
' for each menu name set the initial state to OFF
sqlStr2 = "SELECT * FROM IFPDB WHERE IFPDB.model='"
sqlStr2 = sqlStr2 & model
sqlStr2 = sqlStr2 & "' AND IFPDB.level='"
sqlStr2 = sqlStr2 & level_name
sqlStr2 = sqlStr2 & "'"
Set objRS2 = objConn.Execute(sqlStr2)
Do While (Not objRS2.EOF)
menu_item = objRS2("menu_names")
dicX(level).Add menu_item, CreateObject("Scripting.Dictionary")
' add a dictionary item
dicX(level)(menu_item).Add "menu_state", "UNCHECKED"
objRS2.MoveNext
Loop
objRS.MoveNext
Loop
Set Session(model) = dicX
End If
The problem now comes when I try to read any of these values. No matter how I've tried to access them I get "Object_required:_'[undefined]'"
I've tried
' Check the last state of this option
menu_name = objResult("menu_names")
response.write(menu_name & "<br>") ' writes correctly
If Not IsEmpty(Session(model))
my_state = Session(model)(current_level)(menu_name).Item("menu_state") ' dies here
response.write(my_state & "<br>")
End If
' tried these as well
my_state = Session(model)(current_level)(menu_name)("menu_state")
'and
my_state = Session(model)(current_level).Item(menu_name).Item("menu_state")
'and others
I guess I just don't know how to read that Session variable that I made. Any ideas?

See:
Can I store a Scripting Dictionary in a session variable?
You have to extract the dictionary from the session and put in into a fresh variable.
dim state
set state = Session(model)
You are also missing the 'item' part:
my_state = state.item(current_level).item(menu_name).item("menu_state")

Use Session("model") instead of Session(model).

Related

Provide two .csv files with one header/HTTP transaction

I currently have code that will generate a CSV from a database call, but I've been asked to create two separate CSV files with two different database calls from one click event. Here is an example of my current code:
'Global variable
Dim Include As List(Of String) = New List(Of String)
'Click event sub
Dim tempID As String = ""
'This gets the value of a checkbox (7th of 7 columns)
' and only adds checked rows to the query.
For Each row In GridView.Rows
If row.Cells(6).Controls(1).Checked Then
tempID = Regex.Replace(row.Cells(0).Controls(0).Text.Trim, "<(?:[^>=]|='[^']*'|=""[^""]*""|=[^'""][^\s>]*)*>", "", RegexOptions.IgnoreCase Or RegexOptions.IgnorePatternWhitespace Or RegexOptions.Multiline Or RegexOptions.Singleline)
Include.Add(tempID)
End If
Next
Dim Chosen As String = String.Join(",", Include)
SQLQuery = "SET ANSI_NULLS, ANSI_WARNINGS, ARITHABORT ON; "
SQLQuery += "SELECT * FROM ( " &
SQLQuery += "SELECT EXP.Account, " &
"EXP.Amount, " &
"EXP.DebitCredit, " &
"EXP.Description, " &
"EXP.BudgetCenter "
SQLQuery += "FROM [DB].[TBL] EXP " &
"INNER JOIN [DB2].[TBL2] REIM " &
"ON EXP.ID = REIM.ID " &
"WHERE EXP.ID IN ( " + Chosen + " ) " &
"AND REIM.StatusCode = 'APPROVED' "
SQLQuery += ") AS ResultTable "
ResultsDataSet = RunQuery(SQLQuery) 'THIS IS WHERE I CALL THE DATABASE
ResultsTable = ResultsDataSet.Tables(0)
For Each row As DataRow In ResultsTable.Rows
Dim item As String
For Each item In row.ItemArray
sb.Append(item.ToString + ","c)
Next
Next
Response.Clear()
Response.Buffer = True
Response.AddHeader("content-disposition", "attachment;filename=JournalReport_" + Date.Today.Month.ToString + "_" + Date.Today.Day.ToString + "_" + Date.Today.Year.ToString + ".csv")
Response.Charset = ""
Response.ContentType = "application/text"
Response.Output.Write(sb.ToString())
Response.Flush()
I have another click event that does the same thing, but with a different query and a different file name in the Response.AddHeader() call.
What I'm trying to do is to, in a way, merge those two click events to create both files in one action. Is there a way I can do this with the code I have? Is there a different way I should be creating these files?
I've written this code with the help of research on GridViews and DataSets over the last few days. So, if it isn't pretty, it's only because it's been a bit rushed and has little knowledge behind it.

Classic ASP: Type mismatch: 'GroupCheck'

I have a function named GroupCheck, which is designed to get the logged in users group from AD. It is, however, giving me the following error:
Microsoft VBScript runtime error '800a000d'
Type mismatch: 'GroupCheck'
/ldap.asp, line 67
Line 67 is where I call the function, passing in the Request.ServerVariables("AUTH_USER")
The following function is stored in a file which is included at the top of the page:
<%
function GroupCheck(user)
dim user, ADUser, objCom, objCon, objRS, membership
ADUser = "LDAP://OU=Staff,OU=Users,DC=example,DC=internal"
' Make AD connection and run query'
Set objCon = Server.CreateObject("ADODB.Connection")
objCon.provider ="ADsDSOObject"
objCon.Properties("User ID") = "EXAMPLE\user"
objCon.Properties("Password") = "Test"
objCon.Properties("Encrypt Password") = TRUE
objCon.open "Active Directory Provider"
Set objCom = CreateObject("ADODB.Command")
Set objCom.ActiveConnection = objCon
objCom.CommandText = "SELECT memberOf FROM '" + ADUser + "' where sAMAccountName='*" + 'user + "*' AND UserAccountControl <> 514"
Set objRS = objCom.Execute
Do While Not objRS.EOF Or objRS.BOF
if isNull(objRS.Fields("memberOf").value) then
membership = ""
else
for each item in objRS.Fields("memberOf").value
membership = item + "<br>"
next
end if
if inStr(membership, "UserGroup") then
GroupCheck = 1
else
GroupCheck = 0
end if
objRS.MoveNext
Response.Flush
Loop
'Clean up'
objRS.Close
objCon.Close
Set objRS = Nothing
Set objCon = Nothing
Set objCom = Nothing
end function
%>
I really don't know what the problem is, because /ldap.asp, line 67 is :
Set getMembership(username)
EDIT: My code for ldap.asp is:
getMembership = GroupCheck(Request.ServerVariables("AUTH_USER"))
'This should fetch all the accounts that appears in the "Contact Centre" group
if getMembership = 1 then
'Response.Write "<td><a href='entry.asp?account_name=" & objRS("sAMAccountName") & "'>Edit</a></td>"
elseif objRS("sAMAccountName") = session("username") then
Response.Write "<td><a href='entry.asp?account_name=" & objRs("sAMAccountName") + "'>Edit</a></td>"
else Response.Write "<td></td>"
end if
Response.Write "</tr>" + vbCrL
objRS.MoveNext
Response.Flush
Loop
Response.Write "</table>"
' Clean up
objRS.Close
objCon.Close
Set objRS = Nothing
Set objCon = Nothing
Set objCom = Nothing
%>
So what exactly is in line 67?
Set getMembership(username)
or
[unknown variable] = GroupCheck(Request.ServerVariables("AUTH_USER"))
?
In any case, this is probably the cause of the problem:
objCom.CommandText = "SELECT memberOf FROM '" + ADUser + "' where sAMAccountName='*" + 'user + "*' AND UserAccountControl <> 514"
In VBScript, the + operator is for arithmetic addition. "SELECT memberOf From '" cannot be converted into a number; hence the type mismatch. Probably. (I can't be sure because I don't know how you're calling or including the function.)
Instead, use the proper VBScript concatenation operator, &.
objCom.CommandText = "SELECT memberOf FROM '" & ADUser & "' where sAMAccountName='*" & user & "*' AND UserAccountControl <> 514"
Also, you're potentially shooting yourself in the foot by dimming a variable with the same name as the function argument:
function GroupCheck(user)
dim user, ADUser, objCom, objCon, objRS, membership
'^^^^
It may still work if you do that, but it's just not a good idea.

Filter taking 2 seconds on small adbodb recordset

I have a small adodb recordset I am trying to filter. This one is 6 records for our test customer.
For some reason the filter is taking 2 seconds to complete, and I am doing this around 30 times on my asp page. Thus, making my page really slow to load. The other recordset filters on this page are running fast.
I have tried setting different CursorLocations and CursorTypes..
Can anyone help me determine why this filter is so slow?
rsAvgPrice.Filter = "CommodityID = 13 AND CropYear = '12'"
Probably the whole query is executed again and only then the filter is being applied.
I would have one single loop over all the items, store the required data in local variables then have my own filter. Best efficiency, much better control.
For example, if you want the data filtered by those two fields, I would use Dictionary like this:
Dim oCommodity_CropYear_Data, curKey
Dim curCommodityID, curCropYear, curData
Set oCommodity_CropYear_Data = Server.CreateObject("Scripting.Dictionary")
Do Until rsAvgPrice.EOF
curCommodityID = rsAvgPrice("CommodityID")
curCropYear = rsAvgPrice("CropYear")
curKey = curCommodityID & "_" & curCropYear
curData = "field1: " & rsAvgPrice("somefield") & ", field 2: " & rsAvgPrice("other_field") & "<br />"
oCommodity_CropYear_Data(curKey) = oCommodity_CropYear_Data(curKey) & curData
rsAvgPrice.MoveNext
Loop
rsAvgPrice.Close
Then to extract the data in a loop:
For x=1 To 30
For y=1 To 12
curKey = x & "_" y
If oCommodity_CropYear_Data.Exists(curKey) Then
Response.Write("Data for Commodity " & x & " and CropYear " & y & ":<br />" & oCommodity_CropYear_Data(curKey)
End If
Next
Next
This is the general idea, hope you can use it for your actual needs.
I have resolved this issue.
The issue was when I declare a record set the following way, the cursor type gets set as adOpenForwardOnly and the cursor location to adUseServer. These settings cannot be changed if you fill your recordset using command.Execute.
Set cmd = Server.CreateObject("ADODB.Command")
cmd.CommandType = adCmdText
cmd.CommandText = mySQL
cmd.CommandTimeout = 3000
cmd.ActiveConnection = cn
Set rs = Server.CreateObject("ADODB.Recordset")
Set rs = cmd.Execute
Set cmd = Nothing
The way I resolved this was manually declaring a permanent recordset with its fields. Then I filled a temporary recordset using the command.execute. I then manually populated my declared recordset with the temporary recordset record by record. This allowed me to set the cursorlocation to adUseClient.
Thus speeding up the filter by leaps and bounds.

Storing a Dictionary to a Session

I created this function but it seems to give me a problem. I want to store a dictionary into an Session variable so I can access the dictionary throughout the website. I keep getting the error Object required: DictionaryObject or it will say This key already exist in the dictionary. Can someone please tell me what I am doing wrong?
I did look storing dictionary in session at this posting but didn't really fit what I am trying to do!
Function LoadPermissions()
Dim SQLString
SQLString ="SELECT datafields here... FROM " & TBL_employees_permissions & " AS p WHERE p.eid = '" & Clng(12) & "';"
If IsObject(Session("dicPermissions")) = True Then
Set dicPermissions = Session("dicPermissions")
Else
Set dicPermissions = Server.CreateObject("Scripting.Dictionary")
End If
db_conn conn, rs '
Set myRS = conn.Execute (SQLString)
For each item in myRS.Fields
If IsObject(Session("dicPermissions")) = True AND DictionaryObject.Exists(Trim(item.Name)) = False Then
dicPermissions.Add Trim(item.Name), Trim(myRS(item.Name))
End If
Next
db_disconn conn, rs
Set Session("dicPermissions") = dicPermissions 'Store Dictionary to session array.
End Function
I was able to get it working and here is what I did? If anyone see anything wrong or if I need to add in any error trapping. This is load once when the user logs in.
Dim SQLString
SQLString ="SELECT Datefields here... & " AS p WHERE p.eid = '" & Clng(12) & "';"
'Create the dictionary object.
Set Session("dicPermissions") = Server.CreateObject("Scripting.Dictionary") 'Create the Dictionary object.
'sets up a connection to the database
db_conn conn, rs 'Open account table.
Set myRS = conn.Execute (SQLString) ' Uses any ADODB connection
For each item in myRS.Fields 'Create the dictionary with the field names and cell data.
'dicPermissions.Add fieldname, feild value
Session("dicPermissions").Add Trim(item.Name), Trim(myRS(item.Name))
Next
db_disconn conn, rs 'Close the database
You can access it like so:
Response.write Session("dicPermissions").Item("itemnamehere...")

Querying Active Directory using VBScript

I want to query Active Directory using VBScript (classic ASP).
How can I accomplish that?
To look at all the members of an OU, try this...
Set objOU = GetObject("LDAP://OU=YourOU,DC=YourDomain,DC=com")
For each objMember in ObjOU ' get all the members'
' do something'
Next
To do a custom search for DNs try this...
set conn = createobject("ADODB.Connection")
Set iAdRootDSE = GetObject("LDAP://RootDSE")
strDefaultNamingContext = iAdRootDSE.Get("defaultNamingContext")
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"
strQueryDL = "<LDAP://" & strDefaultNamingContext & ">;(&(objectCategory=person)(objectClass=user));distinguishedName,adspath;subtree"
set objCmd = createobject("ADODB.Command")
objCmd.ActiveConnection = Conn
objCmd.Properties("SearchScope") = 2 ' we want to search everything
objCmd.Properties("Page Size") = 500 ' and we want our records in lots of 500
objCmd.CommandText = strQueryDL
Set objRs = objCmd.Execute
While Not objRS.eof
' do something with objRS.Fields("distinguishedName")'
objRS.MoveNext
Wend
I had to query WinAD by oldskool username, this .vbs script prints user accounts.
find by sAMAccountname, use * wildcard
print few attributes from each user object
use AccountType filter its most optimized way of iterating AD user objects
Test script first gets an user object by fully qualified string, its just an example. Second part does actual query by smith* filter.
WinADSearch.vbs
' c:> cscript -nologo script.vbs
' c:> wscript script.vbs
' http://msdn.microsoft.com/en-us/library/d6dw7aeh%28v=vs.85%29.aspx
' WindowsAD queries
' http://www.kouti.com/tables/userattributes.htm
Option Explicit
'On Error Resume Next
Dim StdOut: Set StdOut = WScript.StdOut
Dim objUser
Set objUser = GetObject("LDAP://CN=Firstname Lastname,OU=Internal Users,OU=MyCompany,OU=Boston,OU=Root,DC=REGION1,DC=COM")
println(objUser.givenName & " " & objUser.middleName & " " & objUser.lastName)
println("name=" & objUser.name)
println("displayName=" & objUser.displayName)
println("userPrincipalName=" & objUser.userPrincipalName)
println("sAMAccountName=" & objUser.sAMAccountName)
println("distinguishedName=" & objUser.distinguishedName)
println("")
Dim conn, strQueryDL, strAttrs, objCmd, objRs, idx
set conn = createobject("ADODB.Connection")
conn.Provider = "ADsDSOObject"
conn.Open "ADs Provider"
strAttrs = "sAMAccountName,displayName,distinguishedName" ' get attributes
'strQueryDL = "<LDAP://dc=REGION1,dc=COM>;(& (objectCategory=person) );" & strAttrs & ";SubTree"
'strQueryDL = "<LDAP://dc=REGION1,dc=COM>;(& (objectCategory=person)(objectClass=user) );" & strAttrs & ";SubTree"
'strQueryDL = "<LDAP://dc=REGION1,dc=COM>;(& (objectCategory=person)(objectClass=user)(sAMAccountName=smith*) );" & strAttrs & ";SubTree"
strQueryDL = "<LDAP://dc=REGION1,dc=COM>;(& (samAccountType=805306368)(sAMAccountName=smith*) );" & strAttrs & ";SubTree"
set objCmd = createobject("ADODB.Command")
objCmd.ActiveConnection = Conn
objCmd.Properties("SearchScope") = 2 ' search everything
objCmd.Properties("Page Size") = 100 ' bulk operation
objCmd.CommandText = strQueryDL
println(objCmd.CommandText)
Set objRs = objCmd.Execute
idx=0
do while Not objRS.eof
idx=idx+1
println( objRs.Fields("sAMAccountName") & " / " & objRs.Fields("displayName") & " / " & objRs.Fields("distinguishedName") )
if (idx>5) then exit do
objRS.MoveNext
loop
objRs.Close
Conn.close
set objRs = Nothing
set conn = Nothing
println("end")
'********************************************************************
Sub println(ByVal str)
If (StdOut Is Nothing) Then Exit Sub
StdOut.WriteLine str
End Sub
You want to use Active Directory Service Interfaces (ADSI)
The ADSI Scripting Primer is a good place to start learning and find examples.
(btw, these links refer to Windows 2000, but are valid for subsequent versions of Windows as well).

Resources