Change SQL Server Password through MS Access VBA Front-End - sql-server

I have been working on developing a MS Access application that will allow some coworkers to easily interact with data on our SQL Server. The program is about done, but one little thing remains- allowing a user to change their SQL Server password through the MS Access front-end. I have been googling my little heart out, but after a while everything starts to look the same (even if the answer is right in front of me!).
I found a couple links that are helpful, but I can't quite make the leap on how to apply it to my VBA program.
Change expired password without "Password Expired dialog box"
How can I change SQL Server login account password on first login via C#?
http://www.utteraccess.com/forum/Users-Change-SQL-Pass-t2006545.html&pid=2378998
My current connection string looks like this
Dim cn As ADODB.Connection
Dim strCS As String
Set cn = New ADODB.Connection
strCS = "Provider=SQLOLEDB;" _
& "Server=IP ADDRESS GOES HERE;" _
& "Database=" + DBselect.Value + ";" _
& "User ID=" + Uname.Value + ";" _
& "Password=" + pWord.Value + ";" _
& "MARS Connection=True;"
cn.ConnectionString = strCS
cn.Open
This connection string works perfectly fine as long as the user's password hasn't expired.
How would I modify this connection string to change a users password? Any help is really appreciated!
Thanks!

Looks to me, from that 1st link, that this will work:
1) Create a new stored procedure in SQL Server called spChangeLogin. It should look like this:
CREATE procedure [dbo].[spChangeLogin]
#UserName VarChar (50),
#OldPass VarChar (20),
#NewPass VarChar (20)
AS
BEGIN
ALTER LOGIN #UserName WITH
PASSWORD = #NewPass
OLD_PASSWORD = #OldPass
END
;
GO
2) Add this to your Access DB:
Dim cnComments As New ADODB.Connection
Dim strCS As String
Dim P As String
Dim Rsx As ADODB.Recordset
'Set up the connection string
strCS = "Provider=SQLOLEDB;" _
& "Server=IP ADDRESS GOES HERE;" _
& "Database=" + DBselect.Value + ";" _
& "User ID=" + Uname.Value + ";" _
& "Password=" + pWord.Value + ";" _
& "MARS Connection=True;"
cnComments.Open strCS
P = "spChangeLogin '" & Me.UserName & "', '" & Me.OldPass & "', '" & Me.NewPass & "'"
Set Rsx = cnComments.Execute(P)
3) Put 3 fields on your form; UserName, OldPass and NewPass
Requires ALTER ANY LOGIN permission.
NOTE:
My connection string looks like this:
strConn = "PROVIDER=SQLOLEDB;DATA SOURCE=MyServerName;INITIAL CATALOG=MyDatabaseName;UID=GlobalUserID;PWD=GlobalPassword;"
You may need to adjust accordingly.

Related

Issues Connecting to Local SQL Server database

I have been trying to connect to a local SQL Server that I have created via Excel VBA but I am having issues.
I am able to connect to the database using the "Get Data" functionality within Excel and entering in the server as (Local DB)\MSSQLLocalDB.
However when I try connecting using VBA it does not work, using Windows authentication. Any ideas?
Here is the string I used:
strConnString = "Provider=SQLOLEDB;Data Source=(LocalDB)\MSSQLLocalDB;Integrated Security=SSPI"
The error I get is
Run-time error '2147467259 (80004005)'
[DBNETLIB][ConnectionOpen (Connect()).]
SQL Server does not exist or access denied.
This is how I use it, test it. TEST is Database name.
con.ConnectionString = "Provider=SQLOLEDB.1;" _
& "Server=(local);" _
& "Database=TEST;" _
& "Integrated Security=SSPI;" _
& "DataTypeCompatibility=80;"
Try it this way.
Sub ADOExcelSQLServer()
' Carl SQL Server Connection
'
' FOR THIS CODE TO WORK
' In VBE you need to go Tools References and check Microsoft Active X Data Objects 2.x library
'
Dim Cn As ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Dim SQLStr As String
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Server_Name = "Your_Server_Name" ' Enter your server name here
Database_Name = "NORTHWND" ' Enter your database name here
User_ID = "" ' enter your user ID here
Password = "" ' Enter your password here
SQLStr = "SELECT * FROM [Customers]" ' Enter your SQL here
Set Cn = New ADODB.Connection
Cn.Open "Driver={SQL Server};Server=" & Server_Name & ";Database=" & Database_Name & _
";Uid=" & User_ID & ";Pwd=" & Password & ";"
rs.Open SQLStr, Cn, adOpenStatic
' Dump to spreadsheet
For iCols = 0 To rs.Fields.Count - 1
Worksheets("Sheet1").Cells(1, iCols + 1).Value = rs.Fields(iCols).Name
Next
With Worksheets("sheet1").Range("a2:z500") ' Enter your sheet name and range here
'.ClearContents
.CopyFromRecordset rs
End With
' Tidy up
rs.Close
Set rs = Nothing
Cn.Close
Set Cn = Nothing
End Sub

runtime error 3704 on a opened object

I am struggling with this situation
I have a query that when i run in MSSQL server management studio it gives me 18 rows, it it stored in a cell. The database is connected to a live server and we would like to create Excel dashboards out of them so it get refreshed with live data and create graph etc....
***** EDIT *****
I tried a very simple query and it works i can get for example
select max(datetime)from table and i do have the latest sync.
The thing is: my query has
1) A Declared table for validation
2) A temporary table "with table as( ) ;" that sorts all data and rank them with some filtering "RowNumber" that is called later in with a where statement that take only some row numbers to avoid repeats
I think that in between the connection must close, can it be?
Normally this code works out but for this server i get:
"runtime error 3704 operation is not allowed when the object is closed"
I've searched the forum and the google with no luck
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Dim query As String
Set con = New ADODB.Connection
Set rs = New ADODB.Recordset
strCon = "Provider=SQLOLEDB.1;" _
& "Password=*******;" _
& "Persist Security Info=True;" _
& "User ID=********;" _
& "Initial Catalog=*******;" _
& "Data Source=***.**.**.**;" _
& "Use Procedure for Prepare=1;" _
& "Auto Translate=True;Packet Size=4096;" _
& "Use Encryption for Data=False;" _
& "Tag with column collation when possible=False"
con.Open (strCon)
rs.ActiveConnection = Con 'modified with suggestion below
strSQLQuery = Worksheets("Query").Range("B2").Value
rs.Open strSQLQuery
For i = 0 To rs.Fields.Count - 1
Sheet2.Cells(1, i + 1) = rs.Fields(i).Name
Next i
Worksheets("Result").Range("A2").CopyFromRecordset rs
rs.Close
Set rs = Nothing
con.Close
Set cn = Nothing
Can a magician help me out? because now im doing it with excel VBA as a demo but i would like to promote it to a VB tool and want to make sure it is not a server related issue.
Thank you in advance
con.Open (strCon)
rs.ActiveConnection = strCon
should be
con.Open strCon
rs.ActiveConnection = con
ie. you should set ActiveConnection to the Connection object you just opened, not to the connection string.

Connection to a Microsoft SQL Database via VBA (ADODB) with the lowest risk to harm the database

im currently looking for a way to connect to a Microsoft SQL Server Database via VBA (ADODB) with the focus on a minimal risk in harming, block and change the structure of the database. Therefor the access is readonly.
My attemp is the following:
Set DBConn = New ADODB.Connection
Set TmpRecset = New Recordset
DBConn.ConnectionString = pConnStr
DBConn.Open
On Error GoTo TermConnection
With TmpRecset
.ActiveConnection = DBConn
.Source = pQuery
.LockType = adLockReadOnly
.CursorType = adOpenForwardOnly
.CursorLocation = adUseClient
.Open
End With
On Error GoTo TermRecordset
//Doing something useful with TmpRecset
On Error GoTo 0
TermRecordset:
TmpRecset.Close
Set TmpRecset.ActiveConnection = Nothing
TermConnection:
DBConn.Close
Set DBConn = Nothing
End Sub
And I'm using the following connection string:
"Provider=SQLOLEDB;Data Source=IP\Database;Initial Catalog=Databasename;Trusted_connection=yes;"
I used the manual error handling to ensure, that the recordset and the database is closed whatever happens. Via the parameters of the recordset I define the readonly access.
Are there some other mechanisms to make sure, that the integrity of the Database will be ensured?
Best regards
In my opinion there is no reasonable security in Excel. All security should reside on the server. If you want to prevent accidental or malicious changes to the database then the database on the server should be read-only or all users should have read-only access to the SQL server. Furthermore, you can implement traces on the server, SQL audit C2, or make use of extended properties. Yet, all of this is on the side of the SQL server. The things you can do on the "client" side (such as Excel in this case) are only support functions. And so the question is (to me) what kind of support functions can I implement in Excel to ensure SQL server safety. Here are some of the things I do:
(1) Make the connection string dynamic using global variables or storing the string on a hidden sheet. Then you can automatically switch between development server and production server. Example:
Dim conRCServer As ADODB.Connection
Dim rstResult As ADODB.Recordset
Dim strSQL As String
Set conRCServer = New ADODB.Connection
conRCServer.ConnectionString = "PROVIDER=SQLOLEDB; " _
& "DATA SOURCE=" & Ref.Range("C2").Value2 & ";" _
& "INITIAL CATALOG=" & Ref.Range("C4").Value & ";" _
& "Integrated Security=SSPI "
On Error GoTo SQL_ConnectionError
conRCServer.Open
On Error GoTo 0
(2) Have a seperate error handler for connecting to the server and handling SQL syntax errors. Example:
Set rstResult = New ADODB.Recordset
strSQL = "set nocount on; "
strSQL = strSQL & "/* #" & ActiveWorkbook.Path & "/" & ActiveWorkbook.Name & "{" & WorksheetUsers.Name & "}btnDownloadUserDataFromServer */"
strSQL = strSQL & "select v.LastName, "
strSQL = strSQL & " v.FirstName "
strSQL = strSQL & "from vUsers as v "
strSQL = strSQL & "order by v.LastName, v.FirstName "
rstResult.ActiveConnection = conRCServer
On Error GoTo SQL_StatementError
rstResult.Open strSQL
On Error GoTo 0
Here is an error handler for the SQL syntax and in the above example is a seperate handler for the possible SQL connection error.
(3) Incorporate self-identification within the SQL syntax. As you can see in the above example I am also letting the server know which file, which sheet (within the file) and which function within the sheet the user called to execute this statement. If you capture this data on the server with a trace then you can see who is writing their own queries, who is using your standard files and which functions are used (and their respective impact).
(4) If an error occurs you might want to consider writing automated error emails. Example:
SQL_ConnectionError:
Y = MsgBox("Cannot connect to the server. Please make sure that you have a working internet connection. " & _
"Also ensure that are connected to the corporate network and are allowed to access the server. " & _
"Do you want me to prepare an error-email?", 52, "Problems connecting to Server...")
If Y = 6 Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = Ref.Range("C7").Value2
.CC = Ref.Range("C8").Value2
.Subject = "Problems connecting to database '" & Ref.Range("C4").Value & "' on server '" & Ref.Range("C2").Value & "'"
.HTMLBody = "<span style=""font-size:10px"">---Automatically generated Error-Email---" & _
"</span><br><br>Error report from the file '" & _
"<span style=""color:blue"">" & ActiveWorkbook.Name & _
"</span>' located and saved on '<span style=""color:blue"">" & _
ActiveWorkbook.Path & "</span>'.<br>" & _
"Excel is not able to establish a connection to the server. Technical data to follow." & "<br><br>" & _
"Computer Name: <span style=""color:green;"">" & Environ("COMPUTERNAME") & "</span><br>" & _
"Logged in as: <span style=""color:green;"">" & Environ("USERDOMAIN") & "/" & Environ("USERNAME") & "</span><br>" & _
"Domain Server: <span style=""color:green;"">" & Environ("LOGONSERVER") & "</span><br>" & _
"User DNS Domain: <span style=""color:green;"">" & Environ("USERDNSDOMAIN") & "</span><br>" & _
"Operating System: <span style=""color:green;"">" & Environ("OS") & "</span><br>" & _
"Excel Version: <span style=""color:green;"">" & Application.Version & "</span><br>" & _
"<br><span style=""font-size:10px""><br>" & _
"Possible reasons for this error include: (1) no Internet connection, (2) no working VPN connection to the corporate network, " & _
"(3) the server is currently offline, (4) DNS authentication problems, (5) ... other reasons ..., " & _
"(6) the user does not have the required permission to connect to the underlying database on the server." & _
"<br><br>---Automatically generated Error-Email---"
.Display
End With
Set OutMail = Nothing
Set OutApp = Nothing
End If
Exit Sub
I also looked into your approach of changing the connection parameters. But in most corporate environments I have worked for these connection parameters have been overridden (for example ADODB.Connection.CommandTimeout is overridden by the server's SQL timeout per user or Windows corporate presets if they exist). So, they did not work for me. But the above worked rather well for me and the companies I worked for over the last couple of years.
Let me know if this is the kind of answer you've been looking for.

'800a0e78' - object closed - worked previously

I've searched high and low to resolve this one, but can't seem to fix it on my own. I'm new to classic ASP but a very long time PhP dev.
I'm getting
ADODB.Recordset error '800a0e78'
Operation is not allowed when the object is closed.
/sdd/fx_mlogin.asp, line 54
While logging in to the site i'm working on. The line's that's its referencing is:
Set rs = cmd.Execute
If RS.BOF or RS.EOF then
More relevant code:
Set cn = Server.CreateObject("ADODB.Connection")
cn.Open MM_ap_connect_STRING
Set cmd = Server.CreateObject("ADODB.Command")
Set cmd.ActiveConnection = cn
cmd.CommandText = "sd_member_login " & "'" & guid & "', " & """" & trim(user) & """, " & "'" & trim(pw) & "', " & "'" & uip & "', " & "'" & uagent & "', " & "'" & logintrack & "'"
Set rs = cmd.Execute
If rs.BOF or rs.EOF then
The kicker is that the site worked before and we're moving hosts. The connection is apparently working, but I'm suspicious that its still the issue. My connection string is
MM_ap_connect_STRING = "Provider=SQLOLEDB;Data source=sql2103.shared-servers.com,1087;Initial catalog=database;User Id=username;Password=password;"
But obviously with the username, password, and database fields filled in. I'm also connecting to a SQL 2005 database. Any help would be appreciated! Let me know if I need to provide any more information.
Try adding the T-SQL line:
SET NOCOUNT ON
to the top of the SQL being executed.
I had this exact issue. For me the answer was my stored procedure had an owner of DBO. Which my user for the previous database was set to DBO. On our destination database there was a different DBO, which caused a execute permissions issue. Just changed my db user to DBO and it's working now. Hope that helps.

Excel VBA to SQL Server without SSIS

Excel problem: User clicks a button and VBA parses an input file, putting data into cells in the spreadsheet. Then she mails copies of the spreadsheet to people who do work with the data.
I am to replace this with SSRS or ASP or Sharepoint displaying the data from SQL Server.
In order to work on this without interrupting the current process, I'd like to have the Excel VBA, each time it writes a row to the spreadsheet, also insert it into the SQL Server DB via stored proc.
I can have it write the row in CSV to a file for later SSIS import, but I'd rather go direct to the DB.
I know how to do it in VB.Net but I've never written data in VBA (often read data into recordset but not written).
I'd prefer to pass the values as params to a stored proc, but I could generate the slower INSERT command for each row if I have to.
From VBA, the easiest data-access library to use is ADO. Add a reference to "Microsoft ActiveX Data Objects Library" so that you can use the ADODB.* objects.
To execute a stored proc (which in your case will add a record to a table), you could do it:
...the lazy way (creating SQL statements directly, without using Parameter objects; this is prone to SQL-injection hacks):
Public Sub AddFoo _
( _
strServer As String, _
strDatabase As String, _
strUsername As String, _
strPassword As String, _
lFooValue As Long _
)
' Build the connection string
Dim strConnectionString As String
strConnectionString = "Driver={SQL Server}" _
& ";Server=" & strServer _
& ";Database=" & strDatabase _
& ";UID=" & strUsername _
& ";PWD=" & strPassword
' Create & open the connection
Dim oConnection As Connection
Set oConnection = New Connection
oConnection.ConnectionString = strConnectionString
oConnection.Open
' Build the SQL to execute the stored procedure
Dim strSQL As String
strSQL = "EXEC AddFoo " & lFooValue
' Call the stored procedure
Dim oCommand As Command
Set oCommand = New Command
oCommand.CommandType = adCmdText
oCommand.CommandText = strSQL
oCommand.ActiveConnection = oConnection
oCommand.Execute
oConnection.Close
End Sub
...or the correct way (which deals with encoding of all parameters, and is thus not prone to SQL-injection hacks - either deliberate or accidental):
Public Sub AddFoo _
( _
strServer As String, _
strDatabase As String, _
strUsername As String, _
strPassword As String, _
lFooValue As Long _
)
' Build the connection string
Dim strConnectionString As String
strConnectionString = "Driver={SQL Server}" _
& ";Server=" & strServer _
& ";Database=" & strDatabase _
& ";UID=" & strUsername _
& ";PWD=" & strPassword
' Create & open the connection
Dim oConnection As Connection
Set oConnection = New Connection
oConnection.ConnectionString = strConnectionString
oConnection.Open
' Build the SQL to execute the stored procedure
Dim strSQL As String
strSQL = "EXEC AddFoo " & lFooValue
' Create the command object
Dim oCommand As Command
Set oCommand = New Command
oCommand.CommandType = adCmdStoredProc
oCommand.CommandText = "AddFoo"
' Create the parameter
Dim oParameter As Parameter
Set oParameter = oCommand.CreateParameter("foo", adParamInteger, adParamInput)
oParameter.Value = lFooValue
oCommand.Parameters.Add oParameter
' Execute the command
oCommand.ActiveConnection = oConnection
oCommand.Execute
oConnection.Close
End Sub
How do you read data with VBA?
If you use ADO recordsets: Have a look at the ADODB.Command class; this allows you to execute SQL or stored procedures and pass parameters to it (Google for ado command example).
If you use DAO recordsets: The Execute method of your DAO database allows you execute SQL statements.
In the long run, people are finally beginning to accept a better way: automation (not a button click) reads the file directly into the DB (SSIS), and people who need the data look at a report instead of an e-mailed Excel file.

Resources