Getting SQL Server instance name from tcp port number - sql-server

I have a scenario, in which I am using -q option to change the collation of SQL Server Instance. The command is as follows:
sqlservr.exe -m -T4022 -T3659 -s"SQLexpress" -q"SQL_Latin1_General_CP1_CI_AI"
The above command works perfectly, where I have an instance name as ".\SQLExpress". But if I want to use the instance name using TCP port number, such as ".,52407", then how can I execute it above command, because I get the following error:
SQL Server
Your SQL Server installation is either corrupt or has been tampered with (Error: Instance name exceeds maximum length). Please uninstall then re-run setup to correct this problem
I was thinking to get the instance name from this port number to solve this issue. Is it possible to get the instance name from TCP port number through any query? Or is there any other way to execute the above command through TCP port number?

Following piece of code can handle the above situation:
If($ServerInstanceName -like "*,*")
{
Write-Host "SQL Server Instance Name containts TCP Port Number"
$SQLQuery=#"
SET NOCOUNT ON
Declare #key Varchar(100), #PortNumber varchar(100)
if charindex('\',CONVERT(varchar(200),
SERVERPROPERTY('servername')),0<>0
begin
set #key = 'SOFTWARE\MICROSOFT\Microsoft SQL Server\'+##servicename+'\MSSQLServer\Supersocketnetlib\TCP'
end
else
begin
set #key = 'SOFTWARE\MICROSOFT\MSSQLServer\MSSQLServer\Supersocketnetlib\TCP'
end
EXEC master..xp_regread #rootkey='HKEY_LOCAL_MACHINE', #key=#key,#value_name='Tcpport',#value=#PortNumber OUTPUT
SELECT CONVERT(varchar(200), SERVERPROPERTY('servername')) AS ServerName
"#
$ServerInstanceName = (Invoke-Sqlcmd -ServerInstance
$ServerInstanceName -Database 'master' -Query $SQLQuery).ServerName
Write-Host "Compatible ServerName (without TCP Port) to change its Collation:" $ServerInstanceName

Related

Querying Linked Server in Powershell

Wondering if yall can help me resolving an error I'm receiving when using Invoke-Sqlcmd to query a linked server in powershell. Thank you for any help you might be able to provide!
Here's my code
$SQLServer = "SERVER1"
$database = "Database1"
$query = "
SELECT
a.id,
a.location,
a.name,
b.office
FROM [SERVER1].[Database1].[dbo].[Table1] a
LEFT JOIN [SERVER1].[Database1].[dbo].[Table2] b ON b.id = a.id
"
Invoke-Sqlcmd -ServerInstance $SQLServer -Database $database -Query $query
Here's the error I receive:
Invoke-Sqlcmd : A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote
connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
In my experience working with powershell and SQL I've been unable to get Invoke-SQL command to work properly. I have however used this method with much success.
You can change the integrated security to true and it will use the currently logged in Windows account to authenticate with the SQL server instead of providing the credentials in the script.
#creates connection, enter the SQL server host name, the user and password.
$connectionString = “Server=#SQLServer;uid=$User2; pwd=$pwdencrypt2;Integrated Security=False;”
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
#This will be your query bulk insert as an example
[string]$queryCL1 = "
BULK INSERT [Databasename].[dbo].[tablename]
FROM 'filepath'
WITH(
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n',
FIRSTROW = 2
)"
#this uses the set variables to build and execute the command with execute reader
$command = $connection.CreateCommand()
$command.CommandText = $queryCL1
$command.CommandTimeout=0
$resultCL1 = $command.ExecuteReader()

How to drop sql server database that has not been logged in for over 30 days

I have 3 SQL Server instances running on 3 different servers. I want to be able to automatically drop any database that has not been logged in for more than 30 days.I am trying to do this in power-shell see below code:
$SQLInstances = "sql2016", "sql2014", "sql2012"
$SQLQuery = "SELECT * FROM sys.databases WHERE name not in ('tempdb','model', 'msdb', 'master','EVN') and name not like '%report%'"
foreach($sqLInstance in $SQLInstances) {
$ListOfDatabases = Invoke-Sqlcmd -ServerInstance $sqLInstance -Database "master" -Query $SQLQuery
ForEach ($Database in $ListOfDatabases ) {
Invoke-Sqlcmd -ServerInstance $sqLInstance -Database "$Database" -Query "IF (SELECT * FROM sys.dm_exec_sessions WHERE DATEDIFF(day, LOGIN_TIME , GETDATE()) > 30 )
BEGIN
DROP DATABASE $Database
END "
}
}
I'm getting stuck on how to drop the databases. The last thing I would need is to send an email with a list of databases that will be/have been dropped.
Any suggestions on how my code should be like?
The exact thing you need is mentioned in this article.
You can find the no used DB based on the number of connections and the login time.
You can schedule it as a SQL Job, so you do not need external scheduling and powershell to manage it.
There is option to send email from within Stored Procudure. You just need to configure the SMTP details for the outgoing EMail.
https://www.mssqltips.com/sqlservertip/3171/identify-sql-server-databases-that-are-no-longer-in-use/

How to use ApplicationIntent=ReadOnly inside my powershell code in SQL command

I need to use ApplicationIntent=ReadOnly with my SQL command in powershell which is connecting to a replica database. Can anyone help ?
Since replicas servers could not be accessed directly. So I need to use this command. I know how to manually do it but need help on code.
$SQLQuery = "SELECT x.SCode, x.DatabaseName FROM dbo.Logins x ORDER BY x.SCode"
$auth = #{Username = $SQLUserName; Password = $SQLAdminPassword}
try
{
$allTenants = Invoke-Sqlcmd -Query $SQLQuery -ServerInstance $SQLServerName -Database 'SShared'-QueryTimeout -0 #Auth -ErrorAction Stop
Write-Log -LogFileName $logfile -LogEntry ("Found {0} tenants" -f $allTenants.Count)
}
I am geeting the below error using this -
Exception Message A network-related or instance-specific error
occurred while establishing a connection to SQL Server
The server was not found or was not accessible. Verify that the
instance name is correct and that SQL Server is configured to allow
remote connections. (provider: Named Pipes Provider, error: 40
- Could not open a connection to SQL Server)
There's a few ways that you can do this.
Easy way
dbatools
There is a PowerShell module for interacting with SQL Server created by the SQL Server community called dbatools.
In the module, there is a function called Invoke-DbaQuery which is essentially a wrapper for Invoke-Sqlcmd.
This function has a parameter, -ReadOnly, that you can use that was created exactly for this scenario.
# Changing your $auth to a PSCredential object.
$cred = [System.Management.Automation.PSCredential]::New(
$SqlUserName,
(ConvertTo-SecureString -String $SqlAdminPassword -AsPlainText -Force))
# Splatting the parameters for read-ability.
$QueryParams = #{
Query = $SQLQuery
SqlInstance = $SQLServerName
Database = 'SShared'
QueryTimeout = 0
SqlCredential = $cred
ReadOnly = $true # <-- Specifying read-only intent.
ErrorAction = 'Stop'
}
$allTenants = Invoke-DbaQuery #QueryParams
Other way
Invoke-Sqlcmd
If you can't, won't, don't want to use dbatools, you can still use Invoke-Sqlcmd. The latest release at the time of writing, has the option to specify the parameter -ConnectionString.
You can state that it's read-only there.
# Splatting again for read-ability.
$SqlcmdParams = #{
Query = $SQLQuery
QueryTimeout = 0
ConnectionString = "Data Source=$SQLServerName;Initial Catalog=SShared;User ID=$SqlUserName;Password=$SqlAdminPassword;Integrated Security=false;ApplicationIntent=ReadOnly" # <-- Specifying read-only intent.
ErrorAction = 'Stop'
}
Invoke-Sqlcmd #SqlcmdParams

SQL Server FileTable - IP Address instead of Host name

Is there any way to configure SQL Server so that the function FileTableRootPath() returns an IP address instead of the host name?
Some of our servers are not in the domain and are accessible only by their IP address.
I think you have a few options, this should give you the IP of the SQL box:
SELECT
client_net_address = CASE WHEN client_net_address = '<local machine>'
THEN '127.0.0.1'
ELSE client_net_address
END
, local_net_address = ISNULL(local_net_address, '127.0.0.1')
, server_name = ##SERVERNAME
, machine_name = SERVERPROPERTY('MachineName')
FROM sys.dm_exec_connections
WHERE session_id = ##SPID;
or if you have xp_cmdshell enabled, you could do something like:
exec xp_cmdshell 'ipconfig'

SQLAgent job powershell step fails with "login failed for <DOMAIN>\<COMPUTER>$"

I am using a SQL Server job to get some wmiobject details into a table.
This code runs with default installation, but fails when I execute it on a named instance. So far I have seen only one difference in connection, for the named instance, SQL Agent is using with a user name which has "$" as part of the name (i.e. NT Service\SQLAgent$instance)
Is there anyway I can overcome this? Changing the agent account is not an option as most of the servers run with this account and my code needs to work with all accounts.
$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=$SqlSvr;Initial Catalog=$Database; Integrated Security=SSPI")
$conn.Open()
Executed as user: NT Service\SQLAgent$instance. A job step received
an error at line 21 in a PowerShell script. The corresponding line is
' $conn.Open() '... The error information returned by PowerShell
is: 'Exception calling "Open" with "0" argument(s): "Login failed for
user '(DOMAIN)(COMPUTER)$'." '. Process Exit Code -1.
I tried with "identity impersonate =true" but it didn't accept the command.
Any ideas?
Ether use ' instead of " or use the escape Char ` or use char(36)
"blahblah`$blahblah"
'blahblah$blahblah'
"blahblah$([char](36))blahblah"

Resources