I'm having trouble connecting to an Oracle database from Powershell using the Oracle.ManagedDataAccess.dll.
I followed this tutorial on Technet and ended up with this code:
add-type -path "C:\oracle\product\12.1.0\client_1\ODP.NET\managed\common\Oracle.ManagedDataAccess.dll"
$username = "XXXX"
$password = "XXXX"
$data_source = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=XXXX)(PORT=XXXX))(CONNECT_DATA = (SERVER=dedicated)(SERVICE_NAME=XXXX)))"
$connection_string = "User Id=$username;Password=$password;Data Source=$data_source"
try{
$con = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connection_string)
$con.Open()
} catch {
Write-Error (“Can’t open connection: {0}`n{1}” -f `
$con.ConnectionString, $_.Exception.ToString())
} finally{
if ($con.State -eq ‘Open’) { $con.close() }
}
Unfortunately I'm getting this error:
C:\Users\XXXX\Desktop\oracle_test.ps1 : Can’t open connection: User Id=XXXX;Password=XXXX;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=XXXX)(PORT=XXXX))(CONNECT_DATA =
(SERVER=dedicated)(SERVICE_NAME=XXXX)))
System.Management.Automation.MethodInvocationException: Exception calling "Open" with "0" argument(s): "The type initializer for 'Oracle.ManagedDataAccess.Types.TimeStamp' threw an exception." --->
System.TypeInitializationException: The type initializer for 'Oracle.ManagedDataAccess.Types.TimeStamp' threw an exception. ---> System.Runtime.Serialization.SerializationException: Unable to find assembly
'Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=XXXX'.
at OracleInternal.Common.OracleTimeZone.GetInstance()
at Oracle.ManagedDataAccess.Types.TimeStamp..cctor()
--- End of inner exception stack trace ---
at OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, String instanceName)
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at CallSite.Target(Closure , CallSite , Object )
--- End of inner exception stack trace ---
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,oracle_test.ps1
I have checked, that the connection string is correct (it works for tnsping)
The Username and password are correct as well
I replaced anything that shouldn't be disclosed with XXXX
The database version is: Oracle Database 12c Release 12.1.0.1.0
The error is the same for the 32-Bit and 64-Bit Powershell instances
Before the first run the Oracle.ManagedDataAccess.dll isn't loaded, after the run it stays loaded until I close that shell
Unfortunately I'm neither an Oracle nor a Powershell Expert (I prefer MySQL and Python), therefore I would really appreciate any ideas and/or insights you might have.
Im not sure if this is technically a solution - I'd classify it more as a workaround, but it worked for me.
After doing some more research I found a suitable alternative to the Oracle.ManagedDataAccess.dll. I found the System.Data.OracleClient class of the .Net Framework. (It requires an installed Oracle Client, which the machine fortunately has)
Here's an outline of the solution that worked for me:
add-type -AssemblyName System.Data.OracleClient
$username = "XXXX"
$password = "XXXX"
$data_source = "XXXX"
$connection_string = "User Id=$username;Password=$password;Data Source=$data_source"
$statement = "select level, level + 1 as Test from dual CONNECT BY LEVEL <= 10"
try{
$con = New-Object System.Data.OracleClient.OracleConnection($connection_string)
$con.Open()
$cmd = $con.CreateCommand()
$cmd.CommandText = $statement
$result = $cmd.ExecuteReader()
# Do something with the results...
} catch {
Write-Error (“Database Exception: {0}`n{1}” -f `
$con.ConnectionString, $_.Exception.ToString())
} finally{
if ($con.State -eq ‘Open’) { $con.close() }
}
Use the server:port/service syntax.
$dataSource="server.network:1522/service1.x.y.z"
Here is my (Powershell, but you can adapt to C#) code to do this with ODP.NET managed data access.... which I load directly using the Powershell Add-Type but in C# would be a using/reference...
create a connection, using the connection builder class to ensure the resulting connection string is exactly as desired. Of course you can simplify but this is self-documenting:
function New - OracleConnection { <
#
.SYNOPSIS# generate a well - formed connection string with individual properties
Create and open a new Oracle connection using optional connectionstring argument
.DESCRIPTION
Create and open a new Oracle connection using optional connectionstring argument
.EXAMPLE
New - OracleConnection
New - OracleConnect - connectionString "My well-formed Oracle connections string"
.NOTES
Connection is opened here by
default# > #Add - Type - Path ".\Oracle.ManagedDataAccess.dll" [OutputType([Oracle.ManagedDataAccess.Client.OracleConnection])]
Param(
[Parameter(Mandatory = $false)]
[string] $theConnectionString, [Parameter(Mandatory = $false)]
[string] $openOnCreate = "1"#
means true - open the connection...
)[Oracle.ManagedDataAccess.Client.OracleConnection] $con = New - Object - TypeName Oracle.ManagedDataAccess.Client.OracleConnection;
if ([string]::IsNullOrEmpty($theConnectionString)) {#
$dataSource = "*********:1521/******;"
$conStringBuilder = New - Object Oracle.ManagedDataAccess.Client.OracleConnectionStringBuilder;
$conStringBuilder["Data Source"] = $dataSource;
$conStringBuilder["User ID"] = "*******";
$conStringBuilder["Password"] = "*******";
$conStringBuilder["Persist Security Info"] = $True;
$conStringBuilder["Connection Lifetime"] = 180;
$conStringBuilder["Connection Timeout"] = 10;
$conStringBuilder["Pooling"] = $true;
$conStringBuilder["Min Pool Size"] = 10;
$conStringBuilder["Max Pool Size"] = 20;
$conStringBuilder["Incr Pool Size"] = 5;
$conStringBuilder["Decr Pool Size"] = 2;
$conStringBuilder["Statement Cache Size"] = 200;
$conStringBuilder["Statement Cache Purge"] = $false;#
default
$con.ConnectionString = $conStringBuilder.ConnectionString;
} else {
$con.ConnectionString = $theConnectionString;
}
if (Get - IsTrue - yesNoArg $openOnCreate) {
if (-not(Get - ConnectionStateIsOpen($con))) {#
attempt open, ignore error
if already open.State is normally open after successful create
try {
$con.Open();
} catch {
$null;
}
}
}
Write - Output - NoEnumerate $con;
}
get a connection:
$con = New - OracleConnection;
open / close as necessary(it defaults to open...)
...
...
if ($con.State - ne[System.Data.ConnectionState]::Open) {
$con.Open();#
no arguments that I know of ...
}
use it and then close/dispose...
$sql = "SELECT * FROM YOUR_TABLE t WHERE t.SOMETHING = :the_parm";
[Oracle.ManagedDataAccess.Client.OracleCommand]$cmd = New-Object -TypeName Oracle.ManagedDataAccess.Client.OracleCommand;
$cmd.Connection = Get-OracleConnection;
$cmd.CommandText = $sql;
$cmd.BindByName = $true;
$dbType = ([Oracle.ManagedDataAccess.Client.OracleDbType]::VarChar2);
$cmd.Parameters.Add(( New-Param -name "the_parm" -type $dbType -size 15 )).Value = $the_criteria_value ;
Write-Output -NoEnumerate ($cmd.ExecuteScalar());
$cmd.Connection.Close();
$cmd.Dispose();
It could very well be an issue with oracle 12.2.x
I had to add the following lines to the sqlnet.ora file on the database server to allow connections from older oracle clients:
SQLNET.ALLOWED_LOGON_VERSION_CLIENT=8
SQLNET.ALLOWED_LOGON_VERSION_SERVER=8
Once added I could login with oracle 10g and 11g clients
I had the exact same issue and I switched from ODAC version 12.2.0.1.0 to version 11.2.0.3 and it worked like a charm to Open connection and read data. Hope this helps.
Thanks,
SK
Related
I'm using winexe from my backend api to run commands on Windows Domain Server. I want to set IIS App Pool Identity as an Account from Active Directory. The problem is that while using this command :
%windir%\system32\inetsrv\appcmd.exe set config /section:applicationPools ^
/[name='POOLNAME'].processModel.identityType:SpecificUser ^
/[name='POOLNAME'].processModel.userName:DOMAIN\USER ^
/[name='POOLNAME'].processModel.password:PASSWORD
It runs successfully everytime even if the username and password is incorrect. Even the pool gets Started with wrong password. However setting wrong password through GUI fails.
I want to identify when the password or username is being set wrongly.
PS: I even tried using Set-ItemProperty on powershell and the result was the same.
You can't test your credentials with AppPool, but you can definitely test them.
# Service Principal credentials
$username = 'Username'
$password = 'Password' | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList $username, $password
if (Test-Credential -Credential $credential) {
Write-Verbose "Credentials for $($credential.UserName) are valid..."
# do the appcmd stuff
}
else {
Write-Warning 'Credentials are not valid or some other logic'
}
Just add Test-Credential function definition at the top of your script
function Test-Credential {
[CmdletBinding()]
Param
(
# Specifies the user account credentials to use when performing this task.
[Parameter()]
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$DS = $null
$Username = $Credential.UserName
$SplitUser = $Username.Split('\')
if ($SplitUser.Count -eq 2 ) {$Username = $SplitUser[1]}
if ($SplitUser.Count -eq 1 -or $SplitUser[0] -eq $env:COMPUTERNAME ) {
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('machine', $env:COMPUTERNAME)
}
else {
try {
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('domain')
}
catch {
return $false
}
}
$DS.ValidateCredentials($Username, $Credential.GetNetworkCredential().Password)
}
(PS: Code is valid even though prettifier break with backslash quote syntax)
amazingly i puzzled out that you can do it like this - but it still doesn't validate
appcmd set apppool junkapp /processmodel.password:junkpassword
add-type -AssemblyName System.Data.OracleClient
$username = "SYSTEM"
$password = "password"
$data_source = "production"
$connection_string = "User Id=$username;Password=$password;Data Source=$data_source"
try{
$statement = "SELECT SYSDATE FROM DUAL"
$con = New-Object System.Data.OracleClient.OracleConnection($connection_string)
$con.Open()
$cmd = $con.CreateCommand()
$cmd.CommandText = $statement
$result = $cmd.ExecuteReader()
# Do something with the results...
Write-Host $result + "data"
If($result.HasRows) {
try {
while ($result.Read())
{
"[0] : " + $result.GetValue(0)
}
}
catch
{
#log error
}
finally
{
$con.Close()
}
}
} catch {
Write-Error (“Database Exception: {0}`n{1}” -f `
$con.ConnectionString, $_.Exception.ToString())
} finally{
if ($con.State -eq ‘Open’) { $con.close() }
}
I am executing SELECT SYSDATE FROM DUAL
I am expecting 21-MAY-19
However no data is returned. (no error is presented either)
As mentioned in the above comments, you've to send the content of $result to PowerShells output stream. The output stream is used to realize the pipeline feature of Powershell. If you wrap your code in e.g. "myCode.ps1" and invoke it via:
.\myCode.ps1
The content of $result is pushed in the output stream (pipeline). Since no other cmdlet is attached to the call of myCode.ps1 the Powershell host (= your command line) will receive the content. The default behavior of the host is to dump the content.
So add the following to your code:
$result = $cmd.ExecuteReader()
# Return $result to the pipeline
$result
Read more about pipelines here and more about streams here.
UPDATE1: This link describes more or less the code sample of the question. Maybe the Orcale .NET data provider is missing. Add it via:
Add-Type -Path "PathToDll\Oracle.ManagedDataAccess.dll"
Hope that helps.
We have two APIs that does a POST and GET requests. Both of them used to work perfectly fine but the API that does POST started giving an error:
Invoke-WebRequest : The underlying connection was: An unexpected error occurred on a receive.`
I have been trying to research for few days and all the KBs pointing to some sort of SSL/TLS and adding this piece of code:
[Net.ServicePointManager]::SecurityProtocol = "SystemDefault,Tls12, Tls11, Tls, Ssl3"
but I already had this code from the start. However, I cannot find a solution to my problem.
OS : Windows 2012
PowerShell Version: 4.0
function funName ($Val1, $Val2) {
[Net.ServicePointManager]::SecurityProtocol = "SystemDefault,Tls12, Tls11, Tls, Ssl3"
#[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
$url = "https://someAPI/post.request/do-something"
$user = "username"
$pass = "password"
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$basicAuthValue = "Basic $encodedCreds "
$Headers = #{
"Accept"="application/json"
Authorization = $basicAuthValue
}
$Body = #{
'#type' ='x'
parm1 = $Val1
parm2 = $Val2
}
#[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -Headers $Headers -Method Post -Body $Body | Out-Null
}
## Deactivation Request ffffffff##
funName -RequestID Val1 adID Val2
As stated earlier, this used to work up until last week.
Set this to the top of your script:
Add-Type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace myTrust
{
public class TrustAllCertsPolicy : ICertificatePolicy
{
public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem)
{
return true;
}
}
}
"#
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
[System.Net.ServicePointManager]::CertificatePolicy = New-Object myTrust.TrustAllCertsPolicy
I was working on a similar request to retrieve data from API and I found out that I was calling my function as funName -val1 1234 val2 9999 where I was missing "-" on my seconda parameter. As soon as I fixed that it starting working again funName -val1 1234 -val2 9999 . Thanks Stackoverflow community for the help on this.
I am trying to create a new Octopus deploy step, which will call a http endpoint.
I have found the following step type that seems promising, but can get any documentation on it:
"Http Json Value Check
Gets json from http endpoint, looks-up a value by key and checks that it matches a predefined value. If value matches then script exists with a success code, if value does not match then script exists with a failure code."
I am not sure what to enter for the:
"Json Key" and the "Expected Value"
Has anyone done this? have an example or suggest a different method to achieve what I am trying?
Here is a PowerShell script I use to get the JSON from an endpoint and check for a valid Value. If I could remember where I got the code base before I modified it a little I would give credit to the original author. It will work with either a string or a regex.
#-------------------------------------------------------------------------
# Warmup.ps1
#-------------------------------------------------------------------------
[int]$returnme = 0
[int]$SleepTime = 5
[string]$regex = '[>"]?[aA]vailable["<]?'
[string]$strContains = $regex
# [string]$strContains = "log in"
[string]$hostName = hostname
[string]$domainName = (Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName .).DNSDomain
[string]$warmMeUp = "http://$hostName.$domainName/endpoint"
[string]$html = "Will Be Set Later"
#-------------------------------------------------------------------------
# Get-WebPage
#-------------------------------------------------------------------------
function Get-WebPage([string]$url)
{
try
{
$wc = new-object net.webclient;
$wc.credentials = [System.Net.CredentialCache]::DefaultCredentials;
[string]$pageContents = $wc.DownloadString($url);
$wc.Dispose();
}
catch
{
Write-Host "First Try Failed. Second Try in $SleepTime Seconds."
try
{
Start-Sleep -s $SleepTime
$wc = new-object net.webclient;
$wc.credentials = [System.Net.CredentialCache]::DefaultCredentials;
$pageContents = $wc.DownloadString($url);
$wc.Dispose();
}
catch
{
$pageContents = GetWebSiteStatusCode($url)
}
}
return $pageContents;
}
#-------------------------------------------------------------------------
# GetWebSiteStatusCode
#-------------------------------------------------------------------------
function GetWebSiteStatusCode
{
param (
[string] $testUri,
[int] $maximumRedirection = 5
)
$request = $null
try {
$request = Invoke-WebRequest -Uri $testUri -MaximumRedirection $maximumRedirection -ErrorAction SilentlyContinue
}
catch [System.Net.WebException] {
$request = $_.ErrorDetails.Message
}
catch {
Write-Error $_.Exception
return $null
}
return $request
}
#-------------------------------------------------------------------------
# Main Application Logic
#-------------------------------------------------------------------------
"Warming up '{0}'..." -F $warmMeUp;
$html = Get-WebPage -url $warmMeUp;
Write-Host "Looking for Pattern $strContains"
if ($html.ToLower().Contains("unavailable") -or !($html -match $strContains))
{
$returnme = -1
Write-Host "Warm Up Failed. html returned:`n" + $html
}
exit $returnme
I need to verify that the underlying server-side account running my WCF Service has correct ACL permissions to various points on the local file system. If I can get the underlying Windows Identity, I can take it from there. This folds into a larger Powershell script used after deployment.
Below is my powershell snippet, that get the ApplicationPoolSid, how do you map this to the AppPool's Windows Identity?
$mywcfsrv = Get-Item IIS:\AppPools\<MyWCFServiceName>;
Updated below to include Keith's snippet
For completeness, here's the solution:
Function Get-WebAppPoolAccount
{
param ( [Parameter(Mandatory = $true, Position = 0)]
[string]
$AppPoolName )
# Make sure WebAdmin module is loaded.
$module = (Get-Module -ListAvailable) | ForEach-Object { if ($_.Name -like 'WebAdministration') { $_ } };
if ($module -eq $null)
{
throw "WebAdministration PSSnapin module is not available. This module is required in order to interact with WCF Services.";
}
Import-Module $module;
# Get the service account.
try
{
$mywcfsrv = Get-Item (Join-Path "IIS:\AppPools" $AppPoolName);
}
catch [System.Exception]
{
throw "Unable to locate $AppPoolName in IIS. Verify it is installed and running.";
}
$accountType = $mywcfsrv.processModel.identityType;
$account = $null;
if ($accountType -eq 'LocalSystem')
{
$account = 'NT AUTHORITY\SYSTEM';
}
elseif ($accountType -eq 'LocalService')
{
$account = 'NT AUTHORITY\LOCAL SERVICE';
}
elseif ($accountType -eq 'NetworkService')
{
$account = 'NT AUTHORITY\NETWORK SERVICE';
}
elseif ($accountType -eq 'SpecificUser')
{
$account = $mywcfsrv.processModel.userName;
}
return $account;
}
Like so:
$mywcfsrv = Get-Item IIS:\AppPools\<MyWCFServiceName>
$mywcfsrv.processModel.identityType