私は、ドメイン内で実行されているSQL Serverのすべてのインスタンスを発見する任務を負っています。サーバーごとに複数のインスタンスがある場合があります。これらのインスタンスを検出するための2つの異なるPowerShellメソッドを確認しましたが、どちらもすべてのインスタンスを検出するようには見えません。
1)WMIを使用する
$srvr = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer $computerName
$instances = $srvr | ForEach-Object {$_.ServerInstances} | Select @{Name="fullName";Expression={$computerName +"\"+ $_.Name}}
return $instances
2)リモートレジストリを使用する(Get-SQLInstance 1 と同様)
私が遭遇している最大の問題は、私が知っているすべてのサーバーがSQL Server WMIプロバイダーで実行されているわけではなく、リモートレジストリを許可しているサーバーもすべてないということです。 3番目の方法はありますか?リモートデスクトップを使用してすべてのサーバーにアクセスできますが、約30台のマシンを調べており、可能であれば手動での手順を避けたいと考えています。これはSQL Server 2008以降でのみ機能する必要があり、他のSQL Serverサービス(SSIS/SSAS/SSRS)について知っておくと便利ですが、私の主な焦点はSQL Server自体です。
将来的に役立つ何かが必要な場合は、レジストリを検索することを避けます。 SQL Serverのじんましんは、長年の間に少し変わっており、それに追いつくのは面倒な場合があります。
SqlDataSourceEnumerator
を使用した方法は不安定な場合がありますが、使用しますが、インスタンスがネットワーク上にあるという具体的な証拠はありません。 SQLブラウザサービスにも依存していると思います。ほとんどの場合、無効になっています。
WMIクラスwin32_Service
を使用します。 Get-Service
コマンドレットよりもサービスに関する詳細情報を提供するため、これを使用します。
トラブルシューティングのためにサービスの毎日のチェックや検証を実際に行うためにこれを使用できるため、すべてを関数として一般的に記述します。
function Get-ServiceStatus ([string[]]$server)
{
foreach ($s in $server)
{
if(Test-Connection $s -Count 2 -Quiet)
{
Get-WmiObject win32_Service -Computer $s |
where {$_.DisplayName -match "SQL Server"} |
select SystemName, DisplayName, Name, State, Status, StartMode, StartName
}
}
}
これは、私が通常使用するものより少し多いですが、誰かがそれに遭遇してそれを使用したい場合に備えて。 Test-Connection
はDOSプロンプトのping myserver
に相当し、-Quiet
フラグは単にtrue
またはfalse
を返します。これはデフォルトで4つのpingになるため、-Count 2
を設定すると、代わりに2回実行されます。
変数[string[]]$server
は、$server
がサーバー名の配列を受け入れることを示すために使用されるメソッドです。したがって、この関数の呼び出し例は次のようになります。
Get-ServiceStatus -server (Get-Content C:\temp\MyServerList.txt)
または
$servers = 'MyServer1','MyServer2','MyServer3'
Get-ServiceStatus -server $servers
[〜#〜]編集[〜#〜]
上記のコメントは、提供されているサーバーのリストに依存することに注意してください。そのリストが提供されていない場合は、他にいくつかのオプションがあります。
Active Directory環境にいる場合は、PowerShellで ActiveDirectory モジュールを使用して、Get-ADComputer
コマンドレットでドメイン上のすべてのサーバーのリストをプルできます。ただし、大規模なドメインでは適切な-Filter
を使用してください。
また、ポート1433が開いていることが判明したIPアドレスを提供するネットワークのIPスキャンを(承認付きで)単純に実行しました。そのIPリストを取得し、Get-ADComputer
を使用してドメインコンピュータ名を見つけ、それを上記の関数に渡します
例:
Import-Module ActiveDirectory
$sList = $ipList | Select -ExpandProperty IP
$results = foreach ($i in $sList) {
Get-ADComputer -Filter 'IPv4Address -eq $i' -Properties * | Select Name}
Get-ServiceStatus -server $results
[〜#〜]編集[〜#〜]
Write-Verbose
を利用し、try/catchブロックを追加することをお勧めしますが、これは便利な場合があります。ほとんどの場合、コードの練習では、この関数を使用して追加する人に任せます。追加のコードまたは機能。続行するための基本的な例を提供しようとしています。実際のサーバー名を返す情報を含めるためにSystemName
プロパティを出力に追加しましたが、他の関数でこれを行うと、通常、一度に複数のサーバーでこれを使用しないため、気になりませんでした。
可能性のあるすべての所有サーバーとその特定の名前を知らなくても、環境全体でインスタンスを検出する唯一の方法は、 System.Data.Sql.SqlDataSourceEnumerator.GetDataSources() を呼び出すことです。 =ただし、このメソッドには多数の脚注が付属しています。以下は、そのMSDNリソースから直接プルされたスニペットです。
SqlDataSourceEnumeratorがネットワーク上のデータソースを見つけるために使用するメカニズムの性質上、このメソッドは常にa利用可能なサーバーの完全なリスト。リストはすべての呼び出しで同じであるとは限りません。この関数を使用してユーザーがリストからサーバーを選択できるようにする場合は、サーバーの列挙で使用可能なすべてのサーバーが返されない場合に備えて、リストにない名前を入力するオプションも必ず指定してください。さらに、このメソッドの実行にはかなりの時間がかかる場合があるため、パフォーマンスが重要な場合は呼び出しに注意してください。
呼び出しはPowerShellから簡単です。
[System.Data.Sql.SqlDataSourceEnumerator]::Instance.GetDataSources()
そのメソッドは、それに応じて処理できるDataTable
オブジェクトを返します。
SQL Browserサービスがアクティブな場合、以下のPowerShellコードを使用して、SQLインスタンスのサービスをクエリできます。クエリを実行する次のコマンドレットを実装します。
Get-SqlBrowserInstanceDac
function Parse-ServerResponse([byte[]] $responseData)
{
[PSObject[]] $instances = @()
if (($responseData -ne $null) -and ($responseData[0] -eq 0x05))
{
$responseSize = [System.BitConverter]::ToInt16($responseData, 1)
if ($responseSize -le $responseData.Length - 3)
{
# Discard any bytes beyond the received response size. An oversized response is usually the result of receiving multiple replies to a broadcast request.
$responseString = [System.Text.Encoding]::Default.GetString(($responseData | Select -Skip 3 -First $responseSize))
$instanceResponses = $responseString.Split(@(";;"), [System.StringSplitOptions]::RemoveEmptyEntries)
$instances = foreach ($instanceResponse in $instanceResponses)
{
$instanceResponseValues = $instanceResponse.Split(";")
$instanceResponseHash = @{}
for ($index = 0; $index -lt $instanceResponseValues.Length; $index += 2)
{
$instanceResponseHash[$instanceResponseValues[$index]] = $instanceResponseValues[$index + 1]
}
New-Object PSObject -Property $instanceResponseHash
}
}
else
{
Write-Warning "The response was too short. Expected $($responseSize) bytes but got $($responseData.Length - 3)."
}
}
return ,$instances
}
function Parse-ServerResponseDac([byte[]] $responseData)
{
$dacPort = 0
if (($responseData -ne $null) -and ($responseData[0] -eq 0x05))
{
$responseSize = [System.BitConverter]::ToUInt16($responseData, 1)
if (($responseData.Length -eq 6) -and ($responseSize -eq 6))
{
if ($responseData[3] -eq 0x01)
{
$dacPort = [System.BitConverter]::ToUInt16($responseData, 4)
}
else
{
Write-Error "An unexpected protocol version was returned. Expected 0x01 but got $($requestData[3])."
}
}
else
{
Write-Error "The response size was incorrect."
}
}
return $dacPort
}
function Get-SqlBrowserInstanceList
{
<#
.SYNOPSIS
Gets the list of available SQL Instances on the server.
.DESCRIPTION
Gets the list of available SQL Instances on the server by querying the SQL Browser Service on port 1434.
.EXAMPLE
Get-SqlBrowserInstanceList servername
.EXAMPLE
Get-SqlBrowserInstanceList servername.dnsdomain.tld
.EXAMPLE
Get-SqlBrowserInstanceList $env:COMPUTERNAME
.EXAMPLE
Get-SqlBrowserInstanceList 192.168.1.255 -Broadcast
.EXAMPLE
Get-SqlBrowserInstanceList 255.255.255.255 -Broadcast
.PARAMETER $ServerName
The name or IP Address of the server.
.PARAMETER $Broadcast
If the broadcast switch is specified, the query will be sent as a broadcast and may receive replies from multiple hosts; otherwise, the query is sent to a single server.
#>
[CmdletBinding(SupportsShouldProcess = $False)]
param
(
[Parameter(Mandatory = $True, ValueFromPipeLine = $True)]
[string] $ServerName,
[switch] $Broadcast
)
process
{
[System.Net.IPAddress] $ipAddress = [System.Net.Dns]::GetHostAddresses($serverName) | Select -First 1
$parsedResponses = @()
if ($ipAddress -ne $null)
{
[System.Net.IPEndPoint] $localIPEndPoint = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
[System.Net.IPEndPoint] $remoteIPEndPoint = New-Object System.Net.IPEndPoint($ipAddress, 1434)
if ($ipAddress -eq [System.Net.IPAddress]::Broadcast)
{
$Broadcast = $true
}
[System.Net.Sockets.UdpClient] $receiver = New-Object System.Net.Sockets.UdpClient
$receiver.Client.ReceiveTimeout = 30000
[byte] $queryMode = 0x03
$sleepDuration = 1
[System.Net.Sockets.UdpClient] $sender = $null
if ($Broadcast -eq $true)
{
Write-Verbose "Using broadcast mode."
$queryMode = 0x02
$sleepDuration = 30
# Set the receiver to allow another client on the same socket.
$receiver.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket, [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true)
$receiver.Client.Bind($localIPEndPoint)
# Because broadcasting from this UdpClient instance causes the underlying socket to be unable to receive normally, a separate sender must be bound to the same socket as the receiver.
# NOTE: Windows Firewall does not view a reused socket as being part of the same conversation. If Windows Firewall is active, this requires special firewall rules to work.
$sender = New-Object System.Net.Sockets.UdpClient
$sender.EnableBroadcast = $Broadcast
$sender.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket, [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true)
$sender.Client.Bind($receiver.Client.LocalEndPoint);
}
else
{
$sender = $receiver
$receiver.Client.Bind($localIPEndPoint)
}
$responses = @{}
try
{
# Send the broadcast.
Write-Verbose "Sending request to $($ipAddress)..."
$sender.Connect($remoteIPEndPoint)
$bytesSent = $sender.Send(@($queryMode), 1)
# Wait to give responses time to arrive.
Sleep $sleepDuration
do
{
[System.Net.IPEndPoint] $responderIPEndPoint = $null
$response = $receiver.Receive([ref] $responderIPEndPoint)
$responder = $responderIPEndPoint.ToString()
if ($responses.Contains($responder))
{
$responses[$responder] += $response
}
else
{
$responses.Add($responder, $response)
}
} while ($receiver.Available -gt 0)
}
finally
{
if ($sender -ne $receiver)
{
$sender.Close()
$sender.Dispose()
}
$receiver.Close()
$receiver.Dispose()
}
foreach ($responseItem in $responses.GetEnumerator())
{
Write-Verbose "Parsing the response from $($responseItem.Name)..."
$parsedResponse = Parse-ServerResponse $responseItem.Value
$parsedResponses += $parsedResponse
Write-Verbose ($parsedResponse | ft ServerName, InstanceName, tcp, np, Version, IsClustered -AutoSize |Out-String)
}
}
return $parsedResponses
}
}
function Get-SqlBrowserInstanceInfo
{
<#
.SYNOPSIS
Gets information about the specified SQL Instance from the server.
.DESCRIPTION
Gets information about the specified SQL Instance from the server by querying the SQL Browser Service on port 1434.
.EXAMPLE
Get-SqlBrowserInstanceInfo servername instancename
.EXAMPLE
Get-SqlBrowserInstanceInfo servername.dnsdomain.tld instancename
.EXAMPLE
Get-SqlBrowserInstanceInfo $env:COMPUTERNAME
.PARAMETER $ServerName
The name or IP Address of the server.
.PARAMETER $InstanceName
The name of the SQL Instance. #>
[CmdletBinding(SupportsShouldProcess = $False)]
param
(
[Parameter(Mandatory = $True, ValueFromPipeLine = $True)]
[string] $ServerName,
[Parameter(Mandatory = $True, ValueFromPipeLine = $False)]
[string] $InstanceName
)
process
{
$instances = @()
[System.Net.IPAddress] $ipAddress = $null
$ipAddress = [System.Net.Dns]::GetHostAddresses($serverName) | Select -First 1
if ($ipAddress -ne $null)
{
[System.Net.IPEndPoint] $ipEndPoint = New-Object System.Net.IPEndPoint($ipAddress, 1434)
[System.Net.Sockets.UdpClient] $udpClient = New-Object System.Net.Sockets.UdpClient
$udpClient.Client.ReceiveTimeout = 10000
$instanceNameData = [System.Text.Encoding]::Default.GetBytes($instanceName)
[byte[]] $requestData = @(0x04) + $instanceNameData + 0x00
[byte[]] $responseData = $null
try
{
$udpClient.Connect($ipEndPoint)
$bytesSent = $udpClient.Send($requestData, $requestData.Length)
$responseData = do
{
$udpClient.Receive([ref] $ipEndPoint)
} while ($udpClient.Available -gt 0)
}
finally
{
$udpClient.Close()
$udpClient.Dispose()
}
$instances = Parse-ServerResponse $responseData
}
return $instances
}
}
function Get-SqlBrowserInstanceDac
{
<#
.SYNOPSIS
Gets the Dedicated Administrator Connection port number for the specified SQL Instance on the server.
.DESCRIPTION
Gets the Dedicated Administrator Connection port number for the specified SQL Instance on the server by querying the SQL Browser Service on port 1434.
.EXAMPLE
Get-SqlBrowserInstanceDac servername instancename
.EXAMPLE
Get-SqlBrowserInstanceDac servername.dnsdomain.tld instancename
.EXAMPLE
Get-SqlBrowserInstanceDac $env:COMPUTERNAME instancename
.PARAMETER $ServerName
The name or IP Address of the server.
.PARAMETER $InstanceName
The name of the SQL Instance.
#>
[CmdletBinding(SupportsShouldProcess = $False)]
param
(
[Parameter(Mandatory = $True, ValueFromPipeLine = $True)]
[string] $ServerName,
[Parameter(Mandatory = $True, ValueFromPipeLine = $False)]
[string] $InstanceName
)
process
{
[System.UInt16] $dacPort = 0
[System.Net.IPAddress] $ipAddress = $null
$ipAddress = [System.Net.Dns]::GetHostAddresses($serverName) | Select -First 1
if ($ipAddress -ne $null)
{
[System.Net.IPEndPoint] $ipEndPoint = New-Object System.Net.IPEndPoint($ipAddress, 1434)
[System.Net.Sockets.UdpClient] $udpClient = New-Object System.Net.Sockets.UdpClient
$udpClient.Client.ReceiveTimeout = 30000
$instanceNameData = [System.Text.Encoding]::Default.GetBytes($instanceName)
[byte[]] $requestData = @(0x0F) + 0x01 + $instanceNameData + 0x00
[byte[]] $responseData = $null
try
{
$udpClient.Connect($ipEndPoint)
$bytesSent = $udpClient.Send($requestData, $requestData.Length)
$responseData = do
{
$udpClient.Receive([ref] $ipEndPoint)
} while ($udpClient.Available -gt 0)
}
finally
{
$udpClient.Close()
$udpClient.Dispose()
}
$dacPort = Parse-ServerResponseDac($responseData)
}
return $dacPort
}
}
考えられるSQLインスタンスを識別する別の方法は、Active Directoryにリストされているサービスプリンシパル名(SPN)を調べることです。 Windows認証を使用してリモートでSQL Serverに接続すると、認証プロセスでSPNが使用されます。 SPNの存在は、サーバー/インスタンスが確実にそこにあり、実行されていることを意味するものではありませんが、他のいくつかのアプローチより包括的であることがわかった、可能なインスタンスのリストを提供します。
人生を楽にするために、次のGet-SPNコマンドレットを使用します。 https://gallery.technet.Microsoft.com/scriptcenter/Get-SPN-Get-Service-3bd5524a
Get-SPN.ps1スクリプトをダウンロードして、C:\ powershell_scripts\Get-SPN.ps1に保存し、PowerShellで次のコマンドを実行します。
. "C:\powershell_scripts\Get-SPN.ps1"
Get-SPN -ServiceClass MSSQLSvc
(もちろん、スクリプトを別の場所に保存できます。必要に応じて、最初の行を更新してください。)
これにより、サービスのポート/インスタンスに関連する「仕様」を含む、現在のドメイン上のすべてのSQL Server SPNが一覧表示されます。
Get-Service -ComputerName * MSSQL * | Where-Object {$ _。status -eq "Running"}
名前付きインスタンスとデフォルトインスタンスが取得されます。マシンのリストなどを反復するだけです。