I'm trying to return an array from a function that query a sql table.
All ok but only if the elements of array is more than one. If the array is composed by only one element the function doesn't return a type array but a type string. I'm a newbie to powershell and so confused...
Here my function :
Function test2{
$query = #"
SELECT DfsTgtPath
FROM DfsData_v2 WHERE TgtSrvName = 'compname' AND DfsTgtPath LIKE
'%string%' ORDER BY DfsTgtPath"#
$connection = new-object system.data.sqlclient.sqlconnection("server=SQLSERV;database=DB;trusted_connect>i on=true;" )
$adapter = new-object system.data.sqlclient.sqldataadapter ($query,$connection)
$table = new-object system.data.datatable
$recs = $adapter.Fill($table)
$aDfsTgtPath = #($table | select -ExpandProperty DfsTgtPath)
return #($aDfsTgtPath)
}
$result = test2
I would expect the $result as an array containing one single string element but it's seems to be not an array but of type System.String.
Related
I am writing a script in PowerShell Core 7.2. I get a list of files from a folder that I check against Oracle db. I need the data of Description, and NC_Name column if the file is in db.
The issue is that even when the file is not in db it still returns the data but of some other file.
For example: I have a list of files, File#1, File#2,File#3. If File#2 is not in the db it still returns the data of File#1.
I have tried counting the number of rows and putting it as a condition. As in
$rowNum = $connection.count
The issue with this is that $rowNum is never zero because it returns data for some other file; because the variable $fileName is never empty.
I also tried checking for the file name in the query itself but it gave a lot of errors. The query was
$query="DECLARE record_exists INTEGER; BEGIN SELECT COUNT(*) INTO record_exists FROM NC_PROGRAMS WHERE NC_PROGRAMS.NC_NAME = '$fileName' AND ROWNUM = 1; IF record_exists = 1 THEN Select DESCRIPTION, NC_NAME"
The code is:
#Get all files
$result = $start.EnumerateDirectories() | ForEach-Object -Parallel {
$_.GetFiles('*.EIA', $using:enum)
}
$result | Format-Table -AutoSize
foreach($item in $result){
$fileName = $item.BaseName
#Oracle connection
Add-Type -Path C:\lib\netstandard2.1\Oracle.ManagedDataAccess.dll
$query = "Select DESCRIPTION, NC_NAME From NC_PROGRAMS WHERE
NC_PROGRAMS.NC_NAME = '$fileName' "
$connectionString = "connectionString"
$connection = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connectionString)
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $query
$reader = $command.ExecuteReader()
$rowNum = $connection.count
Write-host "Number of rows-"$rowNum
while($reader.Read()) {
$description=$reader.GetString(0)
$fastemsFileName = $reader.GetString(1)
}
$connection.Close()
}
My function works perfectly if I provide one instance of ComputerName value. My question is how to modify SQL query so it could accept an array? I don't believe creating a loop to query a database several times is a proper way. For example, I think this SQL query with IN clause is a proper way:
SELECT * FROM Customers WHERE Country IN ('Germany', 'France', 'UK');
In other words, I'd like to be able to call this function providing multiple ComputerName values. Like this:
PS C:\>Get-Query_Database_Query1('comp01','comp02')
The code I need help with. Please use SQLParameters to build SQL query:
function Get-Query_Database_Query1
{
[OutputType([System.Data.DataTable])]
param
(
[Parameter(Mandatory = $false,
Position = 1)]
[string]$PCname
)
#Database Query
$QueryString = "select * from [Table1] where [ComputerName]=#PCname"
#Database Connection String
$ConnectionString = 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Open\Database4.mdb;Password=;User ID=Admin'
$command = New-Object System.Data.OleDb.OleDbCommand ($QueryString, $ConnectionString)
$Command.Parameters.Add("#PCname", [System.Data.OleDb.OleDbType]::VarChar, 50).Value = $PCname;
$adapter = New-Object System.Data.OleDb.OleDbDataAdapter ($command)
#Load the Dataset
$dataset = New-Object System.Data.DataSet
[void]$adapter.Fill($dataset)
#Return the Dataset
return #( ,$dataset.Tables[0])
}
You need to do a little bit of string manipulation, also when working with SQL queries is a lot easier to use Here Strings.
If you are going to pass multiple computers to your functions, the parameter $PCname has to be able to accept an array of strings, hence changing [string] to [string[]].
Check out this code and see if it works for you:
function Get-Query_Database_Query1
{
[OutputType([System.Data.DataTable])]
param
(
[Parameter(Mandatory = $false,
Position = 1)]
[string[]]$PCname
)
#Database Query
$QueryString = #"
SELECT *
FROM [Table1]
WHERE [ComputerName] IN ('{0}')
"# -f ($PCname -join "','")
$QueryString
}
Get-Query_Database_Query1 -PCname 'computer1','computer2','computer3','computer4'
Here is how the query should look like:
PS /home/> Get-Query_Database_Query1 -PCname 'computer1','computer2','computer3','computer4'
SELECT *
FROM [Table1]
WHERE [ComputerName] IN ('computer1','computer2','computer3','computer4')
I'm trying to operate with the result of this query to then run an update query on specific values of the result. What i'm trying to do is to get all the values from the table and then check if those values are between 1 and 5 and turn those to null. Since i can't do this in one update query, i'm doing first a select and then operate on the singular values that i get from the result, but the query returns me a dataset result which i can't operate with in PowerShell (or at least i don't know how). What can i do? The main objective of this should be an update to all the columns of the table on the db to change the columns with values between 1 and 5 and turn them into null values
Here is the code:
$SQLServer = "Server\SQLEXPRESS"
$SQLDBName = "Prova"
$SqlQuery = "Select * from table_2 where id=1"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; trusted_connection=true;"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter.SelectCommand = $SqlCmd
$Dataset = New-Object System.Data.DataSet
$SqlAdapter.Fill($Dataset)
$array=$Dataset.Tables[0]
$SqlConnection.Close()
A fellow few-months old newbie here(me), ill try to give this a shot!
You can actually loop through the rows of the dataset you have, and access the properties (columns) in those rows, modify it and then dynamically create an update statement and execute it on your server.
The main part is presented below, the rest are just the functions i defined myself. Not sure if this is what you had in mind but my testing setup went something like this. (Note please execute/define the functions first in your powershell session before you run the code below)
# SET VARIABLES
$Serv = <Your Server>
$DB = <Your DB>
$TSQL = "SELECT * FROM TestTBL"
# Target Results table from SQL
$MainResultsTable = (GetSQLData $Serv $DB $TSQL).Tables[0]
#Get Column names
$Colnames = ($MainResultsTable.Rows | gm -MemberType NoteProperty,Property).Name
# Loop through each row of data from SQL results
foreach($row in $MainResultsTable.Rows)
{
# Construct the TSQL update statement. Using an array to construct the multi column updates.
$TSQLUpdate = "UPDATE TestTBL SET "
$TSQLUpdateArr =#()
foreach($Col in $Colnames)
{
# We don't need to update the ID
if($Col -ne 'ID')
{
$TSQLUpdateArr += "$Col = $(EvaluateColumnData $row.$Col)`n"
}
}
# join the columns with the corresponding end of TSQL where the target ID is specified
$TSQLUpdate += $($TSQLUpdateArr -join ",").ToString() + " WHERE ID = $($row.ID);"
# Execute the update on SQL server
UpdateSQL $Serv $DB $TSQLUpdate
}
Putting a few snippets of the functions I wrote for SQL here too. [Open to optimization and critics to make this faster or more 'semanticy']
# Define custom user function to set the values to be used for updating
function EvaluateColumnData()
{
param( $data )
if($data -le 5){ return "NULL" }
else { return $data }
}
# Get data from SQL
function GetSQLData()
{
param( $tgtServ,$tgtDB,$tgtTSQL )
# Create connection obj
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "server="+$tgtServ+";database="+$tgtDB+";trusted_connection=true;"
# Open SQL connection
$SqlConnection.open()
# Create TSQL CMD object and pass the connection object
$SQLCommand = New-Object System.Data.SQLClient.SQLCommand
$SQLCommand.Connection = $SqlConnection
# TSQL statement to be executed
$SQLCommand.CommandText = $tgtTSQL
$SQLCommand.CommandTimeOut = 0
# Container/adapter for SQL result
$resultAdapter = New-Object System.Data.SqlClient.SqlDataAdapter($SQLCommand)
# DataSet where the results are dumped
$resultDS = New-Object System.Data.DataSet
$resultAdapter.Fill($resultDS) | Out-Null
$SqlConnection.Close()
return ,$resultDS
}
# Execute TSQL statement without results
function UpdateSQL()
{
Param( $tgtServ,$tgtDB,$tgtTSQL )
$ServerConn = New-Object System.Data.SQLClient.SQLConnection
$ServerConn.ConnectionString = "server="+$tgtServ+";database="+$tgtDB+";trusted_connection=true;"
$ServerConn.Open()
$ServerCMD = New-Object System.Data.SQLClient.SQLCommand
$ServerCMD.Connection = $ServerConn
$ServerCMD.CommandText = $tgtTSQL
$ServerCMD.CommandTimeOut = 0
$ServerCMD.ExecuteNonQuery() | out-null
$ServerConn.Close()
}
Hope this helps. There are a lot of things out there you can read(which im still reading lol) which offers better explanation, I suggest focusing on the basics.
Recommended reading: DataTables, PS objects/Custom objects, hashtable, Functions.
I want to write a query in powerShell which checks an attribute value in an xml column called(xml_multiple) and return boolean value 1 if it exist(otherwise 0) and pass it to a variable and call a sendemail function.
According to the value of variable the email will be sent.
1- for success
0- for failure
I'm new to powershell and not very good at it. I'm open to suggestion as long it works.Thanks in advance. Check the code below and xml
$dataSource = "DB.abc.com"
$connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$query = “ ” <#here i want to write my query#>
$command = $connection.CreateCommand()
$command.CommandText = $query
$result = $command.ExecuteReader()
$table = new-object “System.Data.DataTable”
$table.Load($result)
$connection.Close()
function sendemail()
{
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = "abc#xyz.com"
if ($send -eq 1) <#here i want to pass value from db#>
{
$Mail.Subject = "Process Successful"
$Mail.Body ="Success`n`nThank you"
}
else
{
$Mail.Subject = "Process Unsuccessful"
$Mail.Body ="Unsuccess`n`nPlease look into it"
}
$Mail.Send()
}
Note: This is the xml and if any xml has a attribute start="1" return 1 else 0. for a particular day(There will be only one record in a day which will have this attribute,so we can use a filter in the query for that)
<jobparameters start="1">
<work>1
</work>
</jobparameters>
P
lease give suggestions
It is possible to get the needed results directly from SQL Server:
DECLARE #x XML = '
<jobparameters start="1">
<work>1
</work>
</jobparameters>';
DECLARE #t TABLE (xml_multiple XML);
INSERT #t(xml_multiple) VALUES(#x);
SELECT c.value('#start','INT') send
FROM #t
OUTER APPLY xml_multiple.nodes('/jobparameters')x(c);
What I need to do are:
1, query a row of xml from a sql server datatable. See pic below,the Row named StageDesccontents xml file.
2, the xml file contents a path //sharespace/test1/10.0.1212.0which I need to get, this was forming as<releasepath>//sharespace/test1/10.0.1212.0</releasepath> in the xml file.
Here are my codes try to get it:
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlQuery = "SELECT Stage.Description as StageDesc,Stage.StageStatusId FROM [Build].[dbo].[WorkflowInstance_View] as Build
join [Build].[dbo].[Stage_View] as Stage on Build.Id=Stage.[WorkflowInstanceId] where Stage.ParentId is null and Stage.StageStatusId <>4 and Stage.StageStatusId <>7 order by Build.Id desc"
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $Connection
$DBResult = $sqlcmd.ExecuteReader()
$DataTable = New-Object system.data.datatable
$DataTable.load($DBResult)
foreach ($StageDesc in $DataTable) {
[XML]$ReturnedXML=$StageDesc.releasepath
}
The code passed but returned nothing. Why this happened? Could anybody would like to help me?
You're assigning your xml data to a variable $RetrunedXML and overwriting the assignment on each iteration of your foreach. Have you checked $ReturnedXML?
Using the sample database for SQL Server 2008, I can use this:
$serverName = "$env:computername\sql1"
$databaseName = "AdventureWorks"
$query = "SELECT * from Person.Contact where AdditionalContactInfo IS NOT NULL"
$conn=new-object System.Data.SqlClient.SQLConnection
$connString = “Server=$serverName;Database=$databaseName;Integrated Security=SSPI;”
$conn.ConnectionString=$connString
$conn.Open()
$cmd=new-object system.Data.SqlClient.SqlCommand($Query,$conn)
$da = New-Object “System.Data.SqlClient.SqlDataAdapter” ($cmd)
$dt = New-Object “System.Data.DataTable”
$da.fill($dt) | out-null
$conn.Close()
$dt | foreach {[xml]$ReturnedXML = $_.AdditionalContactInfo; $ReturnedXML}
All you do in the code is declaring and assigning variables. There is no code that outputs or displays anything. Nor do you return any variable. So what do you expect the code should return? In which line? Did you even try to debug the code?
$da.fill($dt)
Loads the query results into DataTable $dt.
$dt | Out-GridView
Shows all the data.
The script worked great for me (except the last line, which didn't apply for my case).