Sql server 使用不同的凭据调用SQLCmd
背景: 我正在本地运行一个脚本,该脚本必须作为系统运行,让我们不要深入了解原因。:) 脚本试图通过一个简单的查询来检查我的MSSQL集群的运行状况。然而,我遇到的问题是本地系统帐户无法访问远程数据库。在这一点上,我已经尝试了很多事情,我会在一段时间内进入,但我诚实地为任何有意义的解决方案。如果这意味着在数据库中创建一个本地帐户来回答我的简单查询,那也没关系 到目前为止,我有以下几点:Sql server 使用不同的凭据调用SQLCmd,sql-server,powershell,Sql Server,Powershell,背景: 我正在本地运行一个脚本,该脚本必须作为系统运行,让我们不要深入了解原因。:) 脚本试图通过一个简单的查询来检查我的MSSQL集群的运行状况。然而,我遇到的问题是本地系统帐户无法访问远程数据库。在这一点上,我已经尝试了很多事情,我会在一段时间内进入,但我诚实地为任何有意义的解决方案。如果这意味着在数据库中创建一个本地帐户来回答我的简单查询,那也没关系 到目前为止,我有以下几点: $Server = 'myserver.domain.tld' $Database = 'myDatabase'
$Server = 'myserver.domain.tld'
$Database = 'myDatabase'
$Query = 'SELECT DB_NAME() AS DataBaseName'
$Username = 'myDomain\myUsername'
$Password = 'myPasswordWithPlainText'
Invoke-SQLCmd -ServerInstance $Server -Database $Database -ConnectionTimeout 300 -QueryTimeout 600 -Query $Query -Username $Username -Password $Password
结果:Invoke-Sqlcmd:Login用户'myDomain\myUsername'失败。
也许调用SQL不需要Windows身份验证,但它不使用-Credential。然后我尝试使用Invoke命令作为包装器
$Server = 'myserver.domain.tld'
$Database = 'myDatabase'
$Query = 'SELECT DB_NAME() AS DataBaseName'
$Username = 'myDomain\myUsername'
$Password = 'myPasswordWithPlainText'
$secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($Username, $secpasswd)
Invoke-Command -script {Invoke-SQLCmd -ServerInstance $Server -Database $Database -ConnectionTimeout 300 -QueryTimeout 600 -Query $Query} -Credential $Credential
这让我明白了:Invoke命令:无法使用指定的命名参数解析参数集。
所以。。我卡住了。有什么想法吗 对于这类事情,我们取得了很大的成功 不确定Powershell是否有等效的东西(可能只是使用RUNAS/NETONLY运行Powershell)。如果您正在将其构建到应用程序中,我们将使用Windows API重新启动:
另外:我使用Get-Credential,然后调用命令-AsJob从.sql文件运行脚本。e、 g
$s = 'myserver.domain.tld';
$scriptpath = 'C:\myfile.sql';
$cred = Get-Credential -credential domain\user;
$sess = New-PSSession -ComputerName $s -Credential $cred -Authentication CredSSP -Name 'S1';
$job1 = Invoke-Command -Session $sess -FilePath $scriptpath -AsJob -JobName 'J1';
# -ArgumentList $args;
Get-Job | Wait-Job;
Get-Job -Name 'J1';
Get-PSSession | Remove-Session;
Get-Job | Remove-Job;
但是请注意,$cred行将启动一个确认/验证凭据的提示-我在脚本中也有数据库名称,因此我不确定如何更改此逻辑以将脚本指向任何数据库(如果需要针对每台服务器进行自定义)。如果尚未检查用户是否有权访问数据库:-) 如果他这样做了,你就可以避开这个问题,使用.net对象——不是那么简洁,可能还有其他问题,但可以像使用连接字符串一样工作 这是未经测试的:-) 可悲的是,我尝试了所有的方法(包括马特的建议),然后又尝试了一些,但在以下参数下,我无法让它工作。 1) 脚本是从作为系统帐户运行的服务启动的。2) 系统位于SQL群集以外的单独域/子网/etc中。3) 查询必须实时运行并返回,因为查询只是较大脚本的一部分
现在,我已经认输了,创建了一个本地SQL登录名,然后使用-username和-password选项按原样调用SQL。这不是我想如何处理这种情况,而是事实。谢谢大家! 您可以尝试提交作业并传递凭据
#Submit the job with creds
$job = Start-Job {importsystemmodules; Invoke-Sqlcmd -Query 'select @@version' -ServerInstance LOCALHOST} -Credential $creds | Get-Job | Wait-Job
#Receive the job
$jobInfo = Receive-Job -Job $job
这对我来说很有效。无需远程登录即可运行SQL查询。您可以使用下面的函数并根据需要传递变量。无论哪个帐户具有访问权限,都可以作为凭据传递。(适用于Windows和SQL身份验证)
希望有帮助。我会试试看,它的一个变种听起来很有希望。谢谢。它不会立即运行,但希望它能让您有一个开始。很抱歉,我忽略了提到脚本作为服务运行,因此没有GUI可供使用。实际上,说服务运行脚本(Nagios客户端,NRPE/NSClient)更为“正确”,我想我可以将sanur与runas一起使用。@Aaron Wurthmann我最终构建了一个自定义runas,它只允许CreateProcessWithLogonW使用登录\网络凭据\而不提示输入凭据。但我们从未在生产中使用过它,因为存储密码的安全考虑。是的,我听说了。在本例中,我用于监视的帐户权限非常小,运行脚本的服务器位于内部网络和域上,而不是生产网络和域上。也许有一天我会回到这个问题上来,从.NET的角度来解决这个问题。确实您已经检查了这个问题,但是用户(mydomain\myusername)确实可以访问数据库?您可以授予计算机访问远程SQL Server的权限。无法通过GUI进行设置,但在远程计算机上,使用WINDOWS中的创建登录名[myDomain\myMachine$]添加了myDomain\myMachine$;然后从脚本中删除所有用户名、密码等内容。@Matt当然可以,因为从Shell运行时,帐户可以工作。但是,嘿,有时我们忽略的小事情又回来咬我们了。@Chad,那会很酷的。除了系统与SQL server尚不在同一域中。这不会在今天发生。我将保留此尝试。您确定您的PowerShell实例具有正确的远程权限吗?容易被忽视。在过去,它一直在折磨着我……在一个我已经可以访问的系统上工作。在不同的系统上,它只是产生了一个错误
[localhost]启动后台进程时出错。报告的错误:登录失败:未知用户名或错误密码。
Ok。这对我来说很有效,但我无法让它在scriptblock中使用变量作为参数。更新为$using:并且有效。如下所示:$query='select@@version'Start Job{importsystemmodules;调用Sqlcmd-query$using:query-ServerInstance LOCALHOST}-Credential$creds | Get Job | Wait Job这并不能完成op所寻找的任务。在此代码中提供用户名和密码时,它使用SQL身份验证。“集成”身份验证只传递用户在运行此代码时的登录身份。但是,如果您不想在PS环境中安装SQL Powershell工具并添加依赖项,那么这是一段有用的代码,因此我将在另一个项目中使用它!:)@马特。OP在他的问题中提到“如果这意味着在数据库中创建一个本地帐户,它也可以回答我的简单查询”,这意味着他可以创建sql用户ID。这就是答案
#Submit the job with creds
$job = Start-Job {importsystemmodules; Invoke-Sqlcmd -Query 'select @@version' -ServerInstance LOCALHOST} -Credential $creds | Get-Job | Wait-Job
#Receive the job
$jobInfo = Receive-Job -Job $job
$SQLInstance = "Instance Name"
$Database = "Database"
$ID = "User ID"
$Password = "Password"
function Invoke-Sqlcommand
{
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)] [string]$ServerInstance,
[Parameter(Position=1, Mandatory=$false)] [string]$Database,
[Parameter(Position=2, Mandatory=$false)] [string]$Query,
[Parameter(Position=3, Mandatory=$false)] [string]$Username,
[Parameter(Position=4, Mandatory=$false)] [string]$Password,
[Parameter(Position=5, Mandatory=$false)] [Int32]$QueryTimeout=600,
[Parameter(Position=6, Mandatory=$false)] [Int32]$ConnectionTimeout=15,
[Parameter(Position=7, Mandatory=$false)] [ValidateScript({test-path $_})] [string]$InputFile,
[Parameter(Position=8, Mandatory=$false)] [ValidateSet("DataSet", "DataTable", "DataRow")] [string]$As="DataRow"
)
if ($InputFile)
{
$filePath = $(resolve-path $InputFile).path
$Query = [System.IO.File]::ReadAllText("$filePath")
}
$conn=new-object System.Data.SqlClient.SQLConnection
if ($Username)
{ $ConnectionString = "Server={0};Database={1};User ID={2};Password={3};Trusted_Connection=False;Connect Timeout={4}" -f $ServerInstance,$Database,$Username,$Password,$ConnectionTimeout }
else
{ $ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerInstance,$Database,$ConnectionTimeout }
$conn.ConnectionString=$ConnectionString
#Following EventHandler is used for PRINT and RAISERROR T-SQL statements. Executed when -Verbose parameter specified by caller
if ($PSBoundParameters.Verbose)
{
$conn.FireInfoMessageEventOnUserErrors=$true
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] {Write-Verbose "$($_)"}
$conn.add_InfoMessage($handler)
}
$conn.Open()
$cmd=new-object system.Data.SqlClient.SqlCommand($Query,$conn)
$cmd.CommandTimeout=$QueryTimeout
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[void]$da.fill($ds)
$conn.Close()
switch ($As)
{
'DataSet' { Write-Output ($ds) }
'DataTable' { Write-Output ($ds.Tables) }
'DataRow' { Write-Output ($ds.Tables[0]) }
}
}
Invoke-Sqlcommand -ServerInstance $SQLInstance -Database $Database -Query "Query Goes here" -Username $ID -Password $Password