├── linux-x64
├── SQLite.Interop.dll
└── System.Data.SQLite.dll
├── dbtest.xlsx
├── Get-SQL.vsdx
├── Database1.accdb
├── GetSqlGuide.docx
├── GetSqlGuide.pdf
├── TestData.sqlite
├── osx-x64
├── SQLite.Interop.dll
└── System.Data.SQLite.dll
├── win-x64
├── SQLite.Interop.dll
└── System.Data.SQLite.dll
├── win-x86
├── SQLite.Interop.dll
└── System.Data.SQLite.dll
├── filter Test-SQlite.ps1
├── Install-SQLite.ps1
├── GetSQL.psd1
├── License.txt
├── odbcObject.Format.ps1xml
├── .vscode
└── launch.json
├── sqlServer.tests.ps1
├── ArgumentCompleters.ps1
├── Lite.tests.ps1
├── Excel.tests.ps1
├── Access.tests.ps1
└── Get-SQL.ps1
/linux-x64/SQLite.Interop.dll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dbtest.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/dbtest.xlsx
--------------------------------------------------------------------------------
/Get-SQL.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/Get-SQL.vsdx
--------------------------------------------------------------------------------
/Database1.accdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/Database1.accdb
--------------------------------------------------------------------------------
/GetSqlGuide.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/GetSqlGuide.docx
--------------------------------------------------------------------------------
/GetSqlGuide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/GetSqlGuide.pdf
--------------------------------------------------------------------------------
/TestData.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/TestData.sqlite
--------------------------------------------------------------------------------
/osx-x64/SQLite.Interop.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/osx-x64/SQLite.Interop.dll
--------------------------------------------------------------------------------
/win-x64/SQLite.Interop.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/win-x64/SQLite.Interop.dll
--------------------------------------------------------------------------------
/win-x86/SQLite.Interop.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/win-x86/SQLite.Interop.dll
--------------------------------------------------------------------------------
/osx-x64/System.Data.SQLite.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/osx-x64/System.Data.SQLite.dll
--------------------------------------------------------------------------------
/win-x64/System.Data.SQLite.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/win-x64/System.Data.SQLite.dll
--------------------------------------------------------------------------------
/win-x86/System.Data.SQLite.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/win-x86/System.Data.SQLite.dll
--------------------------------------------------------------------------------
/linux-x64/System.Data.SQLite.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jhoneill/GetSQL/HEAD/linux-x64/System.Data.SQLite.dll
--------------------------------------------------------------------------------
/filter Test-SQlite.ps1:
--------------------------------------------------------------------------------
1 | filter Test-SQlite {
2 | <#
3 | .synopsis
4 | By piping files through this command those which NOT SQlite database will be discarded
5 | .example
6 | dir '~\AppData\Local\google\chrome\User Data\Default\' -File | Test-SQlite
7 | Gives a directory listing of SQlite files in the user data for Google Chrome
8 | #>
9 | [char[]]$c = " " *16
10 | $o = $_.OpenText()
11 | [void]$o.read($c,0,16)
12 | $o.Close()
13 | if ([string]::new($c) -match "SQLite") {$_}
14 | }
--------------------------------------------------------------------------------
/Install-SQLite.ps1:
--------------------------------------------------------------------------------
1 | Install-Package -ProviderName nuget -Name System.Data.SQLite.Core -Scope CurrentUser -Verbose -Force
2 | $dir = Get-ChildItem ~\AppData\Local\PackageManagement\NuGet\Packages\Stub.System.Data.SQLite.Core.NetStandard* -Directory |
3 | Select-Object -Last 1
4 | Get-ChildItem "$dir\runtimes" -Directory | ForEach-Object {
5 | $dest = mkdir $_.name
6 | Get-ChildItem $_ -Recurse -Include *.dll | Copy-Item -Destination $dest -Verbose
7 | Copy-Item $dir\lib\netstandard2.0\System.Data.SQLite.dll -Destination $dest -Verbose
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/GetSQL.psd1:
--------------------------------------------------------------------------------
1 | @{ # This GUID was generated on 16 August 2011
2 | GUID = "{8b883169-bbd6-42bd-9121-6fdbaa5ded60}"
3 | Description = "Support for querying SQL Server, SQlite and ODBC sources."
4 | Author = "James O'Neill"
5 | Copyright = "James O'Neill 2024"
6 | ModuleVersion = "1.4.1.1"
7 | NestedModules = "Get-SQL.ps1",
8 | "ArgumentCompleters.ps1"
9 | FormatsToProcess = "odbcObject.Format.ps1xml"
10 | PowerShellVersion = "3.0"
11 | PrivateData = @{
12 | PSData = @{
13 | Tags = 'SQL','SQlite','SQLServer','MySql','Access','Excel','Database','Query'
14 | LicenseUri = 'https://opensource.org/licenses/MIT'
15 | ProjectUri = 'https://github.com/jhoneill/GetSQL'
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 | Copyright 2020 James O'Neill
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
4 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
5 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
6 | Software is furnished to do so, subject to the following conditions:
7 |
8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
11 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
13 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14 |
--------------------------------------------------------------------------------
/odbcObject.Format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OdbcConnectionTable
5 |
6 | System.Data.Odbc.OdbcConnection
7 | System.Data.SqlClient.SqlConnection
8 | System.Data.SQLite.SQLiteConnection
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | DataSource
30 |
31 |
32 | Database
33 |
34 |
35 | State
36 |
37 |
38 | ConnectionString
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Attach",
9 | "type": "coreclr",
10 | "request": "attach",
11 | "processId": "${command:pickProcess}"
12 | },
13 | {
14 | "name": "Start PowerShell",
15 | "type": "coreclr",
16 | "request": "launch",
17 | "program": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
18 | "args": [],
19 | "cwd": "${workspaceFolder}",
20 | "stopAtEntry": false,
21 | "externalConsole": true
22 | },
23 | {
24 | "type": "PowerShell",
25 | "request": "launch",
26 | "name": "PowerShell Pester Tests",
27 | "script": "Invoke-Pester",
28 | "args": ["-Script",
29 | "${file}"],
30 | "cwd": "${workspaceRoot}"
31 | },
32 | {
33 | "type": "PowerShell",
34 | "request": "launch",
35 | "name": "PowerShell Launch Current File",
36 | "script": "${file}",
37 | "args": [],
38 | "cwd": "${file}"
39 | },
40 | {
41 | "type": "PowerShell",
42 | "request": "launch",
43 | "name": "PowerShell Launch Current File in Temporary Console",
44 | "script": "${file}",
45 | "args": [],
46 | "cwd": "${file}",
47 | "createTemporaryIntegratedConsole": true
48 | },
49 | {
50 | "type": "PowerShell",
51 | "request": "launch",
52 | "name": "PowerShell Launch Current File w/Args Prompt",
53 | "script": "${file}",
54 | "args": [
55 | "${command:SpecifyScriptArgs}"
56 | ],
57 | "cwd": "${file}"
58 | },
59 | {
60 | "type": "PowerShell",
61 | "request": "attach",
62 | "name": "PowerShell Attach to Host Process",
63 | "processId": "${command:PickPSHostProcess}",
64 | "runspaceId": 1
65 | },
66 | {
67 | "type": "PowerShell",
68 | "request": "launch",
69 | "name": "PowerShell Interactive Session",
70 | "cwd": "${workspaceRoot}"
71 | }
72 | ]
73 | }
--------------------------------------------------------------------------------
/sqlServer.tests.ps1:
--------------------------------------------------------------------------------
1 | # This was written to test against databases keeping call data records for Skype for business.
2 | # At some point I will replace it with a more generic SQL database test.
3 | Describe "Connect to and query SQL Server " {
4 |
5 | BeforeAll {
6 | $tableName = "CallType"
7 | $fieldName1 = "CallType" #Must be a name used to test wild card
8 | $fieldName2 = "CallTypeId" #Test for values 2,3,4
9 | $dbName = "LcsCDR"
10 | $sessionName = "LcsCDR"
11 | $sqlconn = "bp1xeucc023"
12 | $End = [datetime]::Now ;
13 | $Start = $End.AddHours(-1)
14 | $ArbitrarySQL = "exec dbo.CdrP2PSessionList @_StartTime ='" + $Start.ToString("yyyy-MM-dd HH:mm") + "', @_EndTime ='" + $End.ToString("yyyy-MM-dd HH:mm") + "'"
15 | $session = Get-SQL -MSSqlServer -Connection $sqlconn -use $dbName -Session $sessionName -ForceNew }
16 |
17 | It "Creates a PowerShell alias, matching the session name '$sessionName'" {
18 | {Get-Alias -Name $sessionName} | Should -not -throw
19 | (invoke-command -ScriptBlock ([scriptblock]::Create("$sessionname")) ).database | Should -Be $sessionName
20 | }
21 | It "Creates an open session in `$DBSessions, named '$sessionName'" {
22 | $DbSessions["$sessionName"].State | Should -Be "Open"
23 | }
24 | It "Can select a database using the -USE Alias" {
25 | $DbSessions["$sessionName"].database | Should -Be $dbName
26 | }
27 | It "Can show tables in the database" {
28 | (Get-SQL -Session $sessionName -ShowTables ).Count | Should -BeGreaterThan 0
29 | }
30 | It "Can describe the fields in the table [$tableName]" {
31 | (Get-SQL -Session $sessionName -Describe $tableName ).Count | Should -BeGreaterThan 0
32 | }
33 | It "Can return the [whole] table [$tableName]" {
34 | (Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -BeGreaterThan 0
35 | }
36 | It "Can run abritrary SQL as passed as via the pipe" {
37 | ($ArbitrarySQL | Get-SQL -Session $sessionName -Quiet ).Count | Should -BeGreaterThan 0
38 | }
39 | It "Can run abritrary SQL as passed as a parameter" {
40 | (Get-SQL -Session $sessionName -Quiet $ArbitrarySQL ).Count | Should -BeGreaterThan 0
41 | }
42 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters" {
43 | (Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldName1 `
44 | -Distinct -OrderBy $fieldName1 -Where $fieldName2 -gt 0 ).Count | Should -BeGreaterThan 0
45 | }
46 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters, and values for where condition Piped " {
47 | (2,3,4 |
48 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldName1 `
49 | -Distinct -OrderBy $fieldName1 -Where $fieldName2 -eq ).Count | Should -BeGreaterThan 0
50 | }
51 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters and where condition piped " {
52 | ("=2","=3",">=4" |
53 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldName1 `
54 | -Distinct -OrderBy $fieldName1 -Where $fieldName2 ).Count | Should -BeGreaterThan 0
55 | }
56 | It "Can run a SELECT query with -Select, -Distinct and -OrderBy parameters and WHERE... clause piped " {
57 | ("Where $fieldName2 =2","Where $fieldName2 =3","Where $fieldName2 >=4" |
58 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldName1 `
59 | -Distinct -OrderBy $fieldName1 ).Count | Should -BeGreaterThan 0
60 | }
61 | It "Can run a SELECT query with the WHERE... clause piped but no -Select, -Distinct or -OrderBy " {
62 | ("Where $fieldName2 =2","Where $fieldName2 =3","Where $fieldName2 >=4" |
63 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -BeGreaterThan 0
64 | }
65 | It "Can run a SELECT query with multiple fields in -Select and -OrderBy" {
66 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldName1,
67 | $fieldName2 -OrderBy $fieldName1, $fieldName2 ).Count | Should -BeGreaterThan 0
68 | }
69 | It "Can run a SELECT query with -Select holding a 'Top' clause " {
70 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "Top 5 *" `
71 | -OrderBy $fieldName1,$fieldName2 ).Count | Should -BeGreaterThan 0
72 | }
73 | It "Can run a SELECT query with a different final clause (e.g. 'order by') as a parameter " {
74 | ( Get-SQL -Session $sessionName -Quiet `
75 | -Table $tableName "order by $fieldName1 " ).Count | Should -BeGreaterThan 0
76 | }
77 | It "Can run a SELECT query with a different final clause piped " {
78 | ("order by $fieldName1 " |
79 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -BeGreaterThan 0
80 | }
81 | It "Can run a SELECT ... WHERE ... LIKE query with 'naked' syntax and translate * as a wildcard" {
82 | ( SQL -Session $sessionName -Quiet -Select CallType,CallTypeId `
83 | -From CallType -Where CallType -Like audio* ).Count | Should -BeGreaterThan 0
84 | }
85 | It "Can run a SELECT query with a date object as a value for where, -GroupBy and both fieldName & aggreate function in -Select " {
86 | ( Get-SQL -Session $sessionname -Quiet -Table "Registration" -Select RegistrarId,
87 | "Count(*) As total" -Where "RegisterTime" -GT ([datetime]::Today) `
88 | -GroupBy "RegistrarId" ).Count | Should -BeGreaterThan 0
89 | }
90 | It "Can add a row to a table" {} -Pending
91 | It "Can Delete a row from a table" {} -Pending
92 | It "Can Change a row in a table" {} -Pending
93 |
94 | AfterAll {Get-Sql -Session $sessionName -Close }
95 | }
96 |
--------------------------------------------------------------------------------
/ArgumentCompleters.ps1:
--------------------------------------------------------------------------------
1 | function SQLDBSourceCompletion {
2 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
3 | (get-item 'HKLM:\SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources','HKCU:\software\ODBC\ODBC.INI\ODBC Data Sources' -ErrorAction SilentlyContinue).Property.Where({$_ -notmatch " Files$" -and $_ -like "$wordToComplete*" }) |
4 | Sort-Object | ForEach-Object {
5 | $tooltip = (Get-ItemProperty -name $_ -path 'HKLM:\SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources', 'HKCU:\software\ODBC\ODBC.INI\ODBC Data Sources' -ErrorAction SilentlyContinue).$_
6 | New-Object System.Management.Automation.CompletionResult "DSN=$_", "DSN=$_", ([System.Management.Automation.CompletionResultType]::ParameterValue) , $tooltip
7 | }
8 | }
9 |
10 | function SQLDBSessionCompletion {
11 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
12 | $Global:DbSessions.Keys | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object | ForEach-Object {
13 | New-Object System.Management.Automation.CompletionResult $_,$_, ([System.Management.Automation.CompletionResultType]::ParameterValue) , $_
14 | }
15 | }
16 |
17 | function SQLDBNameCompletion {
18 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
19 | $cmdnameused = $commandAst.toString() -replace "^(.*?)\s.*$",'$1'
20 | if ($Global:DbSessions[$cmdnameused]) {
21 | $session = $cmdnameused
22 | }
23 | else { $session = $(if($fakeBoundParameter['Session']) {$fakeBoundParameter['Session']} else {'Default'} ) }
24 | if ($DbSessions[$session] -is [System.Data.SqlClient.SqlConnection]) {
25 | $dbList = (Get-SQL -Session $session -SQL "SELECT name FROM sys.databases" -Quiet).name
26 | }
27 | else { $dblist = (Get-SQL -Session $session -SQL "show databases" -quiet).database}
28 |
29 | $dblist | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object | ForEach-Object {
30 | New-Object System.Management.Automation.CompletionResult $_,$_, ([System.Management.Automation.CompletionResultType]::ParameterValue) , $_
31 | }
32 | }
33 |
34 | function SQLTableNameCompletion {
35 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
36 | $cmdnameused = $commandAst.toString() -replace "^(.*?)\s.*$",'$1'
37 | if ($Global:DbSessions[$cmdnameused]) {
38 | $session = $cmdnameused
39 | }
40 | else { $session = $(if($fakeBoundParameter['Session']) {$fakeBoundParameter['Session']} else {'Default'} ) }
41 | if (-not $global:DbSessions[$session] -and $fakeBoundParameter['Connection'] ) {
42 | Get-SQL -Connection $fakeBoundParameter['Connection'] -Session $session | Out-Null
43 | }
44 | if ( $global:DbSessions[$session] ) {
45 | $wordToComplete = ($wordToComplete -replace "^`"|^'|'$|`"$", '' )
46 | Get-SQL -Session $session -Showtables | Where-Object { $_ -like "*$wordToComplete*" } | Sort-Object | ForEach-Object {
47 | $display = $_ -replace "^\[(.*)\]$",'$1' -replace "^'(.*)'$",'$1'
48 | $returnValue = """$_"""
49 | New-Object -TypeName System.Management.Automation.CompletionResult -ArgumentList $returnValue,
50 | $display , ([System.Management.Automation.CompletionResultType]::ParameterValue) ,$display
51 | }
52 | }
53 | }
54 |
55 | function SQLFieldNameCompletion {
56 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
57 | $TableName = $fakeBoundParameter['Table']
58 | $cmdnameused = $commandAst.toString() -replace "^(.*?)\s.*$",'$1'
59 | if ($Global:DbSessions[$cmdnameused]) {
60 | $session = $cmdnameused
61 | }
62 | else {
63 | $session = $(if($fakeBoundParameter['Session']) {$fakeBoundParameter['Session']} else {'Default'} ) }
64 | $wordToComplete = ($wordToComplete -replace "^`"|^'|'$|`"$", '' )
65 | Get-SQL -Session $session -describe $TableName | Where-Object { $_.column_name -like "*$wordToComplete*" } | Sort-Object -Property column_name |
66 | ForEach-Object {
67 | $display = $_.COLUMN_NAME -replace "^\[(.*)\]$",'$1' -replace "^'(.*)'$",'$1'
68 | $returnValue = '"' + $_.COLUMN_NAME + '"'
69 | New-Object -TypeName System.Management.Automation.CompletionResult -ArgumentList $returnValue,
70 | $display , ([System.Management.Automation.CompletionResultType]::ParameterValue) ,$display
71 | }
72 | }
73 |
74 |
75 | #In PowerShell 3 and 4 Register-ArgumentCompleter is part of TabExpansion ++. From V5 it is part of Powershell.core
76 | if (Get-Command -ErrorAction SilentlyContinue -name Register-ArgumentCompleter) {
77 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Connection' -ScriptBlock $Function:SQLDBSourceCompletion #-Description 'Selects an ODBC Data Source'
78 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Session' -ScriptBlock $Function:SQLDBSessionCompletion #-Description 'Selects a session already opend by Get-SQL '
79 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'changeDB' -ScriptBlock $Function:SQLDBNameCompletion #-Description 'Selects an alternate Database available in a session'
80 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Table' -ScriptBlock $Function:SQLTableNameCompletion #-Description 'Complete Table names'
81 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Insert' -ScriptBlock $Function:SQLTableNameCompletion #-Description 'Complete Table names'
82 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Describe' -ScriptBlock $Function:SQLTableNameCompletion #-Description 'Complete Table names'
83 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Where' -ScriptBlock $Function:SQLFieldNameCompletion #-Description 'Complete Field names'
84 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Set' -ScriptBlock $Function:SQLFieldNameCompletion #-Description 'Complete Field names'
85 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Set' -ScriptBlock $Function:SQLFieldNameCompletion #-Description 'Complete Field names'
86 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'Select' -ScriptBlock $Function:SQLFieldNameCompletion #-Description 'Complete Field names'
87 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'GroupBy' -ScriptBlock $Function:SQLFieldNameCompletion #-Description 'Complete Field names'
88 | Register-ArgumentCompleter -CommandName 'Get-SQL' -ParameterName 'OrderBy' -ScriptBlock $Function:SQLFieldNameCompletion #-Description 'Complete Field names'
89 | }
--------------------------------------------------------------------------------
/Lite.tests.ps1:
--------------------------------------------------------------------------------
1 |
2 | Describe "Connect to and query Excel Spreadsheet " {
3 |
4 | BeforeAll {
5 | $sessionName = "lite"
6 | $liteconn = ".\TestData.sqlite"
7 | $tableName = "F1Results"
8 | $ArbitrarySQL = "SELECT * from $tableName"
9 | $fieldname1 = "Driver"
10 | $fieldname2 = "Points"
11 | $session = Get-SQL -Lite -Connection $liteConn -Session $sessionName -ForceNew
12 | }
13 |
14 | It "Creates a PowerShell alias, matching the session name '$sessionName'" {
15 | {Get-Alias -Name $sessionName} | Should -not -throw
16 | (invoke-command -ScriptBlock ([scriptblock]::Create("$sessionname")) ).database | Should -be 'main'
17 | }
18 | It "Creates an open session in `$DBSessions, named '$sessionName'" {
19 | $DbSessions["$sessionName"].State | Should -be "Open"
20 | }
21 | It "Can show tables in the database" {
22 | (Get-SQL -Session $sessionName -ShowTables ).Count | Should -beGreaterThan 0
23 | }
24 | It "Can describe the fields in the table $tableName" {
25 | (Get-SQL -Session $sessionName -Describe $tableName ).Count | Should -beGreaterThan 0
26 | }
27 | It "Can return the [whole] table $tableName" {
28 | (Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -beGreaterThan 0
29 | }
30 | It "Can return the [whole] table $tableName and capture the data table in a variable " {
31 | [void](Get-Sql -Session $sessionName -Quiet -Table $tableName -OutputVariable Table )
32 | $table.GetType().fullname | Should -be "System.Data.DataTable"
33 | }
34 | It "Can run abritrary SQL as passed as via the pipe" {
35 | ($ArbitrarySQL | Get-SQL -Session $sessionName -Quiet ).Count | Should -beGreaterThan 0
36 | }
37 | It "Can run abritrary SQL as passed as a parameter" {
38 | (Get-SQL -Session $sessionName -Quiet $ArbitrarySQL ).Count | Should -beGreaterThan 0
39 | }
40 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters" {
41 | (Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 -GT 20 ).Count | Should -beGreaterThan 0
42 | }
43 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters, and values for where condition Piped " {
44 | (5,10 , 20 |
45 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 -GT ).Count | Should -beGreaterThan 0
46 | }
47 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters and where condition piped " {
48 | ("> 5","> 10",">= 20" |
49 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 ).Count | Should -beGreaterThan 0
50 | }
51 | It "Can run a SELECT query with -Select, -Distinct and -OrderBy parameters and WHERE... clause piped " {
52 | ("Where Points >5 ","Where Points >10","Where Points >= 20" |
53 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 ).Count | Should -beGreaterThan 0
54 | }
55 | It "Can run a SELECT query with the WHERE... clause piped but no -Select, -Distinct or -OrderBy " {
56 | ("Where Points >5 ","Where Points >10","Where Points >= 20" |
57 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -beGreaterThan 0
58 | }
59 | It "Can run a SELECT query with multiple fields in -Select and -OrderBy" {
60 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "Race",$fieldname1 -OrderBy $fieldname2,"GridPosition" ).Count | Should -beGreaterThan 0
61 | }
62 | It "Can run a SELECT query with -Select holding a date formula" { #SQlite doesn't support "Top"
63 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "datetime(date, 'unixepoch') as RaceDate","*" -OrderBy $fieldname1 ).Count | Should -beGreaterThan 0
64 | }
65 | It "Can run a SELECT query with a different final clause (e.g. 'order by') as a parameter " {
66 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName "order by $fieldname1 " ).Count | Should -beGreaterThan 0
67 | }
68 | It "Can run a SELECT query with a different final clause piped " {
69 | ("order by $fieldname1 " |
70 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -beGreaterThan 0
71 | }
72 | It "Can run a SELECT ... WHERE ... LIKE query with 'naked' syntax and translate * as a wildcard" {
73 | (sql -Session $sessionName -Select Race,GridPosition,Points -from "F1Results" -Where Driver -like "Lewis*" -Quiet ).Count | Should -beGreaterThan 0
74 | }
75 | It "Can run a SELECT Query with -GroupBy and both fieldName & aggreate function in -Select " {
76 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -select $fieldname1,"Count(*) as total" -GroupBy $fieldname1 ).Count | Should -beGreaterThan 0
77 | }
78 | It "Can INSERT rows into a table via the pipeline or a parameter and translate dates" {
79 | $raceResult = @{Race="Portugese"; Date=([datetime]"2020-10-25"); Driver="Lewis Hamilton"; Team="Mercedes";FinishPosition=1;GridPosition=1;Points=26}
80 | $raceResult | Get-sql -Session $sessionName -Insert $tableName
81 | Get-sql -Session $sessionName -Insert $tableName $raceResult
82 | (Get-sql -Session $sessionName -table $tableName -where "date" -eq $raceResult.Date.Subtract([datetime]::UnixEpoch).totalseconds -Quiet).Count | Should -be 2
83 | }
84 | # Excel Driver doens not support "Can Delete a row from a table"
85 | It "Can SET new values in a row in a table" {
86 | Get-SQL -Session $sessionName -Table $tableName -WHERE "Race" -eq "Portugese"`
87 | -set "Race" -Values "Portugal" -Confirm:$false
88 | $new = Get-SQL -Session $sessionName -Table $tableName -WHERE "Race" -eq "Portugal" -Quiet
89 | $New.count | Should -be 2
90 | $new[0].Points | Should -be 26
91 | }
92 |
93 | It "Can Delete rows from a table" {
94 | Get-SQL -Session $sessionName -Table $tableName -WHERE "Race" -eq "Portugal" -Delete -Confirm:$false
95 | $new = Get-SQL -Session $sessionName -Table $tableName -WHERE "Race" -eq "Portugal" -Quiet
96 |
97 | $new | Should -BeNullOrEmpty
98 | }
99 |
100 |
101 |
102 | AfterAll {Get-Sql -Session $sessionName -Close }
103 | }
104 |
--------------------------------------------------------------------------------
/Excel.tests.ps1:
--------------------------------------------------------------------------------
1 |
2 | Describe "Connect to and query Excel Spreadsheet " {
3 |
4 | BeforeAll {
5 | $sessionName = "XL"
6 | $xlconn = ".\dbtest.xlsx "
7 | $tableName = "[TestData$]"
8 | $ArbitrarySQL = "SELECT * from $tableName"
9 | $fieldname1 = "Extension"
10 | $fieldname2 = "Length"
11 | $session = Get-SQL -Excel -Connection $xlconn -Session $sessionName -ForceNew
12 | }
13 |
14 | It "Creates a PowerShell alias, matching the session name '$sessionName'" {
15 | {Get-Alias -Name $sessionName} | Should -not -throw
16 | (invoke-command -ScriptBlock ([scriptblock]::Create("$sessionname")) ).database | Should -be (Resolve-Path $xlconn).Path.Trim()
17 | }
18 | It "Creates an open session in `$DBSessions, named '$sessionName'" {
19 | $DbSessions["$sessionName"].State | Should -be "Open"
20 | }
21 | It "Can show tables in the database" {
22 | (Get-SQL -Session $sessionName -ShowTables ).Count | Should -beGreaterThan 0
23 | }
24 | It "Can describe the fields in the table $tableName" {
25 | (Get-SQL -Session $sessionName -Describe $tableName ).Count | Should -beGreaterThan 0
26 | }
27 | It "Can return the [whole] table $tableName" {
28 | (Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -beGreaterThan 0
29 | }
30 | It "Can return the [whole] table $tableName and capture the data table in a variable " {
31 | [void](Get-Sql -Session $sessionName -Quiet -Table $tableName -OutputVariable Table )
32 | $table.GetType().fullname | Should -be "System.Data.DataTable"
33 | }
34 | It "Can run abritrary SQL as passed as via the pipe" {
35 | ($ArbitrarySQL | Get-SQL -Session $sessionName -Quiet ).Count | Should -beGreaterThan 0
36 | }
37 | It "Can run abritrary SQL as passed as a parameter" {
38 | (Get-SQL -Session $sessionName -Quiet $ArbitrarySQL ).Count | Should -beGreaterThan 0
39 | }
40 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters" {
41 | (Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 -GT 500 ).Count | Should -beGreaterThan 0
42 | }
43 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters, and values for where condition Piped " {
44 | (500,1000 , 10000 |
45 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 -GT ).Count | Should -beGreaterThan 0
46 | }
47 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters and where condition piped " {
48 | ("> 500","> 1000",">= 10000" |
49 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 ).Count | Should -beGreaterThan 0
50 | }
51 | It "Can run a SELECT query with -Select, -Distinct and -OrderBy parameters and WHERE... clause piped " {
52 | ("Where Length >500 ","Where Length >1000","Where Length >= 10000" |
53 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 ).Count | Should -beGreaterThan 0
54 | }
55 | It "Can run a SELECT query with the WHERE... clause piped but no -Select, -Distinct or -OrderBy " {
56 | ("Where Length >500 ","Where Length >1000","Where Length >= 10000" |
57 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -beGreaterThan 0
58 | }
59 | It "Can run a SELECT query with multiple fields in -Select and -OrderBy" {
60 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "Name",$fieldname1 -OrderBy $fieldname1,$fieldname2 ).Count | Should -beGreaterThan 0
61 | }
62 | It "Can run a SELECT query with -Select holding a 'Top' clause " {
63 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "Top 5 *" -OrderBy $fieldname1,$fieldname2 ).Count | Should -beGreaterThan 0
64 | }
65 | It "Can run a SELECT query with a different final clause (e.g. 'order by') as a parameter " {
66 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName "order by $fieldname1 " ).Count | Should -beGreaterThan 0
67 | }
68 | It "Can run a SELECT query with a different final clause piped " {
69 | ("order by $fieldname1 " |
70 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -beGreaterThan 0
71 | }
72 | It "Can run a SELECT ... WHERE ... LIKE query with 'naked' syntax and translate * as a wildcard" {
73 | (sql -Session $sessionName -Select Name,Length,LastWriteTime -from [TestData$] -Where Extension -like ".ps*" -Quiet ).Count | Should -beGreaterThan 0
74 | }
75 | It "Can run a SELECT Query with a date object as a parameter, -GroupBy and both fieldName & aggreate function in -Select " {
76 | (Get-SQL -Session $sessionName -Quiet -Table $tableName -Where "CreationTime" -LT ([datetime]::Now).AddDays(-3) `
77 | -select $fieldname1,"Count(*) as total" -GroupBy $fieldname1 ).Count | Should -beGreaterThan 0
78 | }
79 | It "Can INSERT rows into a table via the pipeline or a parameter" {
80 | $dirEntry = Get-Item (Get-Command -name powershell).Source | Select-Object -Property * -ExcludeProperty mod*
81 | $dirEntry, $dirEntry | Get-sql -Session $sessionName -Insert $tableName
82 | Get-sql -Session $sessionName -Insert $tableName $dirEntry
83 | (Get-sql -Session $sessionName -table $tableName -where "PSPath" -eq $dirEntry.PSPath -Quiet ).Count | Should -beGreaterThan 0
84 | }
85 | # Excel Driver doens not support "Can Delete a row from a table"
86 | It "Can SET new values in a row in a table" {
87 | $old = Get-SQL -Session $sessionName -Table $tableName -Select "top 1 *" -Quiet
88 | Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc `
89 | -set "Attributes" -Values "Modified" -Confirm:$false
90 | $new = Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc -Quiet
91 | $new.PSPath | Should -be $old.PSPath
92 | $new.Attributes | Should -be "Modified"
93 |
94 | Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc `
95 | -set "Attributes" -Values $old.Attributes -Confirm:$false
96 | $end = Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc -Quiet
97 | $end.attributes | Should -be $old.Attributes
98 | }
99 |
100 | AfterAll {Get-Sql -Session $sessionName -Close }
101 | }
102 |
--------------------------------------------------------------------------------
/Access.tests.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments","")]
3 | Param()
4 |
5 | Describe "Connect to and query Access Database " {
6 |
7 | BeforeAll {
8 | $sessionName = "ACCESS"
9 | $ACCconn = ".\Database1.accdb"
10 | $tableName = "TestData"
11 | $ArbitrarySQL = "SELECT * from $tableName"
12 | $fieldname1 = "Extension"
13 | $fieldname2 = "Length"
14 | $null = Get-SQL -Access -Connection $ACCconn -Session $sessionName -ForceNew
15 | }
16 |
17 | It "Creates a PowerShell alias, matching the session name '$sessionName'" {
18 | {Get-Alias -Name $sessionName} | Should -not -throw
19 | (invoke-command -ScriptBlock ([scriptblock]::Create("$sessionname")) ).database | Should -Be (Resolve-Path $ACCconn).Path.Trim()
20 | }
21 | It "Creates an open session in `$DBSessions, named '$sessionName'" {
22 | $DbSessions["$sessionName"].State | Should -Be "Open"
23 | }
24 | It "Can show tables in the database" {
25 | (Get-SQL -Session $sessionName -ShowTables ).Count | Should -BeGreaterThan 0
26 | }
27 | It "Can describe the fields in the table $tableName" {
28 | (Get-SQL -Session $sessionName -Describe $tableName ).Count | Should -BeGreaterThan 0
29 | }
30 | It "Can return the [whole] table $tableName" {
31 | (Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -BeGreaterThan 0
32 | }
33 | It "Can return the [whole] table $tableName and capture the data table in a variable " {
34 | [void](Get-Sql -Session $sessionName -Quiet -Table $tableName -OutputVariable Table )
35 | $table.GetType().fullname | Should -Be "System.Data.DataTable"
36 | }
37 | It "Can run abritrary SQL as passed as via the pipe" {
38 | ($ArbitrarySQL | Get-SQL -Session $sessionName -Quiet ).Count | Should -BeGreaterThan 0
39 | }
40 | It "Can run abritrary SQL as passed as a parameter" {
41 | ( Get-SQL -Session $sessionName -Quiet $ArbitrarySQL ).Count | Should -BeGreaterThan 0
42 | }
43 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters" {
44 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 -GT 500 ).Count | Should -BeGreaterThan 0
45 | }
46 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters, and values for where condition Piped " {
47 | (500,1000 , 10000 |
48 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 -GT ).Count | Should -BeGreaterThan 0
49 | }
50 | It "Can run a SELECT query with -Select, -Distinct, -OrderBy and -Where parameters and where condition piped " {
51 | ("> 500","> 1000",">= 10000" |
52 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 -Where $fieldname2 ).Count | Should -BeGreaterThan 0
53 | }
54 | It "Can run a SELECT query with -Select, -Distinct and -OrderBy parameters and WHERE... clause piped " {
55 | ("Where Length >500 ","Where Length >1000","Where Length >= 10000" |
56 | Get-SQL -Session $sessionName -Quiet -Table $tableName -Select $fieldname1 -Distinct -OrderBy $fieldname1 ).Count | Should -BeGreaterThan 0
57 | }
58 | It "Can run a SELECT query with the WHERE... clause piped but no -Select, -Distinct or -OrderBy " {
59 | ("Where Length >500 ","Where Length >1000","Where Length >= 10000" |
60 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -BeGreaterThan 0
61 | }
62 | It "Can run a SELECT query with multiple fields in -Select and -OrderBy" {
63 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "Name",$fieldname1 -OrderBy $fieldname1,$fieldname2 ).Count | Should -BeGreaterThan 0
64 | }
65 | It "Can run a SELECT query with -Select holding a 'Top' clause " {
66 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Select "Top 5 *" -OrderBy $fieldname1,$fieldname2 ).Count | Should -BeGreaterThan 0
67 | }
68 | It "Can run a SELECT query with a different final clause (e.g. 'order by') as a parameter " {
69 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName "order by $fieldname1 " ).Count | Should -BeGreaterThan 0
70 | }
71 | It "Can run a SELECT query with a different final clause piped " {
72 | ("order by $fieldname1 " |
73 | Get-SQL -Session $sessionName -Quiet -Table $tableName ).Count | Should -BeGreaterThan 0
74 | }
75 | It "Can run a SELECT ... WHERE ... LIKE query with 'naked' syntax and translate * as a wildcard" {
76 | ( Get-SQL -Session $sessionName -Select Name,Length,LastWriteTime -from TestData -Where Extension -like ".ps*" -Quiet ).Count | Should -BeGreaterThan 0
77 | }
78 | It "Can run a SELECT Query with a date object as a parameter, -GroupBy and both fieldName & aggreate function in -Select " {
79 | ( Get-SQL -Session $sessionName -Quiet -Table $tableName -Where "CreationTime" -LT ([datetime]::Now).AddDays(-3) `
80 | -select $fieldname1,"Count(*) as total" -GroupBy $fieldname1 ).Count | Should -BeGreaterThan 0
81 | }
82 | It "Can INSERT rows via the pipeline or a parameter" {
83 | $dirEntry = Get-Item (Get-Command -name powershell).Source | Select-Object -Property * -ExcludeProperty mod*
84 | $dirEntry, $dirEntry | Get-sql -Session $sessionName -Insert $tableName
85 | Get-SQL -Session $sessionName -Insert $tableName $dirEntry
86 | ( Get-SQL -Session $sessionName -Table $tableName -Where "PSPath" -EQ $dirEntry.PSPath -Quiet ).Count | Should -BeGreaterThan 0
87 | }
88 | It "Can DELETE rows from a table " {
89 | $dirEntry = Get-Item (Get-Command -name powershell).Source | Select-Object -Property * -ExcludeProperty mod*
90 | $dirEntry, $dirEntry | Get-sql -Session $sessionName -Insert $tableName
91 | Get-SQL -Session $sessionName -Table $tableName -where "PSPath" -EQ $dirEntry.PSPath -Delete -Confirm:$false
92 | ( Get-SQL -Session $sessionName -Table $tableName -where "PSPath" -EQ $dirEntry.PSPath -Quiet ).Count | Should -Be 0
93 | }
94 | It "Can SET values in a row in a table" {
95 | $old = Get-SQL -Session $sessionName -Table $tableName -Select "top 1 *" -Quiet
96 | Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc `
97 | -set "Attributes" -Values "Modified" -Confirm:$false
98 | $new = Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc -Quiet
99 | $new.PSPath | Should -Be $old.PSPath
100 | $new.Attributes | Should -Be "Modified"
101 | Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc `
102 | -set "Attributes" -Values $old.Attributes -Confirm:$false
103 | $end = Get-SQL -Session $sessionName -Table $tableName -WHERE "Format(LastWriteTimeUtc)" -eq $old.LastWriteTimeUtc -Quiet
104 | $end.attributes | Should -Be $old.Attributes
105 | }
106 |
107 | AfterAll {Get-Sql -Session $sessionName -Close }
108 | }
109 |
--------------------------------------------------------------------------------
/Get-SQL.ps1:
--------------------------------------------------------------------------------
1 | if (-not $Global:DbSessions ) { $Global:DbSessions = @{} } #I have supressed warnings about global variables, this needs to be accessible inside and outside the module.
2 |
3 | function Get-SQL {
4 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword','',Justification='The Credential parameter accepts a SQL cred or a PS cred but not a string')]
5 | <#
6 | .Synopsis
7 | Queries an ODBC, SQLite or SQL Server database
8 | .Description
9 | Get-SQL queries SQL databases using either ODBC, the ADO driver for SQLite or the native SQL-Server client.
10 | Connections to databases are kept open and reused to avoid the need to make connections for every query,
11 | but the first time the command is run it needs a connection string; this come from $DefaultDBConnection.
12 | (e.g. set in your Profile) rather than being passed as a parameter: if it is set you can run
13 | sql "Select * From Customers"
14 | without any other setup, PowerShell will assume "sql" means "GET-SQL" if there is no other command named SQL.
15 |
16 | Get-SQL -Connection allows a connection to be specified explicitly; -MsSQLserver forces the use of
17 | the native SQL Server driver, -lite allows the file name of a SQLite Database to be used
18 | and -Excel or -Access allow a file name to be used without converting it into an ODBC connection string.
19 |
20 | Multiple named sessions may be open concurrently, and the global variable $DbSessions holds objects
21 | for each until Get-SQL is run with -Close. Note that you can run a query and make and/or close
22 | the connection in a single command. However, if you pipe the output into a command like
23 | Select-Object -First 2 then when Get-SQL is stopped by the downstream command it is unable to
24 | close the connection.
25 |
26 | Get-Sql will also build simple queries, for example
27 | Get-SQL -Table Authors
28 | Will run the "Select * from Authors" and a condition can be specified with
29 | Get-SQL -Table Authors -Where Name -like "*Smith"
30 | Get-SQL -ShowTables will show the available tables, and Get-SQL -Describe Authors will show the design of the table.
31 |
32 | Argument completers fill in names of ODBC connections, databases, tables, and columns where needed.
33 | .Parameter SQL
34 | A SQL statement. If other parameters (such as -Table, or -Where) are provided, it becomes the end of the SQL statement.
35 | If no statement is provided, or none can be built from the other parameters, Get-SQL returns information about the connection.
36 | .Parameter Connection
37 | An ODBC connection string or an Access, Excel, or SQLite file name or the name of a SQL Server
38 | It can be in the form "DSN=LocallyDefinedDSNName;" or
39 | "Driver={MySQL ODBC 5.1 Driver};SERVER=192.168.1.234;PORT=3306;DATABASE=xstreamline;UID=johnDoe;PWD=password;"
40 | A default connection string can be set in in $DBConnection so that you can just run "Get-SQL " «SQL Statement» ".
41 | .Parameter Excel
42 | Specifies that the string in -Connection is an Excel file path to be converted into a connection string.
43 | .Parameter Access
44 | Specifies that the string in -Connection is an Access file path to be converted into a connection string.
45 | .Parameter Lite
46 | Specifies the SQLite driver should be used and the string in -Connection may be the path to a SQLite file.
47 | .Parameter MsSQLserver
48 | Specifies the SQL Native client should be used and string in -Connection may be the name of a SQL Server.
49 | .Parameter Session
50 | Allows a database connection to be Identified by name: this sets the name used in the global variable $DBSessions.
51 | In addition, an alias is added: for example, if the session is named "F1" you can use the command F1 in place of Get-SQL -Session F1
52 | .Parameter ForceNew
53 | If specified, makes a new connection for the default or named session.
54 | If a connection is already established, -ForceNew is required to change the connection string.
55 | .Parameter ChangeDB
56 | For SQL server and ODBC sources which support it (like MySQL) switches to a different database at the same server.
57 | .Parameter Close
58 | Closes a database connection. Note this is run in the "end" phase of the command. If Get-SQL is stopped by another command
59 | in the pipeline (for example Select-object -first ) then it may not close the connection, so although this command can be
60 | combined with a select query, care is needed to ensure it is not defeated by another command in the same pipeline.
61 | .Parameter Table
62 | Specifies a table to select or delete from or to update.
63 | .Parameter Where
64 | If specified, applies a SQL WHERE condition to the selected table. -Where specifies the field and the text in -SQL supplies the condition.
65 | .Parameter GT
66 | Used with -Where specifies the > operator should be used, with the operand for the condition found in -SQL.
67 | .Parameter GE
68 | Used with -Where specifies the >= operator should be used, with the operand for the condition found in -SQL.
69 | .Parameter EQ
70 | Used with -Where specifies the = operator should be used, with the operand for the condition found in -SQL.
71 | .Parameter NE
72 | Used with -Where specifies the <> operator should be used, with the operand for the condition found in -SQL.
73 | .Parameter LE
74 | Used with -Where specifies the <= operator should be used, with the operand for the condition found in -SQL.
75 | .Parameter LT
76 | Used with -Where specifies the < operator should be used, with the operand for the condition found in -SQL.
77 | .Parameter Like
78 | Used with -Where specifies the Like operator should be used, with the operand for the condition found in -SQL. "*" in -SQL will be replaced with "%".
79 | .Parameter NotLike
80 | Used with -Where specifies the Not Like operator should be used, with the operand for the condition found in -SQL. "*" in -SQL will be replaced with "%".
81 | .Parameter Select
82 | If Select is omitted, -Table TableName will result in "SELECT * FROM TableName".
83 | Select specifies field-names (or other text) to use in place of "*".
84 | .Parameter Distinct
85 | Specifies that "SELECT DISTINCT ..." should be used in place of "SELECT ...".
86 | .Parameter OrderBy
87 | Specifies fields to be used in a SQL ORDER BY clause added at the end of the query.
88 | .Parameter Delete
89 | If specified, changes the query from a SELECT to a DELETE. This allows a query to be tested as a SELECT before adding -Delete to the command.
90 | -Delete requires a WHERE clause and not all ODBC drivers support deletion.
91 | .Parameter Set
92 | If specified, changes the query from a Select to a Update -Set Specifies the field(s) to be updated.
93 | -Set requires a WHERE clause.
94 | .Parameter Values
95 | If -Set is specified, -Values contains the new value(s) for the fields being updated.
96 | .Parameter Insert
97 | Specifies a table to insert into. The SQL parameter should contain a hash table or PSObject which holding the data to be inserted.
98 | .Parameter DateFormat
99 | Allows the format applied to Dates to be inserted to be changed if a service requires does not follow standard conventions.
100 | .Parameter GridView
101 | If specified, sends the output to gridview instead of the PowerShell console.
102 | .Parameter GroupBy
103 | If specified, adds a group by clause to a select query; in this case the SELECT clause needs to contain fields suitable for grouping.
104 | .Parameter Describe
105 | Returns a description of the specified table - note that some ODBC providers don't support this.
106 | .Parameter ShowTables
107 | If specified, returns a list of tables in the current database - note that some ODBC providers don't support this.
108 | .Parameter Paste
109 | If specified, takes an SQL statement from the clipboard.
110 | Line breaks and any text before SELECT , UPDATE or DELETE will be removed.
111 | .Parameter Quiet
112 | If specified, suppresses printing of the console message saying how many rows were returned.
113 | .Parameter OutputVariable
114 | Behaves like the common parameters errorVariable, warningvariable etc.to pass back a table object instead of an array of data rows.
115 | .Example
116 | Get-SQL -MsSQLserver -Connection "server=lync3\rtclocal;database=rtcdyn; trusted_connection=true;" -Session Lync
117 | Creates a new session named "LYNC" to the rtcdyn database on the Rtclocal SQL instance on server Lync
118 | .Example
119 | Get-SQL -Session LR -Connection "DSN=LR" -Quiet -SQL $SQL
120 | Runs the SQL in $SQL - if the Session LR already exists it will be used, otherwise it will be created to the ODBC source "LR"
121 | Note that a script should always name a its session(s), something else may already have set the defualt session
122 | .Example
123 | Get-Sql -showtables *dataitem
124 | Gives a list of tables on the default connection that end with "dataitem"
125 | .Example
126 | Get-SQL -Session f1 -Excel -Connection C:\Users\James\OneDrive\Public\F1\f1Results.xlsx -showtables
127 | Creates a new connection named F1 to an Excel file, and shows the tables available.
128 | .Example
129 | f1 -Insert "[RACES]" @{RaceName = $raceName, RaceDate = $racedate.ToString("yyyy-MM-dd") }
130 | Uses the automatically created alias "f1" which was created in the previous example to insert a row of data into the "Races" Table
131 | .Example
132 | Get-SQL -Session F1 -Table "[races]" -Set "[poleDriver]" -Values $PoleDriver -SQL "WHERE RaceDate = $rd" -Confirm:$false
133 | Updates the races table in the "F1" session, setting the value in the column "PoleDriver" to the contents of
134 | the variable $PoleDriver, in those rows where the RaceDate = $RD. This time the session is explicitly specified
135 | (using aliases is OK at the command line but not in scripts especially if the alias is created by a command run in the script)
136 | Changes normally prompt the user to confirm but here -Confirm:$false prevents it
137 | .Example
138 | "CREATE USER 'johndoe' IDENTIFIED BY 'password'" , "GRANT ALL PRIVILEGES ON *.* TO 'johndoe'@'%' WITH grant option" | Get-SQL
139 | Pipes two commands into the default connection, giving a new mySql user full access to all tables in all databases
140 | .Example
141 | Get-Sql -paste -gridview
142 | Runs the query currently in the clipboard against the default existing and outputs to the Gridview
143 | .Example
144 | SQL -table catalog_dataitem -select dataStatus -distinct -orderBy dataStatus -gridView
145 | Builds the query " SELECT DISTINCT dataStatus FROM catalog_dataitem ORDER BY dataStatus",
146 | runs it against the default existing connection and displays the results in a grid.
147 | .Example
148 | [void](Get-sql $sql -OutputVariable Table)
149 | PowerShell unpacks Datatable objects into rows; so anything which needs a DataTable object cannot get it with
150 | $table = Get-Sql $sql
151 | because $table will contain an Array of DataRow objects, not a single DataTable.
152 | To get round this Get-SQL has -OutputVariable which behaves like the common parameters errorVariable, warningvariable etc.
153 | (using the Name of the variable 'Table' not its value '$table' as the parameter value)
154 | After running the command, the variable in the scope where the command is run contains the DataTable object.
155 | Usually the datarow objects will not be required, so the output can be cast to a void or piped to Out-Null.
156 | #>
157 | [CmdletBinding(DefaultParameterSetName='Describe',SupportsShouldProcess=$true,ConfirmImpact="High")]
158 | param (
159 | [parameter(Position=0, ValueFromPipeLine=$true)]
160 | $SQL,
161 | [parameter(Position=1)][ValidateNotNullOrEmpty()]
162 | [string]$Connection = $global:DefaultDBConnection ,
163 | [ValidateNotNullOrEmpty()]
164 | [string]$Session = "Default",
165 | [parameter(Position=2)]
166 | [alias('Use')]
167 | [string]$ChangeDB,
168 | [alias('Renew')]
169 | [switch]$ForceNew ,
170 | [parameter(ParameterSetName="Paste")]
171 | [parameter(ParameterSetName="Describe")]
172 | [parameter(ParameterSetName="Select")]
173 | [parameter(ParameterSetName="SelectWhere")]
174 | [alias('g')][switch]$GridView,
175 | [parameter(ParameterSetName="Describe")]
176 | [alias('d')][string]$Describe,
177 | [parameter(ParameterSetName="ShowTables" , Mandatory=$true)]
178 | [switch]$ShowTables,
179 | [parameter(ParameterSetName="Paste" , Mandatory=$true)]
180 | [switch]$Paste,
181 | [parameter(ParameterSetName="UpdateWhere", Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
182 | [parameter(ParameterSetName="DeleteWhere", Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
183 | [parameter(ParameterSetName="SelectWhere", Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
184 | [parameter(ParameterSetName="Update" , Mandatory=$false)]
185 | [parameter(ParameterSetName="Delete" , Mandatory=$false)]
186 | [parameter(ParameterSetName="Select" , Mandatory=$false)]
187 | [alias('from','update','T')][string]$Table,
188 | #region Parameters for queries with a WHERE clause
189 | [parameter(ParameterSetName="UpdateWhere", Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
190 | [parameter(ParameterSetName="DeleteWhere", Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
191 | [parameter(ParameterSetName="SelectWhere", Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
192 | [string]$Where,
193 | [parameter(ParameterSetName="UpdateWhere")]
194 | [parameter(ParameterSetName="DeleteWhere")]
195 | [parameter(ParameterSetName="SelectWhere")]
196 | [switch]$GT,
197 | [parameter(ParameterSetName="UpdateWhere")]
198 | [parameter(ParameterSetName="DeleteWhere")]
199 | [parameter(ParameterSetName="SelectWhere")]
200 | [switch]$GE,
201 | [parameter(ParameterSetName="UpdateWhere")]
202 | [parameter(ParameterSetName="DeleteWhere")]
203 | [parameter(ParameterSetName="SelectWhere")]
204 | [switch]$EQ,
205 | [parameter(ParameterSetName="UpdateWhere")]
206 | [parameter(ParameterSetName="DeleteWhere")]
207 | [parameter(ParameterSetName="SelectWhere")]
208 | [switch]$NE,
209 | [parameter(ParameterSetName="UpdateWhere")]
210 | [parameter(ParameterSetName="DeleteWhere")]
211 | [parameter(ParameterSetName="SelectWhere")]
212 | [switch]$LE,
213 | [parameter(ParameterSetName="UpdateWhere")]
214 | [parameter(ParameterSetName="DeleteWhere")]
215 | [parameter(ParameterSetName="SelectWhere")]
216 | [switch]$LT,
217 | [parameter(ParameterSetName="UpdateWhere")]
218 | [parameter(ParameterSetName="DeleteWhere")]
219 | [parameter(ParameterSetName="SelectWhere")]
220 | [switch]$Like,
221 | [parameter(ParameterSetName="UpdateWhere")]
222 | [parameter(ParameterSetName="DeleteWhere")]
223 | [parameter(ParameterSetName="SelectWhere")]
224 | [switch]$NotLike,
225 | #endregion
226 | #Parameters for SELECT Queries
227 | [parameter(ParameterSetName="Select")]
228 | [parameter(ParameterSetName="SelectWhere")]
229 | [alias('Property')][string[]]$Select,
230 | [parameter(ParameterSetName="Select")]
231 | [parameter(ParameterSetName="SelectWhere")]
232 | [switch]$Distinct,
233 | [parameter(ParameterSetName="Select")]
234 | [parameter(ParameterSetName="SelectWhere")]
235 | [string[]]$OrderBy,
236 | [parameter(ParameterSetName="Select")]
237 | [parameter(ParameterSetName="SelectWhere")]
238 | [String[]]$GroupBy,
239 | #Parameters for Delete queries
240 | [parameter(ParameterSetName="DeleteWhere", Mandatory=$true)]
241 | [parameter(ParameterSetName="Delete" , Mandatory=$true)]
242 | [switch]$Delete,
243 | #Parameters for Update queries
244 | [parameter(ParameterSetName="UpdateWhere", Mandatory=$true)]
245 | [parameter(ParameterSetName="Update" , Mandatory=$true)]
246 | [string[]]$Set,
247 | [parameter(ParameterSetName="UpdateWhere", Mandatory=$true,Position=1)]
248 | [parameter(ParameterSetName="Update" , Mandatory=$true,Position=1)]
249 | [Object[]]$Values,
250 | #Parameters for INSERT Queries
251 | [parameter(ParameterSetName="Insert" , Mandatory=$true)]
252 | [alias('into')][string]$Insert,
253 | [parameter(ParameterSetName="Insert")]
254 | [parameter(ParameterSetName="Update")]
255 | [parameter(ParameterSetName="UpdateWhere")]
256 | [parameter(ParameterSetName="DeleteWhere")]
257 | [parameter(ParameterSetName="SelectWhere")]
258 | [String]$DateFormat = "'\''yyyy'-'MM'-'dd HH':'mm':'ss'\''",
259 | [parameter(ParameterSetName="Paste")]
260 | [parameter(ParameterSetName="Describe")]
261 | [parameter(ParameterSetName="Select")]
262 | [parameter(ParameterSetName="SelectWhere")]
263 | [Alias("Q","Qu")]
264 | [switch]$Quiet,
265 | [switch]$MsSQLserver,
266 | [switch]$MySQL,
267 | [switch]$Lite,
268 | [switch]$Access,
269 | [switch]$Excel,
270 | $CredForMsSQL,
271 | [String]$OutputVariable,
272 | [alias('TimeOut')]
273 | [int]$QueryTimeOut,
274 | [switch]$Close
275 | )
276 | begin {
277 | #Prepare session, if needed, and leave it in the global variable DBSessions - a hash table with Name and connection object
278 | #If the function was invoked with an Alias of "DB" and there is session named "DB" switch to using that session
279 | if (("Default" -eq $Session) -and $Global:DbSessions[$MyInvocation.InvocationName]) {$Session = $MyInvocation.InvocationName}
280 |
281 | #if the session doesn't exist or we're told to force a new session, then create and open a session
282 | if ( ($ForceNew) -or ( -not $Global:DbSessions[$session]) ) { #-and -not $Close
283 | if ($Lite -and $PSVersionTable.PSVersion.Major -gt 5 -and $IsMacOS ) {
284 | Add-Type -Path (Join-Path $PSScriptRoot "osx\System.Data.SQLite.dll" )
285 | }
286 | elseif ($Lite -and $PSVersionTable.PSVersion.Major -gt 5 -and $linux ) {
287 | Add-Type -Path (Join-Path $PSScriptRoot "linux-x64\System.Data.SQLite.dll" )
288 | }
289 | elseif ($lite -and -not [System.Environment]::Is64BitProcess) {
290 | Add-Type -Path (Join-Path $PSScriptRoot "win-x86\System.Data.SQLite.dll" )
291 | }
292 | elseif ($lite ) {
293 | Add-Type -Path (Join-Path $PSScriptRoot "win-x64\System.Data.SQLite.dll" )
294 | }
295 | #Catch -force to refresh instead of replace the current connection (e.g. Server has timed out )
296 | if (($ForceNew) -and $Global:DbSessions[$session] -and -not $PSBoundParameters.ContainsKey('Connection')) {
297 | if ($Global:DbSessions[$session].GetType().name -eq "SqlConnection" ) {$MsSQLserver = $true}
298 | elseif ($Global:DbSessions[$session].GetType().name -eq "SQLiteConnection" ) {$Lite = $true}
299 | elseif ($Global:DbSessions[$session].GetType().name -eq "MySqlConnection" ) {$MySQL = $true}
300 | }
301 | #If -MySQL switch is used check we have the MySQL objects
302 | if ($MySQL) {
303 | $t = 'MySql.Data.MySqlClient.MySqlConnection' -as [Type]
304 | if (-not $t) {throw 'Native MySQL was requested by MSSQL objects have not been load (use Add-Type -path <>\MySql.Data.Dll)' ; return}
305 | else {$dllVerForMySql = $t.Assembly.FullName -replace '^.*version=([\d\.]+).*$','$1'}
306 | }
307 | if ($CredForMsSQL -and ($Access -or $Excel -or $lite -or $mysql)) {Write-Warning '-CredForMsSQL Ignored'}
308 | if ($CredForMsSQL -and -not $MsSQLserver) {$MsSQLserver = $true}
309 | #If -MSSQLServer switch is used assume connection is a server if there is no = sign in the connection string
310 | if ($MsSQLserver -and $Connection -and $connection -notmatch "=") {
311 | $Connection = "server=$Connection;timeout=60"
312 | if (-not $CredForMsSQL){$Connection = "server=$Connection;trusted_connection=true;timeout=60"}
313 | }
314 | #If -Lite switch is used assume connection is a file if there is no = sign in the connection string, check it exists and build the connection string
315 | if ($Lite -and $Connection -and $connection -notmatch "=") {
316 | if (Test-Path -Path $Connection) {
317 | $Connection = "Data Source=" + (Resolve-Path -Path $Connection -ErrorAction SilentlyContinue).Path + ";"
318 | }
319 | else { Write-Warning -Message "Can't create database connection: could not find $Connection" ; return}
320 | }
321 | #If the -Excel or Access switches are used, then the connection parameter is the path to a file, so check it exists and build the connection string
322 | if ($Excel) {
323 | if (Test-Path -Path $Connection) {
324 | $Connection = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DriverId=790;ReadOnly=0;Dbq=" +
325 | (Resolve-Path -Path $Connection -ErrorAction SilentlyContinue).Path + ";"
326 | }
327 | else { Write-Warning -Message "Can't create database connection: could not find $Connection" ; return}
328 | }
329 | if ($Access) {
330 | if (Test-Path -Path $Connection) {
331 | $Connection = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq="+
332 | (Resolve-Path -Path $Connection -ErrorAction SilentlyContinue).Path + ";"
333 | }
334 | else { Write-Warning -Message "Can't create database connection: could not find $Connection" ; return}
335 | }
336 | if (-not $Connection) { Write-Warning -Message "A connection was needed but -Connection was not provided."; break}
337 | Write-Verbose -Message "Connection String is '$connection'"
338 | #Use different types for SQL server, SQLite and ODBC. They (and the logic) are almost interchangable.
339 | if ($CredForMsSQL -is [pscredential]) {
340 | $u=([pscredential]$CredForMsSQL).UserName
341 | $p=([pscredential]$CredForMsSQL).Password
342 | $p.MakeReadOnly()
343 | $CredForMsSQL = [System.Data.SqlClient.SqlCredential]::new($u,$p)
344 | }
345 | if ($CredForMsSQL -and $CredForMsSQL -isnot [System.Data.SqlClient.SqlCredential]) {throw 'Invalid SQL Credential'}
346 | elseif ($CredForMsSQL) { $Global:DbSessions[$Session] = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $Connection, $CredForMsSQL }
347 | elseif ($MsSQLserver) { $Global:DbSessions[$Session] = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $Connection }
348 | elseif ($Lite) { $Global:DbSessions[$Session] = New-Object -TypeName System.Data.SQLite.SQLiteConnection -ArgumentList $Connection }
349 | elseif ($MySQL) { $Global:DbSessions[$Session] = New-Object -TypeName MySql.Data.MySqlClient.MySqlConnection -ArgumentList $Connection }
350 | else { $Global:DbSessions[$Session] = New-Object -TypeName System.Data.Odbc.OdbcConnection -ArgumentList $Connection
351 | $Global:DbSessions[$Session].ConnectionTimeout = 30
352 | }
353 | #Open our connection. NB, if 32 bit office is installed Excel, Access ETC have 32 bit ODBC drivers which need 32 bit Powershell not 64 bit.
354 | try { $Global:DbSessions[$Session].open() }
355 | catch { Write-Warning -Message "Error opening connection to '$Connection'"
356 | if (($Access -or $Excel) -and [System.Environment]::Is64BitProcess) {
357 | Write-Warning -Message "This is 64-bit PowerShell, If Office is 32-bit you need to use 32 bit-PowerShell"}
358 | $Global:DbSessions[$Session] = $null
359 | break
360 | }
361 | if ($MySQL -and [version]::new(8,0,28) -lt $Global:DbSessions[$Session].ServerVersion -and [version]::new(8,0,30) -gt $dllVerForMySql) {
362 | Write-Warning "The combinaton of .NET driver and Server version may need 'Set Names utf8MB4' to avoid errors about character set 'utf8MB4'"
363 | # V8 non-odbc drivers need .net newer than 5 so Windows PowerShell, native drivers and new servers are a bad combo
364 | }
365 | #Create an alias which matches the connection name.
366 | if ("Default" -eq $Session) { $Global:DefaultDBConnection = $Connection }
367 | else { New-Alias -Name $Session -Value Get-SQL -Scope Global -Force}
368 | }
369 | if ($ChangeDB) { $Global:DbSessions[$Session].ChangeDatabase($ChangeDB) } #This method to change DB won't work with every provider
370 | if ( ($Paste) -and (Get-Command -Name 'Get-Clipboard' -ErrorAction SilentlyContinue)) {
371 | #You could use [windows.clipboard]::GetText() - be warned this may not work in the older releases of the standard shell
372 | #For older versions of PowerShell I have a Get-Clipboard function which wraps this
373 | $SQL = (Get-Clipboard) -replace "^.*?(?=select|update|delete)","" -replace "[\n|\r]+"," "
374 | }
375 | }
376 | process {
377 | #If $table is specified make sure $SQL isn't empty otherwise we won't get to Select * from $Table; also make sure conditions allow for it to be zero!
378 | if ($Table -and $null -eq $SQL) { $SQL = " "}
379 | if ($SQL.SQL) { $SQL = $SQL.SQL}
380 | if ($Describe) { #support -Describe [tablename] to descibe a table
381 | if ($Global:DbSessions[$Session].driver -match "SQORA" ) { #Oracle is special ...
382 | Get-SQL -Session $Session -Quiet -SQL ("select COLUMN_NAME, data_type as TYPE_NAME, data_length AS COLUMN_SIZE " +
383 | " from user_tab_cols where table_name = '$Describe' order by COLUMN_NAME")
384 | }
385 | else { #Remove any [] around the table name - because that's how .GetSchema() works ...
386 | $Describe = $Describe -replace "\[(.*)\]",'$1'
387 | # For some drivers .GetSchema() can get the columns for a single table. But the Excel driver can't, so get all columns and filter.
388 | if ($Global:DbSessions[$Session].Driver -match "ACEODBC.DLL" ) {
389 | $columns = $Global:DbSessions[$Session].GetSchema("Columns") | Where-Object {$_.TABLE_NAME -eq $Describe }
390 | }
391 | elseif ($Global:DbSessions[$Session].gettype().name -eq "SqlConnection" ) {#SQL server uses slightly differnet syntax
392 | $columns = $Global:DbSessions[$Session].GetSchema("Columns", @("%","%",$Describe,"%"))
393 | }
394 | else { $columns = $Global:DbSessions[$Session].GetSchema("Columns", @("","",$Describe)) }
395 | if ($GridView) {$columns | Out-GridView -Title "Table $Describe"}
396 | else {$columns | Select-Object -Property @{n="COLUMN_NAME";e={if ($_.Column_Name -match "\W") {"[$($_.Column_Name)]"} else {$_.column_Name} }},
397 | TYPE_NAME, COLUMN_SIZE, IS_NULLABLE
398 | }
399 | }
400 | }
401 | elseif ($Showtables) { #ODBC method to get tables won't work with every provider, but nor will executing "show tables". $SQL param becomes a filter
402 | if ($Global:DbSessions[$Session].driver -match "SQORA" ) {#Oracle is special ...
403 | (Get-SQL -Session $Session -Quiet -SQL "select OBJECT_NAME from user_objects where object_type IN ('VIEW','TABLE'); ").object_name |
404 | Where-Object {$_ -like "$SQL*"}
405 | }
406 | else {$Global:DbSessions[$Session].GetSchema("Tables") | Where-Object {$Global:DbSessions[$Session].DataSource -ne "Access" -or $_.TABLE_TYPE -ne "SYSTEM TABLE"} |
407 | ForEach-Object {
408 | if ($_.TABLE_NAME -like "$SQL*" -and $_.TABLE_NAME -match "\W") {"[" + $_.TABLE_NAME + "]"}
409 | elseif ($_.TABLE_NAME -like "$SQL*") { $_.TABLE_NAME }
410 | } | Sort-Object
411 | }
412 | }
413 | elseif ($null -ne $SQL) { #$SQL holds any SQL which we can't (or don't want to( assemble from the cmdline, a whole statement or final clause
414 | ForEach ($s in $SQL) { #More than one statement/clause can be passed
415 | if ($Delete -or $Set -and -not $Table) { Write-Warning -Message "You must specifiy a table and where condition to use -Delete or -Set" ; return }
416 | if ($Table) { #If $Table was specified, build a Select, Delete or Update query
417 | #Support -table [tablename] -Where [ColumnName] -eq 99 and similar syntax.
418 | # -eq -ne and other operators are *switches*. The operand for = (etc.) is in $SQL so only Operator is allowed. Too complex to enforce this in Param() block!
419 | $opCount = (($Like, $EQ, $NE , $LT , $GT , $GE, $LE, $NotLike) -eq $true).Count
420 | #Can't have multiple operators, and operator requires -Where to be specified and a value in -SQL (-SQL usually implied in cmdline)
421 | if ((($opCount) -gt 1) -or (($opCount -eq 1) -and -not $Where ) -or ($Where -and " " -eq $s )) {
422 | Write-Warning -Message "You can't specify a where condition like that"
423 | return
424 | }
425 | if (($opCount) -eq 1) { #If we have an operator, column and value in $s turn $s into the condition (add the column name after)
426 | #if the operand for -eq etc is a date format it for SQL
427 | if ($s -is [datetime]) {
428 | $s = $s.tostring($DateFormat) #Default format has "'" this works for Excel inserts and SQL server.
429 | if ($Global:DbSessions[$Session].Driver -eq "ACEODBC.DLL") { #For Excel where needs # not quotes as date markers
430 | $s = $s -replace "'","#"
431 | }
432 | } #if the operand for -eq etc is not a number or isn't wrrapped in quotes. Wrap it in quotes and double up the ' character
433 | elseif (($s -notmatch "^\d+\.?\d*$") -and ($s -notmatch "^'.*'$"))
434 | {$s = "'" + ($s -replace "(? $s " }
437 | if ($GE) {$s = " >= $s " }
438 | if ($LE) {$s = " <= $s " }
439 | if ($GT) {$s = " > $s " }
440 | if ($LT) {$s = " < $s " }
441 | if (($Like) -or ($NotLike) ) { #for the like operators replace * wildcard with SQL % wildcard
442 | $s = $s -replace "\*","%" }
443 | if ($Like) {$s = " like $s " }
444 | if ($NotLike) {$s = " not like $s " }
445 | #At the end of this $s holds the condition but not the column name
446 | }
447 | if ($Delete) { #Support Delete queries -Table [tableName] -Delete -where [Column] -eq [Value]
448 | #A careless -Delete could wipe out a table - so insist on either -where [columnName] and a condition, or "Where blah blah" in $SQL
449 | if ((($Where) -and $s) -or ($s -match "where\s+\w+")) {
450 | if ($Where) {$s = "DELETE FROM $Table WHERE $Where " + $S }
451 | else {$s = "DELETE FROM $Table " + $S }
452 | }
453 | else {Write-Warning -Message "You must specifiy a where condition to use -Delete"; return }
454 | }
455 | elseif ($Set) {
456 | #Support update ... set queries -Table [tableName] -Set [Columns] -Values [values] -Where [Column] -EQ [Value]
457 | #Don't allow set to modify all the rows (same logic as Delete)
458 | if ( ( $Where -and $s) -or ($s -match "where\s+\w+")) {
459 | #We have a list of columns in Set and values for them need the same number of each - then build the set clause, wrapping text values in ''
460 | if ($Set.Count -ne $Values.Count) {Write-Warning -Message "Must have the same number of columns to set as values to set them to"; return }
461 | $setList = ""
462 | for ($i = 0; $i -lt $set.count; $i++) {
463 | if ( $Values[$i] -is [datetime]) {
464 | if ($Global:DbSessions[$Session].gettype().name -match "SQLiteConnection") {
465 | $Vi = [int]($Values[$i].Subtract([datetime]::UnixEpoch).TotalSeconds)
466 | }
467 | else { $Vi = $Values[$i].tostring($DateFormat)} #Default format has "'" this works for Excel, Access and SQL server.
468 | $SetList = $SetList + $Set[$i] + "= " + $vi +" ,"
469 | }
470 | # Wrap text in ' and escape ' char
471 | elseif ($Values[$i] -notmatch "^[\d\.]*$") {$SetList = $SetList + $Set[$i] + "='" + ($Values[$i] -replace "'","''") +"' ," }
472 | else {$SetList = $SetList + $Set[$i] + "= " + $Values[$i] +" ," }
473 | }
474 | #will have an extra "," at the end.
475 | $setList = $setList -replace ",$",""
476 | if ($Where) {$s = "UPDATE $Table SET $setList WHERE $Where " + $s }
477 | else {$s = "UPDATE $Table SET $setList " + $s }
478 | }
479 | else {Write-Warning -Message "You must specifiy a where condition to use -Set" ; return }
480 | }
481 | else {#If we're not updating or deleting and -Table was passed we must be selecting ....
482 | if ( $Select) {$SelectClause = ($Select -join ", ") + " FROM $Table " }
483 | else {$SelectClause = " * FROM $Table " }
484 | if ( $Where) {$SelectClause = $SelectClause + "WHERE $Where " } #note we need to have the "what" part of SQL. but SQL could be @("=10",">73") we'll run 2 queries
485 | if ( $Distinct) {$s = "SELECT DISTINCT " + $SelectClause + $s }
486 | else {$s = "SELECT " + $SelectClause + $s }
487 | if ( $GroupBy) {$s = $s + " GROUP BY " + ($GroupBy -join ", ")}
488 | if ( $OrderBy) {$s = $s + " ORDER BY " + ($OrderBy -join ", ")}
489 | }
490 | }
491 | elseif ($Insert) {
492 | #Support -insert [IntoTableName] @{hashtable of fields and values}
493 | if ($s -is [Hashtable]) {$index = $s.keys}
494 | elseif ($s -is [psobject] ) {$index = (Get-Member -InputObject $s -MemberType NoteProperty).Name }
495 | else { Write-Warning -Message "Can't build an Insert statement from $s. Pass a hashtable or a PSObject" ; return}
496 | $fieldsPart = " "
497 | $valuesPart = " "
498 | foreach ($name in $index) {
499 | $fieldsPart = $fieldsPart + $name + " , "
500 | $v = $s.$name
501 | if ($Global:DbSessions[$Session].gettype().name -match "SQLiteConnection") {
502 | if ($v -is [datetime] ) {$v = [int]($v.Subtract([datetime]::UnixEpoch).TotalSeconds)}
503 | if ($v -is [Boolean] ) {$v = [int]$v}
504 | }
505 | #$DateFormat defaults to the standard date format which SQL dialects support, but it can be overridden for special cases
506 | if ($v -is [datetime] ) {$valuesPart = $valuesPart + $v.tostring($DateFormat) + " , " }
507 | elseif ($v -is [int] -or
508 | $v -is [float] -or
509 | $v -is [boolean] ) {$valuesPart = $valuesPart + $v.tostring() + " , " }
510 | elseif ($v -match "^\d+$" ) {$valuesPart = $valuesPart + $v.tostring() + " , " }
511 | else {$valuesPart = $valuesPart + "'" + ($v -replace "'","''") + "' , " }
512 | }
513 | $s = ("INSERT INTO {0} ({1}) VALUES ({2})" -f $Insert,($fieldsPart -replace ",\s*$",""),($valuesPart -replace ",\s*$",""))
514 | $s = $s -replace ",\s*,",", null ," -replace "(?<=[(,])\s*''\s*(?=[),])"," null " -replace ",\s*\)",", null)"
515 | }
516 | Write-Verbose -Message $s
517 | #Choose suitable data adapter object based on session type.
518 | if ($Global:DbSessions[$Session].gettype().name -match "MySqlConnection" ) { #Test this first or it will match on SQLConnection which is for MS SQL Server
519 | $da = New-Object -TypeName MySql.Data.MySqlClient.MySqlDataAdapter -ArgumentList (
520 | New-Object -TypeName MySql.Data.MySqlClient.MySqlCommand -ArgumentList $s,$Global:DbSessions[$Session] )
521 | }
522 | elseif ($Global:DbSessions[$Session].gettype().name -match "SqlConnection" ) {
523 | $da = New-Object -TypeName System.Data.SqlClient.SqlDataAdapter -ArgumentList (
524 | New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList $s,$Global:DbSessions[$Session] )
525 | }
526 | elseif ($Global:DbSessions[$Session].gettype().name -match "SQLiteConnection" ) {
527 | $da = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter -ArgumentList (
528 | New-Object -TypeName System.Data.SQLite.SQLiteCommand -ArgumentList $s,$Global:DbSessions[$Session] )
529 | }
530 | else {
531 | $da = New-Object -TypeName System.Data.Odbc.OdbcDataAdapter -ArgumentList (
532 | New-Object -TypeName System.Data.Odbc.OdbcCommand -ArgumentList $s,$Global:DbSessions[$Session])
533 | }
534 | if ($QueryTimeOut -and $da.SelectCommand) {$da.SelectCommand.CommandTimeout = $QueryTimeOut}
535 | if ($QueryTimeOut -and $da.InsertCommand) {$da.InsertCommand.CommandTimeout = $QueryTimeOut}
536 | if ($QueryTimeOut -and $da.UpdateCommand) {$da.UpdateCommand.CommandTimeout = $QueryTimeOut}
537 | $dt = New-Object -TypeName System.Data.DataTable
538 | #And finally we get to execute the SQL Statement.
539 | try { if ((-not ($Set -or $Delete -or ($Insert -and $ConfirmPreference -ne "high"))) -or ($PSCmdlet.ShouldProcess("$Session database", $s)) ) {
540 | $rows = $da.fill($dt)
541 | if (-not ($Quiet -or $Delete -or $Set -or $Insert)) {Write-Host -Object ("" + [int]$rows + " row(s) returned")}
542 | }}
543 | catch {
544 | if($S) { #if we get an error and -SQL was passed show the final SQL statement.
545 | $e=$Global:error[0]
546 | throw ( New-Object -TypeName "System.Management.Automation.ErrorRecord" `
547 | -ArgumentList (($e.exception.message -replace "^(.*])\s*","`$1`n") + "`n `n>>> $S `n `n" ), $e.FullyQualifiedErrorId ,"ParserError" ,$e.TargetObject)
548 | }
549 | else { throw }
550 | }
551 | if (($GridView) -and (($PSVersionTable.PSVersion.Major -GE 3)-or ($host.name -match "ISE" )) ) {$dt | Out-GridView -Title $s}
552 | else {$dt}
553 | if ($OutputVariable) {Set-Variable -Scope 2 -Name $OutputVariable -Value $dt -Visibility Public}
554 | }
555 | }
556 | elseif (-not $Close -and -not $Quiet) { #If $SQL, $table, $describe or $showtimes weren't included either we're opening a new connection, or we're checking or closing an existing one.
557 | $Global:DbSessions[$Session]
558 | }
559 | }
560 | end {
561 | if ($Close -and $Global:DbSessions[$Session]) {
562 | $Global:DbSessions[$Session].close()
563 | $Global:DbSessions[$Session].dispose()
564 | $Global:DbSessions.Remove($Session)
565 | Remove-Item -Path (Join-Path -Path "Alias:\" -ChildPath $Session) -ErrorAction SilentlyContinue
566 | }
567 | }
568 | }
569 |
570 | function Hide-GetSQL {
571 | <#
572 | .Synopsis
573 | Allows a command line with quote marks to passed into Get-SQL, can be used simply as ¬
574 | .Example
575 | ¬ select host,user from mysql.user
576 | Sends the command "select host,user from mysql.user" to the default ODBC session
577 |
578 | #>
579 | Get-Sql -sql ($MyInvocation.line.substring($MyInvocation.OffsetInLine)) | Format-Table -AutoSize
580 | }
581 | Set-Alias -Name ¬ -Value Hide-GetSQL
582 |
--------------------------------------------------------------------------------