I have upgraded a database server from SQL Server 2012 to SQL Server 2017. A SQL Server Agent Job that previously ran now fails with this error:
Unable to start execution of step 1
(reason: JobOwner DOMAIN\USERNAME doesn't have permissions to use proxy 4 for subsystem PowerShell).
The step failed.
This job ran before the upgrade, so I'm confused why permissions would have changed. But no matter, I grant permissions with this script:
USE msdb
GO
EXEC dbo.sp_grant_login_to_proxy
#login_name = N'DOMAIN\USERNAME',
#proxy_id = 6
GO
Which then reminds me that the user in question is an admin, and can be neither granted nor denied anything:
'DOMAIN\USERNAME' is a member of sysadmin server role and cannot be granted to or revoked from the proxy. Members of sysadmin server role are allowed to use any proxy.
So what am I missing? How can I fix this, or where should I look to determine what the underlying problem is?
I ended up creating the proxy under a new name, then reassigning all the jobs over to the new proxy.
Here are the steps I used:
Right click on the existing proxy, and do script as>create.
Modify the resulting creation script by changing the name to "BROKEN PROXY NAME - TEMP", and run it.
At this point, I have the old broken proxy, and a new copy of it, with a TEMP suffix in the name.
Use the script below to generate a script that will assign all jobs from the old proxy to the new one using the script below. Run the SELECT, copy the "Sql to change proxy" column, and run that series of EXEC statements.
Delete the old proxy
Rename the new proxy to have the old name
declare #broken_proxy_name nvarchar(100) = 'BROKEN PROXY NAME'
declare #temporary_proxy_name nvarchar(100) = #broken_proxy_name + ' - TEMP'
SELECT
sj.[name] as jobname
,sjs.proxy_id
,spx.[name] as "Proxy name"
,'EXEC msdb.dbo.sp_update_jobstep #job_id=N'' + convert(nvarchar(36),sj.job_id) + '', #step_id=' + convert(nvarchar(10),sjs.step_id) + ',#proxy_name=N''' + #temporary_proxy_name + '''--' + sj.[name] as "Sql to change proxy"
,'EXEC sp_start_job N'' + replace(sj.[name],'''','''''') + ''' as "Sql to run the job"
,sjs.*
FROM
msdb.dbo.sysjobs sj
join msdb.dbo.sysjobsteps sjs on sjs.job_id = sj.job_id
join msdb.dbo.sysproxies spx on spx.proxy_id = sjs.proxy_id
where spx.[name] = #broken_proxy_name
and sj.[enabled] = 1
Related
We extensively use the OPENROWSET function to import .CSV and Excel files into our SQL Server 2012 environment, using MSDASQL or ACE:
SELECT *
FROM OPENROWSET ('MSDASQL',
'DRIVER={MICROSOFT access TEXT DRIVER (*.TXT, *.CSV)};',
'SELECT * FROM E:\INCOMING\REPORT_EXTRACT.CSV')
Or using ACE:
SELECT * FROM OPENROWSET('MICROSOFT.ACE.OLEDB.12.0','TEXT;DATABASE=E:\INCOMING\;HDR=YES;', 'SELECT * FROM [REPORT_EXTRACT.CSV]');
We're experiencing the classic error message:
Msg 7415, Level 16, State 1, Line 1
Ad hoc access to OLE DB provider 'MSDASQL' has been denied. You must access this provider through a linked server.
The ONLY workaround to enable this, is granting said user(s) with the SYSADMIN role - obviously not ideal.
The location of the file(s) is on the server itself, for which the users accessing DO have the necessary permissions to access that file folder. The SQL Server service is running under the local system account with permission to interact with the desktop.
We've tried the following workarounds/fixes to no avail:
1 Executed the following code:
EXEC master . dbo. sp_MSset_oledb_prop N’Microsoft.ACE.OLEDB.12.0′ , N’AllowInProcess’ , 1
GO
EXEC master . dbo. sp_MSset_oledb_prop N’Microsoft.ACE.OLEDB.12.0′ , N’DynamicParameters’ , 1
GO
*2 The DisAllowAdHocAccess registry fix:
This is the current state:
3 Adding the ADMINISTER BULK OPERATIONS permission to the said users
We have dozens of expressions and files within our procedures that use OPENROWSET, therefore BULK INSERT, building SSIS packages, leverage Excel files as linked servers are NOT feasible options.
Any suggestions?
Wow - After YEARS of troubleshooting, I finally figured out what it was!
The registry entry value that controls the Allowing of Ad-hoc access, relies on the DisallowAdHocAccess being in that EXACT sentence case.
In our case, the "A" in AdHoc was not capitalized:
To fix this, I:
Deleted the registry value as described
Re-enabled the Disallow AdHoc Access option (Which re-created the registry value)
Manually set the Registry DisallowAdHocAccess value to "0"
Problem solved!
I need to run SSIS2016 package from older SSIS (another server) because of extending legacy system. The package runs fine from SQL Agent, but I am unable to run it using tsql or DTEXEC. The problem is that package is unable to access network even when run in elevated cmd (under sysadmin)
I am able to access network drive from account I am running package (admin)
I know that package runs fine when it is run from Sql agent under same account.
The package runs fine when file is saved to local temp folder (both DTEXEC and TSQL)
The package fails to save file to network when run using execute is SSMS, TSQL or DTEXEC.
DTEXEC /ISSERVER "\SSISDB\XXXX\Exports\package.dtsx" /SERVER "." /Par
"$Package::FilePath(String)";"C:\TEMP"
From all what I have read on internet, it seems that the only way to run SSIS2016 package is by using SQL Agent and jobs.
I am surprised by the fact that DTEXEC ignores the security context of account which execute the command line.
Is there a way to force it to use proxy account?
I find it hard to believe, that only way to run package with permission to network is to use Sql agent and jobs.
Thank you.
p.s. Here is good article about running packages, but it completely omits network access problem.
EDIT 2019-06-10
I applied MSSQL2016 CU7 and restarted the server.
After this,
Iam able to save file to network using DTEXEC command ran on local server (logged as sysadmin)
Iam able to save file to network using sp ran from local server (logged as sysadmin)
I cant save file to network drive when logged as sysadmin on different machine. The error is
Flat File Destination failed the pre-execute phase and returned error
code 0xC020200E.
Cannot open the datafile ..
there is also warning "Access is denied" in data flow which should save the file.
Source code of stored procedure
DECLARE #execution_id BIGINT;
EXEC [SSISDB].[catalog].[create_execution]
#package_name = N'package.dtsx',
#execution_id = #execution_id OUTPUT,
#folder_name = N'XXXX',
#project_name = N'Exports',
#use32bitruntime = False,
#reference_id = NULL;
SELECT #execution_id;
DECLARE #var0 SQL_VARIANT = N'\\NETWORK\PATH\Export\test_files';
EXEC [SSISDB].[catalog].[set_execution_parameter_value]
#execution_id,
#object_type = 30,
#parameter_name = N'FilePath',
#parameter_value = #var0;
DECLARE #var1 SMALLINT = 1;
EXEC [SSISDB].[catalog].[set_execution_parameter_value]
#execution_id,
#object_type = 50,
#parameter_name = N'LOGGING_LEVEL',
#parameter_value = #var1;
EXEC [SSISDB].[catalog].[start_execution]
#execution_id;
I also added System::UserName to log on start of package and I see correct account.
I assume, that problem might be in double hop as #Piotr mentions.
Iam digging the fileserver logs to see.
EDIT2 2019-06-10
Ok. After much dancing around I can narrow problem down to delegation executing user rights to CIFS.
What i did
Setup a share on dev computer
Create package with scriptask which tries to create test file and get security context of calling user WindowsIdentity.GetCurrent().Name
Then I ran stored procedure with code above in scenario that always ended by access denied.
Until I enabled anonymous access (using this article), the package was not able to save file.
AFAIK we have enabled only MSSQLSvc kerberos delegation.
Closure:
The problem is caused by behaviour of SSIS catalog, when called from TSQL, which gets users security context, but in order to work this properly, when accessing netwrok shares, you need to setup Kerberos delegation for CIFS also.
I was not able to do this in our environment, so I reverted back to xp_cmdshell.
Thanks to all for support.
I am trying to use liquibase to add members to a role, but the SQL is different from SQL Server 2008 to 2012.
SQL Server 2008:
exec sp_addrolemember db_datareader, MYUSER
SQL Server 2012:
ALTER ROLE db_datawriter ADD MEMBER MYUSER
The following SQL when run via liquibase against SQL Server 2012 works correctly, but when ran against SQL Server 2008 it fails and says:
Incorrect syntax near the keyword 'ADD'
Code:
DECLARE #ver nvarchar(50),
#intVer int,
#ver2008 int = 10
SET #ver = CAST(serverproperty('ProductVersion') AS nvarchar)
SET #intVer = CAST(SUBSTRING(#ver, 1, CHARINDEX('.', #ver) - 1) AS int)
IF (#intVer = #ver2008)
exec sp_addrolemember db_datawriter, MYUSER
ELSE
ALTER ROLE db_datawriter ADD MEMBER MYUSER;
I tried separating the versions, putting SQL Server 2008 in one file and 2012 in another and using a 'precondition' at the top of the changelog (outside of a changeset). But there are only 2 OnFail options, HALT, which stops the entire update, or WARN, which just continues the script, both of which do not give me what I need.
I need to be able for the script to figure out which version of SQL Server it is working with and only run that particular liquibase script, whether it be a changeset or changelog.
The compilation of the entire batch will fail if the syntax is unrecognized. You can work around the issue by wrapping the statements in EXECUTE or by using sp_executesql.
IF (#intVer = #ver2008)
EXECUTE(N'exec sp_addrolemember db_datawriter, MYUSER;')
ELSE
EXECUTE(N'ALTER ROLE db_datawriter ADD MEMBER MYUSER;');
I have two Windows Server 2012 R2 servers in a workgroup, on the first one I have MS SQL Server, the other is used (among other things) as a storage for backups. On the database server both the SQL Server Database Engine and SQL Server Agent run with default virtual accounts - NT Service\MSSQLSERVER and NT Service\SQLSERVERAGENT.
Now, I want to use Ola Hallengren maintenance jobs to backup my MS SQL Server databases. These scripts are wrapped into a SQL Server Agent job but the backup is a t-sql procedure thus executed by the SQL Server Database Engine with NT Service\MSSQLSERVER.
I've created an account on the storage server and a shared folder with access permissions for this account. I'm able to connect the share on the database server with a net use command providing credentials for the created account.
There's a catch: the share is connected for an account which runs the net use command.
If I connect the share with Local System account (which supposed to be for all users) then still NT Service\MSSQLSERVER cannot access it, neither any other account can. Seems like the hack previously proposed on stackoverflow is fixed in Windows Server 2012 R2.
And if I run the net use command as a step in SQL Server Agent job, then it is done with the other virtual account - NT Service\SQLSERVERAGENT - and the backup step fails with "folder not found" error.
So I would like to know a way to create a Windows service account with all the necessary permissions for the SQL Server Database Engine service to be used in a workgroup environment. Or an explanation why it cannot be done.
Ideally it should be a script - Powershell or VBScript.
I tried to run both SQL Server Dabase Engine and SQL Server Agent as Local System and the backup worked like a charm. But I would not consider this as a solution because it's not recommended from a security perspective.
Also I would not consider a solution to run the net use command with xp_cmdshell due to the same security reasons.
Okay, the correct way to get it done is to do the following:
Create a user account on both servers with exactly the same name. This can be done if the user is named .\UserName rather than ServerName\UserName.
Once it is done, you need to sniff permissions of a virtual service account NT Service\MSSQLSERVER. And this can be done with the use of SubInACL utility. This tool is created by Microsoft exactly for the purpose and can be downloaded from official Microsoft Download Center. Or you can skip sniffing the actual permissions and proceed to the next point.
All of the permissions described in the knowledge base article https://msdn.microsoft.com/en-us/library/ms143504.aspx can be set in place for the newly created account with the same SubInACL tool. There are several articles across the Internet on how to use the tool, I used this one - https://redmondmag.com/articles/2008/03/01/dive-deep-with-subinacl.aspx
The last steps will be: launch SQL Server service under the newly created user account and provide access to the shared folder on the other server.
Probably this should go to superuser.com
Will it be possible to use an SSISpackage to do the following:
Create and script via tsql with the login-details,etc. and export it to a script file on disk.
Run the run the script.
Delete the script file again.
Example:
https://www.simple-talk.com/sql/ssis/adding-the-script-task-to-your-ssis-packages/
To create batch file using T-sql:
--Set first day of Week to Monday
--Value First day of the week is
--1 Monday
--2 Tuesday
--3 Wednesday
--4 Thursday
--5 Friday
--6 Saturday
--7 (default, U.S. English) Sunday
SET DATEFIRST 1
Declare #CmdSource varchar(100),
#CmdDestination varchar(100),
#Year varchar(4),
#Week varchar (2),
#Difference int
Set #Difference = 0
Set #Year = Convert(varchar(4), DatePart(Year, GetDate()-#Difference))
Set #Week = Convert(varchar(2), DatePart(week, GetDate()-#Difference))
If #Year = '2010'
BEGIN
Set #Week = #Week - 1
END
SELECT #Week =
CASE Len(#Week)
WHEN 1
THEN '0' + #Week
else #Week
END
Set #CmdSource = 'XCopy "<sourcepath>' + #Year + '\extras text' + #Year + #Week + '.bak" '
Set #CmdDestination = '"<Destination path>" /Y'
SELECT #CmdSource + #CmdDestination as Batchfile
We opted for creating the file at a set time. We then setup a separate windows scheduled task to run independently from SQL at a set time after the creation. Running with SSIS at that time 2010 was unpredictable. There is only one very long destination column (length 200, up to you how long.)
IMHO, your best bet still is to run net use \\remotehost\folder password /user:remotehost\username in xp_cmdshell.
You only need to run it once and then can close off xp_cmdshell again if you don't like it; it's not like changing that option requires a reboot =)
For that I'd suggest to put this into 'startup' procedure. You can even add WITH RECOMPILE if you're afraid someone will sp_helptext it to find the pwd of that login. Then again, people might freak out when finding a startup proc that's encrypted =)
USE master
GO
CREATE PROCEDURE sp_net_use_that_other_server
AS
-- To allow advanced options to be changed.
EXEC sp_configure 'show advanced options', 1;
-- To update the currently configured value for advanced options.
RECONFIGURE;
-- To enable the feature.
EXEC sp_configure 'xp_cmdshell', 1;
-- To update the currently configured value for this feature.
RECONFIGURE;
-- you might want to fetch this dynamically from the database somewhere, or simply leave it hardcoded here...
EXEC master..xp_cmdshell 'net use \\remotehost\folder password /user:remotehost\username'
-- To disable the feature.
EXEC sp_configure 'xp_cmdshell', 0;
-- To update the currently configured value for this feature.
RECONFIGURE;
Return
GO
-- set this up as a startup procedure
EXEC sp_procoption #ProcName = 'sp_net_use_that_other_server'
, #OptionName = 'startup'
, #OptionValue = 'on';
GO
After that, the database engine should be able to BACKUP DATABASE... to that share.
I create a database using ADO.NET SQL queries like this:
create database mydatabase
create login 'loginname' with password='somepassword'
create user 'username' for login loginname
The queries aren't exact, I've typed them as far as I could remember them.
After that I don't see the database in my ms sql server 2008 r2 express management studio.
I also can't log in with the newly created login. The "enable server authentication" is set to true.
What should I do to see that database in the manager?
Why can't I log in with newly created login? I've looked into the logs and it says that the password is incorrect.
I do have 2 sql express instances, but I use the same one when I run my sql
select ##servername when run in management studio returns "BOGDAN".
ADO.NET query returns "BOGDAN\BBF17ECB-69FF-4B" . Code is below:
SqlConnection con = new SqlConnection("Data Source=BOGDAN;Integrated Security=True;User Instance=True");
SqlCommand cmd = new SqlCommand("select ##servername", con);
con.Open();
string s = (string)cmd.ExecuteScalar();
Console.WriteLine("Server name:" + s);
con.Close();
Console.ReadKey(false);
Don't know where BBF17ECB-69FF-4B came from, I explicitly stated server name as "BOGDAN".
the script is:
IF DB_ID('MyDatabase') IS NULL CREATE DATABASE [MyDatabase]
USE MyDatabase
IF NOT EXISTS(SELECT * FROM master.dbo.syslogins WHERE loginname = 'AUsername') CREATE LOGIN AUsername WITH PASSWORD='APassword'
IF NOT EXISTS (SELECT * FROM sys.sysusers WHERE name='AUsername') CREATE USER AUsername FOR LOGIN AUsername
EXEC sp_addrolemember N'db_owner', N'AUsername'
Do you have multiple instances of Sql Server on your box? Maybe an express install, and a developer edition install? It's possible you were pointed at the other instance when you created the db...I have done this before.
Are you sure that the database creation completed without error? Maybe it failed, and the db was never created.
Unfortunately, the details of the query that you would have run are where we would find the evidence for the problem.
The problem was with the connection string: I had to remove "User Instance=true" from it. That fixed the problem!
I thought the problem was with how I configurated the servers or with the SQL requests.