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

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)

Related

Provider cannot be found when try to open/access mdb

I'm writing a powershell 5.1 script to query info from a mdb file based on this article. I get this error message when I try to open/access an mdb file:
MDB Open next
Provider cannot be found. It may not be properly installed.
I'm pretty sure I need to adjust my connection info according to what I have installed. This is what I'm doing:
$pathViewBase = 'C:\Data\EndToEnd_view\' #View dir.
$XML_MDB_Dirs = #('\AppText.mdb') #more files later
foreach($mdbFile in $XML_MDB_Dirs)
{
$pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFile
if(Test-Path $pathToMdb)
{
$cn = new-object -comobject ADODB.Connection
$rs = new-object -comobject ADODB.Recordset
Write-Host "MDB Open next" -ForegroundColor DarkCyan
$cn.Open("Provider = Microsoft.Jet.OLEDB.4.0;Data Source = $pathToMdb") ###error this line
Write-Host "Open done" -ForegroundColor DarkCyan
$rs.Open(“SELECT TOP 1 [TableName].[Message Description],
[TableName].[Column1]
FROM [TableName]
WHERE [TableName].[Message Description] = 'ERROR'”,
$cn, $adOpenStatic, $adLockOptimistic)
$rs.MoveFirst()
Write-Host "Message value obtained for ERROR: " $rs.Fields.Item("Name").Value
Break ##########################
}#test-Path
}#foreach
I found this regarding odbc connections, and it seems to say I need to adjust my connection info. Looking at what's installed on my computer, I see this, but I'm a little unclear what I need to adjust my open code to use. Would I need to replace 'Microsoft.Jet.OLEDB.4.0' with 'SQLNCLI11.dll'?
Update:
I checked,
(Get-WmiObject Win32_OperatingSystem).OSArchitecture
and I am running 64 bit powershell, so since I installed accessdatabaseengine_x64.exe access database engine, per #
Mathias R. Jessen below (and rebooted), that's correct. But I still get the same error. I'm not sure if there's something I could check to see if it's installed correctly, or if I need to use SQLNCLI11.0 as the provider instead of Microsoft.Jet.OLEDB.4.0, or if I need to add "using" at the top? Or do I need to check if a powershell module is installed?

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.

PowerShell - File transfer from windows to unix

I am working on UIpath automation for which I need some files to be transferred back and forth between Windows and Unix machines (only through PowerShell). Kindly provide your inputs as I'm a newbie.
I am using plink in my PowerShell script to connect to a Unix server. Though it works fine, is there any other better way to connect to a Unix server (HP UX) from Windows (through a PowerShell script).
Struggling to find a good module and sample scripts to do a secure copy between the Unix and Windows servers. I came across Posh SSH /WinSCP, sftp etc. but I'm not able to implement any as I do not find the right sample scripts. Also Install-Module does not work (not recognized).
Your help on this would be much appreciated.
Thanks in advance!
If you want to use SFTP I am using the code below to upload some files automatically to an ftp site:
First of all you have to download the winscp SFTP powershell libraries.
https://winscp.net/eng/download.php
then extract the contents at the same location the script is located.
Then in your script you must add:
# Load WinSCP .NET assembly
# Give the path the dll file is located so powershell can call it.
Add-Type -Path "C:\Path where the dll file is located\WinSCPnet.dll"
# Setup session options
# Add all the properties the session needs to be established such as username password hostname and fingerprint.
# The username and password must be in plaintext.
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "HostName"
UserName = "UserName"
Password = "Password"
SshHostKeyFingerprint = "SSH fingerprint"
Then after the session with those credentials is up you must put your next step of copying the files.
# Open a session to the Host
# Try to connect to the Host with the credentials and information provided previously.
# Upload the file from a specific path to the path on the host.
# And then close the session and clean up the session trace data.
# $session.Dispose() -> If session was opened, closes it, terminates underlying WinSCP process, deletes XML log file and disposes object.
$session = New-Object WinSCP.Session
Try
{
# Connect to the SFTP site
$session.Open($sessionOptions)
# Upload the files from local disk to the destination
$session.PutFiles("Path of the file you want to upload", "/import/").Check()
}
Finally
{
# Disconnect, clean up
$session.Dispose()
}
Probably there is an easier way with Power Shell 6 that can do more with the Unix/Linux operating systems but at this point of answering I haven't used it.
Once you get Posh-SSH installed, something like this will probably get you down the road. There are ways to keep the password in plain text out of your script.
$SecurePassword = ConvertTo-SecureString -AsPlainText 'thepassword' -Force
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'me',$SecurePassword
$Session = New-SFTPSession -ComputerName 'zenith' -Credential $Credentials -ConnectionTimeout 30
$r = Set-SFTPFile -Session $Session. -LocalFile 'C:\Users\me\t.txt' -RemotePath '/home/me' -Overwrite
Remove-SFTPSession -SFTPSession $session | Out-Null

How to copy files from one server to other server with powershell when the shared path contains '$' symbol

I have 3 remote servers in my hand. Let us say Server X, Server Y and Server Z. I am running my powershell script from my local machine to login to Remote Server X. This Server X is my base server which has access to other 2 servers. I want to use this Server X as base server and want to copy files from Server Y to Server Z which is impossible through my local machine because of access permissions. So I logged in to Server X using admin credentials which has access to all 3 servers. After logging in, I am just mentioning copy-item command to copy files from shared path of Server Y to Shared Path of Server Z.
This is a similar question to many in this website here goes a twist. When I am debugging, it is showing completed but I am not getting any results. So I tried running this powershell script directly in Server X which contains only copy-item command and source and destination paths of shared folders. When I am debugging I am getting error that, user doesn't have permissions or path is not found. When I am trying to copy and paste files from shared path manually using the same credentials, it is working. But through powershell script, it's now working. I know the reason. It's because of symbol '$' in the shared paths. So I need the solution for this. It is not allowing '$' symbol in my source and destination paths. Is there any alternative for this? If I try to remove that symbol and copy the files, I get the 'Access Denied' Error as it is a shared path, E drive should prefixed with $ symbol.
Here goes my code:
#Calling my Server Name, Credentials from App.Config File
$currentDirectory = [IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Path)
$appConfigFile = [IO.Path]::Combine($currentDirectory, 'App.config')
$appConfig = New-Object XML
$appConfig.Load($appConfigFile)
$ServerName = $appConfig.configuration.appSettings.add[0].value
$Username = $appConfig.configuration.appSettings.add[1].value
$Password = ConvertTo-SecureString -String $appConfig.configuration.appSettings.add[2].value -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$Password
Logging to Server X using credentials and copying files from Server Y to Server Z
Invoke-command -ComputerName $ServerName -Credential $cred -ScriptBlock {
Copy-Item "\\ServerY\E$\SourceTestFolder\Test.docx" "\\ServerZ\E$\DestTestFolder" }
First idea: Replace the " with '. So powershell stops to fall over the $-symbols. The way you have written it now says: "Hey powershell, go ahead and look for a variable named $E and put it in there".
Like previously metioned you can change the double qoutes to single qoutes. By doing this you say to powershell that everything between is a string without variables.
You can also work with a replace and a special symbol like this example.
But what if you have a string with a $ sign in the path and a varriable. something like this $cmd = "sc config something$$variable depend= something/something.
I need the first dollar sign because it is in the name of the service but then it is the variable. What i did was fix it by doing the following.
$cmd = "sc config something#$variable depend= something/something"
$cmd = $cmd -replace "#", '$'
By doing this powershell fills in the variable so i have $cmd = "sc config something#value depend= something/something"
Then I replace the # by the DollarSign and we are set.

Powershell - Copying File to Remote Host and Executing Install exe using WMI

EDITED: Here is my code now. The install file does copy to the remote host. However, the WMI portion does not install the .exe file, and no errors are returned. Perhaps this is a syntax error with WMI? Is there a way to just run the installer silently with PsExec? Thanks again for all the help sorry for the confusion:
#declare params
param (
[string]$finalCountdownPath = "",
[string]$slashes = "\\",
[string]$pathOnRemoteHost = "c:\temp\",
[string]$targetJavaComputer = "",
[string]$compname = "",
[string]$tempPathTarget = "\C$\temp\"
)
# user enters target host/computer
$targetJavaComputer = Read-Host "Enter the name of the computer on which you wish to install Java:"
[string]$compname = $slashes + $targetJavaComputer
[string]$finalCountdownPath = $compname + $tempPathTarget
#[string]$tempPathTarget2 =
#[string]$finalCountdownPath2 = $compname + $
# say copy install media to remote host
echo "Copying install file and running installer silently please wait..."
# create temp dir if does not exist, if exist copy install media
# if does not exist create dir, copy dummy file, copy install media
# either case will execute install of .exe via WMII
#[string]$finalCountdownPath = $compname + $tempPathTarget;
if ((Test-Path -Path $finalCountdownPath) )
{
copy c:\hdatools\java\jre-7u60-windows-i586.exe $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
else {
New-Item -Path $finalCountdownPath -type directory -Force
copy c:\hdatools\dummy.txt $finalCountdownPath
copy "c:\hdatools\java\jre-7u60-windows-i586.exe" $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
I was trying to get $Job = Invoke-Command -Session $Session -Scriptblock $Script to allow me to copy files on a different server, because I needed to off load it from the server it was running from. I was using the PowerShell Copy-Item to do it. But the running PowerShell script waits until the file is done copying to return.
I want it to take as little resources as possible on the server that the powershell is running to spawn off the process on another server to copy the file. I tried to user various other schemes out there, but they didn't work or the way I needed them to work. (Seemed kind of kludgey or too complex to me.) Maybe some of them could have worked? But I found a solution that I like that works best for me, which is pretty easy. (Except for some of the back end configuration that may be needed if it is is not already setup.)
Background:
I am running a SQLServer Job which invokes Powershell to run a script which backups databases, copies backup files, and deletes older backup files, with parameters passed into it. Our server is configured to allow PowerShell to run and under the pre-setup User account with SQL Server Admin and dbo privileges in an Active Directory account to allow it to see various places on our Network as well.
But we don't want it to take the resources away from the main server. The PowerShell script that was to be run would backup the database Log file and then use the another server to asynchronously copy the file itself and not make the SQL Server Job/PowerShell wait for it. We wanted it to happen right after the backup.
Here is my new way, using WMI, using Windows Integrate Security:
$ComputerName = "kithhelpdesk"
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -Command "Copy-Item -Path \\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak -Destination \\YourShareDestination\YourDatabase_2018-08-07_11-45.log.bak"'
Here is my new way using passed in Credentials, and building arg list variable:
$Username = "YouDomain\YourDomainUser"
$Password = "P#ssw0rd27"
$ComputerName = "RemoteServerToRunOn"
$FromFile = "\\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ToFile = "\\YourShareDestination\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ArgumentList = 'powershell.exe -Command "Copy-Item -Path ' + $FromFile + ' -Destination ' + $ToFile + '"'
$SecurePassWord = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $Username, $SecurePassWord
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList $ArgumentList -Credential $Cred
We think that this above one is the preferred one to use.
You can also run a specific powershell that will do what you want it to do (even passing in parameters to it):
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -file "C:\PS\Test1.ps1"'
This example could be changed to pass in parameters to the Test1.ps1 PowerShell script to make it more flexible and reusable. And you may also want to pass in a Credential like we used in a previous example above.
Help configuring WMI:
I got the main gist of this working from: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1
But it may have also needed WMI configuration using:
https://helpcenter.gsx.com/hc/en-us/articles/202447926-How-to-Configure-Windows-Remote-PowerShell-Access-for-Non-Privileged-User-Accounts?flash_digest=bec1f6a29327161f08e1f2db77e64856b433cb5a
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting?view=powershell-5.1
Powershell New-PSSession Access Denied - Administrator Account
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1 (I used to get how to call Invoke-WmiMethod).
https://learn.microsoft.com/en-us/powershell/scripting/core-powershell/console/powershell.exe-command-line-help?view=powershell-6 (I used to get syntax of command line)
I didn't use this one, but could have: How to execute a command in a remote computer?
I don't know for sure if all of the steps in the web articles above are needed, I suspect not. But I thought I was going to be using the Invoke-Command PowerShell statement to copy the files on a remote server, but left my changes from the articles above that I did intact mostly I believe.
You will need a dedicated User setup in Active Directory, and to configure the user accounts that SQL Server and SQL Server Agent are running under to give the main calling PowerShell the privileges needed to access the network and other things to, and can be used to run the PowerShell on the remote server as well. And you may need to configure SQLServer to allow SQL Server Jobs or Stored Procedures to be able to call PowerShell scripts like I did. But this is outside the scope of this post. You Google other places on the internet to show you how to do that.