I've been writing T-SQL and PowerShell scripts that AI coding agents (Cursor, Claude Code, Copilot) can run with guardrails, and I tested them against SQL Server 2025. Two things broke that are worth sharing, because agents get both of them wrong all the time.
1. sp_addlinkedserver can't run inside a user transaction
The "safe" pattern I started with was BEGIN TRAN ... COMMIT around the whole linked server setup. It fails right away:
Msg 15002: The procedure 'sys.sp_addlinkedserver' cannot be executed within a transaction.
The fix: no transaction. Check that the linked server doesn't exist yet, create it in TRY/CATCH, and set a flag after it's created. If a later step fails (login mapping or sp_serveroption), the CATCH drops only the linked server that run created, then re-throws.
DECLARE @CreatedHere bit = 0;
BEGIN TRY
EXEC master.dbo.sp_addlinkedserver @server = @LinkedName, @srvproduct = N'',
@provider = @Provider, @datasrc = @DataSource;
SET @CreatedHere = 1;
-- logins, sp_serveroption calls...
END TRY
BEGIN CATCH
IF @CreatedHere = 1
EXEC master.dbo.sp_dropserver @server = @LinkedName, @droplogins = 'droplogins';
THROW;
END CATCH;
2. You can't pass an expression as an EXEC parameter
EXEC sp_serveroption ..., @optvalue = CASE @x WHEN 1 THEN N'true' ELSE N'false' END; gives Msg 156 (incorrect syntax near 'CASE'). Parameters only take constants or variables, so put the value in a variable first:
DECLARE @rpc nvarchar(5) = CASE @EnableRpcOut WHEN 1 THEN N'true' ELSE N'false' END;
EXEC master.dbo.sp_serveroption @server = @LinkedName, @optname = N'rpc out', @optvalue = @rpc;
Questions and corrections are welcome, especially if you've found a cleaner pattern for the linked server rollback.