anyone know how to rewrite below code, so it can invoke sql script. For instance, instead of put 'SELECT ##SERVERNAME AS ServerName' in the powershell script, I would like to put it into sql file.
$Path = "D:\AdminStuff\PowerShell\Password\Password.txt"
$uid = 'sa'
$pwd = Get-Content D:\AdminStuff\PowerShell\Password\Password.txt | ConvertTo-SecureString
$pwd.MakeReadOnly()
$creds = New-Object System.Data.SqlClient.SqlCredential($uid,$pwd)
$con = New-Object System.Data.SqlClient.SqlConnection
$con.ConnectionString = "Server=SLB-CLMFZ52;Database=master;"
$con.Credential = $creds
$con.Open()
$sql = "SELECT ##SERVERNAME AS ServerName"
$cmd = New-Object System.Data.SqlClient.SqlCommand($sql,$con)
$rdr = $cmd.ExecuteReader()
while($rdr.Read())
{
$rdr["ServerName"].ToString()
}
$con.Close()
While you can use the SqlCredential, SqlConnection, and SqlCommand .NET classes as you show in your question, there are simpler alternatives. It is a lot less work, for example, to use the Invoke-Sqlcmd cmdlet instead. Invoke-Sqlcmd is essentially the venerable sqlcmd utility with a PowerShell disguise. Thus, assuming your query was in a file myScript.sql, you can just run this--the InputFile parameter provides the means to store your SQL in a separate file as you requested:
$InvokeParams = #{
Server = 'SLB-CLMFZ52'
Database = 'Master'
Username = 'sa'
Password = 'xyz'
InputFile = 'myScript.sql'
}
Invoke-SqlCmd #InvokeParams
Now the obvious problem with that, though, is the password must be in plain text. (Of course, the password in the OP was in plain text in a file, as well. :-) Unfortunately Invoke-Sqlcmd does not work with PowerShell credential objects, which would have made it a lot more secure. The only reasonable workaround to get some security is to use Windows Authentication instead of SQL authentication. Then you could, for example, omit the username and password, and the query will be invoked with secure credentials:
$InvokeParams = #{
Server = 'SLB-CLMFZ52'
Database = 'Master'
InputFile = 'myScript.sql'
}
Invoke-SqlCmd #InvokeParams
To use the cmdlet just Import-Module sqlps. For the basics of Invoke-SqlCmd take a look at TechNet and for a more in-depth treatment, including the vagaries of sqlps, see part 1 of my Practical PowerShell for SQL Server Developers and DBAs article.
What about something simple like this:
$sql=get-content $filename
Related
The PowerShell function Invoke-AzOperationalInsightsQuery docs, source allows me to pass arbitrary an KQL string to an App Insights resource.
Set-AzContext -Subscription "my-sub"
$workspaceName = "vl-loganalytics-workspace"
$workspaceRG = "vl-loganalytics"
$WorkspaceID = (Get-AzOperationalInsightsWorkspace -Name $workspaceName -ResourceGroupName $workspaceRG).CustomerID
$query = "print current_cluster_endpoint()"
$kqlQuery = Invoke-AzOperationalInsightsQuery -WorkspaceId $WorkspaceID -Query $query
$kqlQuery.Results
HT learningbydoing.cloud
Does an equivalent method exist for querying an Azure Data Explorer cluster directly? No public function is listed in the Az.Kusto module as of version 2.1.0, but perhaps there is a community module or blog post documenting an ad-hoc method for this?
Referencing Kusto .NET client libraries from PowerShell, this is possible with the below helper code after downloading & unzipping the Microsoft.Azure.Kusto.Tools NuGet package
$clusterUrl = 'https://help.kusto.windows.net;Fed=True'
# DatabaseName may be null, empty, or incorrect
$databaseName = 'Samples'
$query = 'print current_cluster_endpoint()'
$packagesRoot = Resolve-Path "tools\net6.0"
[System.Reflection.Assembly]::LoadFrom("$packagesRoot\Kusto.Data.dll")
$kcsb = New-Object Kusto.Data.KustoConnectionStringBuilder ($clusterUrl, $databaseName)
$queryProvider = [Kusto.Data.Net.Client.KustoClientFactory]::CreateCslQueryProvider($kcsb)
$crp = New-Object Kusto.Data.Common.ClientRequestProperties
$crp.ClientRequestId = "MyPowershellScript.ExecuteQuery." + [Guid]::NewGuid().ToString()
$crp.SetOption([Kusto.Data.Common.ClientRequestProperties]::OptionServerTimeout, [TimeSpan]::FromSeconds(30))
$reader = $queryProvider.ExecuteQuery($query, $crp)
$dataTable = [Kusto.Cloud.Platform.Data.ExtendedDataReader]::ToDataSet($reader).Tables[0]
$dataView = New-Object System.Data.DataView($dataTable)
$dataView
Note that $databaseName does not need to correspond to an existing database to establish a connection. This can cause errors if you typo a database name; or it can be helpful if the command you wish to execute does not require a database context.
There's an .mdb located on a shared drive in my organization that's password protected and needs to stay password protected. I have the password. I use a local copy for data analysis. The shared drive is very slow for me so I copy it daily using powershell. I need to remove the password manually because the analysis software available to me doesn't support .mdb passwords.
The code below successfully opens the .mdb so I can manually unset the password, but I'd like to automate unsetting the password.
$path = "C:\path\to\db\"
$file = "db.mdb"
$access = New-Object -com Access.Application
$access.Visible = $True
$access.OpenCurrentDataBase($path + $file, $True, "password")
I think my problem is I don't understand PowerShell's implementation of the object model. I want to use Database.NewPassword to change the password. In VB implementations it requires a database object, however, and when I substitute $db = $access.OpenCurrentDataBase($path + $file, $True, "password") for $access.OpenCurrentDataBase($path + $file, $True, "password") the $db variable is $null.
Is there a way to refer to the database object in PowerShell?
You can manage the database password with Access DDL.
ALTER DATABASE PASSWORD newpassword oldpassword
This is how I removed the password with PowerShell:
$path = "C:\Temp\DbPwd_foo.mdb"
$newpassword = "Null"
$oldpassword = "foo"
$accessApp = new-object -com access.application
$accessApp.OpenCurrentDatabase($path, -1, $oldpassword)
$sql = "ALTER DATABASE PASSWORD " + $newpassword + " " + $oldpassword
$accessApp.CurrentProject.Connection.Execute($sql)
$accessApp.Quit()
You can restore the previous password by swapping the values of $newpassword and $oldpassword, and calling OpenCurrentDatabase without its password argument.
You can use DAO for that, the DbEngine.Compact method. It's a pain that powershell does not allow naming parameters and skipping the optionals, though, unless you want to do complicated stuff.
$path = "C:\path\to\db\"
$file = "db.mdb"
$newfile = "decrypted.mdb"
$dbe= New-Object -com DAO.DbEngine.120
$dbe.Compact($path + $file, $path + $newfile, ";LANGID=0x0409;CP=1252;COUNTRY=0", 64, ";PWD=password")
Cheers everyone,
I am getting the weirdest problem for which I need your helping ideas how to approach the issue.
So, I have a download script that pulls content off a company intranet using Webclient objects. It requires credentials and it is working on about 80% of the computers. The script pulls a listing using .DownloadString and then parses and gets some files using .DownloadFile.
On the machines that won't work the initial .DownloadString hangs until it appears to run into a timeout and returns $null.
User credentials are irrelevant on these types of machines meaning a user that works on another machine fails on this one.
Addresses, if entered into browser returns content.
Spoken in code I try it this way:
$wc = new-object System.Net.WebClient
$wc.Credentials = new-object System.Net.NetworkCredential($user, $pass, $domain)
$old_eap = $ErrorActionPreference
$ErrorActionPreference = "Stop"
try
{
$tmp = $wc.DownloadString($url)
if ([String]::IsNullOrEmpty($tmp))
{
throw "Intranet server did not return directory listing"
}
Return $tmp #the code is actually part of a function...
}
catch
{
write-error $_.Exception.Message
Return $null
}
finally
{
$ErrorActionPreference = $old_eap
}
I have no idea other than looking for changed settings between different machines. But which settings could be relevant for Webclient behaving like this? Any Ideas? I am seriously stuck...
I forgot... To make things a little easier I am stuck with Version 2.0 and we cant update yet. Bummer...
Thanks in advance
Alex
Maybe try to use xmlhttp as a client. Below is the usage example.
$url = "https://example.com/"
$http = New-Object -ComObject Msxml2.XMLHTTP
$user = "Domain\username"
$pwd = "password"
$utf = [System.Text.Encoding]::UTF8
$http.open("GET", $url, $false, $user, $pwd)
$http.send()
$result = $utf.GetString($http.responseBody)
I am trying to perform an insert to the Oracle database using Powershell script. This approach works fine for a select query but for insert it gives an error. I read lot of Stack Overflow posts and various other sites and tried various methods but none of them are working.
How can I debug this? I am no expert in Powershell. I am quite sure there is some issue with the SQL.
Add-Type -Path "P:\Home\Full Oracle\ora11g_x86\odp.net\bin\2.x\Oracle.DataAccess.dll"
try
{
$compConStr = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=**)(PORT=1552)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=**)));User Id=**;Password=**;"
$oraConn= New-Object Oracle.DataAccess.Client.OracleConnection($compConStr)
$sid = "0001"
$region = "CH"
$timestamp = "2017-04-20 14:14:00"
$dep = "17-04-2017"
$scenario = "A"
$milestone = "ASB_XREF_GLCC_LOAD_2ND_END_E"
$finishtime = "2017-04-18/11:11"
$sql = "INSERT INTO APP_PDM_MART.PDM_GEAR_KPI_REP_SNOW(ST_ID,PRIORITY,STATUS,ACTIVE,ACTIVITY_DUE,ADD_REPORTED_BY,BUSINESS_CRITICALITY) VALUES($sid,$region,$timestamp,$dep,$scenario,$milestone,$finishtime)"
$oraConn.Open()
$command = New-Object Oracle.DataAccess.Client.OracleCommand($sql,$oraConn)
$tx = $oraConn.BeginTransaction()
$command.ExecuteNonQuery()
For me it looks like the server doesn't like the spaces in your variables. Wihout adding quotes to the variables it won't look like a connected string in the SQL Statement. Try defining your variables like this:
$sid = "`'0001`'"
$region = "`'CH`'"
$timestamp = "`'2017-04-20 14:14:00`'"
$dep = "`'17-04-2017`'"
$scenario = "`'A`'"
$milestone = "`'ASB_XREF_GLCC_LOAD_2ND_END_E`'"
$finishtime = "`'2017-04-18/11:11`'"
So for example 2017-04-20 14:14:00 will be '2017-04-20 14:14:00' in the INSERT statement and it will be clear for the server where to separate the values.
Keep in mind that this will handle all the variables as strings (I don't know the data types of your table columns).
Printing out the final SQL query that is being executed I see this -
INSERT INTO APP_PDM_MART.PDM_GEAR_KPI_REP_SNOW (ST_ID, PRIORITY, STATUS, ACTIVE, ACTIVITY_DUE, ADD_REPORTED_BY, BUSINESS_CRITICALITY)
VALUES(0001, CH, 2017-04-20 14:14:00, 17-04-2017, A, ASB_XREF_GLCC_LOAD_2ND_END_E, 2017-04-18/11:11)
You need to correctly insert the date time properties. See this.
I am not able to see the connection string in the query. Where is the $oraConn getting created.
I am considering you do have the db details.
$username = Read-Host -Prompt "Enter database username"
$password = Read-Host -Prompt "Enter database password"
$datasource = Read-Host -Prompt "Enter database TNS name"
$query = "INSERT INTO APP_PDM_MART.PDM_GEAR_KPI_REP_SNOW(ST_ID,PRIORITY,STATUS,ACTIVE,ACTIVITY_DUE,ADD_REPORTED_BY,BUSINESS_CRITICALITY) VALUES($sid,$region,$timestamp,$dep,$scenario,$milestone,$finishtime)"
$connectionString = 'User Id=' + $username + ';Password=' + $password + ';Data Source=' + $datasource
$connection = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connectionString)
$connection.open()
$command=$connection.CreateCommand()
$command.CommandText=$query
$reader=$command.ExecuteReader()
<#
while ($reader.Read()) {
$reader.GetString(1) + ', ' + $reader.GetString(0)
}
#>
$connection.Close()
You do not have to do the while part, thats why I have commented out.
Refer the blog for further thing: Oracle Database Query From Powershell
If still getting issue, then please post the error as well.
As mentioned in the comment that you do not have access to 64 bit and you wish to only use Oracle.DataAccess.dll, then you can try like this:
[Reflection.Assembly]::Assembly.LoadFrom("c:\Oracle\Oracle11gClientR1\ODP.NET\bin\2.x\Oracle.DataAccess.dll")
OR as mentioned in the comment,to use Add-Type:
Add-Type -AssemblyName "c:\Oracle\Oracle11gClientR1\ODP.NET\bin\2.x\Oracle.DataAccess.dll"
Then I believe you should be able to create the connection string like this:
$con = New-Object Oracle.ManagedDataAccess.Client.OracleConnection(“User Id=username;Password=password;Data Source=localhost/db1”)
$con.open()
Hope it helps.
I'm trying to use WinSCP .NET assembly with secure credential, when the password secured in external file.
# Load WinSCP .NET assembly
Add-Type -Path "D:\WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::Sftp
# Env
$sessionOptions.HostName = "blabla.com"
$sessionOptions.UserName = "UUUU"
#$sessionOptions.Password = "PPPP"
$sessionOptions.SshHostKeyFingerprint = "XXXXXXXXX"
$remotePath = "/home/UUUU/"
With hard coded password its working. If I would like to use securestring for the password, how should I do that?
I tried:
read-host -assecurestring | convertfrom-securestring | out-file D:\securestring.txt
To keep the secure password in a file. Then, in my script, I get it back:
$sessionOptions.Password = get-Content D:\securestring.txt | convertto-securestring
$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $sessionOptions.UserName, $sessionOptions.Password}
But it's not working...
Since WinSCP 5.7, the assembly accepts the SecureString using the SessionOptions.SecurePassword.
See https://winscp.net/eng/docs/library_sessionoptions
Thanks for inspiring this improvement.
While the assembly keeps the password encrypted in memory, it still needs to decrypt it eventually. Improvements to limit internal copies of the decrypted password are pending.
As #Matt pointed out, the WinSCP .Net assembly doesn't accept secure strings or credential objects. You need to pass the password as a plaintext string. You can store the secure string in a file, though:
Read-Host 'Enter password' -AsSecureString |
ConvertFrom-SecureString |
Out-File 'C:\password.txt'
and use a PSCredential object to retrieve the decrypted password from the secure string after you read it from the file:
$un = 'username'
$pw = Get-Content 'C:\password.txt' | ConvertTo-SecureString
$cred = New-Object Management.Automation.PSCredential $un, $pw
try {
Add-Type -Path 'WinSCPnet.dll'
$opt = New-Object WinSCP.SessionOptions
$opt.Protocol = [WinSCP.Protocol]::Sftp
$opt.HostName = 'example.org'
$opt.UserName = $cred.UserName
$opt.Password = $cred.GetNetworkCredential().Password
$opt.SshHostKeyFingerprint = 'ssh-rsa 2048 ...'
$sftp = New-Object WinSCP.Session
$sftp.Open($opt)
...
} catch {
...
} finally {
if ($sftp) { $sftp.Dispose() }
}
WinSCP sample code taken from the documentation.
Note, however, that the password must be saved by the same user who is running the SFTP PowerShell script, because the encryption key is derived from that user's password.
According to WinSCP the password property just supports a string. So trying to pass a secure string will not work. If you really want to store the password in a file, you could attempt to store it as the secure string but that is a really bad idea in general since it can be unsecured just as easily (Also not sure if it is possible). I recommend the following option.
# Only stored in memory which is safer.
$sessionOptions.Password = read-host
If you have your heart set on something else you could try this. Just know for previous reasons I do not condone this. Also i have to see if it even works because it looks like you cant output securestring to file.
read-host | out-file D:\securestring.txt
$sessionOptions.Password = get-Content D:\securestring.txt
Ansgar's explains what I didn't know was possible. You can stored the secure string in a file and use it elsewhere.