Create Blank Access Database Using Powershell - powershell

Normally I'd research the topic I need for a day or 2 and then ask here, but I've been struggling to find anything at all about this topic.
Does anyone know how to use PowerShell (V3) to create a new Access 2010 MDB file, with a defined table and column headings?
Thanks for any guidance.

Found some! Just for interests sake for anyone checking, here is the code:
Function Create-DataBase($Db){
$application = New-Object -ComObject Access.Application
$application.NewCurrentDataBase($Db,10)
$application.CloseCurrentDataBase()
$application.Quit()
}
Function Invoke-ADOCommand($Db, $Command){
$connection = New-Object -ComObject ADODB.Connection
$connection.Open("Provider=Microsoft.Ace.OLEDB.12.0;Data Source=$Db")
$connection.Execute($command)
$connection.Close()
}
$Db = "C:\ScheduledCodeRun\CollatedData\Test.mdb"
$table = "MyTest"
$Fields = "F1 Counter, F2 Date, F3 Integer, F4 Text"
$command = "Create Table $table($fields)"
If(Test-Path $Db){
Write-Host 'DB already exists' -fore green
}else{
Create-DataBase $db
Invoke-ADOCommand $Db 'Create Table MyTest(F1 Counter, F2 Date, F3 Integer, F4 Text)'
}

Related

How to Pass a System.Data.DataSet Object as an Argument to a Powershell Workflow?

I'm getting some data from a SQL table, which I then store in a System.Data.DataSet object. I want to pass this data in this DataSet, as an Argument/Parameter, to a workflow, such that I can display all the data in this DataSet in a foreach -parallel style. But I'm at a loss for the correct syntax of passing data from a System.Data.DataSet object to a workflow. Currently I get an Error near the line "param([System.Data.DataSet]$pServiceDataSet)" as shown below.
Function GetSQLData
{
param ($TargetDBServer, $TargetDB, $SQLQuery)
# SQL Connection Object
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = "Server=$TargetDBServer;Database=$TargetDB;User Id=SomeUser;Password=SomePassword;"
$sqlConn.Open()
# SQL Command
$sqlcmd = New-Object System.Data.SqlClient.SqlCommand
$sqlcmd.Connection = $sqlConn
$sqlcmd.CommandText = $SQLQuery
# SQL Adapter
$sqlAdp = New-Object System.Data.SqlClient.SqlDataAdapter ($sqlcmd)
# SQL DataSet
$ResultDataSet = New-Object System.Data.DataSet
$sqlAdp.Fill($ResultDataSet) | Out-Null
$sqlConn.Close()
return $ResultDataSet.Tables[0]
}
$CurrentComputerName = $env:COMPUTERNAME
# Export the Windows Services & it's config parameters from the "DatabaseABC..WindowsServicesConfig" Table.
$SQLQueryForService = "
SELECT [ServiceName], [StartUpParameter], [DBServerName], [DBName]
FROM [dbo].[WindowsServicesConfig] WITH (NOLOCK)
WHERE [HostServerName] = '$CurrentComputerName'
AND [ServiceName] LIKE '%MyService%' "
$ServicesDataSet = GetSQLData -TargetDBServer "ServerABC" -TargetDB "DatabaseABC" -SQLQuery $SQLQueryForService
$ServicesDataSet.GetType()
$ServicesDataSet | Format-Table
workflow DisplayAllServices
{
param([System.Data.DataSet]$pServiceDataSet) # <- I get an Error here
foreach -parallel ($Service in $pServiceDataSet)
{
$Service.ServiceName
$Service.StartUpParameter
$Service.DBServerName
$Service.DBName
}
}
DisplayAllServices -pServiceDataSet $ServicesDataSet
My final objective is to use the data in this DataSet to create Windows Services. But this is my most frustrating hurdle. I cannot get past the Error.
Figured out the Solution to my Problem. Replaced the "param([System.Data.DataSet]$pServiceDataSet)" with "param([PSObject]$pServiceDataSet)".

Execute concurrent processes using PowerShell

I would like to setup a new PowerShell script that invokes my Database Stored Procedure concurrently. I am currently having a Control table that has a Job_ID column and a Code column. There might be more than one Job_ID for a code value in the Control table. Based on the code value I pass in the PowerShell along with a date, I would like the PowerShell to trigger the Stored Procedure which is expecting "Job_ID" and "MyDate" as input parameters.
FYI, I am using PowerShell and SQL Server 2016.
PS C:\PowerShell> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
2 0 -1 -1
Here is some sample data for your reference:
CREATE TABLE control_table(JOB_ID INT, CODE VARCHAR(5));
INSERT INTO control_table(1, 'ABC');
INSERT INTO control_table(2, 'ABC');
INSERT INTO control_table(3, 'ABC');
INSERT INTO control_table(1, 'DEF');
INSERT INTO control_table(1, 'GHI');
CREATE PROCEDURE myschema.run_job (#JOB_ID INT, #MyDate DATE)
AS
BEGIN
-- Do Something
END
When I run the PowerShell script by passing 'ABC" as code, it should execute all the three jobs concurrently by reading the control table.
Something like
.\test.ps1 –MyCode “ABC” –Dt “12/27/2018”
As an alternative to jobs you can use async methods of built-in SQL client. Below is the sample code. I assume you already has some "run_job" procedure that can execute other procedures (jobs) by id.
$code = "ABC"
$date = "2018-12-31"
$jobs = #{} # this will store results of async jobs
$str = "Server = YourServer; Database = YourDB; Integrated Security = True;"
#--------
function Async-Sql { param($connStr, $sql, [switch]$GetDataTable)
$conn = New-Object System.Data.SqlClient.SqlConnection $str
$cmd = $conn.CreateCommand()
$conn.Open()
$cmd.CommandText = $sql
if($GetDataTable) {
$dt = New-Object System.Data.DataTable "result"
$r = $cmd.ExecuteReader()
$dt.Load($r)
$conn.Close()
return #(,$dt)
} else {
$w = $cmd.ExecuteNonQueryAsync()
return [PSCustomObject]#{result=$w; conn = $conn} }
}
# ---------------------------------------------
# get a list of jobs from your control table, this will run synchronously
$jobList = Async-Sql -connStr $str -sql "select job_id, code from test.control_table where code = '$code'" -GetDataTable
# main loop. You should call your stored procedure here. Each iteration will create a new connection and execute command asynchronously
foreach($id in $jobList.job_id) {
$command = "EXEC run_job $id, $date"
$r = Async-Sql -connStr $str -sql $command
$jobs.Add( $id, $r )
}
# wait for all jobs to complete
while ($False -in $jobs.Values.result.isCompleted) { sleep -Milliseconds 500 }
# print results / close connections. If you see status as RanToCompletion the job is completed successfuly
foreach($j in $jobs.Keys) {
$res = $jobs[$j].result
[PSCustomObject]#{JobId=$j; isCompleted = $res.isCompleted; Status = $res.Status; result = $res.Result }
$jobs[$j].conn.close()
}
Since you have powershell V2, I'm adding a solution with PS Jobs. Save the code below as sqlExec.ps1:
param($connStr, $sql)
$conn = New-Object System.Data.SqlClient.SqlConnection $connStr
$cmd = $conn.CreateCommand()
$conn.Open()
$cmd.CommandText = $sql
$r = $cmd.ExecuteNonQuery()
$conn.Close()
return $r
Then use this code as a master script:
$str = "Server = YourServer; Database = YourDB; Integrated Security = True;"
$code = "ABC"
$date = (get-date).ToString("yyyy-MM-dd")
$execSript = "path\to\sqlExec.ps1"
# get a list of ids for code. You can achive the same with Invoke-sqlcmd or similar cmdlet.
$conn = New-Object System.Data.SqlClient.SqlConnection $str
$cmd = $conn.CreateCommand()
$conn.Open()
$cmd.CommandText = "select job_id, code from test.control_table where code = '$code'"
$dt = New-Object System.Data.DataTable "result"
$r = $cmd.ExecuteReader()
$dt.Load($r)
$conn.Close()
# main loop
$jobs = #{}
foreach($id in $dt.job_id) { $top = $id*3
$sql = "EXEC run_job $id, $date"
$jobs.Add($id,(Start-Job -FilePath $execSript -ArgumentList $str, $sql))
}
# Wait for jobs and get result
$jobs.Values | Wait-Job | Receive-Job
If you have Invoke-Sqlcmd module you can use it for sql code execution (instead of creating $conn,$cmd,etc)

PostgreSQL Query export to CSV with PowerShell

$sf = "\\\\domain\\dept\\dcgsi\\Extracts\\Tableau_Unlicensed_Users.csv"
if (Test-Path $sf){
Remove-Item $sf
}
$query = #"
\\copy (SELECT Name
FROM _users
WHERE licensing_role_name = 'Unlicensed')
TO $sf
WITH CSV DELIMITER ','
"#
$conn = New-Object -ComObject ADODB.Connection
# use existing 64 bit ODBC System DSN that we set up manually
$conn.Open('PostgreSQL30')
$conn.Execute($query)
$conn.Close()
I keep getting an error about "\" on the line with the $conn.Execute() when I try and do this. I assume it has to do with character escaping and maybe I am doing it wrong.
Is there a better way to do this with PowerShell if I just need to get the name field of any record from _users and output it to CSV?
Eventually I will be adding more to this to loop through each record in the CSV and execute a tabcmd to remove all the users that are unlicensed.
$sf = "\\domain\dept\dcgsi\Extracts\Tableau_Unlicensed_Users.csv"
if (Test-Path $sf){
Remove-Item $sf
}
$query = #"
SELECT Name
FROM _users
WHERE licensing_role_name = 'Unlicensed'
"#
function Get-ODBC-Data{
$conn = New-Object System.Data.Odbc.OdbcConnection
$conn.ConnectionString = "DSN=PostgreSQL30;"
$conn.Open()
$cmd = New-object System.Data.Odbc.OdbcCommand($query, $conn)
$ds = New-Object system.Data.DataSet
(New-Object System.Data.Odbc.OdbcDataAdapter($cmd)).Fill($ds) | Out-Null
$conn.Close()
$ds.Tables[0] | Export-Csv $sf
}
Get-ODBC-Data
This did like 99% of what I need; I just have to process the csv now and drop the first two lines. The first line is a type info message and the second is the column header.

ORA-00917 missing comma in Powershell

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.

Powershell Datatable.Find Method

I am trying to work with DataTables in powershell, more specifically I am trying to check to see if a row with a certain value exists in the datatable.
Here is the method I am using to create the dataTable.
function GetPropertyIDs()
{
write-host "Retrieving all Property ID's from $DatabaseInstance.$DatabaseName..." -NoNewline
$cn = new-object system.data.SqlClient.SqlConnection("Data Source=$DatabaseInstance;Integrated Security=SSPI;Initial Catalog=$DatabaseName");
$cn.Open()
$cmd = new-Object System.Data.SqlClient.SqlCommand("Select Distinct CAST(ID as varchar(5)) as ID, Name, Code from TableName Order by ID", $cn)
$cmd.CommandType = [System.Data.CommandType]'Text'
$adapter = New-Object System.Data.SqlClient.SqlDataAdapter $cmd
$dataTable = New-Object System.Data.DataTable
$adapter.Fill($dataTable) | out-null
$cn.Close() | out-Null
$cn.Dispose()
$count = $dataTable.rows.count;
write-host "$count records retrieved."
#Set Primary Key
$pk = $dataTable.Columns["ID"]
$dataTable.PrimaryKey = $pk
return $dataTable
}
Here is the code where I am trying to check if a specific value exists in the datatable...
$PropertyIDs = GetPropertyIDs
foreach($PropertySite in $PropertySites)
{
$id = ([System.String] $PropertySite).Replace("$SiteCollectionURL/property/", "")
$found = $PropertyIDs.DefaultView.Find($id)
}
Currently I am getting an error:
"You cannot call a method on a null-valued expression."
I have also tried this with no luck either:
$found = $PropertyIDs.Rows.Contains($id)
It turns out that this was being caused by powershell unravelling the datatable into a collection of rows instead of a datatable like it was defined as, therefor the primary key which is required for .Rows.Contains(...) was not available and thus the error.
By adding the a ',' at the end of the GetPropertyIDs() method above I was able to get powershell to return a datatable with the primary keys intact. For Example:
return ,$dataTable
I ended up using the contains method because it returns a boolean value which is what I was looking for as a test...
Some References:
http://powershellcommunity.org/Forums/tabid/54/aft/6359/Default.aspx