Weird issues with non-english characters - c#

I have code automatically running netsh to check firewall rules:
var process = new Process
{
StartInfo =
{
FileName = fileName,
Arguments = arguments,
LoadUserProfile = true,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.OutputDataReceived += (sendingProcess, outLine) => outputText.AppendLine(outLine.Data);
process.ErrorDataReceived += (sendingProcess, errorLine) => errorText.AppendLine(errorLine.Data);
output = outputText.ToString();
errorOutput = errorText.ToString();
//parse both outputs...
As a filename, I have the following command:
C:\Windows\System32\netsh.exe
And the following is the arguments:
advfirewall firewall show rule name="rulename" dir=in
It mostly works fine, its when output has non-english characters I run into issues. All of them are replaced with "?", so I thought this is encoding issue, but it looks like its not.
When I run same command manually in cmd, I get the very same result. However, if I change the font from default one to consolas, it shows non-english output perfectly fine.
How do I apply the same fix in my code and can I even do it at all? I searched for some time and found nothing, suggesting that I may be doing something wrong here.
Again, encoding doesn't seem to be an issue since both cmd and powershell show output after changing font correctly. I tried setting StartInfo.StandardOutputEncoding to the same encoding used in cmd but nothing is changed - I still get question marks in output. What am I missing?
EDIT: Tried setting StartInfo.StandardOutputEncoding to different values, including cp866, koi8-r and Windows-1251 - result stays the same, still getting question marks.
I'm trying to do this on Windows 2008 R2, with english as display language.

If the rule names contain Cyrillic characters, then you are going to need to read them with an output console or editor that will display them.
In PowerShell, use the following and edit the output in WordPad or Word.
(New-object -comObject HNetCfg.FwPolicy2).Rules | ForEach-Object { $_.Name } >rules.txt

Related

Why does Dart wrap process arguments in quotes where C# does not?

I'm porting some C# code to Dart on Windows and just wasted a couple of hours on a frustrating difference in how Dart passes command line arguments through to the process.
Here's a portion of the C# code being ported, which executes just fine:
var startInfo = new ProcessStartInfo("C:\\Program Files\\Inkscape\\inkscape.exe", "--file=\"C:\\Users\\Kent\\test.svg\" --export-png=\"C:\\Users\\Kent\\test.png\" --export-width=100 --export-area-page")
{
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
var process = Process.Start(startInfo);
process.WaitForExit();
if (process.ExitCode != 0)
{
var stdout = process.StandardOutput.ReadToEnd();
var stderr = process.StandardError.ReadToEnd();
Console.WriteLine(stdout);
Console.WriteLine(stderr);
}
Running this correctly produces an output PNG file. However, the Dart equivalent does not:
final inkscapeResult = await Process.run(
r'C:\Program Files\Inkscape\inkscape.exe',
[
'--file="C:\\Users\\Kent\\test.svg"',
'--export-png="C:\\Users\\Kent\\test.png"',
'--export-width=100',
'--export-area-page',
],
);
final exitCode = inkscapeResult.exitCode;
if (exitCode != 0) {
writeError(inkscapeResult.stdout);
writeError(inkscapeResult.stderr);
}
Instead, the process exits with code 1 and the program outputs:
** (inkscape.exe:5604): WARNING **: 17:30:09.785: Can't open file: "C:\Users\Kent\test.svg" (doesn't exist)
** (inkscape.exe:5604): WARNING **: 17:30:09.785: Can't open file: "C:\Users\Kent\test.svg" (doesn't exist)
** (inkscape.exe:5604): WARNING **: 17:30:09.785: Specified document "C:\Users\Kent\test.svg" cannot be opened (does not exist or not a valid SVG file)
It is pretty well-known that Inkscape is a bit finicky when it comes to executing on the command line, but the advice I've read is to simply pass in full paths, which I am doing.
I found that if I eschew arguments, it works:
final inkscapeResult = await Process.run(
r'C:\Program Files\Inkscape\inkscape.exe --file="C:\\Users\\Kent\\test.svg" --export-png="C:\\Users\\Kent\\test.png" --export-width=100 --export-area-page',
[],
);
So I inferred that Dart must be doing something with the arguments that Inkscape does not like. I managed to catch it in the act using Process Explorer and it has the following command line:
"C:\Program Files\Inkscape\inkscape.exe" "--file=\"C:\Users\Kent\test.svg\"" "--export-png=\"C:\Users\Kent\test.png\"" --export-width=100 --export-area-page
If I run this directly from the command line, I get no output but the image also does not get generated, so presumably it's failing in the same fashion. Compare this with the command line produced by the C# code:
"C:\Program Files\Inkscape\inkscape.exe" --file="C:\Users\Kent\test.svg" --export-png="C:\Users\Kent\test.png" --export-width=100 --export-area-page
Dart is wrapping each individual argument with quotes, where C# is not (though C#'s API does not even separate individual arguments). This is somehow breaking Inkscape's parser.
Who is in the wrong here? Me, Dart, C#, or Inkscape?
I think the simplest way is to split the argument name and the argument value like that:
final inkscapeResult = await Process.run(r'C:\Program Files\Inkscape\inkscape.exe', [
'--file', 'C:\\Users\\Kent\\test.svg',
'--export-png', 'C:\\Users\\Kent\\test.png',
'--export-width', '100',
'--export-area-page',
]);
That way you don't have to worry about escaping or quoting arguments.

Cmd Command (ewfmgr C: -commit) not executed when start it from C# Process

When I try to run cmd command 'efwmgr C: -commit' from C#, got empty log file without any information, and when check manually 'ewfmgr C:', got 'Boot Command NO_CMD', so commit not run.
Same code just changed Arguments = "/C chkdsk C:" it runs and works well, inserted whole output into my log.
Method which I used.
public static void StartProcess()
{
var procStartInfo = new ProcessStartInfo
{
CreateNoWindow = false,
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd",
Arguments = "/C ewfmgr C: -commit",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true
};
var process = new Process { StartInfo = procStartInfo, EnableRaisingEvents = true };
using (StreamWriter writer = new StreamWriter(#"D:\commitFile.txt"))
{
process.OutputDataReceived += (sender, e) =>
{
writer.WriteLine(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
}
}
This is the nearly example I found on https://social.msdn.microsoft.com/Forums/vstudio/en-US/4e014365-8e8f-4f93-998a-156f2e55ebab/how-to-get-and-write-ewf-current-to-text-file-using-c?forum=csharpgeneral
You probably getting an error in process error output stream. Append your log in ErrorDataReceived event handler. And for the 'ewfmgr' is not recognized as an internal or external command you should edit process environment variable or specify full path to your application.
This is how you code should look like:
var procStartInfo = new ProcessStartInfo
{
CreateNoWindow = false,
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd",
//Append PATH environment variable bellow if you use this
Arguments = "/C ewfmgr C: -commit",
//Or use full path to application without changing environment variable
//Arguments = "/C c:\full\path\to\application\ewfmgr C: -commit",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true
};
procStartInfo.EnvironmentVariables["PATH"] += #";c:\full\path\to\application\";
var process = new Process { StartInfo = procStartInfo, EnableRaisingEvents = true };
using (StreamWriter writer = new StreamWriter(#"D:\commitFile.txt"))
{
process.OutputDataReceived += (sender, e) =>
{
writer.WriteLine(e.Data);
};
process.ErrorDataReceived+= (sender, e) =>
{
writer.WriteLine(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
Just wanted to point out an update regarding this issue for anyone that might encounter this, or any other file "missing" from Windows/System32 directory:
First things to check is your system architecture, and your process architecture:
There are several posts about this feature (although I prefer to call it issue), I can safely say that this one explains it correclty, and that ewfmgr.exe works just fine if you set your architecture correclty.
In order not to rely on another post/link, I'll rewrite/copy the answer from David there:
There is one explanation that makes sense:
You are executing the program on a 64 bit machine.
Your C# program is built as x86.
The bcdedit.exe file exists in C:\Windows\System32.
Although C:\Windows\System32 is on your system path, in an x86 process you are subject to the File System Redirector. Which means that C:\Windows\System32 actually resolves to C:\Windows\SysWOW64.
There is no 32 bit version of bcdedit.exe in C:\Windows\SysWOW64.
The solution is to change your C# program to target AnyCPU or x64.
As a side note I'd like to also add that by default, VS projects for C# are set as "Any CPU" configuration, however there's checkbox ticked in project properties on the build tab, that says "Prefer 32-bit": This needs to be unchecked/disabled, or "Any cpu" build will result in 32 bit application as well.
Other than that, I've successfully implemented fully working EWF manager into our service application. Unfortunatelly I haven't had any luck using pInvoke and ewfapi dll, since it didn't seem to return correct results. I'm not sure yet whether there was an issue in implementation, or whether the EWF api itself is broken (to be honest, its really buggy and unreliable. For us specifically, the "Disable" command does nothing - after reboot, ewf is still enabled. The only way to disable it is to Disable and Commit, or use CommitAndDisableLive, which both unfortunatelly commit current state onto the drive, so I had to use fallback and reboot the machine before disabling protection, to be sure its in clean state), so I went the route to call it using command line, and parse response parameters to control it. Unfortunatelly it was time critical and I needed production ready solution, so I had to make a workaround, but I'll post a separate question about the pInvoke, and then put on GitHub altogether as a final solution.
I'll come back and edit this post to include the GitHub link once I have the time to upload it. Should someone need it right away, I'm happy to send it over as-is.
Hope it helps.

Set C# console application to Unicode output

I have a C# console application, and I was trying to do some ASCII art within it. However, some of the characters I wanted to use are Unicode. So, I was searching the internet/SO and couldn't find a consolidated answer on how to set the console to be Unicode in a C# console application.
TDLR: How do I set the console in a C# console application to be Unicode?
Edit: I did find this post after searching for something not related to this question.
It turns out that there are multiple things you need to set up in order to make the console display Unicode characters.
Set the console to a Unicode supported font. To do this, run your C# console application once with Console.ReadKey(); so the window stays open. Right click on the title bar of the window and select Properties. These options will persist when debugging through Visual Studio. You might need to use the Default menu instead for persisting the options throughout the system. In the Fonts tab, you need to set the font to Lucida Console. This font supports Unicode characters. The related post can be found here.
Set the console's code page to UTF-8. This one is a bit tricky. Because, you have to execute a command in the console window to change the code page. For whatever reason, this option is not available as a console preference. To do this, you'll need to make a separate cmd.exe process, and use this instead of the normal console provided.
var cmd = new Process
{
StartInfo =
{
FileName = "cmd.exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
UseShellExecute = false
}
};
cmd.Start();
cmd.StandardInput.WriteLine("chcp 65001");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
The first part of the code above will create a new cmd.exe process. The settings given to StartInfo will make sure that Console is redirected to this new process. The second part of the code sends a command to this console window and runs it. That command, chcp 65001, sets the console's code page to UTF-8. Related posts can be found here and here.
Set the OutputEncoding to UTF-8. This is the only way that Console.WriteLine will actually output Unicode characters. Setting this is very simple.
Console.OutputEncoding = Encoding.UTF8;
Now, any output from Console will be in Unicode. The related post can be found here.
So, that's it! I hope this information helps someone. :-)
Another option is to use P/Invoke to change the code page directly:
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleOutputCP(uint wCodePageID);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCP(uint wCodePageID);
static async Task<int> Main(string[] args)
{
SetConsoleOutputCP(65001);
SetConsoleCP(65001);
Console.WriteLine("This is how you say hello in Japanese: こんにちは");
return 0;
}
}
Output:
The solution I prefer is to change the active console code page of my profile to utf-8 using region under control panel. (see picture)
Restart and select a font which can display the necessary characters.

Redirect standard output of exe to my Console application

There is an executable called jlink.exe that I will like to make of use on my console application. Because jlink.exe is not a .net application it is not possible for me to reference it and call it's methods. As a result I will like to use it reading it's output
When I start that exe from windows explorer this is how it looks:
It then waits for a command. If I type mem 88 2 then I get back:
Now I will like to do the same thing with my .net console application reading it's standard output but for some reason I cannot read the output. This is what I have:
// change working directory
Directory.SetCurrentDirectory(#"C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.4 Evaluation\arm\bin");
Process p = new Process( )
{
StartInfo = new ProcessStartInfo( #"jlink.exe" )
{
UseShellExecute = false ,
RedirectStandardOutput = true ,
RedirectStandardInput = true
}
};
p.Start( );
StreamWriter standardInput = p.StandardInput;
StreamReader standardOutput = p.StandardOutput;
var line = string.Empty;
while ( ( line = standardOutput.ReadLine( ) ) != null )
{
Console.WriteLine( line );
}
why when I run that code I just get a black window... I do not get the same output as when running that executable. When I run that code against other executable it works great.
If I then type mem 88 2 and press ENTER nothing happens. If I press enter one more time then I finally get what I want with extra content. Why am I getting this behavior with that executable?
Edit
I have looked at similar question such as this one:
process.standardoutput.ReadToEnd() always empty?
I don't think I am doing something wrong. I guess there is something weird with that executable. To use that executable you may download it at: http://supp.iar.com/Download/SW/?item=EWARM-EVAL or at http://www.iar.com/en/Products/IAR-Embedded-Workbench/ARM/ . Then go to C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.4 Evaluation\arm\bin and execute jlink.exe (If you do not have a board connected via usb you will get an error but it does not matter. the error message does not show up either).

Displaying command in cmd console

I'm trying to run a command in cmd using C# and am having some difficulties. I'd like to be able to write the command to the cmd console so I can see what it's trying to run (I think there's some issue with the quotes or something, so if I could see the actual string in the command line, I'd be able to see exactly what the problem is). My code looks like this:
var processStartInfo = new ProcessStartInfo("cmd", "/c"+commandString);
processStartInfo.CreateNoWindow = true;
Process.Start(processStartInfo);
So basically, I just want to see the string commandString written in the console. Any help would be greatly greatly appreciated.
string CommandLineString = #"""C:\Program Files\Microsoft SQL Server\100\Tools\Binn\bcp.exe"" ""SELECT * FROM table where date >= '2009-01-01'"" queryout ""C:\Data\data.dat"" -S DBSW0323 -d CMS -n -T";
In this case, the problem is probably just your lack of a space after "/c".
var processStartInfo = new ProcessStartInfo("cmd", "/c " + commandString);
As for viewing in a command window, instead, you will probably be better off inspecting the Arguments property of your processStartInfo instance.
EDIT
Taking into account the command line details you posted, I believe this is what your issue is. Check out the following from cmd help:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
If all of the following conditions are met, then quote characters
on the command line are preserved:
no /S switch
exactly two quote characters
no special characters between the two quote characters,
where special is one of: &<>()#^|
there are one or more whitespace characters between the
the two quote characters
the string between the two quote characters is the name
of an executable file.
Since you are using /c, you have quote and special char issues still. Try wrapping your entire commandString in a set of quotes.
Take this simple example for instance (creating temp.txt manually of course):
string commandString = #"""C:\WINDOWS\Notepad.exe"" ""C:\temp.txt""";
var processStartInfo = new ProcessStartInfo("cmd", "/c " + commandString);
The command line to be executed will be: /c "C:\WINDOWS\Notepad.exe" "C:\temp.txt", but this will fail since "C:\temp.txt" is not an executable.
If you wrap the whole thing in one last set of quotes, you should see the intended result:
string commandString = #"""""C:\WINDOWS\Notepad.exe"" ""C:\temp.txt""""";
var processStartInfo = new ProcessStartInfo("cmd", "/c " + commandString);
Resulting in a command line of: /c ""C:\WINDOWS\Notepad.exe" "C:\temp.txt"" and ultimately opening notepad with your test file.
That string is not "written" to the console, it's part of the argument list for a program you launch (which in this case happens to be cmd.exe). Since the console created is owned by that program, unless it wants to print its arguments for its own reasons (which it won't) this is not directly doable.
If you simply want to debug then why not inspect the value of commandString, or write it out into a log file?
If you absolutely need the command line to be displayed in the console then you could resort to hacks (run another intermediate program that prints the command line and then calls cmd.exe with it), but unless there is some other good reason to use this approach I would not recommend it.

Categories

Resources