Automating Database Counts for All SQL Servers - sql-server

I need database counts for every SQL server instance (PROD/Non PROD) in an environment.
If I logged into each and every SQL Server then it is very tedious task for me, so I need to automate it.
Is there any t-sql or powershell script from which I can get consolidated report for database counts for all servers at one place.

You can use Azure Functions with Timer schedule to automate what you want.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer
And you can use stored procedures with azure functions.

Take a look at the SqlServer module documentation, specifically the Get-SqlDatabase cmdlet. You can import your server names from a file or define them in an array and then iterate through them.
#get your credential
$credentials = get-credential
#read server names from a file
$servers = get-content "C:\Some\Path\servers.txt"
#use calculated properties
$servers | select-object `
#{Name='ServerName';Expression={$_}},
#{Name='DatabaseCount';Expression={
#force to array to ensure .count exists
#(Get-SqlInstance -MachineName $_ -Credential $credential | Get-SqlDatabase).Count
}}
If you are unable to install the SqlServer module you can do it with the SMO
#load the assembly
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
#read server names from a file
$servers = get-content "C:\Some\Path\servers.txt"
#use calculated properties
$servers | select-object `
#{Name='ServerName';Expression={$_}},
#{Name='DatabaseCount';Expression={
(New-Object Microsoft.SqlServer.Management.SMO.Server $_).Databases.Count
}}
Output:
ServerName DatabaseCount
---------- -------------
ServerOne 12
ServerTwo 22
ServerThree 6
Note that there is no error checking and I am assuming that you are running in a context that has rights to the server and DB engine.

Related

Replace backup location in SQL jobs

We are trying to replace a backup location in a SQL Backup Jobs step (running power shell through several servers)
Below is a PS script i would like to use it:
# $Server is a file with SERVERNAME names
$Jobs = Get-SQLAgentJob -ServerInstance
$Servers Foreach ($job in $Jobs.Where{$_.Name -like 'DatabaseBackup' -and $_.isenabled -eq $true}) {
foreach ($Step in $Job.jobsteps.Where{$_.Name -like 'DatabaseBackup'}) {
$Step.Command = $Step.Command.Replace("Directory = N'C:\Backup\oldname1\oldname2\SERVERNAME'", "Directory = N'C:\Backup2\newname1\newname2\SERVERNAME'")
$Step.Alter()
}
}
It seems like this should work. The only potential problems I see are the following:
named SQL instances: The $servers variable will need to have the servername\instancename format if not using the default instance name
Job and step names: If your job names and job step names are not exactly databasebackup, case excluded, then the -like operator combined with the exact string will not find a match. If the names contain the databasebackup string, you will be safer to use -match "databasebackup" or -like with asterisks on both sides of the string.
Otherwise, this code should just work provided there are not network connectivity or permissions issues.

Powershell script scripts on dbachecks to compare the MaxMemory of server listed in a table

Run checks against servers
Import-Module dbatools
Import-Module dbachecks
$Server = "AMCB123"
$Database = "DBA"
# Create recordset of servers to evaluate
$sconn = new-object System.Data.SqlClient.SqlConnection("server=$Server;Trusted_Connection=true");
$q = "SELECT DISTINCT servername FROM DBA.[dbo].[Server_Group] WHERE ID =1;"
$sconn.Open()
$cmd = new-object System.Data.SqlClient.SqlCommand ($q, $sconn);
$cmd.CommandTimeout = 0;
$dr = $cmd.ExecuteReader();
# Loop through the servers and build an array
while ($dr.Read()) {
Get-DbaMaxMemory -SqlServer $dr.GetValue(0) | Format-Table
}
$dr.Close()
$sconn.Close()
I have Listed the sql server(stage, prod, DR servers in a table as per the groups), Now I want to compare the servers with group id's to check wethere the servers(stage,prod, DR) with same group id is having same MAXMemory cofiguration or not.
For this I'm using the below powershell script can you please help me with this, I have created a table with all the servewith grop id.
Request to please help me with the loop thorugh the servers and build an array, so that I can run the MAXMEMORY powershell command to compare it using the group id for all servers.
I have collected all the servers details into a table dbo.server groups
the powershell script should iterate through the table by using the ID and check whether the servers in the ID group has same MAXMEMORY configuration ID server_name Environment
1 ABC0123 prod
1 ABC5123 stage
1 ABC4123 DR
2 DEF0123 prod
2 DEF5123 stage
2 DEF4123 DR
I'm trying to use a powershell script which will check and compare the MAXMEMORY configuration as per the ID(to check whether stage, prod, DR server of the same group_id have similar setting or not), if not then it will display a warning/message as group_ids servers are not configured similarly.
Please help me with the script
You're making this script longer than it needs to be. Also, you're using Format-Table prematurely - you should only use the Format-* functions for displaying final information to the user; they output strings, not properly typed data/variables that can be used down the line.
Use the tools that PowerShell and dbatools give you to get your server list, and then pass that list to Get-DbaMaxMemory as a collection.
import-module dbatools
$ServerList = Invoke-DbaSqlQuery -ServerInstance $Server -query "select distinct servername from dba.dbo.server_group where group_id = 1" | Select-Object -ExpandProperty servername;
Get-DbaMaxMemory -ServerInstance $ServerList | Select-Object SqlInstance, SqlMaxMB;
This will give you a list of your SQL instances and the memory they're configured to use. What you do after that...it's hard to say as you haven't clearly defined what you're looking for.
But this may not tell the full story. Wouldn't it be better to check the configured values and what you're currently running with? You can do that with Get-DbaSpConfigure.
import-module dbatools
$ServerList = Invoke-DbaSqlQuery -ServerInstance $Server -query "select distinct servername from dba.dbo.server_group where group_id = 1" | Select-Object -ExpandProperty servername;
Get-DbaSpConfigure -ServerInstance $ServerList | Select-Object ServerName,ConfiguredValue,RunningValue;
You can even create a computed column in that final Select-Object to tell you if the configured & running values differ.
If you just wanted to use dbachecks (which uses dbatools in the background) you can use
$ServerList = (Invoke-DbaSqlQuery -ServerInstance $Server -query "select distinct servername from dba.dbo.server_group where group_id = 1").servername
and
Invoke-DbcCheck -SQlInstance $ServerList -Check MaxMemory
Or you can set the configuration item app.computername and app.sqlinstance to your server list using
Set-DbcConfig -Name app.sqlinstance -Value $serverlist
Set-DbcConfig -Name app.computername -Value $serverlist
and then you can run this (or any other checks) using
Invoke-DbcCheck -Check MaxMemory

Powershell: Find all SQL Server instances per ser server?

Strictly speaking, the question is, I use this solution and it works, but is there a better way?
With the following caveats.
1) I don't want to do a network wide search for SQL instances, I am interrogating known SQL servers, but I want to grab the instance names on each.
2) The code assumes Microsoft will never change the display name for the SQL Server Service.
function getSQLInstance ([string]$SERVER) {
$services = Get-Service -Computer $SERVER
# Filter for SQL services
$services = $services | ? DisplayName -like "SQL Server (*)"
# Remove MSSQL$ qualifier to get instance name
try {
$instances = $services.Name | ForEach-Object {($_).Replace("MSSQL`$","")}
}catch{
# Error if none found
return -1
}
return $instances
}
getSQLInstance "YOUR_SERVER"
Rather than re-invent the wheel, take a look at how SQL Power Doc discovers instances on a server. Which, from looking at NetworkScan.psm1, appears to be very similar to your approach:
$ManagedComputer.Services | ForEach-Object {
if (($_.Name).IndexOf('$') -gt 0) {
$InstanceName = ($_.Name).Substring(($_.Name).IndexOf('$') + 1)
$IsNamedInstance = $true
$ManagedComputerServerInstanceName = $InstanceName
} else {
$InstanceName = $null
$IsNamedInstance = $false
$ManagedComputerServerInstanceName = $_.Name
}
Or, just use SQL Power Doc and point it at specific server names to collect this and more data about the instances.

How to transfer data from a newer to an older MS SQL server using cmd?

I have a database server (let's call it S) with some data running MS SQL 2012. On the other end of the world there are tablets running MS SQL 2012 EXPRESS (let's call them TS). A part of the data must be transferred from S to TS. Due to many reasons the only way to communicate is to send files from S to proxy servers to have them picked up by TS later.
Currently I'm using backup files (.BAK) so I can simply create a partial backup of S' database and restore it on TS.
Now here is the problem:
It might happen that in a while S will switch to MS SQL 2014. It's not possible to install 2014 on TS because I have no direct access to them. In this case S will still be able to restore data created with SQL 2012 on TS but not the other way around because it's impossible to restore backups from a newer SQL version on an older one. So this is the point I need help in.
I've tried to export the data using the server management tool on S instead of creating a backup and import everything on TS. This works well but the export must happen automatically per command line. The good old sqlpubwiz is not an option because it was discontinued and only works up to version 2008 R2.
So I need ideas how to export from S using cmd/powershell and import on TS only using files to communicate even if they are running different versions of MS SQL Server.
I've used detatched databases before to distribute databases to laptops before. They are much quicker to import than a backup, but I'm not sure about inter-version compatibility.
You could write a tool that you package up as an exe that contains CSV files and a loader script which uses Bcp.exe
I would look at using the built-in replication features, setting up S as a snapshot replication publisher, and TS as a subscriber via FTP. SQL Server Express can act as a subscriber (but not a published) in a replication scenario.
http://msdn.microsoft.com/en-us/library/ms151832.aspx
If you want to write a more intricate scenario, you may want to consider Sync Framework
Problem solved! Powershell does the trick but it was way too slow. At the end I've still used BCP. BCP means a lot of scripting to do but works about 30 times faster than using powershell. However, here is the powershell script I've used:
set-psdebug -strict
$DirectoryToSaveTo='...' #path where to save the data
$ServerName='...' #Hostname\Instance
$Database='...' #database to export
$ErrorActionPreference = "stop"
Trap {
$err = $_.Exception
write-host $err.Message
while( $err.InnerException ) {
$err = $err.InnerException
write-host $err.Message
};
break
}
$v = [System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.SqlServer.SMO')
if ((($v.FullName.Split(','))[1].Split('='))[1].Split('.')[0] -ne '9') {
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMOExtended') | out-null
}
$My='Microsoft.SqlServer.Management.Smo'
$s = new-object ("$My.Server") $ServerName
$Server=$s.netname -replace '[\\\/\:\.]',' '
$instance = $s.instanceName -replace '[\\\/\:\.]',' '
$DatabaseName =$database -replace '[\\\/\:\.]',' '
$DirectoryToSaveTo=$DirectoryToSaveTo+'\'+$Instance+'\'
$CreationScriptOptions = new-object ("$My.ScriptingOptions")
$CreationScriptOptions.ExtendedProperties= $true
$CreationScriptOptions.DRIAll= $true
$CreationScriptOptions.Indexes= $true
$CreationScriptOptions.Triggers= $true
$CreationScriptOptions.ScriptBatchTerminator = $true
$CreationScriptOptions.Filename = "$($DatabaseName)_Schema.sql";
$CreationScriptOptions.IncludeHeaders = $true;
$CreationScriptOptions.ToFileOnly = $true # no need of string output as well
$CreationScriptOptions.IncludeIfNotExists = $true # not necessary but it means the script can be more versatile
$transfer = new-object ("$My.Transfer") $s.Databases[$Database]
$transfer.options=$CreationScriptOptions # tell the transfer object of our preferences
$scripter = new-object ("$My.Scripter") $s # script out the database creation
$scripter.options=$CreationScriptOptions # with the same options
$scripter.Script($s.Databases[$Database]) # do it
"USE $Database" | Out-File -Append -FilePath "$($DatabaseName)_Schema.sql"
"GO" | Out-File -Append -FilePath "$($DatabaseName)_Schema.sql"
$transfer.options.AppendToFile=$true
$transfer.options.ScriptDrops=$true
$transfer.EnumScriptTransfer()
$transfer.options.ScriptDrops=$false
$transfer.EnumScriptTransfer()
"All written to $($DatabaseName)_Schema.sql"
This script exports only the schema but it should be quite obvious how to export also all the data.

Change DNS Search Order with Powershell with different settings on different server

Hi dear lord(s) of Powershell :)
I have 380 server to modify.
Some DNS server in forest and domain have changed and I need to change the Dns search order parameter.
If my server have following DNSsearchOrder : 172.xx.xx.1 I want to change to 172.xx.xx.2
If my server have following DNSsearchOrder : 172.xx.xx.1 AND 172.xx.xx.10 I want to change only the first IP to 172.xx.xx.2 and let the 2nd
etc etc (I Have 10dns server moving and they're used on different domain and server)
I retrieve all my server export to CSV file with the following command :
Import-csv "C:\Julien\Script\CheckNchangeRegKeyValue\listOfcomputerOS_OK.csv" -Delimiter ";" |
Foreach-object{
$ServerToAnalyse=$_.Server
Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "ipenabled='true'" -ComputerName $ServerToAnalyse |Where-Object {$_.DNSServerSearchOrder -ne $null}| Where-Object {$_.DNSServerSearchOrder -ine "127.0.0.1"} |`
select DNSHostName,#{Name="DNSParam"; Expression={$(($_.DNSServerSearchOrder))}},MACAddress,description,caption,index
} | Export-csv "C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv" -notypeinformation -delimiter ";"
first file is a csv contain data like that :
"Caption";"Server"
"Microsoft(R) Windows(R) Server 2003, Standard Edition";"d0001doi.Mydomain.com"
"Microsoft(R) Windows(R) Server 2003, Standard Edition";"d0001ira.Mydomain.com"
"Microsoft Windows Server 2008 R2 Standard ";"D0005DLF.Mydomain.com"
"Microsoft(R) Windows(R) Server 2003, Standard Edition";"d0001ath.Mydomain.com"
"Microsoft Windows Server 2008 R2 Enterprise ";"D0002TEH.Mydomain.com"
"Microsoft Windows Server 2008 R2 Standard ";"D0003MAD.Mydomain.com"
The output CSV is like that :
"DNSHostName";"DNSParam";"MACAddress";"description";"caption";"index"
"v1068bel";"172.19.1.3";"xx:xx:xx:xx:xx";"VMware Accelerated AMD PCNet Adapter";"[00000010] VMware Accelerated AMD PCNet Adapter";"10"
The output file contain the actual settings and my idea is to modify this file with the following command to use this output file to modify the settings of my server :
[io.file]::readalltext("C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv").replace("172.19.1.1","172.19.16.211").replace("172.18.37.8","172.19.17.52").replace("172.19.1.5","172.19.16.211").replace("172.19.1.3","172.19.16.28").replace("172.18.37.4","172.19.16.28").replace("172.19.1.6","172.19.16.27").replace(" ",",") | Out-File "C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv" -Encoding ascii –Force
After this modification I try to use the following command :
Import-Csv "C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv" -Delimiter ";" |
ForEach-Object{
$Server=$_.DNSHostName
$DNS=$_.DNSParam
$DNS=$DNS -replace "$DNS","`"$DNS`""
$DNS=($DNS -replace ",","`",`"")#.tostring()
$DNSIP=#("$DNS")
#$DNS=#($DNS)
#$DNS.GetType().fullname
#= New-Object System.Object
Write-Host "settings to put : $DNS"
(Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server).SetDNSServerSearchOrder(("$DNSIP"))#|Out-Null
$ActualDNS = (Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server)|Where-Object {$_.DNSServerSearchOrder -ne $null}| Where-Object {$_.DNSServerSearchOrder -ine "127.0.0.1"} |select #{Name="actualSettings"; Expression={$(($_.DNSServerSearchOrder))}}
Write-Host "actual settings $ACtualDNS"
}
If I put manually SetDNSServerSearchOrder((“198.102.234.125",”198.102.234.126")) instead of .SetDNSServerSearchOrder(("$DNSIP"))
it's working
but with $dnsip variable the result is 70 (bad IP address)
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 70
PSComputerName :
actual settings #{actualSettings=172.19.1.1}
anyone can help me ?
Thanks a lot
Regards
Julien
According to this article you really need a string array so you should replace $DNSIP=#("$DNS") by $DNSIP.split(',').
Explanation : when you write “198.102.234.125",”198.102.234.126" you create an array, because in PowerShell , is the array operator. $DNSIP=#("$DNS") just create an array of one string which is not an IP address.

Resources