Powershell How to query multiple classes and write in to SQL Table - sql

Not knowing Powershell very well and indeed sql it's taken me all week to piece together a script thatkind of works but I need help expanding on it. It works for retrieving more than 1 value from the same class and inserts the values. What I need to do is to be able to retrieve values from other classes and insert the result in to the appropriate column. Any help / advice would be so appreciated.
$servernames = Get-WmiObject -computername Anycompname -class win32_ComputerSystem | Select Name, Manufacturer
# Open Connection
$conn = New-Object System.Data.SqlClient.SqlConnection
$connectionString = "Server=;Database=;user=;pwd=;"
$conn.ConnectionString = $connectionString
$conn.Open()
# Create the Command object to execute the queries
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.Connection = $conn
$cmd.CommandType = [System.Data.CommandType]::Text
# Write Data
foreach ($servername in $servernames)
{
# Compose Query for this $servername - watch the single quotes for string values!!
$query = "INSERT INTO dbo.U_Server (ServerName, OSVersion) VALUES ('" + $servername.Name + "', '" + $servername.Manufacturer + "')"
# Uncomment next line to display query for checking
$query
# Setup Command
$cmd.CommandText = $query
# Execute Command to insert data for this $drive
$result = $cmd.ExecuteNonQuery()
}
# Tidy Up
$conn.Close()

Just get the other WMI object(s) in the foreach loop and keep adding to your insert string as needed.
foreach ($servername in $servernames)
{
## Get other WMI info as needed here.
$os = Get-WmiObject -class win32_operatingsystem –computername $servername.Name
$processors = Get-WmiObject Win32_Processor -computername $servername.Name
# Compose Query for this $servername
$query = "Insert Into dbo.U_Server (ServerName, OSVersion, OSName, OSServicePack) Values
('$($servername.Name)', '$($servername.Manufacurer)', ‘$($os.Caption)’, ‘$($os.ServicePackMajorVersion)’ )"
## The rest of your foreach loop follows
} ## End of foreach

Related

Powershell Rename file based on SQL query

We take a lot of photograph's for product imagery . I have found a piece of software that will read a Barcode embeded in the image and rename the Image to the Barcode within the image , what i now want to do is rename the File again with the Productid using powershell with an SQL query within ,
declare #$CliRef nvarchar(max)
set #$CliRef = '5015807416980'
Select convert(nvarchar(max), productid) as ID FROM products WHERE products.Barcode = #$CliRef
I Found a Powershell script online but I must be doing something wrong as its renaming the file blank rather than a productid , I'm really new to Powershell so a little stuck so any help appreciated
$Database = "training"
$Server = "ART-WM01"
##Not sure i need this bit
function Select-Info($CliRef)
{
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$Server;Initial Catalog=$Database;Integrated Security = True"
$SqlConnection.Open()
$conn.open()
$query = “Select convert(varchar,producdid )as ID FROM products WHERE barcode = '$CliRef'”
$cmd = New-Object System.Data.SqlClient.SqlCommand($sql,$conn)
$cmd.connection = $SqlConnection
$cmd.commandtext = $query
$result = $cmd.executenonquery()
$SqlConnection.Close()
return $query
}
## Return ID from Database
function Return-Info($CliRef)
{
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$Server;Initial Catalog=$Database;Integrated Security = True"
$SqlConnection.Open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.commandtext = “Select convert(varchar, productid) as ID FROM products WHERE barcode = '$CliRef'”
$cmd.connection = $SqlConnection
$result = $cmd.ExecuteScalar()
$SqlConnection.Close()
return $result
}
## Collect the image names
$FiNms = Get-ChildItem C:\JJC\Test_Dump -Name
## Loop through each Image name
foreach ($FiNm in $FiNms)
{
## Variable for current File path
$file = “C:\JJC\Test_Dump\” + $FiNm
## Variable for new File path
$newFile = “C:\JJC\Test_Dump\renamed” + $FiNm
$ID = Return-Info $FiNm
$ID = $ID + “.tiff”
##Copy-Item $file -Destination $newFile
##Copy-Item $file -Destination = “C:\JJC\\Test_Dump\renamed\”
Rename-Item $file $ID -force
}

Cyclic csv-Import to SQL file by file

I try to write a short script that cyclic imports csv-files to a SQL data table that are being dropped in an import folder ($sourceSQL). Each csv-file consists of one line of information (here three columns). To make sure that the file was successfully written to the data table, I check if the unique Id can be found in the table.
So far it works with the first file. However, the second file gets only moved to the destination folder without being written to the data table. I can't find the problem. Is it because of the $data variable?
$StartButton.Add_Click({
$script:ActiveLoop = $true
while ($script:ActiveLoop){
If (Test-Path $sourceSQL){
$data = $null
Do{
$data = import-csv $impcsv -Header A,B,C
foreach($i in $data)
{
$Id = $i.A
$State = $i.B
$Sequence = $i.C
$query = INSERT INTO $SQLTable (Id, State, Sequence)
VALUES ('$Id','$State','$Sequence')"
$impcsv = invoke-sqlcmd -Database $SQLDatabase -Query $query -serverinstance $SQLInstance -Username $SQLUsername -Password $SQLPassword}
$SqlQueryId = "SELECT TOP 1 Id from $SQLTable ORDER BY Id DESC"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLInstance; Database = $SQLDatabase; User ID = $SQLUsername; Password = $SQLPassword"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQueryId
$SqlCmd.Connection = $SqlConnection
$SqlConnection.Open()
$IdCheck= [string]$SqlCmd.ExecuteScalar()
$SqlConnection.Close()
} Until ($Id -eq $IdCheck)
Move-Item $sourceSQL -Destination $destinationSQL
}
[System.Windows.Forms.Application]::DoEvents()
}
})
$objForm.Controls.Add($StartButton)

PowerShell Script that Queries SQL Table to CSV File using Loop

I have a basic SQL table of Employees. Using a powershell script I want to export all the employees who have made over 1000 sales to a .csv file and the rest into a different .csv file. I want to accomplish this task by using a loop. I am new to powershell and want to learn the foundations. Can anyone help?
SQL Table (not real employees)
This is what I have so far:
$connection.Open()
[System.Data.SqlClient.SqlDataReader]$result = $cmd.ExecuteReader()
$highDestFile = "C:\high-sales.csv"
$lowDestFile = "C:\low-sales.csv"
while($result.Read()) {
$ename = $result.GetValue(3);
$job = $result.GetValue(4);
$sales = $result.GetValue(7);
$tableArray = New-Object System.Collections.ArrayList
$tableArray.Add($ename)
$tableArray.Add($job)
$tableArray.Add($sales)
if($sales -ge 1000) {
Out-File -FilePath $highDestFile -InputObject $tableArray -Encoding ASCII -Append
} else {
Out-File -FilePath $lowDestFile -InputObject $tableArray -Encoding ASCII -Append
}
}
$connection.Close()
I'm not real familiar with the method you're using to get your results, but I think I have something similar that might be easier to work with for you. It will get all results into PS, and you can filter things from there, rather than getting one result at a time. You obviously know how to make your own SqlConnection and SqlCommand, I'm just including them for future readers to reference.
# Define SQL query
$sqlQuery = #"
SELECT *
FROM MyTable
"#
# Create a SqlConnection to connect to the SQL DB
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = "Server = $SqlServer; Database =$SqlCatalog; User Id = $User; Password = $Password"
# Create a SqlCommand object to define the query
$sqlCmd = New-Object System.Data.SqlClient.SqlCommand
$sqlCmd.CommandText = $sqlQuery
$sqlCmd.Connection = $sqlConnection
# Create a SqlAdapter that actually does the work and manages everything
$sqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$sqlAdapter.SelectCommand = $sqlCmd
# Create an empty DataSet for the query to fill with its results
$dataSet = New-Object System.Data.DataSet
# Execute the query and fill the DataSet (then disconnect)
$sqlAdapter.Fill($dataSet)
$sqlConnection.Close()
# Convert DataSet table to array for ease of use
[Array]$Results = $dataSet.Tables[0]
Beyond that you could just use a pair of Where statements to filter your results, and output to files.
$Results | ?{[int]$_.Sales -ge 1000} | Set-Content $highDestFile
$Results | ?{[int]$_.Sales -lt 1000} | Set-Content $lowDestFile

Powershell import csv to SQL queries, export multiple csvs

I'm struggling to get my head around this one, I've only just begun looking at scripting in SQL, and my powershell is very limited. The requirments are basically this:
Utilisng Powershell, import a csv file which contains one column that needs to feed into multiple SQL queries via a loop, exporting a seperate csv file for each different query.
example import of csv:
Project (heading)
1000
1001
1002
Powershell:
$importProjectsCSV = e:\Projects.csv
$server = servername
$database = database
import-csv $importProjectsCSV | ForEach-Object {
$query = "
Select ProjectLeader, ProjectTitle
FROM dbo.PROJECTS
Where Project = $_.Project;
Select ProjectClient, Name
FROM dbo.CLIENTS
Where Project = $_.Project;
$connectionTemplate = "Data Source={0};Integrated Security=SSPI;Initial Catalog={1};"
$connectionString = [string]::Format($connectionTemplate, $server, $database)
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$command = New-Object System.Data.SqlClient.SqlCommand
$command.CommandText = $query
$command.Connection = $connection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $command
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$connection.Close()
$dataset.Table[0] | Export-csv "E:\" + $_.ProjectName + ".csv"
$dataset.Table[1] | Export-csv "E:\" + $_.ProjectName + ".csv"
The problem is that the variable isn't coming into the SQL query.
Is there a better way to handle this type of example?
Appreciate any pointers
Paul.
I would do something like this:
I must admit i havent been able to test it, and personally i usually use c# to query sql servers. So i might have gone a bit wrong somewhere.
$importProjectsCSV = e:\Projects.csv
$server = servername
$database = database
$Projects = Import-Csv -Path $importProjectsCSV | % {$_.Project}
$DS_Projects = New-Object System.Data.DataSet
$DS_Clients = New-Object System.Data.DataSet
$query_pro = "Select ProjectLeader, ProjectTitle, Project FROM dbo.PROJECTS";
$query_Clients = "Select ProjectClient, Name, Project FROM dbo.CLIENTS";
$connectionTemplate = "Data Source={0};Integrated Security=SSPI;Initial Catalog={1};"
$connectionString = [string]::Format($connectionTemplate, $server, $database)
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand();
$command.CommandText = $query_pro;
$sqlAdap = New-Object System.Data.SqlClient.SqlDataAdapter($command)
$sqlAdap.Fill($DS_Projects)
$command2 = $connection.CreateCommand();
$command2.CommandText = $query_Clients;
$sqlAdap2 = New-Object System.Data.SqlClient.SqlDataAdapter($command2)
$sqlAdap2.Fill($DS_Clients)
$connection.Close();
foreach($project in $Projects)
{
$DS_Projects.Tables[0].Select("Project=$project") | Export-Csv "E:\$project.csv"
$DS_Clients.Tables[0].Select("Project=$project") | Export-Csv "E:\$project.csv"
}
If I get every right you could do this with something like this:
$Projects = Import-Csv -Path 'C:\Temp\Projects.csv'
ForEach ($Project in $Projects.Projects) {
$Query= #"
Select ProjectLeader, ProjectTitle
FROM dbo.PROJECTS
Where Project = '%{0}';
"# -f $Project
# just dummy action
$results = Invoke-Sqlcmd -ServerInstance "foo" -Database "bar" -Query $Query
# In Case results is a dataset do something like
$results | Export-Csv -Path ("E:\{0}.csv" -f $Project )
}

Insert Microsoft Updates into Database

I'm trying to modify this script so that it inserts the installed updates into an SQL Server database table.
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Data Source=sqlserver; Initial Catalog=updates; Integrated Security=SSPI;"
$conn.Open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.Connection = $conn
$cmd = $conn.CreateCommand()
$wu = new-object -com “Microsoft.Update.Searcher”
$totalupdates = $wu.GetTotalHistoryCount()
$all = $wu.QueryHistory(0,$totalupdates)
$OutputCollection= #()
Foreach ($update in $all){
$Regex = “KB\d*”
$KB = $string | Select-String -Pattern $regex | Select-Object { $_.Matches }
$output = New-Object -TypeName PSobject
$output | add-member NoteProperty “HotFix ID” -value $KB.‘ $_.Matches ‘.Value
$output | add-member NoteProperty “Title” -value $string
$OutputCollection += $output
$cmd.CommandText += "INSERT INTO dbo.updates (hotfixid, hotfixdescription) VALUES ('$($kb.'$_.Matches'.Value)', ('$($string)'))"
}
$cmd.ExecuteNonQuery()
$conn.close()
At the moment, I'm getting correct number of rows for updates in sql server but it isn't showing hotfixid and in hotfix descriptien columns there is a only one update in all rows.
Thanks!
Do the INSERTs inside the loop. I would, however, recommend that you use prepared statements instead of building the SQL statements via string concatenation. Also, there's no need to build $OutputCollection objects when you're not using it anywhere.
Something like this should work:
...
$wu.QueryHistory(0, $totalupdates) | % {
$KB = $_.Title | ? { $_ -match '(KB\d+)' } | % { $matches[1] }
$cmd = $conn.CreateCommand()
$cmd.CommandText = "INSERT INTO dbo.updates (hotfixid, hotfixdescription) " +
"VALUES (#id, #descr)"
$cmd.Parameters.AddWithValue("#id", $KB)
$cmd.Parameters.AddWithValue("#descr", $_.Title)
$cmd.Prepare()
$cmd.ExecuteNonQuery()
}
...
Untested, though, since I don't have an SQL Server at hand. I also suspect that there's a more efficient way to handle the prepared statements, but I'm not that familiar with SQL Server.