The term 'Microsoft.SqlServer.Dac.BacPackage::Load' is not recognized - powershell

I have created a bacpac from an azure sql db, copied it to blob, from blob brought it down locally.
I run this code in powershell
Add-Type -path "C:\Program Files (x86)\Microsoft SQL Server\140\DAC\bin\Microsoft.SqlServer.Dac.dll"
$restoredDatabaseName = 'AuditTest'
$bacpacFile = "H:\backup\audit\audit.bacpac"
$conn = "Data Source=.;Initial Catalog=master;Connection Timeout=0;Integrated Security=True;"
$importBac = New-Object Microsoft.SqlServer.Dac.DacServices $conn
$loadBac = Microsoft.SqlServer.Dac.BacPackage::Load($bacpacFile)
$importBac.ImportBacpac($loadBac, $restoredDatabaseName)
#Clean up
$loadBac.Dispose()
Get this error back:
Microsoft.SqlServer.Dac.BacPackage::Load : The term 'Microsoft.SqlServer.Dac.BacPackage::Load' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and try again.
I have also tried to use the import data tier wizard and get the following error.
Could not load file or assembly 'Microsoft.SqlServer.Dac, Version=13.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. (Microsoft.SqlServer.Management.Dac.DacWizard)
It is driving me nuts, I have found a few things about registry hacking and so on for the wizard error, nothing helpful at all for the powershell one.
SQL Azure DB PRS1
Restoring to SQL 2016 in an Azure VM.

When invoking a static method, the full type name goes in square brackets.
So should be:
Add-Type -path "C:\Program Files (x86)\Microsoft SQL Server\140\DAC\bin\Microsoft.SqlServer.Dac.dll"
$restoredDatabaseName = 'AuditTest'
$bacpacFile = "H:\backup\audit\audit.bacpac"
$conn = "Data Source=.;Initial Catalog=master;Connection Timeout=0;Integrated Security=True;"
$importBac = New-Object Microsoft.SqlServer.Dac.DacServices $conn
$loadBac = [Microsoft.SqlServer.Dac.BacPackage]::Load($bacpacFile)
$importBac.ImportBacpac($loadBac, $restoredDatabaseName)
#Clean up
$loadBac.Dispose()

Related

powershell copy data from csv to postgres

hitting an issue where you hopefully can help me with:
I want to import a csv file to postgres with powershell. For this have written following code:
$ConnectionString = "Driver={PostgreSQL UNICODE(x64)};Server=$SQLServer;Port=$SLQPort;Database=$SQLDB;Uid=$SQLUser;Pwd=$SQLPass;"
$connection = New-Object System.Data.ODBC.ODBCConnection
$connection.ConnectionString = $ConnectionString
$connection.Open()
$query= "copy sensorhistory from 'C:\Powershell_Scripts\Postgres\Eurogate\data\export.csv' Delimiter ',' csv header;"
$DBCmd = $connection.CreateCommand();
$DBCmd.CommandText = $query
$DBCmd.ExecuteNonQuery() | Out-Null
$DBCmd.ExecuteReader();
But I am getting the error "No such file or directory"
the link is correct and already made changes to allow access to everybody, but still not working.
Any help is welcome
You're pointing to the wrong file system!
From the $SQLServer argument in the connection string, it appears that Postgres might be hosted on a remote machine.
When encountering a file path like C:\[...]\export.csv in a query, the database engine is going to ask the operating system to open the corresponding file, and the operating system goes "C:\? That's a local drive, let me find that file for you" - and fails to locate the file because you actually meant the C:\ drive on your computer.
Two ways to fix this:
1. Pass a network path in the query:
Update the query so the file path explicitly points to a file share on a different machine:
$query = "copy sensorhistory from '\\ClientComputer01\ShareName\path\to\data\export.csv' Delimiter ',' csv header;"
2. Copy the file to the server that hosts Postgres
Of course, opening the file from the local filesystem wouldn't fail if the file also existed there. Assuming WinRM is configured in the environment and you have admin access on the DB server, copy the file ahead of time:
$remoteSession = New-PSSession -ComputerName $SQLServer
Copy-Item C:\Powershell_Scripts\Postgres\Eurogate\data\export.csv -Destination C:\Powershell_Scripts\Postgres\Eurogate\data\ -ToSession $remoteSession
Alternatively, copy the file over SMB if you have write access to a file share:
Copy-Item C:\Powershell_Scripts\Postgres\Eurogate\data\export.csv \\$SQLServer\ShareName\path\to\data\
After which the DB engine will be able to open the new local copy of the file and you can keep the local file path in the query.

File opened that is not a database file (but it is)

I'm trying to pull information from an SQLite database using a Powershell script from a Redgate article.
#I've installed the 64 bit System.Data.SQLite ADO.NET data provider in this directory
Add-Type -Path "C:\Program Files (x86)\SQLite.NET\bin\x64\System.Data.SQLite.dll"
#I just create a connection to my existing database
$con = New-Object -TypeName System.Data.SQLite.SQLiteConnection
# I then give it a simple connection string
$con.ConnectionString = "Data Source=C:\Users\name\Desktop\fax.sqlite"# CHANGE THIS
#and open the connection
$con.Open()
#We'll just start by creating a SQL statement in a command
$sql = $con.CreateCommand()
$sql.CommandText = "select column from table;"
# we now execute the SQL and return the results in a dataset
$adapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter $sql
#we create the dataset
$data = New-Object System.Data.DataSet
#and then fill the dataset
[void]$adapter.Fill($data)
#we can, of course, then display the first one hundred rows in a grid
#(1..100)|foreach{$data.tables[0].Rows[$_]}|out-gridview #-Title 'Authors and books'
I viewed the database using SQLite DB Browser (didn't need a password to open). However, whenever I use this script I get the below error:
Exception calling "Open" with "0" argument(s): "File opened that is
not a database file file is encrypted or is not a database" At
C:\Users\name\Desktop\query sqlite db.ps1:9 char:1
$con.Open()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SQLiteException
Assuming you have all the libraries in place, to import the assemblies you need to use the Add-Type command:
Add-Type -Path "C:\Program Files\System.Data.SQLite\2010\bin\System.Data.SQLite.dll"
To connect to the database using the ADO.NET protocol, you need to create a SQLiteConnection object with the proper connection string:
$connection_details = New-Object -TypeName System.Data.SQLite.SQLiteConnection
$connection_details.ConnectionString = "Data Source=C:\database\test.db"
Your $con.ConnectionString = "Data Source=C:\Users\name\Desktop\fax.sqlite" is having issue. It is expecting a proper DB connection but instead it is getting a string statement.
I got the same error when running a 32-bit dll on a 64-bit system.
If you are running a 64-bit Windows system then download sqlite-netFx46-static-binary-x64-2015-1.0.116.0.zip from https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
and extract the contents to C:\Program Files\System.Data.SQLite\2010\bin\
Then run this command once or place it in your PowerShell script before making your connection object:
Add-Type -Path "C:\Program Files\System.Data.SQLite\2010\bin\System.Data.SQLite.dll"

Receive SSIS execution result from powershell

when I'm executing a SSIS package from powershell, the return data only consisting the SSIS process result not the actual result
I'm trying to get the resultset from SSIS process when it is done executing,
I'm executing the packages from powershell by using PS' package.execute
#connecting to sql server
$sqlConnStr = "Data Source=" + $targetServer + ";Initial Catalog=master;Integrated Security=SSPI;"
$sqlConn = New-Object System.Data.SqlClient.SqlConnection $sqlConnStr
#create new SSIS object
$ssisService = New-Object $ssisNameSpace".IntegrationServices" $sqlConn
#select SSIS catalog
$cat = $ssisService.Catalogs["SSISDB"]
#select SSIS folder
$folder = $cat.Folders[$targetFolder]
#select target project
$project = $folder.Projects[$projectName]
#select target package
$targetPackage = $project.Packages[$package.PackageName]
#execute package and get the result
$actualVal = $targetPackage.Execute("false", $null)
expected value:
the dataset from SSIS process
actual value:
SSIS process result code only
in the end I dump the result into table and then select the result again after my SSIS process is done, just like Jacob said.
thank you for your input.
I don't think you can get the result set using Powershell or other languages and tools since it is an SSIS internal part, you can only retrieve the execution result and package log (errors, warning, information).
dtexec Utility
DTEXEC Command Line Parameters Using Command Files
As a workaround you can export the result set into a flat file and read it using Powershell

Reference WinSCP.exe from PowerShell script executed from SSIS

I am trying to execute a PowerShell script from within SSIS. My script starts with the Add-Type -Path "WinSCPnet.dll" and it is erroring out because it cannot find the WinSCP.exe in the folder that houses my PowerShell script. Come to find out the server admin did NOT install WinSCP into the GAC. Is this creating my problem?
If so, how and where can I reference the WinSCP.exe in my script using $session.ExecutablePath? Any help/direction would be appreciated. Thanks.
Here is my script below:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Declare variables
$date = Get-Date
$dateStr = $date.ToString("yyyyMMdd")
#$fileDirectory = "\\abicfs2\apps\CoverageVerifier\"
#$filePath = "\\abicfs2\apps\CoverageVerifier\cvgver." + $dateStr + ".0101"
$filePath = "\\empqaapp1\coverageverifier_scripts\CoverageVerifier\cvgver.20190121.0101"
# Write-Output $filePath
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "secureftp.iso.com"
UserName = "account"
Password = "password"
SshHostKeyFingerprint = "ssh-rsa 2048 8C1lwAjxCNRF6B4kbPIeW52/GB+98FmLMt0AJNf/Sf4="
}
#$sessionOptions.AddRawSettings("FSProtocol", "2")
$session = New-Object WinSCP.Session
# $session.SessionLogPath = "\\share\apps\CoverageVerifier\UploadLog.log"
try
{
# Connect
$session.Open($sessionOptions)
# Transfer files
$session.PutFiles($filePath,"/").Check()
}
finally
{
$session.Dispose()
}
I am trying to execute a Powershell script from within SSIS
It seems you believe you need to have WinSCP .NET assembly in GAC, so that you can execute it from a PowerShell script executed from SSIS. I do not think it's true. You need an assembly in GAC, only if you directly use it from an SSIS code. What is not your case.
You can simply store the WinSCPnet.dll and WinSCP.exe to your PowerShell script directory.
Anyway to answer your question:
If so, how and where can I reference the WinSCP.exe in my script using $session.ExecutablePath?
$session = New-Object WinSCP.Session
$session.ExecutablePath = "C:\path\WinSCP.exe"
(but as per above, I do not think you need it)
Come to find out the server admin did NOT install WinSCP into the GAC.
You cannot install .exe file to GAC.
Excerpt from WinSCP assembly installation instruction (https://winscp.net/eng/docs/library_install):
The package includes the assembly itself (winscpnet.dll) and a
required dependency, WinSCP executable winscp.exe.
The binaries interact with each other and must be kept in the same
folder for the assembly to work. In rare situations this is not
possible (e.g. when installing the assembly to GAC), make use of the
Session.ExecutablePath property to force the assembly to look for the
winscp.exe in a different location.

How to run Powershell script on local computer but with credentials of a domain user

I have to implement a solution where I have to deploy a SSIS project (xy.ispac) from one machine to another. So far I've managed to copy-cut-paste the following stuff from all around the internet:
# Variables
$ServerName = "target"
$SSISCatalog = "SSISDB" # sort of constant
$CatalogPwd = "catalog_password"
$ProjectFilePath = "D:\Projects_to_depoly\Project_1.ispac"
$ProjectName = "Project_name"
$FolderName = "Data_collector"
# Load the IntegrationServices Assembly
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Management.IntegrationServices")
# Store the IntegrationServices Assembly namespace to avoid typing it every time
$ISNamespace = "Microsoft.SqlServer.Management.IntegrationServices"
Write-Host "Connecting to server ..."
# Create a connection to the server
$sqlConnectionString = "Data Source=$ServerName;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString
$integrationServices = New-Object "$ISNamespace.IntegrationServices" $sqlConnection
$catalog = $integrationServices.Catalogs[$SSISCatalog]
# Create the Integration Services object if it does not exist
if (!$catalog) {
# Provision a new SSIS Catalog
Write-Host "Creating SSIS Catalog ..."
$catalog = New-Object "$ISNamespace.Catalog" ($integrationServices, $SSISCatalog, $CatalogPwd)
$catalog.Create()
}
$folder = $catalog.Folders[$FolderName]
if (!$folder)
{
#Create a folder in SSISDB
Write-Host "Creating Folder ..."
$folder = New-Object "$ISNamespace.CatalogFolder" ($catalog, $FolderName, $FolderName)
$folder.Create()
}
# Read the project file, and deploy it to the folder
Write-Host "Deploying Project ..."
[byte[]] $projectFile = [System.IO.File]::ReadAllBytes($ProjectFilePath)
$folder.DeployProject($ProjectName, $projectFile)
This seemed to be working surprisingly well on the development machine - test server pair. However, the live environment will be a bit different, the machine doing the deployment job (deployment server, or DS from now on) and the SQL Server (DB for short) the project is to be deployed are in different domains and since SSIS requires windows authentication, I'm going to need to run the above code locally on DS but using credentials of a user on the DB.
And that's the point where I fail. The only thing that worked is to start the Powershell command line interface using runas /netonly /user:thatdomain\anuserthere powershell, enter the password, and paste the script unaltered into it. Alas, this is not an option, since there's no way to pass the password to runas (at least once with /savecred) and user interactivity is not possible anyway (the whole thing has to be automated).
I've tried the following:
Simply unning the script on DS, the line $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString would use the credentials from DS which is not recognized by DB, and New-Object does not have a -Credential arg that I could pass to
Putting everything into an Invoke-Command with -Credential requires using -Computername as well. I guess it would be possible to use the local as 'remote' (using . as Computername) but it still complains about access being denied. I'm scanning through about_Remote_Troubleshooting, so far without any success.
Any hints on how to overcome this issue?
A solution might be to use a sql user (with the right access rights) instead of an AD used.
Something like this should work.
(Check also the answer to correct the connection string)