SQL Server audit extended event metadata change - sql

We have extended event running in SQL Server 2014. We also have a task that run every few minutes and check that the Xevent is running -> Audit the Xevent trace.
I'm trying to find a way (in T-SQL) to audit also changes on the Xevent metadata.
If the Xevent change (by alter), or drop and create.
No need to monitor stop and start session.
I thought about hash function on the Xevent metadata, but I can not find a T-SQL way to get the Xevent string.
Any idea how this can be achieved?
Thanks,

I managed to get the Xevent metadata by using PowerShell SQLPS module.
Then Hash function on the string result:
$server="localhost"
Import-Module sqlps -DisableNameChecking
CD SQLSERVER:\
CD xevent\$server\default\Sessions
$xe=Get-ChildItem |Where-Object {$_.name -eq $XeName}
#$xe.Targets
#$xe.IsRunning
$Xeventmetadata=$xe.ScriptCreate().GetScript()
$Xeventmetadata
#Getting String hash value
function Hash($textToHash)
{
$hasher = new-object System.Security.Cryptography.SHA256Managed
$toHash = [System.Text.Encoding]::UTF8.GetBytes($textToHash)
$hashByteArray = $hasher.ComputeHash($toHash)
foreach($byte in $hashByteArray)
{
$res += $byte.ToString()
}
return $res;
}
Hash("$Xeventmetadata")

Related

How to read/fetch data from Oracle SQL database using PowerShell Core?

I have been researching on this for a couple of days but have been going in circles here.
I need to write a script that fetches the data from Oracle db and do something with the data. In my script I will have to fetch data multiple times.
My machine has the SQLDeveloper-21.4.3 which I got from installing InstantClient-Basic-Windows-21.3.0. I use the SQL Developer to connect to the db which is on another machine; this is how I can look into tables, views etc. of the db.
Secondly, this script will be hosted on another server that runs Windows-Server-2012-R2. I am just using my machine to write the script because I cannot use the server to do this. Therefore, I am looking for a solution that requires minimum amount of installing.
Thirdly, we do not have Oracle commercial license. This Oracle db I am trying to access is on the machine installed by a third party that installed some instruments. This company uses Oracle as they collect data on the instruments installed.
I was hoping the solution would be something similar to invoking connection to MS SQL where I downloaded module that gave cmdlets to connect to the MS SQL.
Oracle does have Oracle Modules for PowerShell but neither have I found information on how to use them nor have I understood the little information provided by Oracle on this. For this to work one of the requirement is:
A configuration file and key pair used for signing API requests, with
the public key uploaded to Oracle Cloud using Oracle Cloud
Infrastructure Console. Only the user calling the API should possess
the private key.
I don't know the heck Oracle is talking about here. Like, what is this configuration file, where is it? Where would I get the key pair from for signing API request. What is Oracle Infrastructure Console, where do I get it from? You get the idea.
Link: https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/powershell.htm
Therefore, I went the .DLL route.
This is what I have done so far:
I installed Oracle.ManagedDataAccess.Core -Version 3.21.61 from NuGet.
Unzipped the package and moved the Oracle.ManagedDataAccess.dll to the location of my script.
The code is:
$OracleDLLPath = "C:\Users\Desktop\CNC_File_Transfer_VSCode\Fastems_NicNet\Oracle.ManagedDataAccess.dll"
$datasource = " (DESCRIPTION =
(ADDRESS =
(PROTOCOL = TCP)
(HOST = 10.50.61.9)(PORT = 1521))
(CONNECT_DATA = (SERVER = DEDICATED)
(SERVICE_NAME = Fa1)
(FAILOVER_MODE = (TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5))))"
$username = "username"
$password = "password"
$queryStatment = "SELECT [PROG_TYPE] FROM NC_PROGRAMS FETCH FIRST 10 ROWS ONLY"
#Load Required Types and modules
Add-Type -Path $OracleDLLPath
Import-Module SqlServer
Write-Host $queryStatment
#Create the connection string
$connectionstring = 'User Id=' + $username + ';Password=' + $password + ';Data Source=' + $datasource
#Creates a data adapter for the command
$da = New-Object Oracle.ManagedDataAccess.Client.OracleDataAdapter($cmd);
#The Data adapter will fill this DataTable
$resultSet = New-Object System.Data.DataTable
#Only here the query is sent and executed in Oracle
[void]$da.fill($resultSet)
#Close the connection
$con.Close()
WRITE-HOST $resultSet
This gives an error though:
Add-Type : Unable to load one or more of the requested types. Retrieve
the LoaderExceptions property for more information.
I am new to programming in general. I would really appreciate if someone could provide detailed steps on resolving this. Thanks in advance.

How to determine SQL database replication roles using the Azure PowerShell command Get-AzureRMSqlDatabase

Using the Azure Resource Manager PowerShell commands, is there a simple way to tell whether a database is involved in geo-replication role as either a Primary or Secondary? I used to read the Status property returned by Get-AzureSqlDatabase, and a value of 0 meant that the database was Primary. However, there is no corresponding property returned by Get-AzureRMSqlDatabase; it still returns a status column, but the value is "Online" for both primary and secondary databases.
The reason I need this is that I'm trying to maintain dozens of databases across multiple subscriptions and servers, and I am trying to automate actions that should only be taken on the primary databases.
I found a reasonable solution to this problem, making one extra call per database. The commandlet Get-AzureRmSqlDatabaseReplicationLink does exactly what I needed, with one caveat; I know that I'm not supposed to be passing the same value as both ResourceGroupName and PartnerResourceGroupName, but it seems to work (at least for now), so I'm going with it to avoid having to make one call per resource group in the subscription.
Using that, I was able to create this simple function:
Function IsSecondarySqlDatabase {
# This function determines whether specified database is performing a secondary replication role.
# You can use the Get-AzureRMSqlDatabase command to get an instance of a [Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel] object.
param
(
[Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel] $SqlDB
)
process {
$IsSecondary = $false;
$ReplicationLinks = Get-AzureRmSqlDatabaseReplicationLink `
-ResourceGroupName $SqlDB.ResourceGroupName `
-ServerName $SqlDB.ServerName `
-DatabaseName $SqlDB.DatabaseName `
-PartnerResourceGroupName $SqlDB.ResourceGroupName
$ReplicationLinks | ForEach-Object -Process `
{
if ($_.Role -ne "Primary")
{
$IsSecondary = $true
}
}
return $IsSecondary
}
}

create auto sql script that runs in every hour - in c# or any other easy way

I have simple sql script:
Select * from student where score > 60
What i am trying to do is run this above script every 1 hour and getting notified on my computer in any way possibe that above condition was met. So basically i dont want to go in there and hit F5 every hour on the above statement and see if i get any result. I am hoping someone out here has something exactly for this, if you do please share the code.
You can use Sql Agent to create a job, Sql server 2008 also has mail functionality
Open SQL Management Studio and connect to your SQL Server
Expand the SQL Server Agent node (if you don't see it, use SQL configuration manager or check services and ensure that SQL Server Agent (SQLINSTANCENAME) is started)
Right click on Jobs and choose 'New Job'
You can run a SQL statement in a job. I'll let you figure out the rest of that part (it's pretty intuitive)
You may want to send your mail using xp_sendmail
Check out the SQL documentation for xp_sendmail
http://msdn.microsoft.com/en-us/library/ms189505(v=sql.105).aspx
You might need to turn the feature on (afaik it's off by default) and you need some server/machine to deliver the mail (so you might need IIS and SMTP installed if on a local machine)
Edit:
Assuming you can't access the server and want to do this on the client side, you can create a .NET framework app or windows service to do the work for you using a schedule or a timer approach:
Schedule approach:
Create a simple command line application which does the query and mails the results, and use the windows scheduler to invoke it every hour (or whatever your interval may be)
Timer approach:
Create a simple application or windows service that will run a timer thread which does the work every x number of minutes
I'd probably just go for the former. The code would be quite simple - new console app:
static void Main(string args[])
{
// No arguments needed so just do the work
using(SqlConnection conn = new SqlConnection("ConnectionString"))
{
using(SqlCommand cmd = new SqlCommand("sql query text", conn))
{
var dr = cmd.ExecuteReader();
List<myClass> results = new List<myClass>();
// Read the rows
while(dr.Read())
{
var someValue = dr.GetString(dr.GetOrdinal("ColumnName"));
// etc
// stuff these values into myClass and add to the list
results.Add(new myClass(someValue));
}
}
}
if(results.Count > 0) // Send mail
{
//Send the message.
SmtpClient client = new SmtpClient(server);
// Add credentials if the SMTP server requires them.
client.Credentials = CredentialCache.DefaultNetworkCredentials;
MailMessage message = new MailMessage(
"recipient#test.com",
"sender#test.com",
"Subject",
"Body");
// Obviously you'd have to read the rows from your list, maybe override ToString() on
// myClass and call that using a StringBuilder to build the email body and append the rows
// This may throw exceptions - maybe some error handling (in any of this code) is advisable
client.Send(message);
}
}
Disclaimer: probably none of this will compile :D
Edit 2: I'd go this way as it's much easier to debug than a windows service as you can just run it from the command line. You can also pass command line arguments so you don't need an application configuration file

Powershell to find the principal/mirror in SQL servers

I would like to know if it is possible to know if a instance of sql server is in mirror/prinicipal by running any sql query? and secondly i want to run this on say 60-80 instances everyday at 4am automatically possible? I would like to use powershell used it before quite easy to use from experience. Tks
It is possible. You will need to play around with SMO objects.
$server = "dwhtest-new"
$srv = New-Object Microsoft.SqlServer.Management.Smo.Server $server
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$dbs = $srv.Databases
foreach ($db1 in $dbs)
{
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$db = $db1
$DatabaseName = $db.Name
Write-Host $DatabaseName
Write-Host "MirroringStatus:" $db.MirroringStatus
Write-Host "DBState:" $db.Status
Write-Host
}
If your DB's mirroring is still intact you will recieve 'Synchronized' for MirroringStatus and its its the Primary it will say "Normal" for the status and if its the failover it will say "Restoring". Unfortunately there is no way, that im aware of, to just pull out the status of "Mirror" or "principle". You will jsut have to build logic to check both fo those values.
Restoring
It depends on how are you going to setup the job?
If you want to run it from one central server that collects all the information then SMO would be the way to go with PowerShell. The answer provided by KickerCost can work but would need some more work to be able to run it for multiple servers. It would be best to take his example and turn it into a working function that will allow the server names to be piped in.
If you are going to just run a job locally on each server (scheduled task or SQL Agent job) that may point to the script on a network share, then maybe output that info to a file (like servername_instance.log) you can use a one-liner with SQLPS:
dir SQLSERVER:\SQL\KRINGER\Default\Databases | Select Name, MirroringStatus
KRINGER is my server name, with a default instance. If you have named instances then replace the "default" with the instance name.
Your output from this command would be similar to this:
Name MirroringStatus
---- ---------------
AdventureWorks None
AdventureWorksDW None
Obviously I don't have any databases involved in mirroring.

SQL SMO Objects SqlRestore Method (ReadFileList)

Good afternoon all-
I've searched around quite a bit, and found a few good resources on how to dynamically determine the names of the logical data file names contained within an and SQL .bak file. The SMO method Im working with requires that I pass the ServerName, however my requirement calls for passing the actual file path to the backup. I can get what I need in T-SQL, but I'd really like to determine a way to do it leveraging SMO's. Below is the T-SQL which gets me the information I require:
RESTORE FILELISTONLY
FROM N'C:\Directory\File.bak'
WITH FILE = 1
Unfortunately SqlRestore.ReadFileList(ServerName) will not work, as the backup set has not been restored to a server yet. Essentially I need this information so I can pass it to Restore.RelocateFiles.Add. I'm actually a DBA just dabbling in C#, so if you need more information just let me know and I will try to fill in the gaps. Thanks for any assistance!
The Powershell script below shows how you can read a backup file based on a file path:
$ServerName="SERVER\MYSQLSERVER"
$svrConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$svrConn.ServerInstance=$secondaryServerName
$svrConn.LoginSecure = $true
$svr = new-object Microsoft.SqlServer.Management.Smo.Server ($svrConn)
$fullResotrePath = "\\Path\MyDatabase.bak"
$res = new-object Microsoft.SqlServer.Management.Smo.Restore
$res.Devices.AddDevice($fullRestorePath, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
$dt = $res.ReadFileList($svr)
foreach($r in $dt.Rows)
{
foreach ($c in $dt.Columns)
{
Write-Host $c "=" $r[$c]
}
}