I wrote a script to execute SQL query and send email to user with SQL results.
Database column has Date field in format YYYY-MM-DD hh:mm:ss:mi but the SQL result in power shell giving me the format of YYYY/MM/DD hh:mm:ss. The result is not consisting of Milliseconds and date is in different format. If I have to get milliseconds also in the result date, how should I format??
param (
[Parameter(mandatory = "true")]
[string]$sqlserver,
[Parameter(mandatory = "true")]
[string]$sqlusername,
[Parameter(mandatory = "true")]
[string]$sqlpassword,
[Parameter(mandatory = "true")]
[string]$databasename
)
$query = "select * from dbo.UserDetails where createdate > '2020-04-13' order by createdate"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$databasename'; User ID = 'sqlusername' password= '$sqlpassword'"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = $query
$DataAdapter = new-object System.Data.SqlClient.SqlDataAdapter $Command
$Dataset = new-object System.Data.Dataset
$DataAdapter.Fill($Dataset)
$Connection.Close()
$noOfRows = $Dataset.Tables[0].Rows.Count
$UserCreateDate = $Dataset.Tables[0].Rows[$noOfRows - 1].ItemArray[6]
Write-Host ("The Latest User created " + $UserCreateDate)
Output:
4/14/2020 12:25:03
Value in DB: 2020-04-14 12:25:03.6028312
Powershell is converting your SQL output into a DateTime-Object. The default output format is determined by your set culture (try (Get-Culture).datetimeformat for more informations about your settings).
There are multiple ways to get the desired output:
Format the Output to a string using the .ToString-Method:
$UserCreateDate = ($Dataset.Tables[0].Rows[$noOfRows - 1].ItemArray[6]).ToString("yyyy-MM-dd HH:mm:ss.fff")
Using Get-Date and the -Format parameter:
$UserCreateDate = Get-Date ($Dataset.Tables[0].Rows[$noOfRows - 1].ItemArray[6]) -Format "yyyy-MM-dd HH:mm:ss.fff"
Please keep in mind that both options will convert the output into a string and won't keep the DateTime-Object.
Both solutions format the datetime with a given format-string. #Lee_Dailey was so nice to point out the possible formats from the documentation here: Custom date and time format strings
Related
This question already has answers here:
How can you use an object's property in a double-quoted string?
(5 answers)
Closed 9 months ago.
This has probably been answered somewhere before, but I can't figure out how to ask google the right question. To be able to define fewer variables, I would like to be able to pass a member of a variable or array to a SQL query. As an example, I would like to be able to define something like $date = get-date and use $date.month to just pass just the month in the query.
The issues I run into is that the period used to define the member seems to break things in a SQL query. Is there a way to properly punctuate this type of variable in this situation?
For fuller context:
$ConnectionString = "Server=" + $TargetServer + ";Database=" + $TargetDatabase + ";Trusted_Connection=$true;";
$TargetConnection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString);
$TargetConnection.Open();
$date = get-date
$sql = "SELECT *
FROM [database].[dbo].[table]
where ([MONTH] = $date.month and [YEAR] = $date.year)"
$TargetCommand = New-Object System.Data.SqlClient.SqlCommand($sql, $TargetConnection);
$TargetCommand.ExecuteScalar()
$TargetConnection.Close()
The month and year columns have the values stored as int.
As I mentioned, what you have above injection, not parametrisation. You don't tell us why what you have isn't working, so this is some what of a guess, but most likely you want something like this:
$connectionString = 'Server=' + $TargetServer + ';Database=' + $TargetDatabase + ';Trusted_Connection=$true;'
$sqlConn = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
#Start a try, so that we can close the connection on error
try{
$sqlConn.Open()
$sqlCmd = $sqlConn.CreateCommand()
$sqlCmd.Connection = $sqlConn #Assign the connection to the command
$query = "SELECT *
FROM [dbo].[table] --Database isn't needed, you have defined it in your connection string
WHERE [MONTH] = #Month and [YEAR] = #Year;" #Define the query
$sqlCmd.CommandText = $query
$date = get-date #Get the current date
$sqlCmd.Parameters.Add("#Month", 8).Value = $date.month #Add Month Parameter
$sqlCmd.Parameters.Add("#Year", [System.Data.SqlDbType]::Int).Value = $date.year #Add year Parameter
#I don't know what you want to do with the data, so I put it into a data adapter
$sqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd
$dataSet = New-Object System.Data.DataSet
$sqlAdapter.Fill($dataSet)
}
finally{
if ($sqlAdapter -ne $null) { $sqlAdapter.Dispose(); }
if ($sqlConn -ne $null) { $sqlConn.Close(); }
}
$dataSet.Tables
You can get the list of the enum values for the parameter types in the documentation; note I use 8 in the above for int. AlwaysLearninghas since reminded me of the correct syntax, so I now demonstrate both. #Month passes uses an enum value, an #Year uses the name of the datatype from sqlDbType.
From the comments it seems like you want to inject; in some ways this defeats of the object of using the .Net objects. If you simply want to inject the data, the you could just use Invoke-SqlCmd:
Invoke-Sqlcmd -Query "SELECT * FROM dbo.[table] WHERE Month = $($(get-date).month) AND [Year] = $($(get-date).year);" -ServerInstance $TargetServer -Database $TargetDatabase
I'm trying to operate with the result of this query to then run an update query on specific values of the result. What i'm trying to do is to get all the values from the table and then check if those values are between 1 and 5 and turn those to null. Since i can't do this in one update query, i'm doing first a select and then operate on the singular values that i get from the result, but the query returns me a dataset result which i can't operate with in PowerShell (or at least i don't know how). What can i do? The main objective of this should be an update to all the columns of the table on the db to change the columns with values between 1 and 5 and turn them into null values
Here is the code:
$SQLServer = "Server\SQLEXPRESS"
$SQLDBName = "Prova"
$SqlQuery = "Select * from table_2 where id=1"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; trusted_connection=true;"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter.SelectCommand = $SqlCmd
$Dataset = New-Object System.Data.DataSet
$SqlAdapter.Fill($Dataset)
$array=$Dataset.Tables[0]
$SqlConnection.Close()
A fellow few-months old newbie here(me), ill try to give this a shot!
You can actually loop through the rows of the dataset you have, and access the properties (columns) in those rows, modify it and then dynamically create an update statement and execute it on your server.
The main part is presented below, the rest are just the functions i defined myself. Not sure if this is what you had in mind but my testing setup went something like this. (Note please execute/define the functions first in your powershell session before you run the code below)
# SET VARIABLES
$Serv = <Your Server>
$DB = <Your DB>
$TSQL = "SELECT * FROM TestTBL"
# Target Results table from SQL
$MainResultsTable = (GetSQLData $Serv $DB $TSQL).Tables[0]
#Get Column names
$Colnames = ($MainResultsTable.Rows | gm -MemberType NoteProperty,Property).Name
# Loop through each row of data from SQL results
foreach($row in $MainResultsTable.Rows)
{
# Construct the TSQL update statement. Using an array to construct the multi column updates.
$TSQLUpdate = "UPDATE TestTBL SET "
$TSQLUpdateArr =#()
foreach($Col in $Colnames)
{
# We don't need to update the ID
if($Col -ne 'ID')
{
$TSQLUpdateArr += "$Col = $(EvaluateColumnData $row.$Col)`n"
}
}
# join the columns with the corresponding end of TSQL where the target ID is specified
$TSQLUpdate += $($TSQLUpdateArr -join ",").ToString() + " WHERE ID = $($row.ID);"
# Execute the update on SQL server
UpdateSQL $Serv $DB $TSQLUpdate
}
Putting a few snippets of the functions I wrote for SQL here too. [Open to optimization and critics to make this faster or more 'semanticy']
# Define custom user function to set the values to be used for updating
function EvaluateColumnData()
{
param( $data )
if($data -le 5){ return "NULL" }
else { return $data }
}
# Get data from SQL
function GetSQLData()
{
param( $tgtServ,$tgtDB,$tgtTSQL )
# Create connection obj
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "server="+$tgtServ+";database="+$tgtDB+";trusted_connection=true;"
# Open SQL connection
$SqlConnection.open()
# Create TSQL CMD object and pass the connection object
$SQLCommand = New-Object System.Data.SQLClient.SQLCommand
$SQLCommand.Connection = $SqlConnection
# TSQL statement to be executed
$SQLCommand.CommandText = $tgtTSQL
$SQLCommand.CommandTimeOut = 0
# Container/adapter for SQL result
$resultAdapter = New-Object System.Data.SqlClient.SqlDataAdapter($SQLCommand)
# DataSet where the results are dumped
$resultDS = New-Object System.Data.DataSet
$resultAdapter.Fill($resultDS) | Out-Null
$SqlConnection.Close()
return ,$resultDS
}
# Execute TSQL statement without results
function UpdateSQL()
{
Param( $tgtServ,$tgtDB,$tgtTSQL )
$ServerConn = New-Object System.Data.SQLClient.SQLConnection
$ServerConn.ConnectionString = "server="+$tgtServ+";database="+$tgtDB+";trusted_connection=true;"
$ServerConn.Open()
$ServerCMD = New-Object System.Data.SQLClient.SQLCommand
$ServerCMD.Connection = $ServerConn
$ServerCMD.CommandText = $tgtTSQL
$ServerCMD.CommandTimeOut = 0
$ServerCMD.ExecuteNonQuery() | out-null
$ServerConn.Close()
}
Hope this helps. There are a lot of things out there you can read(which im still reading lol) which offers better explanation, I suggest focusing on the basics.
Recommended reading: DataTables, PS objects/Custom objects, hashtable, Functions.
I want to write a query in powerShell which checks an attribute value in an xml column called(xml_multiple) and return boolean value 1 if it exist(otherwise 0) and pass it to a variable and call a sendemail function.
According to the value of variable the email will be sent.
1- for success
0- for failure
I'm new to powershell and not very good at it. I'm open to suggestion as long it works.Thanks in advance. Check the code below and xml
$dataSource = "DB.abc.com"
$connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$query = “ ” <#here i want to write my query#>
$command = $connection.CreateCommand()
$command.CommandText = $query
$result = $command.ExecuteReader()
$table = new-object “System.Data.DataTable”
$table.Load($result)
$connection.Close()
function sendemail()
{
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = "abc#xyz.com"
if ($send -eq 1) <#here i want to pass value from db#>
{
$Mail.Subject = "Process Successful"
$Mail.Body ="Success`n`nThank you"
}
else
{
$Mail.Subject = "Process Unsuccessful"
$Mail.Body ="Unsuccess`n`nPlease look into it"
}
$Mail.Send()
}
Note: This is the xml and if any xml has a attribute start="1" return 1 else 0. for a particular day(There will be only one record in a day which will have this attribute,so we can use a filter in the query for that)
<jobparameters start="1">
<work>1
</work>
</jobparameters>
P
lease give suggestions
It is possible to get the needed results directly from SQL Server:
DECLARE #x XML = '
<jobparameters start="1">
<work>1
</work>
</jobparameters>';
DECLARE #t TABLE (xml_multiple XML);
INSERT #t(xml_multiple) VALUES(#x);
SELECT c.value('#start','INT') send
FROM #t
OUTER APPLY xml_multiple.nodes('/jobparameters')x(c);
I have a Powershell script that is successfully connecting to a SQL Server database and executing a procedure. The SQL procedure contains a select as follows:
SELECT #sql AS 'ColDemo1'
The variable #sql is nvarchar(max). I want the full contents of #sql returned to a new sql file however I only get the first line and an unwanted column heading as below:
ColDemo1
------------
First line of data...
The Powershell script is as follows:
$server = "SERVER\DEMO"
$database = "dbDemo"
$pZero = "PVal0"
$pOne = "PVal1"
$pTwo = "PVal2"
$pThree = "PVal3"
function Run-SQLUSP {
param (
$pZero,
$pOne,
$pTwo,
$pThree
)
$conn = New-Object System.Data.SqlClient.SqlConnection("Server=${server};Database='${database}';Integrated Security=TRUE")
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "dbo.demoSp '$pZero', '$pOne', '$pTwo', '$pThree'"
$adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
$dataset = New-Object System.Data.DataSet
[void]$adapter.Fill($dataset)
$dataset.tables[0]
}
Run-SQLUSP $pZero $pOne $pTwo $pThree | Out-File "c:\DemoFolder\DemoScriptName.sql" -width 8000
How can I amend my Powershell script to return all lines of the output to the new sql file? When executing the procedure in SSMS the resultset is returned in a single table cell (not multiple rows).
Two changes were required:
To avoid truncating the output: Change Out-File to Set-Content -Path and remove -width 8000.
To only return the first cell: Append .rows[0][0] to $dataset.tables[0] within the function.
Below is the revised code in full:
$server = "SERVER\DEMO"
$database = "dbDemo"
$pZero = "PVal0"
$pOne = "PVal1"
$pTwo = "PVal2"
$pThree = "PVal3"
function Run-SQLUSP {
param (
$pZero,
$pOne,
$pTwo,
$pThree
)
$conn = New-Object System.Data.SqlClient.SqlConnection("Server=${server};Database='${database}';Integrated Security=TRUE")
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "dbo.demoSp '$pZero', '$pOne', '$pTwo', '$pThree'"
$adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
$dataset = New-Object System.Data.DataSet
[void]$adapter.Fill($dataset)
$dataset.tables[0].rows[0][0]
}
Run-SQLUSP $pZero $pOne $pTwo $pThree | Set-Content -Path "c:\DemoFolder\DemoScriptName.sql"
I was having the same issue, then discovered I could fix it if I used the Column Name to access the cell value from the table row.
#Trunacted
$data.Tables[0].Rows[0][0]
#Complete data
$data.Tables[0].Rows[0]["XMLData"]
What I need to do are:
1, query a row of xml from a sql server datatable. See pic below,the Row named StageDesccontents xml file.
2, the xml file contents a path //sharespace/test1/10.0.1212.0which I need to get, this was forming as<releasepath>//sharespace/test1/10.0.1212.0</releasepath> in the xml file.
Here are my codes try to get it:
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlQuery = "SELECT Stage.Description as StageDesc,Stage.StageStatusId FROM [Build].[dbo].[WorkflowInstance_View] as Build
join [Build].[dbo].[Stage_View] as Stage on Build.Id=Stage.[WorkflowInstanceId] where Stage.ParentId is null and Stage.StageStatusId <>4 and Stage.StageStatusId <>7 order by Build.Id desc"
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $Connection
$DBResult = $sqlcmd.ExecuteReader()
$DataTable = New-Object system.data.datatable
$DataTable.load($DBResult)
foreach ($StageDesc in $DataTable) {
[XML]$ReturnedXML=$StageDesc.releasepath
}
The code passed but returned nothing. Why this happened? Could anybody would like to help me?
You're assigning your xml data to a variable $RetrunedXML and overwriting the assignment on each iteration of your foreach. Have you checked $ReturnedXML?
Using the sample database for SQL Server 2008, I can use this:
$serverName = "$env:computername\sql1"
$databaseName = "AdventureWorks"
$query = "SELECT * from Person.Contact where AdditionalContactInfo IS NOT NULL"
$conn=new-object System.Data.SqlClient.SQLConnection
$connString = “Server=$serverName;Database=$databaseName;Integrated Security=SSPI;”
$conn.ConnectionString=$connString
$conn.Open()
$cmd=new-object system.Data.SqlClient.SqlCommand($Query,$conn)
$da = New-Object “System.Data.SqlClient.SqlDataAdapter” ($cmd)
$dt = New-Object “System.Data.DataTable”
$da.fill($dt) | out-null
$conn.Close()
$dt | foreach {[xml]$ReturnedXML = $_.AdditionalContactInfo; $ReturnedXML}
All you do in the code is declaring and assigning variables. There is no code that outputs or displays anything. Nor do you return any variable. So what do you expect the code should return? In which line? Did you even try to debug the code?
$da.fill($dt)
Loads the query results into DataTable $dt.
$dt | Out-GridView
Shows all the data.
The script worked great for me (except the last line, which didn't apply for my case).