Powershell SQL returns - sql

I am trying to view the results of a sql query into a remote server. My issue is that on return i see the first value repeated for each of the other values.
Here is the code:
#Connect to VPN
cls
C:
cd "C:\Program Files (x86)\Cisco Systems\VPN Client"
& ".\vpnclient.exe" connect WWVPN1 user sceris pwd ******
$vendorNumber = "2130196"
$vendorName = ""
$invoiceNumber = "1362433"
$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=wwfinance; Initial Catalog=ScerIS; Integrated Security=False; uid=Peter; pwd=*****; MultipleActiveResultSets=true")
## Open DB Connection
$conn.Open()
$sqlText = "SELECT UdiValue1, UdiValue37, UdiValue38, UdiValue3
FROM ScerIS.dbo.indexedRangesView_4
WHERE (UdiValue37 like '%$vendorName%' OR UdiValue38 like '$VendorNumber') AND UdiValue3 = '$invoiceNumber'"
$cmd = New-Object System.Data.SqlClient.SqlCommand($sqlText, $conn)
$Reader = $cmd.ExecuteReader()
while ($Reader.Read()) {
$ArchiveDate = $Reader.GetValue($1)
$VendorNumber = $Reader.GetValue($2)
$VendorName = $Reader.GetValue($3)
$InvoiceNumber = $Reader.GetValue($4)
}
write-host $ArchiveDate
write-host $VendorNumber
write-host $VendorName
write-host $InvoiceNumber
$conn.close()
#Disconnect from VPN
cd "C:\Program Files (x86)\Cisco Systems\VPN Client"
& ".\vpnclient.exe" disconnect
The output will show the archive date 4 times once for each write-host. How can i successfully get the other values to display?
Sample Output
9/4/2015 12:00:00 AM
9/4/2015 12:00:00 AM
9/4/2015 12:00:00 AM
9/4/2015 12:00:00 AM

$1, $2, $3, and $4 are never defined. If you want to get the values from the first 4 columns use:
while ($Reader.Read()) {
$ArchiveDate = $Reader.GetValue(0)
$VendorNumber = $Reader.GetValue(1)
$VendorName = $Reader.GetValue(2)
$InvoiceNumber = $Reader.GetValue(3)
}

Related

Data inserting to ODBC destination with powershell

I need to load data table to ODBC driver connection with powershell.
With OLEDB and SQL server we can use Bulk Copy and insert data quickly.
Is there such posibility with ODBC ?
I'm using powershell because it shoud have the best support for these kind of opperations,
but my current code doesn't utillise an of the dlls.
So my code firstly needs to create an insert statements with two for loops and iterate on every row and hold it in its memory,
and then to construct INSERT INTO with 1000 rows, and then repeat same thing.
Am i doomed to something like this ?
$Datatable = New-Object System.Data.DataTable
$tabledump= $src_cmd.ExecuteReader()
$Datatable.Load($tabledump)
foreach ($item in $Datatable.Rows) {
$f +=1
for ($i = 0; $i -lt $item.ItemArray.Length; $i++) {
$items = $item[$i] -replace "'" , "''"
$val +="'"+ $items + "',"
}
$vals += $val
if ($f % 1000 -eq 0 -or $f -eq $row_cnt) {
$values = [system.String]::Join(" ", $vals)
$values = $values.TrimEnd(",")
$cols = [system.String]::Join(",", $columns)
$postgresCommand = "Insert Into $dst_schema.$dst_table ($cols) values $values"
$dest_cmd_.CommandText = $postgresCommand
$dest_cmd_.ExecuteNonQuery()
Bad code i admit, any advice on code compositions are welcomed.
You can use Get-ODBCDSN command to retrieve the values of the ODBC connections and use it with a query
$conn.ConnectionString= "DSN=$dsn;"
$cmd = new-object System.Data.Odbc.OdbcCommand($query,$conn)
$conn.open()
$cmd.ExecuteNonQuery()
$conn.close()
https://www.andersrodland.com/working-with-odbc-connections-in-powershell/
But the ODBC provider doesnt do bulk copy
https://learn.microsoft.com/en-us/sql/relational-databases/native-client-odbc-bulk-copy-operations/performing-bulk-copy-operations-odbc?view=sql-server-ver15
I know this post is not new, but i've been fiddeling around looking for a solution and also found nothing, however this post gave me a couple of insights.
First: There is no such thing as 'Bad Code'. If it works is not bad, heck even if it didn't worked, but helped with something..
Alright, what i did is not the best solution, but i'm trying to import Active Directory data on PostgreSQL, so...
I noticed that you're trying with pgsql as well, so you can use the COPY statement.
https://www.postgresql.org/docs/9.2/sql-copy.html
https://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/
In my case i used it with a csv file:
*Assuming you have installed pgsql ODBC driver
$DBConn = New-Object System.Data.Odbc.OdbcConnection
$DBConnectionString = "Driver={PostgreSQL UNICODE(x64)};Server=$ServerInstance;Port=$Port;Database=$Database;Uid=$Username;Pwd=$(ConvertFrom-SecureString -SecureString $Password);"
$DBConn.ConnectionString = $DBConnectionString
try
{
$ADFObject = #()
$ADComputers = Get-ADComputer -Filter * -SearchBase "OU=Some,OU=OrgU,OU=On,DC=Domain,DC=com" -Properties Description,DistinguishedName,Enabled,LastLogonTimestamp,modifyTimestamp,Name,ObjectGUID | Select-Object Description,DistinguishedName,Enabled,LastLogonTimestamp,modifyTimestamp,Name,ObjectGUID
foreach ($ADComputer in $ADComputers) {
switch ($ADComputer.Enabled) {
$true {
$ADEnabled = 1
}
$false {
$ADEnabled = 0
}
}
$ADFObject += [PSCustomObject] #{
ADName = $ADComputer.Name
ADInsert_Time = Get-Date
ADEnabled = $ADEnabled
ADDistinguishedName = $ADComputer.DistinguishedName
ADObjectGUID = $ADComputer.ObjectGUID
ADLastLogonTimestamp = [datetime]::FromFileTime($ADComputer.LastLogonTimestamp)
ADModifyTimestamp = $ADComputer.modifyTimestamp
ADDescription = $ADComputer.Description
}
}
$ADFObject | Export-Csv $Env:TEMP\TempPsAd.csv -Delimiter ',' -NoTypeInformation
docker cp $Env:TEMP\TempPsAd.csv postgres_docker:/media/TempPsAd.csv
$DBConn.Open()
$DBCmd = $DBConn.CreateCommand()
$DBCmd.CommandText = #"
COPY AD_Devices (ADName,ADInsert_Time,ADEnabled,ADDistinguishedName,ADObjectGUID,ADLastLogonTimestamp,ADModifyTimestamp,ADDescription)
FROM '/media/TempPsAd.csv'
DELIMITER ','
CSV HEADER
"#
$DBCmd.ExecuteReader()
$DBConn.Close()
docker exec postgres_docker rm -rf /media/TempPsAd.csv
Remove-Item $Env:TEMP\TempPsAd.csv -Force
}
catch
{
Write-Error "$($_.Exception.Message)"
continue
}
Hope it helps!
Cheers!

PowerShell creating a backup of a stored procedure results in a blank file

I am trying to create a backup of a SQL stored procedure using PowerShell, but it produces a blank file. It's not throwing an error.
Here is my code:
param([String]$step='exeC dbo.test',[String]$sqlfile='',[String]$servename = 'test',[String]$dbname = 'test')
$step2=$step
$step3=$step2.Replace('[','')
$step4 = $step3.Replace(']','')
$step4 = $step4.Split(" ")[1]
$step5 = $step4.Split(".")
Write-Output $step5[0,1]
[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SqlServer.SMO”) | out-null
$logfolder = 'C:\Users\fthoma15\Documents\sqlqueries\Logs'
$bkupfolder = 'C:\Users\fthoma15\Documents\sqlqueries\Backup'
$statsfolder = 'C:\Users\fthoma15\Documents\sqlqueries\stats'
$SMOserver = new-object ("Microsoft.SqlServer.Management.Smo.Scripter") #-argumentlist $server
$srv = new-Object Microsoft.SqlServer.Management.Smo.Server("$servename")
#Prompt for user credentials
$srv.ConnectionContext.LoginSecure = $false
$credential = Get-Credential
#Deal with the extra backslash character
$loginName = $credential.UserName -replace("\\","")
#This sets the login name
$srv.ConnectionContext.set_Login($loginName);
#This sets the password
$srv.ConnectionContext.set_SecurePassword($credential.Password)
$srv.ConnectionContext.ApplicationName="MySQLAuthenticationPowerShell"
#$srv.Databases | Select name
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$db = $srv.Databases.Item("$dbname")
#$db.storedprocedures | Select name
$Objects = $db.storedprocedures[$step5[1,0]]
#Write-Output $step5[1,0]
#Write-Output $Objects
$scripter = new-object ("$SMOserver") $srv
$Scripter.Script($Objects) | Out-File $bkupfolder\backup_$($step5[1]).sql
Please help
This was an issue with permission to the database. I gave the SQL id permission to the database and now it works.

Update two different SNMP OID values through Powershell

I'm trying to update info from 4 ups's with two different OID values through powershell. I can update one but when I try to update both values I receive an error. I figured out why it's not updating the values by inserting the values onto a new table. When it inserts/updates the values the script enters both values into the table column instead of having one value for temp and one value for battery. My question is how can I update both values if there is a way. Below is my loop I am running.
# If success go call func SNMP
if($ping_reply.status -eq "Success"){
try {
$frm_snmp = Invoke-SNMPget $ups_ip $oidTemp, $oidBatload "public"
} catch {
Write-Host "$ups_ip SNMP Get error: $_"
Return null
}
# if the data doesn't match record update ups_data
if([String]::IsNullOrWhiteSpace($frm_snmp.Data)){
Write-Host "Given string is NULL"
}else{
if(($ups_temp -and $battery_load -ne $frm_snmp.Data)) {
Write-Output "database update needed"
Write-Output $ups_ip, $ups_upsname $frm_snmp.Data
$new_temp = $frm_snmp.Data
$new_battery_load = $frm_snmp.Data
$update_con = New-Object System.Data.SqlClient.SqlConnection
$update_con.ConnectionString = "connection info"
$update_con.Open()
$SQLstmt = "update ups_data set temp = '$new_temp', batteryload = '$new_battery_load' where ip_address = '$ups_ip'"
$up_cmd = $update_con.CreateCommand()
$up_cmd.CommandText = $SQLstmt
$up_cmd.ExecuteNonQuery()
$update_con.Close()
This is the working code below
# If success go call func SNMP
if($ping_reply.status -eq "Success"){
try {
$frm_snmp = Invoke-SNMPget $ups_ip $oidTemp, $oidBatload "public"
} catch {
Write-Host "$ups_ip SNMP Get error: $_"
Return null
}
# if the data doesn't match record update ups_data
if([String]::IsNullOrWhiteSpace($frm_snmp.Data)){
Write-Host "Given string is NULL"
}else{
if(($ups_temp -and $battery_load -ne $frm_snmp.Data)) {
Write-Output "database update needed"
Write-Output $ups_ip, $ups_upsname $frm_snmp.Data
$new_temp = $frm_snmp.Data
$new_battery_load = $frm_snmp.Data
$update_con = New-Object System.Data.SqlClient.SqlConnection
$update_con.ConnectionString = "connection info"
$update_con.Open()
$SQLstmt = "update ups_data set temp = '$($new_temp[0])', batteryload = '$($new_battery_load[1])' where ip_address = '$ups_ip'"
$up_cmd = $update_con.CreateCommand()
$up_cmd.CommandText = $SQLstmt
$up_cmd.ExecuteNonQuery()
$update_con.Close()

How to match SQL results with AD results and the other way around

I have to write a script that will query AD for users from a specific department that I will prompt user to input initially and then to output the software that is installed on the all machines that a specific user from the chosen department. I want to be able to see all the software from all the machine(s) that specific is logging on.
Presently I am using the following parts:
1) A query in AD to get the users from a specific department:
Import-Module ActiveDirectory
$Dept = Read-Host "Enter the desired department"
$strFilter = "(&(objectCategory=User)(Department=*$Dept*))"
$colResults = Get-ADUser -LDAPFilter $strFilter |
Select-Object -Expand DistinguishedName
2) I am also using a script from the person before me, that performs a query in SQL combined with LanDesk. See below:
$SQLServerLANDESK = "usernam\password"
$SqlConnectionLANDESK = New-Object System.Data.SqlClient.SqlConnection
$global:dt = new-object System.Data.DataTable
$LONA = ""
$o = 0
function doit() {
$SqlConnectionLANDESK.ConnectionString = "Server=$SQLServerLANDESK; Database= $SQLDBNameLANDESK;uid=useraidi; pwd=parola"
$SqlConnectionLANDESK.Open()
$QueryLANDesk = #"
SELECT DISTINCT A0.DISPLAYNAME, A0.LOGINNAME,A0.PRIMARYOWNER,A0.TYPE, A1.OSTYPE, A2.SUITENAME, A2.PUBLISHER, A2.VERSION
FROM Computer A0 (nolock) LEFT OUTER JOIN Operating_System A1 (nolock) ON A0.Computer_Idn = A1.Computer_Idn LEFT OUTER JOIN AppSoftwareSuites A2 (nolock) ON A0.Computer_Idn = A2.Computer_Idn
WHERE A0.DEVICENAME like '%D02DI0907061%'
or A0.DEVICENAME like '%D02DI0929860%'
"#
$CommandLANDesk = new-object System.Data.SqlClient.SqlDataAdapter ($QueryLANDesk, $SqlConnectionLANDESK)
$CommandLANDesk.fill($dt) | out-null
$dtrc = $dt.Rows.Count
Write-Host "($i) Searching all cores ($dtrc machines)..."
$SqlConnectionLANDESK.Close()
}
foreach ($i in 1..10)
{if ($i -eq 6) {continue}
$SQLDBNameLANDESK = "database"
$SQLServerLANDESK = "username\parola"
doit
}
Write-Host
$dt.select("displayname like '%$LONA%'") | export-csv H:\TEST\add-remove_TEST_LOGINNAME.csv # | foreach { $o++ }
# "$o machines found."
I want to be able to basically connect the result search from point 1 and match it with the "PRIMARYOWNER" which is in DistinguishedName format and to store those in a table back in SQL. How do I do that?

Add SQL Server Instances to Central Management Server Groups with Powershell

I am trying to create a script to automatically iterate through a text file of all our SQL Server instances and add each on if it doesn't already exist to the CMS. I want to try doing this through SMO instead of hardcoding sql strings in. Below is what I have so far but it doesn't seem to be working. Any help would be appreciated. Thanks.
Eventually I will add more If statements in to distribute the instances to certain groups but for now I'm just trying to get it to populate everything.
$CMSInstance = "cmsinstancename"
$ServersPath = "C:\Scripts\InPutFiles\servers.txt"
#Load SMO assemplies
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.RegisteredServers') | out-null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.Common') | out-null
$connectionString = "Data Source=$CMSINstance;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = new-object System.Data.SqlClient.SqlConnection($connectionString)
$conn = new-object Microsoft.SqlServer.Management.Common.ServerConnection($sqlConnection)
$CMSStore = new-object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServersStore($conn)
$CMSDBStore = $CMSStore.ServerGroups["DatabaseEngineServerGroup"]
$Servers = Get-Content $ServersPath;
foreach($Server in $Servers)
{
#Put this in loop to deal with duplicates in list itself
$AlreadyRegisteredServers = #()
$CMSDBStore.GetDescendantRegisteredServers()
$RegServerName = $Server.Name
$RegServerInstance = $Server.Instance
if($AlreadyRegisteredServers -notcontains $RegServerName)
{
Write-Host "Adding Server $RegServerName"
$NewServer = New-Object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer($CMSDBStore, "$RegServerName")
$NewServer.SecureConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ServerName = "$RegServerInstance"
$NewServer.Create()
}
else
{
Write-Host "Server $RegServerName already exists - cannot add."
}
}
I cut your script down to just the basics and it works for me. I did have to change the connection command to work in my environment but other than that and registering a default instance of SQL Server there were no errors. Once I did a refresh of the CMS server the newly registered server was visible and accessible.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.RegisteredServers') | Out-Null
$CMSInstance = 'CMS_ServerName'
$connectionString = "Data Source=$CMSInstance;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = new-object System.Data.SqlClient.SqlConnection($connectionString)
$conn = New-Object System.Data.SqlClient.SqlConnection("Server=$CMSInstance;Database=master;Integrated Security=True")
$CMSStore = new-object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServersStore($conn)
$CMSDBStore = $CMSStore.ServerGroups["DatabaseEngineServerGroup"]
$RegServerName = 'ServerToRegister'
$RegServerInstance = $RegServerName
$NewServer = New-Object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer($CMSDBStore, "$RegServerName")
$NewServer.SecureConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ServerName = "$RegServerInstance"
$NewServer.Create()