How to delete a file from a SFTP server using Tamir Gal's SharpSSH? I have been able to accomplish other functionality but deletion.
The SshExec class didn't work for me, but a little Reflection magic worked:
var prop = sftp.GetType().GetProperty("SftpChannel", BindingFlags.NonPublic | BindingFlags.Instance);
var methodInfo = prop.GetGetMethod(true);
var sftpChannel = methodInfo.Invoke(sftp, null);
((ChannelSftp) sftpChannel).rm(ftpPath);
To accomplish this you will need to modify the SharpSSH assembly to expose the functionality you require.
Obtain the source code and open $\SharpSSH-1.1.1.13.src\SharpSSH\Sftp.cs
Insert the following lines of code before the end of the class:
public void Delete(string path)
{
SftpChannel.rm(path);
}
Recompile and reference the recompiled DLL in your project. You will now be able to delete files on the SFTP server.
Well you can also use SshExec class and then execute the "rm" command using "RunCommand" method. This way you wont have to recompile and build a new dll.
Using Tamir's dll I would suggest to delete using the below code. In this way, you need not modify Tamir's dll, whereas the below code can be written in your class.
string fromFile = "/a/b/MyFile.txt"
SshExec se = new SshExec(host, username, password);
se.Connect(port);
se.RunCommand("rm " + fromFile);
Related
Using VSTO and COM Interop, I am trying to access and manipulate a database that is already open in Microsoft Access. I can get hold of the Access application object, the current user name, and other properties. But when I try to get a list of the tables to print the table names, the code fails.
My end goal is to run an Access VBA macro using 'application.Run("MyMacroName")'. Can anyone tell me what I am missing or doing wrong? Thank you.
UPDATE SOLUTION
Thank you to Albert (see below) who kept providing (Visual Basic) information until I was able to get the C# code to work. The biggest things I was missing were 1) the DAO using reference (VStudio said I didn't need it, originally), and 2) an explicit DAO TableDef type for the loop ('var' would not work).
UPDATED CODE THAT WORKS:
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Access;
using Microsoft.Office.Interop.Access.Dao; // *MUST* have DAO as well
using Access = Microsoft.Office.Interop.Access; // Access = a namespace qualifier
[TestMethod()]
public void MsAccessComInteropTest() {
// explicitly cast the object to an Access.Application
// I used 'Access.Application' to qualify from a System.xxxx.Application type
var app = (Access.Application) Marshal.GetActiveObject("Access.Application");
Dprint($"{app.Name}"); // prints Microsoft Access
Dprint($"{app.CurrentUser()}"); // prints Admin
var db = app.CurrentDb();
// *MUST* use TableDef type explicitly from DAO in loop - cannot use 'var'
foreach (TableDef tbl in db.TableDefs) {
// Attributes == 0 means a user-defined table
if (tbl.Attributes == 0) {
Debug.Print($"{tbl.Name} '{tbl.Attributes.ToString()}'");
}
}
app.Run("MyVbaMacroName");
}
You need a reference to both Access, and also DAO.
These two:
Microsoft.Office.Interop.Access
C:\Program Files (x86)\Microsoft Visual Studio 12.0\
Visual Studio Tools for Office\PIA\Office14\
Microsoft.Office.Interop.Access.dll
And you need this:
Microsoft.Office.Interop.Access.Dao
C:\Program Files (x86)\Microsoft Visual Studio 12.0\
Visual Studio Tools for Office\PIA\Office14\
Microsoft.Office.interop.access.dao.dll
And thus your code will look like this:
{
Access.Application app;
app = Interaction.GetObject(Class: "Access.Application");
Access.Dao.Database db;
db = app.CurrentDb;
Access.Dao.TableDef tblDef;
foreach (var tblDef in db.TableDefs)
Debug.Print(tblDef.Name);
}
In fact, you could use late binding, and NOT even reference the interop assembles.
eg this:
{
var app = Interaction.GetObject(Class: "Access.Application");
var db = app.CurrentDB;
var tblDef;
foreach (var tblDef in db.TableDefs)
Debug.Print(tblDef.Name);
}
but, if you go 100% late binding, then you not get any intel-sense.
Also, this looks strange:
using Access = Microsoft.Office.Interop.Access;
Why the "=" in above - I don't think that looks right.
should be:
using Access Microsoft.Office.Interop.Access;
So, if you going to reference using interop - you need both Access + the DAO. (and they are different assembles, but use the same name space - not sure if that an issue in c#, but it is in vb.net
If you want a full list of tables, it's usual to use CurrentDb.Tabledefs
var db = app.CurrentDb();
foreach (var td in db.TableDefs) {
Dprint(td.Name);
}
I use Invoke-ASCmd in PowerShell right now to create a database in SQL Server, like this:
Invoke-ascmd -Query $MyScript -Server $ASServer
Where $MyScript is a string holding the contents of an .xmla file that I read in previously.
This works great. Now I need to do something similar in C#, but am unable to find a simple solution like the one that exists in PowerShell.
I see some people using a Microsoft DLL called Microsoft.AnalysisServices.XMLA.dll, but it's not supported, and the class in question is "internal", so I can't even reference it.
I found this DLL Microsoft.AnalysisServices.AdomdClient.dll while searching around, but don't see any of the classes being relevant to what I need: https://learn.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.adomdclient?view=analysisservices-dotnet
using Microsoft.AnalysisServices.AdomdClient;
try
{
var xmlaFileContents = File.ReadAllText("path/to/your/file.xmla");
using (AdomdCommand cmd = conn.CreateCommand())
{
cmd.CommandText = xmlaFileContents;
cmd.ExecuteNoQuery();
}
}
catch(Exception)
{
}
** please note that I have not run this code **
As the AdomdConnection is inherited from IDbConnection, it's pretty similar to how the SqlConnection works, and therefor, similar syntax can be used, as #jogi presented for you.
I wrote a PS function a few years back which we use in TFS builds. It uses the .NET assemblies rather than the PS layer, so I figured since you seem savvy in PS, you can perhaps get something out of it. Still essentially the same as what #jogi wrote, only wrapped in PS.
function Invoke-XmlaScript {
[CmdletBinding()] param (
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$ServerInstance,
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$XmlaScript
)
process {
$connection = New-Object Microsoft.AnalysisServices.AdomdClient.AdomdConnection("Data Source=$ServerInstance;Provider=MSOLAP.4;Integrated Security=SSPI;Impersonation Level=Impersonate;")
$connection.Open()
try {
$command = $connection.CreateCommand()
$command.CommandTimeout = 20000
$command.CommandType = [System.Data.CommandType]::Text
$command.CommandText = $Xmla
$reader = $command.ExecuteXmlReader()
if($reader.Read()) {
Write-Output $reader.ReadOuterXml()
}
}
catch { }
$connection.Dispose()
}
}
I'm trying to rename a branch programaticly using "PendRename" method from Microsoft.TeamFoundation.VersionControl.Client.
Moves working, so, if I use this to move everything to a new location, it works, but what I need is to rename a branch.
It is possible to do this by commandline "tfs.exe rename " (even this is given me errors if I have more than one workspace mapped for the same server url. the ... could not be found in your workspace, or you do not have permission to access it.)
So, could you please help to understand why rename a branch is not working?
Thank you,
To Rename or move files and folders in TFVC, you must be one of the Contributors for your team project. See Team Foundation Server default groups, permissions, and roles.
I tested that and renamed the branch correctly with the "PendRename" method.
Below code sample for your reference:
using System;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace RenameBranch
{
class Program
{
static void Main(string[] args)
{
string oldPath = #"E:\andy\0418Scrum\web0418-0823";
string newPath = #"E:\andy\0418Scrum\web0418-1020";
string collection = #"http://server:8080/tfs/DefaultCollection";
var tfsServer = new Uri(collection);
var tpc = new TfsTeamProjectCollection(tfsServer);
var vcs = tpc.GetService<VersionControlServer>();
Workspace workspace = vcs.GetWorkspace("YourWorkspaceName", vcs.AuthorizedUser);
workspace.PendRename(oldPath, newPath);
}
}
}
Then you need CheckIn it of course. Use a "workspace.GetPendingChanges()" and "workspace.CheckIn()" methods to do it.
Thank you,
The problem was, there are different processes that are generating workspaces to the directory, and then, he can't remove it.
So, I solve this issue doing this steps:
1. reserve a workspace local location for my appĀ“
2. see if this workspace is mapped. If yes, I remove it
3. create a workspace to the previous folder in path and create the map
4. get latest
5. rename
Thank you Andy-MSFT for your support.
In a PowerShell profile, one can identify the PowerShell host in order to do appropriate setup for that host's environment. For example:
if ($host.Name -eq 'ConsoleHost')
{
Import-Module PSReadline
# differentiate verbose from warnings!
$privData = (Get-Host).PrivateData
$privData.VerboseForegroundColor = "cyan"
}
elseif ($host.Name -like '*ISE Host')
{
Start-Steroids
Import-Module PsIseProjectExplorer
}
I would like to be able to do the equivalent identification from a C# context primarily because PowerShell ISE does not support Console.ReadLine so I want to know if it is safe to use it in the current PS host's environment.
I first explored trying to get the output of the Get-Host cmdlet from within C# (per Invoking a cmdlet within a cmdlet). After I located the Microsoft.PowerShell.Commands.Utility assembly (under C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0) I could compile this but it yielded null...
var cmd = new Microsoft.PowerShell.Commands.GetHostCommand();
var myHost = cmd.Invoke();
...while this would not compile due to the InternalHost class being (ironically!) internal:
var cmd = new Microsoft.PowerShell.Commands.GetHostCommand();
var myHost = cmd.Invoke<System.Management.Automation.Internal.Host.InternalHost>();
Next, I then modified my cmdlet to inherit from PSCmdlet rather than Cmdlet (to allow access to the SessionState), so I could then access the PS host object like this:
var psVarObject = SessionState.PSVariable.GetValue("Host");
Of course, that returns a pure Object, which I then needed to cast to... oh, wait... it's still internal!... so this would not compile:
string psHost = ((System.Management.Automation.Internal.Host.InternalHost)psVarObject).Name;
Leaving me no alternative but to use reflection on a foreign assembly (horrors!):
string psHost = (string)psVarObject.GetType().GetProperty("Name").GetValue(psVarObject, null);
That works, but is less than ideal, because reflecting upon any 3rd-party assembly is a fragile thing to do.
Any alternative ideas on either (a) identifying the host or, (b) backing up a bit, being able to use the host's own Read-Host cmdlet to get a typed input from a user?
You can just use Host property from PSCmdlet class. And if you want to do Read-Host:
Host.UI.ReadLine()
When getting
var psVarObject = SessionState.PSVariable.GetValue("Host");
You can cast it to System.Management.Automation.Host.PSHost instead of InternalHost
How do I change the credentials used by a scheduled task using C#.NET?
Instead of using code, you can do it using 'SCHTASKS' command, run it using System.Diagnostic.Process.Start method with the parameters required. It's easy and not much effort required.
Someone has written a task scheduler class library on codeproject.com, it might be what your after...
:)
You must call RegisterTaskDefintion for the task's definition with the new username and password to change just the password.
Code fragment
// Add COM-Reference to "TaskScheduler 1.1 Type Library" to the project
using TaskScheduler;
// code in function X
TaskSchedulerClass TaskClass = new TaskSchedulerClass();
TaskClass.Connect();
// access one task (or search for it or enumerate over all tasks)
IRegisteredTask lTask = null;
lTask = TaskClass.GetFolder("\\").GetTasks(0)[0];
// provide domain\\username and password (ask user for it, use encryption)
string lUsername = "TestDomain\\TestUsername"; // TestDomain can be the hostname for a local user
string lPassword = "xyzPassword";
RegisterTaskDefinition(lTask.Path, lTask.Definition, (int)_TASK_CREATION.TASK_UPDATE, lUsername, lPassword, lTask.Definition.Principal.LogonType, Type.Missing);
Original source for answer:
http://taskscheduler.codeplex.com/discussions/215362
Check out this library for working with TaskSheduler. It's written in VB, but I referenced it easily and called it from C#.