Public/Invoke-Sql.ps1
function Invoke-Sql { <# .SYNOPSIS Runs a T-SQL script using .NET classes (default, no prerequisites needed) or sqlcmd.exe. .DESCRIPTION Runs sql command or sql script file . .OUTPUTS String if Mode = sqlcmd. System.Data.DataSet if Mode = .net. .EXAMPLE Invoke-Sql -ConnectionString $connectionString -Sql $Query-TimeoutInSeconds -SqlCmdVariables $param #> [CmdletBinding()] [OutputType([object])] param( [Parameter(Mandatory=$true)] [string] $ConnectionString, # Sql queries that will be run - need to specify either this parameter or $InputFile. [Parameter(Mandatory=$false)] [string[]] $Query, # File(s) containing sql query to run - need to specify either this parameter or $Query. [Parameter(Mandatory=$false)] [string[]] $InputFile, # Determines how the sql is run - by sqlcmd.exe or .NET SqlCommand. [Parameter(Mandatory=$false)] [string] [ValidateSet($null, 'sqlcmd', '.net')] $Mode = '.net', # Sql command mode to use if Mode = .net (NonQuery / Scalar / Dataset). Ignored if mode is different than .net. [Parameter(Mandatory=$false)] [string] [ValidateSet($null, 'NonQuery', 'Scalar', 'Dataset')] $SqlCommandMode = 'Dataset', # If set ignore errors when sqlcmd.exe is running. [Parameter(Mandatory=$false)] [bool] $IgnoreErrors, [Parameter(Mandatory=$false)] [int] $QueryTimeoutInSeconds = 3600, [Parameter(Mandatory=$false)] [int] $ConnectTimeoutInSeconds = 60, # Hashtable containing sqlcmd variables. [Parameter(Mandatory=$false)] [hashtable] $SqlCmdVariables, # Array of SqlParameters for .NET SqlCommand. [Parameter(Mandatory=$false)] [Data.SqlClient.SqlParameter[]] $SqlParameters, # Credential to impersonate in Integrated Security mode (NOTE: currently it works only when $Mode = 'sqlcmd'). [Parameter(Mandatory=$false)] [PSCredential] $Credential, # Database name to use, regardless of Initial Catalog settings in connection string. # Can also be used to remove database name from connection string (when passed empty string). [Parameter(Mandatory=$false)] [string] $DatabaseName ) if (!$Mode) { $Mode = '.net' } if (!$Query -and !$InputFile) { throw 'Missing -Query or -InputFile parameter' } if ($Mode -eq 'sqlcmd') { $sqlCmdPath = Get-CurrentSqlCmdPath if (!$sqlCmdPath) { Write-Log -Warn 'Cannot find sqlcmd.exe - falling back to .NET' $Mode = '.net' } } if ($InputFile) { foreach ($file in $Inputfile) { if (!(Test-Path -LiteralPath $file)) { throw "$InputFile does not exist. Current directory: $(Get-Location)" } } } $csb = New-Object -TypeName System.Data.SqlClient.SqlConnectionStringBuilder -ArgumentList $ConnectionString if ($PSBoundParameters.ContainsKey('DatabaseName')) { $csb.set_InitialCatalog($DatabaseName) } $params = @{ ConnectionStringBuilder = $csb IgnoreErrors = $IgnoreErrors QueryTimeoutInSeconds = $QueryTimeoutInSeconds ConnectTimeoutInSeconds = $ConnectTimeoutInSeconds SqlCmdVariables = $SqlCmdVariables Credential = $Credential } $targetLog = "$($csb.DataSource)" if ($csb.InitialCatalog) { $targetLog += " / $($csb.InitialCatalog)" } if ($Mode -eq 'sqlcmd') { foreach ($q in $Query) { $params['Query'] = $q if ($q.Trim().Length -gt 40) { $qLog = ($q.Trim().Substring(0, 40) -replace "`r", '' -replace "`n", '; ') + '...' } else { $qLog = $q.Trim() } Write-Log -_Debug "Running custom query at $targetLog using sqlcmd, QueryTimeout = $QueryTimeoutInSeconds s (${qLog}...)" Invoke-SqlSqlcmd @params } [void]($params.Remove('Query')) foreach ($file in $InputFile) { $file = (Resolve-Path -LiteralPath $file).ProviderPath $params['InputFile'] = $file Write-Log -_Debug "Running sql file '$file' at $targetLog using sqlcmd, QueryTimeout = $QueryTimeoutInSeconds s" Invoke-SqlSqlcmd @params } } elseif ($Mode -eq '.net') { $params['Mode'] = $SqlCommandMode $params['SqlParameters'] = $SqlParameters foreach ($q in $Query) { $params['Query'] = $q if ($q.Trim().Length -gt 40) { $qLog = ($q.Trim().Substring(0, 40) -replace "`r", '' -replace "`n", '; ') + '...' } else { $qLog = $q.Trim() } Write-Log -_Debug "Running custom query at $targetLog using .Net (${qLog})" Invoke-SqlDotNet @params } foreach ($file in $InputFile) { $file = (Resolve-Path -LiteralPath $file).ProviderPath Write-Log -_Debug "Running sql file '$file' at $targetLog using .Net, QueryTimeout = $QueryTimeoutInSeconds s" $params['Query'] = Get-Content -LiteralPath $file -ReadCount 0 | Out-String Invoke-SqlDotNet @params } } else { throw "Unrecognized mode: ${Mode}." } } |