I am having a problem which seems really daft. I must be missing something silly. We have a PGP keyring that is on one of our production servers. The user account it belongs to is not allowed to be logged on as interactively for security. Our problem is we sometimes need to add new keys and can not do this easily. So we thought we could create a quick console app that would be run as its ID and would call the PGP commands via the command line.
The command gets called but it asks for input to confirm what we are doing. Our problem is the "y" we send to standardinput is never displayed and the key is not verified.
here is the code:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.DirectoryServices;
using System.Threading;
namespace TestConsoleApp
{
class RegExValidator
{
private System.Diagnostics.Process myProcess;
public RegExValidator()
{
}
public static void Main(string[] args)
{
RegExValidator myValidator = new RegExValidator();
myValidator.InstallKeys("C:\\Test\\batch.asc", "batch.asc");
}
private void InstallKeys(string keyPath, string keyName)
{
myProcess = new System.Diagnostics.Process();
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.CreateNoWindow = false;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = "pgp";
myProcess.StartInfo.Arguments = "-ka " + keyPath + "";
myProcess.Start();
StreamWriter myInput = myProcess.StandardInput;
myInput.AutoFlush = true;
Thread.Sleep(3000);
myInput.WriteLine("y");
myInput.WriteLine(Environment.NewLine);
}
}
}
This is the output we get on the command line.
C:\Test>TestConsoleApp.exe
Pretty Good Privacy(tm) Version 6.5.2
(c) 1999 Network Associates Inc.
Uses the BSafe(tm) Toolkit, which is copyright RSA Data Security, Inc.
Export of this software may be restricted by the U.S. government.
WARNING: Environmental variable TZ is not defined, so GMT timestamps
may be wrong. See the PGP User's Guide to properly define TZ
Looking for new keys...
DSS 2048/1024 0xDE053A3D 2007/05/29 Batch Interface <batch#netgiro.com>
sig? 0xDE053A3D (Unknown signator, can't be checked)
keyfile contains 1 new keys. Add these keys to keyring ? (Y/n)
C:\Test>
Can anyone help?
Thanks
EDIT
We tried this process but instead of PGP we just moved a file and we got the Y/N box and that worked. It would seem that you may not be able to do it with PGP. No idea why though.
The message
keyfile contains 1 new keys. Add these keys to keyring ? (Y/n)
suggests replying with an Uppercase Y. try changing your call to:
myInput.WriteLine("Y");
(I have no PGP installed for checking, but have encountered other command line interfaces that insisted on case.)
Another thing to try is flushing stream buffers, which clears all buffers for the stream and causes any buffered data to be written to the underlying device:
myInput.WriteLine("Y");
myInput.Flush();
Related
When you run Get-ExecutionPolicy in PowerShell, it gets the effective execution policy. I need to know the best way to get that information in C#. I don't need to know how to change it like many other questions about PowerShell Execution Policy, I just need to know how to get it in C#.
Note:
PowerShell execution policies apply only on Windows.
With respect to Windows, the answer below covers both PowerShell editions.
It can be inferred from the docs that boxdog pointed to in a comment, but to spell it out:
using System;
using System.Management.Automation;
namespace demo
{
class ConsoleApp {
static void Main() {
using (var ps = PowerShell.Create()) {
var effectivePolicy = ps.AddCommand("Get-ExecutionPolicy").Invoke()[0].ToString();
ps.Commands.Clear();
Console.WriteLine("Effective execution policy: " + effectivePolicy);
}
}
}
}
Note:
The above assumes that you're using the PowerShell SDK - see this answer for the appropriate NuGet package to add to your project.
If you're using a PowerShell (Core) 7+ SDK, additional considerations apply:
On Unix-like platforms, execution policies fundamentally do not apply (Unrestricted is reported, though in effect it is Bypass), so the following applies to Windows only:
The LocalMachine scope of any - by definition install-on-demand - PowerShell (Core) 7+ version does not apply; only - if defined - the CurrentUser and GPO-based policies (which preempt the former) do.
On Windows:
In the absence of a relevant execution policy being defined, Restricted is the default, which categorically prevents execution of script files (.ps1).
If your application needs to execute .ps1 files when hosting the PowerShell SDK, for predictable behavior it is best to set the execution policy, for the current process only, as shown in this answer.
The most elegant solution would probably be to get the ExecutionPolicy registry key in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell. For this solution to work, your program needs to be running on the same architecture (x64 or x86) as the operating system it's running on or it won't be able to see the registry key. Code to do this would look something like this:
using Microsoft.Win32
...
string executionPolicy = Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell", "ExecutionPolicy", null)?.ToString();
If for any reason you can't do the first solution, the second way I would recommend is by using the System.Management.Automation.PowerShell NuGet package. This method would look something like this:
using(var ps = PowerShell.Create()){
ps.AddScript("Get-ExecutionPolicy");
Collection<PSObject> output = ps.Invoke();
Console.WriteLine($"Execution policy is {output[0]}")
}
If you really don't want to add an extra NuGet package to your project, there is another, but quite a bit messier way of doing this using System.Diagnostics.Process and it's output stream. It would look something like this:
var procInfo = new ProcessStartInfo("powershell.exe", "-Command \"Get-ExecutionPolicy\"")
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
};
var proc = new Process
{
StartInfo = procInfo
};
proc.OutputDataReceived += Proc_OutputDataReceived;
proc.Start();
proc.BeginOutputReadLine();
Console.ReadLine();
...
private static void Proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.Data))
Console.WriteLine($"Execution policy is {e.Data}");
}
I'm new to both C# and Perl, but I've been programming in other languages for a few years now. But anyways, I've been trying to write a simple program that passes a value from a C# program to a Perl script via its STDIN. The C# program opens the Perl script just fine, but I cant seem to figure out a way to pass a '1' to it. what would the best way of doing this be? I've searched far and wide for solutions, with no luck...
The C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace OpenPerl
{
class Program
{
static void Main(string[] args)
{
string path ="Z:\\folder\\test.pl";
Process p = new Process();
Process.Start(path, #"1");
}
}
}
The Perl program
#!/usr/bin/perl
use strict;
use warnings;
print "Enter 1: ";
my $number=<STDIN>;
if($number==1)
{
print "You entered 1\n\n";
}
Try this:
my ($number)=#ARGV;
instead of:
my $number=<STDIN>;
From perldoc: "The array #ARGV contains the command-line arguments intended for the script."
You are passing a command line argument to the perl script , not a user input via Process.Start(string,string).
Try printing the #ARGV received by the perl script and you should be able to see 1.
If you want the perl script to receive its input via STDIN, the C# side would look like this:
Process p = new Process();
p.StartInfo.FileName = path;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.StandardInput.WriteLine("1");
Setting UseShellExecute is required for RedirectStandardInput, but it may prevent the perl script from starting properly. In that case, set FileName="<path to perl.exe>" and Arguments="<path to script.pl>".
I was wondering if there is an online tool that can convert c# code to powershell cmdlet code. I have following code that i need to have it powershell. I dont have visual studio to turn this into an exe or dll. any help or ideas would be great.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
namespace CopyUsersBetweenGroupsInSharepointByRR
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("This tool will copy the users from one group to another group");
Console.WriteLine("Please enter the URL of the site where your groups are available");
String siteUrl = Console.ReadLine();
using (SPSite site = new SPSite(siteUrl))
{
try
{
SPWeb web = site.OpenWeb();
Console.WriteLine("Please enter the name of the source group");
String sourceGroupName = Console.ReadLine();
Console.WriteLine("Please enter the name of the destination group");
String destinationGroupName = Console.ReadLine();
SPGroup sourceGroup = web.Groups[sourceGroupName];
SPGroup destinationGroup = web.Groups[destinationGroupName];
SPUserCollection sourceUsers = sourceGroup.Users;
SPUserInfo[] sourceUserInfoArray = new SPUserInfo[sourceUsers.Count];
for (int i = 0; i < sourceUsers.Count; i++)
{
sourceUserInfoArray[i] = new SPUserInfo();
sourceUserInfoArray[i].LoginName = sourceUsers[i].LoginName;
sourceUserInfoArray[i].Name = sourceUsers[i].Name;
}
destinationGroup.Users.AddCollection(sourceUserInfoArray);
destinationGroup.Update();
web.Update();
Console.WriteLine("Operation Completed Successfully");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
}
}
}
}
It's comments like those above that are turning people away from SO in droves. The OP's question was unambiguous and displayed genuine need.
There are several ways to achieve this. Rewriting your entire C# code repository is not one of them.
As already discussed, as of PS 2 you are able to either run C# (or most any other language) inline, or refer to well-formed external file. I've had mixed success with this and I don't believe it's what the OP was really after.
If you genuinely want to convert code (particularly compiled assemblies) then a decompiler like Reflector is able to do this and - with the PowerShell addon - is also able to convert it on-the-fly.
http://blog.lekman.com/2011/10/converting-c-to-powershell.html
If you want your input and output to take place within the PS console then you'd still have to perform some obvious re-writes. But this method has proved incredibly useful to me.
The fastest way to do it is to write the PowerShell code yourself.
Below is how the code will look in PowerShell, i would say that most C# developers should be able to grasp the concepts of converting C# code to PowerShell in a very short time.
Functions can be a little odd at the beginning, since the usual PS syntax is
myFunction Parameter1 Parameter2
Also you really should install PowerShell 3.0 and use the Windows PowerShell ISE tool to develop the code.
Anyways it should not take you more than 1-2 hours to get your C# code running along in PowerShell.
[System.Reflection.Assembly]::LoadWithPartialName(”Microsoft.SharePoint”)
Write-Host "This tool will copy the users from one group to another group"
Write-Host "Please enter the URL of the site where your groups are available"
[string] $siteUrl = [Console]::ReadLine()
$site = new-object Microsoft.SharePoint.SPSite($siteUrl)
try
{
$web = $site.OpenWeb()
Write-Host "Please enter the name of the source group"
[string] $sourceGroupName = [Console]::ReadLine()
Write-Host "Please enter the name of the destination group"
[string] $destinationGroupName = [Console]::ReadLine()
$sourceUsers = $web.Groups[$sourceGroupName]
(and so on)
}
catch
{
Write-Error ("Failed to copy sharepoint users." + $_)
}
I doubt there is anything remotely like that, however Visual Studio is not required to compile c# code. You could compile an exe without VS. The compiler (csc.exe) and msbuild are included as part of framework. They are located in C:\Windows\Microsoft.NET\Framework\{version}.
If you really want to call this from powershell, have a look at the Add-Type cmdlet. You provide it the source code and it will compile the source on the fly, then load the assembly into your session.
Not sure about online tools, but download the free Visual Studio Express & follow this tutorial should have you creating a cmdlet in no time
You may skip this part
I am using a batch file that I have in my thumb drive in order to
mount a true crypt volume. I created that batch file with the help of
this link. on that batch file I have the username and password
that I pass as arguments to trueCrypt.exe in order for it to be
mounted.
Anyways so my question is: will it be possible to see the arguments being passed to a program from a third party process? In other words, will it be possible to see the arguments being passed to this program:
using System;
using System.Reflection;
using System.Diagnostics;
class Program
{
static string password = "";
static void Main(string[] args)
{
if (args.Length > 0)
password = args[0];
// get location where this program resides
var locationOfThisExe = Assembly.GetExecutingAssembly().Location;
Console.Write("Press enter to start a new instance of this program.");
Console.Read();
var randomArgument = new Random().NextDouble().ToString();
Process.Start(locationOfThisExe, randomArgument);
// I am passing a random argument to a new process!
// is it possible to see these arguments from another process?
}
}
Edit
I am creating an edit cause I think I explained my self incorrectly but this edit should be a solution instead of a question
I think this question has not received enough attention. Executing the command showed by https://stackoverflow.com/users/235660/alois-kraus shows:
(I pasted the output on notepad++)
on the image it does not show very clearly but I was able to see the argument being pass to that process. That matters a lot to me because I mount my true crypt volumes with the command:
"C:\Program Files\TrueCrypt\TrueCrypt.exe" /v "a:\volume.tc" /lz /a /p a
that tells to truecrypt that I want to mount the volume located at a:\volume.tc on drive letter z and the password is a
If I execute that command true crypt will mount that volume on drive z:
the problem is that If I then execute the command wmic process note what shoes up:
Note the password is in there!
So in summary it is not safe to pass secure information as an argument. It may be secure if you close the process that received the arguments but I think it is important to be aware of this...
If other users with administrative rights or with the same user account can execute programs you can see all command lines with
wmic process
from all processes with this single command line.
Note that this has to be on a windows box as I am using c# to access information about windows
(I need information from both a windows box and a linux box, plus I think that making a program/script that runs without gui and accesses windows from a linux box without user intervention would be more difficult, if this is not true please tell me, I would love to do get this running on *nix with only the part that access windows info running on windows).
There is a nice c# api to get this information from windows, on *nix its simple enough to run a command and parse the output to my needs.
There doesn't seem to much decent advice about using ssh from c# out there, sharpSSH and Granados seem to have not been updated for years, are they decent? should I be possible worried about security issues?
(the info I'm retrieving isn't sensitive but if the ssh implementation might have unpatched security flaws(if they haven't been updated for years) I'm worried about someone stealing my credentials.
Are there any other decent c# ssh libraries. If the command output is simple should I just run plink/putty(is it difficult to run a windows cmd shell for plink, and capture output(and is there a way to do it without the shell popping up)?
P.S. while the commercial library seems nice I prefer something free (as in cost and free in source if possible).
Sample Code
There are several commercial SSH client libraries for C#. Following code shows how to connect to a *nix box, run a command and read the response using our Rebex SSH Shell.
// create client, connect and log in
Ssh client = new Ssh();
client.Connect(hostname);
client.Login(username, password);
// run the 'uname' command to retrieve OS info
string systemName = client.RunCommand("uname -a");
// display the output
Console.WriteLine("OS info: {0}", systemName);
client.Disconnect();
For advanced scenarios (such as interactive commands) see SSH Shell Tutorial.
References & Stability
You might be already using Rebex SSH core library without knowing about it. The Rebex SFTP (which uses this SSH lib as a transport layer) is used by Microsoft in several products including Expression Web and Visual Studio 2010. The Rebex SSH Shell is 'just' another layer on top of it (most notable addition is a terminal emulator).
You can download a trial from http://www.rebex.net/ssh-shell.net/download.aspx. Support forum uses engine very similar to this site and runs on http://forum.rebex.net/
Disclaimer: I am involved in development of Rebex SSH
It is quite easy to call plink without the shell popping up.
The trick to not show a window is to set ProcessStartInfo.CreateNoWindow = true.
Add some error handling to this and you're done.
--- PlinkWrapper.cs ---
using System.Collections.Generic;
using System.Diagnostics;
namespace Stackoverflow_Test
{
public class PlinkWrapper
{
private string host { get; set; }
/// <summary>
/// Initializes the <see cref="PlinkWrapper"/>
/// Assumes the key for the user is already loaded in PageAnt.
/// </summary>
/// <param name="host">The host, on format user#host</param>
public PlinkWrapper(string host)
{
this.host = host;
}
/// <summary>
/// Runs a command and returns the output lines in a List<string>.
/// </summary>
/// <param name="command">The command to execute</param>
/// <returns></returns>
public List<string> RunCommand(string command)
{
List<string> result = new List<string>();
ProcessStartInfo startInfo = new ProcessStartInfo("plink.exe");
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.CreateNoWindow = true;
startInfo.Arguments = host + " " + command;
using (Process p = new Process())
{
p.StartInfo = startInfo;
p.Start();
while (p.StandardOutput.Peek() >= 0)
{
result.Add(p.StandardOutput.ReadLine());
}
p.WaitForExit();
}
return result;
}
}
}
--- END PlinkWrapper.cs ---
Call it like
PlinkWrapper plink = new PlinkWrapper("albin#mazarin");
foreach (var str in plink.RunCommand("pwd"))
Console.WriteLine("> " + str);
and the output will be like
> /home/albin
The nice thing with plink is that it is well proven and integrates well with pageant.
I used SharpSsh lib to make an asynchronous directory sync program between linux and windows boxes (i choosed sftp for secure file tranfer). Remained unchanged for years doesn't mean it is unsecure.
it is really easy to use:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tamir.SharpSsh;
namespace sftpex
{
class Program
{
static void Main(string[] args)
{
try
{
SshExec exec = new SshExec(ipAddress, username, password);
Console.Write("Connecting...");
exec.Connect();
Console.WriteLine("OK");
if (exec.Connected)
Console.WriteLine(exec.Cipher);
while (true)
{
Console.Write("Enter a command to execute ['Enter' to cancel]: ");
string command = Console.ReadLine();
if (command == "") break;
string output = exec.RunCommand(command);
string[] m = output.Split('\n');
for(int i=0; i<m.Length; i++)
Console.WriteLine(m[i]);
}
Console.Write("Disconnecting...");
exec.Close();
Console.WriteLine("OK");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If you're not averse to interop with C libs, I believe OpenSSH is one of the best libraries available for the job.
I used SharpSSH in the past to execute commands on a Linux box. There are quite a few bugs, and I had to modify the code to fix some of them, but eventually it kinda worked...
There is a commercial software IP*Works SSH which can do the job.