Using Environment variables in T-SQL - sql

How can I read the value of a system environment variable in a T-SQL script?
This is to run on SQL Server 2005.

To "read the value of a system environment variable in a T-SQL script" you can set SQL Management Studio to use "sqlcmd Mode".
Then you can use like this:
Print '$(TEMP)'
:r $(Temp)\Member.sql
go
I'm not sure how this is done outside of "SQL Management Studio" but it should be hard to find out.

This should give you a list (provided you allow people to execute xp_cmdshell)
exec master..xp_cmdshell 'set'
Note: xp_cmdshell is a security hazard ...
You could also do this with a managed stored proc an extended stored proc or via a com component.

Hey, if you want to get the server name, just call SELECT ##SERVERNAME

xp_cmdshell is generally best avoided for security reasons.
You're better off using a CLR assembly. Here's a good introduction to creating a CLR assembly.
You can use System.Environment.GetEnvironmentVariable() in C# - you'll find more info on how to do that here.

Thanks for the answers.
They helped me get to a working solution, although this is probably not the most advanced method:
declare #val varchar(50)
create table #tbl (h varchar(50))
insert into #tbl exec master..xp_cmdshell 'echo %computername%'
set #val = (select top 1 h from #tbl)
drop table #tbl
Specifically I was trying to get the hostname, the echo %computername% could be replaced with the hostname system command. But this now works for any environment variable.

To determine a specific environment variable in T-SQL (MS SQL Server) you can do something like:
Grant Security Permissions
use [master]
execute sp_configure 'show advanced options', 1
reconfigure
go
execute sp_configure 'xp_cmdshell', 1
reconfigure
go
grant execute on xp_cmdshell to [DOMAIN\UserName]
grant control server to [DOMAIN\UserName]
go
Source: https://stackoverflow.com/a/13605864/601990
Use Environment Variables
-- name of the variable
declare #variableName nvarchar(50) = N'ASPNETCORE_ENVIRONMENT'
-- declare variables to store the result
declare #environment nvarchar(50)
declare #table table (value nvarchar(50))
-- get the environment variables by executing a command on the command shell
declare #command nvarchar(60) = N'echo %' + #variableName + N'%';
insert into #table exec master..xp_cmdshell #command;
set #environment = (select top 1 value from #table);
-- do something with the result
if #environment = N'Development' OR #environment = N'Staging'
begin
select N'test code'
end
else
begin
select N'prod code'
end
Also remember to restart the SQL Server Service when changing the Environment Variables.

Related

Using xp_cmpshell with variable in SQL Server

I want to use xp_cmdshell to ping servers. I created a procedure but I have a little problem, I need to select the server IP from table that is already created.
I created a cursor to get the server IP from the table but I don't know how to use the #ip varchar variable with ping command.
This syntax didn't work:
execute xp_cmdshell 'ping #ip'
You cannot reference parameters directly within xp_cmdshell, so you have to concatenate the value when creating the command. I recommend reading: https://msdn.microsoft.com/en-us/library/ms175046.aspx
In your example, you would do something like:
DECLARE #cmd nvarchar(4000);
SET #cmd = 'ping ' + #ip;
EXEC xp_cmdshell #cmd;

Finding and Reading a XML file using MS SQL

I have an SQL script which I want to run on multiple databases. The script runs a couple of update and insert statements and I also want to open and parse an xml file on different paths.
The issue I have is that I know where the file I want to open is (the directory) but I don't know its name (the name is random) but the extension is always .profile (which is a xml file) and there is only one file in each directory.
I wonder how I can open a XML/profile file without knowing its exact name using MS SQL.
As far as I understand your question correctly:
declare #files table (ID int IDENTITY, fileName varchar(max))
insert into #files execute xp_cmdshell 'dir <yourdirectoryhere>\*.profile /b'
declare #fileName varchar(max)
select top 1 #fineName = fileName * from #files
does what you want but is based on calling xp_cmdshell and it's usually a very bad idea to use it.
Try something along the lines of this:
DECLARE #output NVARCHAR(MAX)
CREATE TABLE #OUTPUT
(
OUTPUT VARCHAR(255) NULL
)
INSERT #OUTPUT
EXEC #output = XP_CMDSHELL
'DIR "C:\temp\*.profile" /B '
SELECT *
FROM #OUTPUT
DROP TABLE #OUTPUT
As explained here (and that's just one way), you can access disk contents from SQL Server, provided your permissions are working fine.
IIRC, the following options need to be enabled. However, you need them anyway to access files from SQL Server.
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
GO

One-line alternative for xp_cmdshell? I tried several things

Hello Microsoft SQL Server Masters,
Well, I have an Microsoft SQL Server 2000 as described below:
Microsoft SQL Server 2000 - 8.00.2039 (Intel X86)
May 3 2005 23:18:38
Copyright (c) 1988-2003 Microsoft Corporation
Desktop Engine on Windows NT 5.2 (Build 3790: Service Pack 2)
I need to execute an Operating System command from this Microsoft SQL Server, I checked that I have sysadmin privileges with the query below and it returned "1", which confirm my privilege.
SELECT IS_SRVROLEMEMBER('sysadmin', 'sa');
I tried the traditional xp_cmdshell and nothing happened, just to make sure it was working I tried the famous:
EXEC xp_cmdshell 'dir c:\'; EXEC master.dbo.xp_cmdshell 'dir c:\';
EXEC master..xp_cmdshell "dir c:\";
And all returned NOTHING, which make me believe that xp_cmdshell is not available. I know that xp_cmdshell comes disable by default in Microsoft SQL Server 2005, but not in 2000, anyway, I tried to reenable it on the same way but it failed.
I looked at internet and I found this way to reenable xp_cmdshell for Microsoft SQL Server 2000:
exec sp_addextendedproc 'xp_cmdshell', 'xplog70.dll'
exec sp_addextendedproc xp_cmdshell, 'C:\Program Files\Microsoft SQL Server\MSSQL\Binn\xplog70.dll'
However, it still doesn't work. I found another article telling that sometimes admins delete this files and I think it may be my case, the article says that if it was deleted I can execute "xp_msver" and in my case it also return nothing.
Reference: http://support.microsoft.com/kb/891984
I also tried this query that I found on the internet to see if xp_cmdshell exist and it returned nothing (but it may be a limitation of my weird SQL client, see below please).
if exists (select * from dbo.sysobjects where id = object_id(N’[dbo].[ xp_cmdshell]‘) and OBJECTPROPERTY(id, N’IsExtendedProc’) = 1);
So, I'm really in trouble, I researched at Google and found potential solutions such as Job agent, SSIS package, CLR stored procedure, sp_OACreate (and friends) and SQLCMD but nothing worked. Maybe I did it incorrect, but another limitation in my case is that I just have access to this Microsoft SQL Server 2000 from a jump-box (Linux) that has a very odd sql-server client that do not accept queries with multiple lines, consequently I can't try with success the following potential solutions:
1# Job Agent
DECLARE #jobID uniqueidentifier, #cmd varchar(1000)
SET #cmd = 'netstat -na > c:\connections.txt'
EXEC msdb.dbo.sp_add_job #job_name = '_tmp_MakeDirectory', #enabled = 1, #start_step_id = 1, #owner_login_name='sa', #job_id = #jobID OUTPUT
EXEC msdb.dbo.sp_add_jobstep #job_id = #jobID, #step_name = 'Create Backup Folder', #step_id = 1, #subsystem = 'CMDEXEC', #command = #cmd
EXEC msdb.dbo.sp_add_jobserver #job_id = #jobID
EXEC msdb.dbo.sp_start_job #job_id = #jobID, #output_flag = 0
WAITFOR DELAY '000:00:05' -- Give the job a chance to complete
IF EXISTS (SELECT name FROM msdb.dbo.sysjobs WHERE name = '_tmp_MakeDirectory')
BEGIN
EXEC msdb.dbo.sp_delete_job #job_name = '_tmp_MakeDirectory'
END
2# SQLCMD
CREATE PROCEDURE SQLCMD_TEST
AS
!!MKDIR "netstat -na > c:\connections.txt"
:OUT "C:\TEST\test.TXT"
SELECT ##VERSION AS 'SERVER VERSION'
!!DIR
GO
SELECT ##SERVERNAME AS 'SERVER NAME'
GO
EXEC SQLCMD_TEST
Unfortunately I don't have any other way to access this Microsoft SQL Server, I know it's not the best way, but it's how it's and I can't do anything. So, I need a solution to execute Operating System commands on this Microsoft SQL Server 2000 with all this limitations. Can someone port any of the two above methods for one single line query, please?
Any other suggestion with example is very welcome.
Thanks a lot.
Regards.
I used to use xp_cmdshell before CLR support came along. Unfortunately, you are a version away from CLR support (SQL Server 2005) and the system.io namespace. You can, however, create your own extended stored procedures which can access the file system and create directories. See here for more info: http://www.devarticles.com/c/a/SQL-Server/Extended-Stored-Procedures-Intro-And-10-Cool-Examples/
By the way, xp_cmdshell is an extended stored procedure.

Which user account is running SQLCMD in T-SQL Script without -U and -P option?

I am using sqlcmd in a T-SQl script to write a text file to a network location. However SQLCMD is failing to write to that location due to access permission to the network folder. SP is being run under my user account which has access to the network folder.
Could you please help me under which account sqlcmd will run if I do not specify -U and -P option in TSQL Script?
Use this to find the user name:
PRINT Suser_Sname();
If you don't provide credentials with -u/-p it will try to use windows authentication; i.e the windows account of whomever is running it.
I often just use Process Monitor to look at what account is being used and what the permission error is.
You say you are using SQLCMD in a T-SQL script, don't you mean you are using SQLCMD to run a T-SQL script? How is your script writing a text file? Does it work in SQL Manager? My guess is that the user account SQL Server is running under doesn't have access to that location.
If you call an SQL script via xp_cmdshell without User and Password parameters it will run in the environment of the mssqlserver service, which is very much restricted, and without changing security parameters you will get mostly an 'Access is denied' message instead of the results of the script.
To avoid this security conflict situation I use the following trick in my stored procedure create_sql_proc. I read the text of the script file, and wrap it in a procedure by adding a head and a foot to it. Now I have a script creating a stored procedure from the SQL-file called #procname.
If you let now run this stored procedure by EXEC #procname, it will run in your security environment, and delivers the result you would get by running it from a command prompt:
CREATE PROCEDURE create_sql_proc(#procName sysname, #sqlfile sysname) AS
BEGIN
DECLARE #crlf nvarchar(2) = char(10)+char(13)
DECLARE #scriptText nvarchar(max)
DECLARE #cmd nvarchar(max)
= N'SET #text = (SELECT * FROM openrowset(BULK '''+#sqlFile+''', SINGLE_CLOB) as script)'
EXEC sp_executesql #cmd , N'#text nvarchar(max) output', #text = #scriptText OUTPUT
DECLARE #ProcHead nvarchar(max) = N'CREATE or ALTER PROCEDURE '+#procName+ ' AS '+#crlf+'BEGIN'+#crlf
DECLARE #ProcTail nvarchar(max) = #crlf + N'END '
SET #scriptText = #ProcHead + #scriptText + #ProcTail
-- create TestGen stored procedure --
EXEC sys.sp_executesql #scriptText
END

SQL Script to take a Microsoft Sql database online or offline?

If I wish to take an MS Sql 2008 offline or online, I need to use the GUI -> DB-Tasks-Take Online or Take Offline.
Can this be done with some sql script?
ALTER DATABASE database-name SET OFFLINE
If you run the ALTER DATABASE command whilst users or processes are connected, but you do not wish the command to be blocked, you can execute the statement with the NO_WAIT option. This causes the command to fail with an error.
ALTER DATABASE database-name SET OFFLINE WITH NO_WAIT
Corresponding online:
ALTER DATABASE database-name SET ONLINE
-- Take all user databases offline
CREATE PROCEDURE SP_TakeOfflineAllDatabase AS
BEGIN
DECLARE #db sysname, #q varchar(max);
DECLARE cur_db CURSOR FOR
SELECT name FROM sys.databases WHERE owner_sid<>0x01;
OPEN cur_db;
WHILE 1=1
BEGIN
FETCH NEXT FROM cur_db INTO #db;
IF ##FETCH_STATUS <> 0
BREAK;
SET #q = N'ALTER DATABASE [' + #db + N'] SET OFFLINE WITH NO_WAIT';
EXEC(#q);
END;
CLOSE cur_db;
DEALLOCATE cur_db;
END;
Restart the server before run the procedure. It will close the existed connections to the databases.
I know this is an old post but, just in case someone comes across this solution and would prefer a non cursor method which does not execute but returns the scripts.
I have just taken the previous solution and converted it into a select that builds based on results.
DECLARE #SQL VARCHAR(8000)
SELECT #SQL=COALESCE(#SQL,'')+'ALTER DATABASE '+name+ N' SET OFFLINE WITH NO_WAIT;
'
FROM sys.databases
WHERE owner_sid<>0x01
PRINT #SQL
Here's a note that just might be very usefull to you :
It's almost always possible to see what the GUI is doing TSQLwise behind the scenes.
c : http://www.mssqltips.com/tip.asp?tip=1505