SQL Server Query in PowerShell, limit my results based on date - sql-server

I am using PowerShell to connect to a SQL Server database, and I want to limit my result.
I use the SqlServer Module, and Invoke-Sqlcmd. I don't want data where the date is older than 90 days. The following code is used to get the complete data
$DataRange = ((Get-date) + (New-TimeSpan -Days -90))
$Database = DB02_Tool.dbo.Cert
$ServerInstans = DBClu01\DbClu01Cert
$Query = "SELECT encoded, not_before, not_after FROM " + $Database
$Data = Invoke-SqlCmd -ServerInstance $ServerInstans -Query $Query -As DataRows
The limit, I want to implement is on the not_before, which is of the datatype datetime, and I want it to limit on dates not older than 90 days back, as the $Daterange is used for.How do I limit the query? Any ideas?

You can do this in the SQL Query. Using DATEADD to add or substract days, and GetDate() to get the current datetime.
$Query = "SELECT encoded, not_before, not_after FROM " + $Database + " WHERE not_before >= DATEADD(Day, -90, GetDate())"
Or you can pass in a parameter from Powershell using -Variable switch. See the example 3 in the documentation.
You first need to convert the string to a universal datetime using ToString("u")
$StringArray = "MYVAR1='$($DataRange.ToString("u"))'"
$Query = "SELECT encoded, not_before, not_after FROM " + $Database + " WHERE not_before >= `$(MYVAR1)"
$Data = Invoke-SqlCmd -ServerInstance $ServerInstans -Query $Query -Variable $StringArray -As DataRows

Related

Passing Powershell variable into a SQL INSERT

I'm quite new when it comes to Powershell and I'm not sure if my method is the best.
How can I pass Powershell variables into SQL using Invoke SQL or the .Net method? All I'm trying to do is to Insert data from the Get-AzureADGroup Display Name and Object Id into a SQL table.
$Groups = Get-AzureADGroup -All $true
foreach($Group in $Groups){
$DN = $Group.DisplayName
$ID = $Group.ObjectId
$insertquery="
INSERT INTO [dbo].[Table]([DsiplayName],[ObjectId])
VALUES(''$DN'',''$ID'')
"
Invoke-Sqlcmd -ServerInstance "Server" -Database "Database" -Query $insertquery
}
However, it comes up with the error 'Incorrect syntax near 'GroupDisplayName'. I've tried using " and ' interchangeably in the query with no luck. Am I missing something?

Invoke-Sqlcmd : Duplicate column names are not permitted in SQL PowerShell

I've spitted Glenn Berry's Performance Query in 14 queries but one of them (number 9) is not working.
This is my PowerShell code:
#Provide SQLServerName
$SQLServer ="localhost"
#Provide Database Name
$DatabaseName ="master"
#Prompt for user credentials
$credential = Get-Credential
$Query1= "-- 09 Index Sizes
-- Note: THIS IS SLOW as it reads index blocks. SAMPLED is not that high, but watch for prod I/O impact if using 'DETAILED'
SELECT DB_NAME() AS DatabaseName,
Object_name(i.object_id) AS TableName
,i.index_id, name AS IndexName
,i.type_desc
,ips.page_count, ips.compressed_page_count
,CAST(ips.avg_fragmentation_in_percent as DECIMAL(5,1)) [fragmentation_pct]
,CAST(ips.avg_page_space_used_in_percent as DECIMAL(5,1)) [page_space_used_pct]
,ips.index_depth, ips.page_count ,ips.forwarded_record_count, ips.record_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'SAMPLED') AS ips -- or SAMPLED
INNER JOIN sys.indexes AS i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
where ips.page_count > 1
ORDER BY ips.record_count desc;"
Invoke-Sqlcmd -Database $DatabaseName -ServerInstance $Server -Credential $credential -Query $Query1 | Format-Table
The error returned says:
Invoke-Sqlcmd : Duplicate column names are not permitted in SQL PowerShell. To repeat a column, use a column alias for the duplicate
column in the format Column_Name AS New_Name.
At C:\Users\FrancescoM\Desktop\CSV\Test.ps1:23 char:1
+ Invoke-Sqlcmd -Database $DatabaseName -ServerInstance $Server -Crede ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : SyntaxError: (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : DuplicateColumnNameErrorMessage,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Not sure what is the duplicate column because if I run the query called into the PowerShell script on SSMS I don't see any duplicate column:
Arrived at home I formatted the query in a decent way and thanks to Notepad++, after clicking on each column I found out that ips.page_count was called twice.
So there was indeed a column called twice.
Use the following parameter for the Invoke-Sqlcmd command.
-OutputSqlErrors $False
It will suppress the error.
Documentation:
https://learn.microsoft.com/en-us/powershell/module/sqlserver/invoke-sqlcmd?view=sqlserver-ps
You get this error when you have duplicate column names in resultset of the query.
invoke-sqlcmd : Duplicate column names are not permitted in SQL PowerShell
Suppose you used below query as to see result-set in your invoke-sqlcmd query-
select test, * from testtable
Now the test column will be duplicate in the result and invoke sqlcmd execution will fail.
To Resolve this use like this-
select test as testColumn, * from testtable

Prevent single quotes from breaking sql command

I have a powershell module that builds a string out of several variables in order to insert into sql server.
$QueryInsert =
"
insert into dbo.Table
(
data
)
values
(
'$data'
)
"
Invoke-Sqlcmd -ServerInstance 'server_name' `
-Database db_name `
-Query $QueryInsert `
-QueryTimeout 20 `
-OutputSqlErrors $True `
-ConnectionTimeout 5 `
-ErrorAction Continue
The problem with this methodology is that it's not particularly safe, and will fail if the variable $data contains any single quotes. Is there a way to prevent this? Is there a way to paramaterize this to keep it safe?
If you have access to the database, you can write the query as a stored procedure and then call the stored procedure with PowerShell. You can pass parameters to a stored procedure in a safe manner that would not allow injecting code through a string like you can with the code above.
You might want to have a look at this question to see how to write a stored procedure and also this one.
In order to call a SPROC from PowerShell, you can use code similar to this.
$sql='NameOfSprocBeingCalled'
$sqlConnection = new-object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = $SqlConnectionString
$sqlConnection.Open()
$sqlCommand = new-object System.Data.SqlClient.SqlCommand
$sqlCommand.Connection = $sqlConnection
$sqlCommand.CommandText= $sql
$sqlCommand.CommandType = [System.Data.CommandType]::StoredProcedure
$sqlCommand.Parameters.Add("#Param1",[system.data.SqlDbType]::VarChar).value =$Param1
$sqlCommand.Parameters.Add("#Param2",[system.data.SqlDbType]::VarChar).value = $EventType
$Datatable = New-Object System.Data.DataTable
$DataReader = $sqlCommand.ExecuteReader()
$Datatable.Load($DataReader)
$sqlConnection.Close()
You just need to make sure you pass in the right type for parameters, using [System.Data.SqlDbType]::
This is an enum with the following types available:
# [enum]::GetValues([System.Data.SqlDbType])
BigInt
Binary
Bit
Char
DateTime
Decimal
Float
Image
Int
Money
NChar
NText
NVarChar
Real
UniqueIdentifier
SmallDateTime
SmallInt
SmallMoney
Text
Timestamp
TinyInt
VarBinary
VarChar
Variant
Xml
Udt
Structured
Date
Time
DateTime2

Using PowerShell to Run a SQL query then insert the results into a table

I have a small PowerShell script that runs a query on about 30+ servers which pulls the server name and which version of SQL Server is installed. I then want to insert that data into a table but can't quite figure out how to do that with the returned data set my query returns. This is my code so far
$SvrNameList = #( invoke-sqlcmd -serverinstance MyServer -Database MyDB -Query "SELECT ServerName FROM ServerNames WHERE [Enabled] = 1" ) | select-object -expand ServerName
foreach ( $i in $SvrNameList )
{
invoke-sqlcmd -ServerInstance $i -Query "SELECT ##ServerName AS ServerName, ##Version AS Version"
}
Any help is appreciated
First, add the instance names and versions into a hash table. After it's populated, you can do inserts into the result table. Like so,
$ht=#{} # Create empty hashtable
foreach ( $i in $SvrNameList ){
$r = invoke-sqlcmd -ServerInstance $i -Query "SELECT s=##ServerName, v=##Version" # Query server names and versions
$ht.Add($r.s, $r.v) # Add name and version into hashtable
}
# Enumerate the hashtable and generate insert commands
$ht.GetEnumerator() | % {
invoke-sqlcmd -ServerInstance foo -query "insert into t(s, v) values ('" + $_.value + "', '"+ $_.name +"');"
}

PowerShell Code failing to retrieve the entire XML column data

I have a requirement to read a XML column from a SQL Server table, and update a table in a different SQL Server database.
Following is the simplified version of the code. What is happening is I’m NOT getting the entire XML value. I need a way to increase XML variable length. The value in $TargetXMLPValue gets truncated.
$sqlSource = "select XMLColumn from T1 where Id = 788"
$result = Invoke-Sqlcmd -ServerInstance 'SourceServer' -Query $sql -ConnectionTimeout 60 -QueryTimeout 99999
$TargetXMLValue = $result.XMLColumn
$sqlTarget = "Update t2 where AnotherXMLColumn = $TargetXMLValue where ID=788"
Invoke-Sqlcmd -ServerInstance 'TargetServer' -Query $sqlTarget -ConnectionTimeout 60 -QueryTimeout 99999
Found the answer! It is nothing to do with XML data type. I had to use MAXCHARLENGTH switch to increase the width of resulting column.
$result = Invoke-Sqlcmd -ServerInstance 'SourceServer' -Query $sql -ConnectionTimeout 60 -QueryTimeout 99999 -MaxCharLength 20000

Resources