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
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?
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
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
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 +"');"
}
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