Powershell Script to pull DMV results from Tabular Model - powershell

Trying to build a PowerShell script to connect to Analysis Services Tabular Model and pull the output of DMV queries(eg : SELECT * FROM $System.DBSchema_Tables)
Tried Below, but its fails, it seems there is something wrong with connection string or the way I am trying to connect:
$connectionString = "server=TabularServerName;database='ModelName';trusted_connection=true;";
$CubeQuery = "SELECT * FROM $System.DBSchema_Tables";
#SQL Connection - connection to SQL server
$sqlConnection = new-object System.Data.SqlClient.SqlConnection;
$sqlConnection.ConnectionString = $connectionString;
#SQL Command - set up the SQL call
$sqlCommand = New-Object System.Data.SqlClient.SqlCommand;
$sqlCommand.Connection = $sqlConnection;
$sqlCommand.CommandText = $CubeQuery;
#SQL Adapter - get the results using the SQL Command
$sqlAdapter = new-object System.Data.SqlClient.SqlDataAdapter
$sqlAdapter.SelectCommand = $sqlCommand
$dataSet = new-object System.Data.Dataset
$recordCount = $sqlAdapter.Fill($dataSet)

What are you not just using the SQLPS module or DBA Tools module?
There are of course other modules you can leverage:
Find-Module -Name '*sql*' | Format-Table -AutoSize
Find-Package -Name '*sql*' | Format-Table -AutoSize
Here is the stuff I've passed on to others messing with SQL.
Install the SQL Server PowerShell module
https://learn.microsoft.com/en-us/sql/powershell/download-sql-server-ps-module?view=sql-server-ver15
https://learn.microsoft.com/en-us/powershell/module/sqlps/?view=sqlserver-ps
https://learn.microsoft.com/en-us/sql/powershell/sql-server-powershell?view=sql-server-ver15
Then see:
Connecting PowerShell to SQL Server
As an overview the following is the list of options I will go over in
this article:
SQL Server PowerShell (SQLPS)
SQL Server Management Objects (SMO)
.NET (System.Data.SqlClient)
SQLPS
SQL Server PowerShell SQLPS is a utility that was first released
with SQL Server 2008, you may see this referenced in various ways. It
exists as a (1) utility and (2) as a PS module. The utility and module
are installed with the SQL Server Management tools from SQL Server
2008 and up. There are a few ways of connecting to SQL Server using
this utility, and each one has strengths and weaknesses.
SQLPS.exe
This is a utility that you should be able to open by typing
it in the run prompt (Start > Run). A second option, right-click a
node under Object Explorer, within SQL Server Management Studio
(SSMS), and select “Start PowerShell”. The SQLPS utility’s main access
point is using the provider “SQLSERVER:\” to browse SQL Server like a
file directory. With that, based on the node you open SQLPS from will
place you within that path of the provider. Under each “folder” you
are in for the provider offers properties to read or set, and some
methods to use for administration.
Get-ChildItem SQLSERVER:\SQL\LOCALHOST\SQL12\Databases | foreach { $_.RecoveryModel = "SIMPLE"; $_.Alter() }
SQLPS Module
Importing the SQLPS module into a PS session provides the
same access using the utility does but allows you to operate in the
PS version of the OS you operate under. In SQL Server 2008 and 2008 R2
you will load the SQLPS as a snap-in (Add-PSSnapin), then with SQL
Server 2012 and up it is imported (Import-Module).
# Loading SMO
Add-Type -AssemblyName "Microsoft.SqlServer.Smo,Version=11.0.0.0,Culture=neutral,PublicKeyToken=89845dcd8080cc91"
# Connecting with SMO
$srv = New-Object Microsoft.SqlServer.Management.Smo.Server “localhost\sql12”
$srv.Databases | select name
# .NET Framework
# Create a connection
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = “Server=localhost\sql12;Integrated Security=true;Initial Catalog=master”
$sqlConn.Open()
# Create your command (the T-SQL that will be executed)
$sqlcmd = $sqlConn.CreateCommand()
<# or #>
$sqlcmd = New-Object System.Data.SqlClient.SqlCommand
$sqlcmd.Connection = $sqlConn
$query = “SELECT name, database_id FROM sys.databases”
$sqlcmd.CommandText = $query
# Create your data adapter (if you want to retrieve data)
$adp = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd
# Create your dataset (the adapter fills this object)
$data = New-Object System.Data.DataSet
$adp.Fill($data) | Out-Null
# Retrieving Your Data
$data.Tables
<# or #>
$data.Tables[0]
Lastly:
USE POWERSHELL TO GET ALL THE MEASURES FROM A 2016 TABULAR CUBE
So, here’s the PowerShell script that will get the measures from a
cube (change the first three variables to fit your environment):
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices.Tabular");
$tab = "YourSSASserver";
$dbId = "ID_or_DB";
$saveas = "C:\YourFolder\{0}.dax" -f $tab.Replace('\', '_');
$as = New-Object Microsoft.AnalysisServices.Tabular.Server;
$as.Connect($tab);
$db = $as.Databases[$dbId];
# in case you want to search by the name of the cube/db:
# $as.Databases.GetByName("DB Name");
$out = "";
foreach($t in $db.Model.Tables) {
foreach($M in $t.Measures) {
$out += "// Measure defined in table [" + $t.Name + "] //" + "`n";
$out += $M.Name + ":=" + $M.Expression + "`n";
}
}
$as.Disconnect();
$out = $out.Replace("`t"," "); # I prefer spaces over tabs :-)
$out.TrimEnd() | Out-File $saveas;

Below is what worked for me
$connectionString = $connectionString = “Provider=MSOLAP;Data Source=TabularServerName;”
$CubeQuery = 'SELECT * FROM $System.DBSchema_Tables';
$connection = New-Object -TypeName System.Data.OleDb.OleDbConnection
$connection.ConnectionString = $connectionString
$sqlCommand = $connection.CreateCommand()
$sqlCommand.CommandText = $CubeQuery;
#SQL Adapter - get the results using the SQL Command
$sqlAdapter = new-object System.Data.SqlClient.SqlDataAdapter
$sqlAdapter.SelectCommand = $sqlCommand
$dataSet = new-object System.Data.Dataset
$recordCount = $sqlAdapter.Fill($dataSet)```

Related

How to Pass a System.Data.DataSet Object as an Argument to a Powershell Workflow?

I'm getting some data from a SQL table, which I then store in a System.Data.DataSet object. I want to pass this data in this DataSet, as an Argument/Parameter, to a workflow, such that I can display all the data in this DataSet in a foreach -parallel style. But I'm at a loss for the correct syntax of passing data from a System.Data.DataSet object to a workflow. Currently I get an Error near the line "param([System.Data.DataSet]$pServiceDataSet)" as shown below.
Function GetSQLData
{
param ($TargetDBServer, $TargetDB, $SQLQuery)
# SQL Connection Object
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = "Server=$TargetDBServer;Database=$TargetDB;User Id=SomeUser;Password=SomePassword;"
$sqlConn.Open()
# SQL Command
$sqlcmd = New-Object System.Data.SqlClient.SqlCommand
$sqlcmd.Connection = $sqlConn
$sqlcmd.CommandText = $SQLQuery
# SQL Adapter
$sqlAdp = New-Object System.Data.SqlClient.SqlDataAdapter ($sqlcmd)
# SQL DataSet
$ResultDataSet = New-Object System.Data.DataSet
$sqlAdp.Fill($ResultDataSet) | Out-Null
$sqlConn.Close()
return $ResultDataSet.Tables[0]
}
$CurrentComputerName = $env:COMPUTERNAME
# Export the Windows Services & it's config parameters from the "DatabaseABC..WindowsServicesConfig" Table.
$SQLQueryForService = "
SELECT [ServiceName], [StartUpParameter], [DBServerName], [DBName]
FROM [dbo].[WindowsServicesConfig] WITH (NOLOCK)
WHERE [HostServerName] = '$CurrentComputerName'
AND [ServiceName] LIKE '%MyService%' "
$ServicesDataSet = GetSQLData -TargetDBServer "ServerABC" -TargetDB "DatabaseABC" -SQLQuery $SQLQueryForService
$ServicesDataSet.GetType()
$ServicesDataSet | Format-Table
workflow DisplayAllServices
{
param([System.Data.DataSet]$pServiceDataSet) # <- I get an Error here
foreach -parallel ($Service in $pServiceDataSet)
{
$Service.ServiceName
$Service.StartUpParameter
$Service.DBServerName
$Service.DBName
}
}
DisplayAllServices -pServiceDataSet $ServicesDataSet
My final objective is to use the data in this DataSet to create Windows Services. But this is my most frustrating hurdle. I cannot get past the Error.
Figured out the Solution to my Problem. Replaced the "param([System.Data.DataSet]$pServiceDataSet)" with "param([PSObject]$pServiceDataSet)".

Powershell to read from database using ODBC DSN instead of connection string

I know how to read value from database using connectionstring, i.e.
Establish database connection to read
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=10.10.10.10;Initial Catalog=database_name;User Id=$username;Password=$password;"
$SQL = "..."
$conn.Open()
# Create and execute the SQL Query
$cmd = New-Object System.Data.SqlClient.SqlCommand($sql,$conn)
$count=0
do{
try{
$rdr = $cmd.ExecuteReader()
while ($rdr.read()){
$sql_output += ,#($rdr.GetValue(0), $rdr.GetValue(1))
$count=$count + 1
}
$transactionComplete = $true
}
catch{
$transactionComplete = $false
}
}until ($transactionComplete)
# Close the database connection
$conn.Close()
How can I accomplish the same thing with ODBC, i.e I have DSN (data source name) set up on the server?
According to https://www.connectionstrings.com/odbc-dsn/ you would use something like...
DSN=myDsn;Uid=myUsername;Pwd=;
Can probably just go with DSN=... if creds not required.
This works if your ODBC connection is under User DSN but not under System DSN. I cannot find a way to make it check for System DSN connections.
$conn = new-object System.Data.Odbc.OdbcConnection
$conn.connectionstring = "DSN=DSNNAME"
$conn.open()
$cmd = New-object System.Data.Odbc.OdbcCommand($sqlCommand,$conn)
$dataset = New-Object System.Data.DataSet
(New-Object System.Data.Odbc.OdbcDataAdapter($cmd)).Fill($dataSet) | Out- Null
$conn.Close()
You may want to put this in front of the code...
If you want to do it on your local machine instead of in the context of SQL server then I would use the following. It is what we use at my company.
if ($env:Processor_Architecture -ne "x86")
{ write-warning 'Launching x86 PowerShell'
&"$env:windir\syswow64\windowspowershell\v1.0\powershell.exe" -noninteractive -noprofile -file $myinvocation.Mycommand.path -executionpolicy bypass
exit
}
Always running in 32bit PowerShell at this point.
$env:Processor_Architecture

Switch on verbosity diagnostic on sql execute powershell

I have script, which connect to db. I need get technical info about execute script. Or when in my sql srcipt exist mistake,I see very scant information. But I need detail of error. How can I get more detail info?
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$query = "SELECT * FROM Animal"
$command = $connection.CreateCommand()
$command.CommandText = $query
$result = $command.ExecuteReader()
$table = new-object “System.Data.DataTable”
$table.Load($result)
$table
//how get info
$connection.Close()
After your code executes run Error[0] | fl -Force to get the details of (last) error.

execute .sql file using powershell and store the output in a text file

I’m trying to run the sql script .sql file from powershell and save the result into .sql file.
Overview : SQL database restore requires a user and permission backup pre-restore and once the restore is complete we need to execute the output( users permissions backup which we did pre-restore ) on the database.
here’s my script and when i execute i dont see any output
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$DataSet = New-Object System.Data.DataSet
$MyQuery = get-content “C:\Users\Security.sql”;
$SqlConnection.ConnectionString = “Server = DBATest; Database = Testdb; Integrated Security = True”
$SqlCmd.CommandText = $MyQuery;
$SqlCmd.Connection = $SqlConnection
$SqlAdapter.SelectCommand = $SqlCmd
$SqlAdapter.Fill($DataSet)|out-null
$DataSet.Tables[0] | out-file C:\users\outputuser.sql
Could someone point me in right direction ? thanks in advance
If you have the SQL Server management tools (2008 or newer) installed, this becomes much easier.
add-pssnapin SqlServerCmdletSnapin100;
$myData = invoke-sqlcmd -InputFile "c:\users\security.sql" -serverinstance dbatest -database testdb;
$mydata | out-file c:\users\outputuser.sql;
Remove-PSSnapin SqlServerCmdletSnapin100;
If you have 2012 (or newer) installed, you can skip the snap-in and import the sqlps module:
push-location;
import-module sqlps;
Pop-Location;
$myData = invoke-sqlcmd -InputFile "c:\users\security.sql" -serverinstance dbatest -database testdb;
$mydata | out-file c:\users\outputuser.sql;
remove-module sqlps;
Whether the output file gives you the formatting you're looking for or not, I can't say, as you have specified what you're looking for, nor shown the query itself. You might want to export it to CSV format instead, or use format-table to structure the plain text a bit more, or convert to HTML.

How do you run a SQL Server query from PowerShell?

Is there a way to execute an arbitrary query on a SQL Server using Powershell on my local machine?
For others who need to do this with just stock .NET and PowerShell (no additional SQL tools installed) here is the function that I use:
function Invoke-SQL {
param(
[string] $dataSource = ".\SQLEXPRESS",
[string] $database = "MasterData",
[string] $sqlCommand = $(throw "Please specify a query.")
)
$connectionString = "Data Source=$dataSource; " +
"Integrated Security=SSPI; " +
"Initial Catalog=$database"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
$connection.Open()
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
$connection.Close()
$dataSet.Tables
}
I have been using this so long I don't know who wrote which parts. This was distilled from others' examples, but simplified to be clear and just what is needed without extra dependencies or features.
I use and share this often enough that I have turned this into a script module on GitHub so that you can now go to your modules directory and execute git clone https://github.com/ChrisMagnuson/InvokeSQL and from that point forward invoke-sql will automatically be loaded when you go to use it (assuming your using PowerShell v3 or later).
You can use the Invoke-Sqlcmd cmdlet
Invoke-Sqlcmd -Query "SELECT GETDATE() AS TimeOfQuery;" -ServerInstance "MyComputer\MyInstance"
http://technet.microsoft.com/en-us/library/cc281720.aspx
This function will return the results of a query as an array of powershell objects so you can use them in filters and access columns easily:
function sql($sqlText, $database = "master", $server = ".")
{
$connection = new-object System.Data.SqlClient.SQLConnection("Data Source=$server;Integrated Security=SSPI;Initial Catalog=$database");
$cmd = new-object System.Data.SqlClient.SqlCommand($sqlText, $connection);
$connection.Open();
$reader = $cmd.ExecuteReader()
$results = #()
while ($reader.Read())
{
$row = #{}
for ($i = 0; $i -lt $reader.FieldCount; $i++)
{
$row[$reader.GetName($i)] = $reader.GetValue($i)
}
$results += new-object psobject -property $row
}
$connection.Close();
$results
}
Here's an example I found on this blog.
$cn2 = new-object system.data.SqlClient.SQLConnection("Data Source=machine1;Integrated Security=SSPI;Initial Catalog=master");
$cmd = new-object system.data.sqlclient.sqlcommand("dbcc freeproccache", $cn2);
$cn2.Open();
if ($cmd.ExecuteNonQuery() -ne -1)
{
echo "Failed";
}
$cn2.Close();
Presumably you could substitute a different TSQL statement where it says dbcc freeproccache.
If you want to do it on your local machine instead of in the context of SQL server then I would use the following. It is what we use at my company.
$ServerName = "_ServerName_"
$DatabaseName = "_DatabaseName_"
$Query = "SELECT * FROM Table WHERE Column = ''"
#Timeout parameters
$QueryTimeout = 120
$ConnectionTimeout = 30
#Action of connecting to the Database and executing the query and returning results if there were any.
$conn=New-Object System.Data.SqlClient.SQLConnection
$ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerName,$DatabaseName,$ConnectionTimeout
$conn.ConnectionString=$ConnectionString
$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()
$ds.Tables
Just fill in the $ServerName, $DatabaseName and the $Query variables and you should be good to go.
I am not sure how we originally found this out, but there is something very similar here.
There isn't a built-in "PowerShell" way of running a SQL query. If you have the SQL Server tools installed, you'll get an Invoke-SqlCmd cmdlet.
Because PowerShell is built on .NET, you can use the ADO.NET API to run your queries.
Invoke-Sqlcmd -Query "sp_who" -ServerInstance . -QueryTimeout 3
To avoid SQL Injection with varchar parameters you could use
function sqlExecuteRead($connectionString, $sqlCommand, $pars) {
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$connection.Open()
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand, $connection)
if ($pars -and $pars.Keys) {
foreach($key in $pars.keys) {
# avoid injection in varchar parameters
$par = $command.Parameters.Add("#$key", [system.data.SqlDbType]::VarChar, 512);
$par.Value = $pars[$key];
}
}
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataset) | Out-Null
$connection.Close()
return $dataset.tables[0].rows
}
$connectionString = "connectionstringHere"
$sql = "select top 10 Message, TimeStamp, Level from dbo.log " +
"where Message = #MSG and Level like #LEVEL"
$pars = #{
MSG = 'this is a test from powershell'
LEVEL = 'aaa%'
};
sqlExecuteRead $connectionString $sql $pars
You can even format string and pass parameters as you want.
case "ADDSQLSERVERUSER":
//0 = coprorateName;
//1 = user password
//2 = servername
command = #"$sqlQuery = Use JazzUWS_'{0}'
Create login UWSUser_'{0}' with password='{1}';
Create user UWSUser_'{0}' for login UWSUser_'{0}';
Grant Execute to UWSUser_'{0}';
Use ReportSvrUWS_'{0}'
Create user UWSUser_'{0}' for login UWSUser_'{0}';
Grant Execute to UWSUser_'{0}';
Invoke-Sqlcmd -Query $sqlQuery -ServerInstance '{2}'";
break;
C# Code for remote execution(you can organize your way)
string script = PowershellDictionary.GetPowershellCommand("ADDSQLSERVERUSER");
script = String.Format(script, this.CorporateName, password, this.SQLServerName)
PowerShellExecution.RunScriptRemote(_credentials.Server, _credentials.Username, _credentials.Password, new List<string> { script });
You could use the best SQL Server module around: DBATOOLS. You would also benefit from running a query to multiple sql instances.
Install-Module dbatools -Scope CurrentUser
$sql = 'SQL1','SQL1\INSTANCE1','SQL2'
$query = "SELECT 'This query would run on all SQL instances'"
Invoke-DbaQuery -SqlInstance $sqlinstances -Query $query -AppendServerInstance