How to execute a PowerShell command from JavaFX - powershell

I have this Powershell command that I would like know how to execute from Java / JavaFx:
powershell.exe Get-WMIObject Get-WMIObject Win32_SerialPort | Select-Object Name,DeviceID,Description,Caption, PNPDeviceID,Status | Out-File -FilePath C:\\path\\to\\file\\test.txt
I've read and tried several examples I found online and in forums. But I'm still stuck! This is the JavaFx method I'm using:
public void PowerShellCommand() throws IOException
{
String command = "powershell.exe Get-WMIObject Get-WMIObject Win32_SerialPort | Select-Object Name,DeviceID,Description,Caption, PNPDeviceID,Status | Out-File -FilePath C:\\path\\to\\file\\test.txt";
Process powerShellProcess = Runtime.getRuntime().exec(command);
powerShellProcess.getOutputStream().close();
}
Executing the command directly in PowerShell produces the right results.
A .txt file with content is created. Like this one (which is correct):
Name : Kommunikationsanschluss (COM1)
Description : Kommunikationsanschluss
Caption : Kommunikationsanschluss (COM1)
PNPDeviceID : ACPI\PNP0501\1
Status : OK
(Goal is to fetch the various results out of the .txt file content and display them on a UI).
But using the code in the above method creates an empty .txt file. I'm certainly doing something wrong, and would need some help to fix it.
Do you have any ideas? Your time and help is very much appreciated!
AveJoe
PS: I'm using a Windows 10 Pro machine.

I believe you are actually asking several questions, including
How to execute powershell command from java?
How to read a file in java?
How to display contents of a text file in JavaFX GUI?
I will answer the first question.
(Indeed, I believe a post should contain a single question.)
The ProcessBuilder constructor takes an array of String. Each word in your command becomes a single element in the array. Words are separated by one or more space characters.
Also you need to read the Process output and error output. I recommend creating two separate threads - one for output and another for error. And since you can easily write the Process output to a file, there is no need to use Out-File in your powershell command.
Here is a java program to execute the powershell command from your question.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class ProcBldr {
public static void main(String[] args) {
ProcessBuilder procBldr = new ProcessBuilder("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
"Get-WMIObject",
"Win32_SerialPort",
"|",
"Select-Object",
"Name,DeviceID,Description,Caption,PNPDeviceID,Status");
Process proc;
try {
proc = procBldr.start(); //throws java.io.IOException
Thread out = new Thread(new ProcOutput(proc.getInputStream(), new File("C:\\Users\\USER\\stdout00.txt")));
Thread err = new Thread(new ProcOutput(proc.getErrorStream(), new File("C:\\Users\\USER\\stderr00.txt")));
out.start();
err.start();
int exitCode = proc.waitFor(); //throws java.lang.InterruptedException
out.join();
err.join();
System.out.println("\nExited with error code : " + exitCode);
}
catch (IOException | InterruptedException x) {
x.printStackTrace();
}
}
}
class ProcOutput implements Runnable {
private BufferedReader buffReader;
private PrintWriter pw;
public ProcOutput(InputStream is, File f) throws IOException {
InputStreamReader isr = new InputStreamReader(is);
buffReader = new BufferedReader(isr);
pw = new PrintWriter(f);
}
public void run() {
try {
String line = buffReader.readLine();
while (line != null) {
pw.append(line);
pw.append(System.lineSeparator());
line = buffReader.readLine();
}
}
catch (IOException xIo) {
throw new RuntimeException(xIo);
}
finally {
pw.close();
try {
buffReader.close();
}
catch (IOException xIo) {
// Ignore.
}
}
}
}
The output of the powershell command is written to file stdout00.txt. The file contains the following...
Name : Communications Port? (COM1)
DeviceID : COM1
Description : Communications Port
Caption : Communications Port? (COM1)
PNPDeviceID : ACPI\PNP0501\0
Status : OK
I recommend you read the article When Runtime.exec() won't. It is very old and was written before class ProcessBuilder was part of the JDK but it also applies to ProcessBuilder and therefore, in my opinion, still relevant to the latest JDK version (12.0.1 at time of writing this).
Note that my environment is Windows 10 (64 bit) and Oracle JDK 12.0.1 (also 64 bit)

Related

How can I replicate New-SmbGlobalMapping in C# code?

I am writing a service which controls docker containers. I want to have the mounted volume as an Azure share, and thus need to use the SMB Global Mapping. If I use the usual WNetAddConnection2A then I can mount the share just fine in my code, but the containers cannot see it as it is not "global". I can't find source for the PowerShell New-SmbGlobalMapping command (is there a way to see it?) and I can't find a suitable API to call. I hope someone knows the magic incantation I can put in my .NET code.
I can't find source for the PowerShell New-SmbGlobalMapping command
(is there a way to see it?) and I can't find a suitable API to call. I
hope someone knows the magic incantation I can put in my .NET code.
PowerShell uses WMI
In your case, it calls
Create method of the MSFT_SmbMapping class (MSFT_SmbGlobalMapping exactly)
You can use WMI Code Creator to generate/test C# code
EDIT : Test with PowerShell.Create
Test as Admin ("requireAdministrator" in manifest) on Windows 10
Test code (C#, VS 2015) =>
// PowerShell calls CredUIPromptForCredentialsW to display the User/Password dialog (you can call it with P/Invoke if needed)
string sUser = "user#provider.com";
string sPassword = "myPassword";
System.Net.NetworkCredential networkCredential = new System.Net.NetworkCredential(sUser, sPassword, null);
System.Security.SecureString securePassword = new System.Security.SecureString();
foreach (var c in networkCredential.Password)
securePassword.AppendChar(c);
// Add reference to :
// C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll
// Add :
// using System.Management.Automation;
PSCredential psCredential = new PSCredential(networkCredential.UserName, securePassword);
// Error handling must be improved : if I pass an invalid syntax for "RemotePath" or not launched as Admin,
// nothing happens (no error, no result) (on Windows 10)
string sLocalPath = "Q:";
string sRemotePath = "\\\\DESKTOP-EOPIFM5\\Windows 7";
using (var ps = PowerShell.Create())
{
ps.AddCommand("New-SmbGlobalMapping");
ps.AddParameter("LocalPath", sLocalPath);
ps.AddParameter("RemotePath", sRemotePath);
ps.AddParameter("Credential", psCredential);
//ps.AddParameter("RequireIntegrity", false);
//ps.AddParameter("RequirePrivacy", false);
try
{
System.Collections.ObjectModel.Collection<PSObject> collectionResults = ps.Invoke();
foreach (PSObject psObl in collectionResults)
{
Console.WriteLine("Status : {0}", psObl.Members["Status"].Value.ToString());
Console.WriteLine("Local Path : {0}", psObl.Members["LocalPath"].Value.ToString());
Console.WriteLine("Remote Path : {0}\n", psObl.Members["RemotePath"].Value.ToString());
}
}
catch (ParameterBindingException pbe)
{
System.Console.WriteLine("\rNew-SmbGlobalMapping error : {0}: {1}",
pbe.GetType().FullName, pbe.Message);
}
}
// To get and remove the test mapping in PowerShell :
// Get-SmbGlobalMapping
// Remove-SmbGlobalMapping -RemotePath "\\DESKTOP-EOPIFM5\Windows 7" -Force

Get the "plain" (end-user readable) name of UWP apps installed on a system

I'm using the following PowerShell script to retrieve and save to a text file the list of UWP apps on a system. It gets the ID, name (system name) and packagefamilyname.
In addition to the name, I'm looking for a way to retrieve the plain name of the app: for example, "OneNote" instead of "Microsoft.Office.OneNote". Ideally, this name would also be localized: for example, "Calculatrice" (on a French system) instead of "Microsoft.WindowsCalculator".
I found this list of info retrieved by Get-AppxPackage but nothing like an end-user readable name... I'm not very familiar this area of expertise. Any help would be appreciated.
$installedapps = get-AppxPackage
$ids = $null
foreach ($app in $installedapps)
{
try
{
$ids = (Get-AppxPackageManifest $app -erroraction Stop).package.applications.application.id
}
catch
{
Write-Output "No Id's found for $($app.name)"
}
foreach ($id in $ids)
{
$line = $app.Name + "`t" + $app.packagefamilyname + "!" + $id
echo $line
$line >> 'c:\temp\output.txt'
}
}
write-host "Press any key to continue..."
[void][System.Console]::ReadKey($true)
[Completed updated]
You can do this pretty easily in C#. You have to reference the correct WinMDs from the Windows SDK (the actual directories will change depending on SDK version):
C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd
C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd
If you can't build a stand-alone EXE and just want pure PowerShell, you might be able to reference the WinMDs %systemroot%\system32\winmetadata. The code is pretty simple (I avoided await since I don't know if PowerShell has that):
// using Windows.Management.Deployment;
static void Main(string[] args)
{
GetList();
}
static void GetList()
{
var pm = new PackageManager();
var packages = pm.FindPackagesForUser("");
foreach (var package in packages)
{
var asyncResult = package.GetAppListEntriesAsync();
while (asyncResult.Status != Windows.Foundation.AsyncStatus.Completed)
{
Thread.Sleep(10);
}
foreach (var app in asyncResult.GetResults())
{
Console.WriteLine(app.DisplayInfo.DisplayName);
}
}
}
I spent some time looking for this today, and finally came up with a solution that doesn't involve a page of code, or digging around in files/registry/etc. Put the below two lines in a script or function, and it will return PoSh-friendly output which you can then pipe into ForEach-Object, Where-Object, Sort-Object, Export-CSV, etc.
$PkgMgr = [Windows.Management.Deployment.PackageManager,Windows.Web,ContentType=WindowsRuntime]::new()
$PkgMgr.FindPackages() | Select-Object DisplayName -ExpandProperty Id
The .FindPackages() method also has an overload which takes a Family Name, but the docs lead me to believe it can only accept exact names, not wildcard matches. So unless you know exactly what you are looking for, I am guessing it is best to retrieve the list of all packages, and then do your own searches on that list.
The docs do say that this will return packages for all users, and that it requires admin/elevated rights to run.

itext: how to tweak text extraction?

I'm using iText 5.5.8 for Java.
Following the default, straightforward text extraction procedures, i.e.
PdfTextExtractor.getTextFromPage(reader, pageNumber)
I was surprised to find several mistakes in the output, specifically all letter ds come out as os.
So how does text extraction in iText really work? Is it some kind of OCR?
I took a look under the hood, trying to grasp how TextExtractionStrategy works, but I couldn't figure out much. SimpleTextExtractionStrategy for example seems to just determine the presence of lines and spaces, whereas it's TextRenderInfo that provides text by invoking some decode method on a GraphicsState's font field and that's as far as I could go without getting a major migraine.
So who's my man? Which class should I override or which parameter should I tweak to be able to tell iText "hey, you're reading all ds wrong!"
edit:
sample PDF can be found at http://www.fpozzi.com/stampastopper/download/ name of file is 0116_LR.pdf
Sorry, can't share a direct link.
This is some basic code for text extraction
import java.io.File;
import java.io.IOException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
public class Import
{
public static void importFromPdf(final File pdfFile) throws IOException
{
PdfReader reader = new PdfReader(pdfFile.getAbsolutePath());
try
{
for (int i = 1; i <= reader.getNumberOfPages(); i++)
{
System.out.println(PdfTextExtractor.getTextFromPage(reader, i));
System.out.println("----------------------------------");
}
}
catch (IOException e)
{
throw e;
}
finally
{
reader.close();
}
}
public static void main(String[] args)
{
try
{
importFromPdf(new File("0116_LR.pdf"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
edit after #blagae and #mkl answers
Before starting to fiddle with iText I have tried text extraction from Apache PDFBox (a project similar to iText I just discoreved) but it does have the same issue.
Understanding how these programs treat text is way beyond my dedication, so I have written a simple method to extract text from raw page content, that is whatever stands between BT and ET markers.
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.itextpdf.text.io.RandomAccessSourceFactory;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.parser.ContentByteUtils;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
public class Import
{
private final static Pattern actualWordPattern = Pattern.compile("\\((.*?)\\)");
public static void importFromPdf(final File pdfFile) throws IOException
{
PdfReader reader = new PdfReader(pdfFile.getAbsolutePath());
Matcher matcher;
String line, extractedText;
boolean anyMatchFound;
try
{
for (int i = 1; i <= 16; i++)
{
byte[] contentBytes = ContentByteUtils.getContentBytesForPage(reader, i);
RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().createSource(contentBytes));
while ((line = raf.readLine()) != null && !line.equals("BT"));
extractedText = "";
while ((line = raf.readLine()) != null && !line.equals("ET"))
{
anyMatchFound = false;
matcher = actualWordPattern.matcher(line);
while (matcher.find())
{
anyMatchFound = true;
extractedText += matcher.group(1);
}
if (anyMatchFound)
extractedText += "\n";
}
System.out.println(extractedText);
System.out.println("+++++++++++++++++++++++++++");
String properlyExtractedText = PdfTextExtractor.getTextFromPage(reader, i);
System.out.println(properlyExtractedText);
System.out.println("---------------------------");
}
}
catch (IOException e)
{
throw e;
}
finally
{
reader.close();
}
}
public static void main(String[] args)
{
try
{
importFromPdf(new File("0116_LR.pdf"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
It appears, at least in my case, that characters are correct. However the order of words or even letters is messy, super messy in fact, so this approach is unusable either.
What really surprises me is that all methods I have tried so far to retrieve text from PDFs, including copy/paste from Adobe Reader, screw something up.
I have come to the conclusion that the most reliable way to get some decent text extraction may also be the most unexpected: some good OCR.
I am now trying to:
1) transform pdf into an image (PDFBox is great at doing that - do not even bother to try pdf-renderer)
2) OCR that image
I will post my results in a few days.
Your input document has been created in a strange (but 'legal') way. There is a Unicode mapping in the resources that maps arbitrary glyphs to Unicode points. In particular, character number 0x64, d in ASCII, is mapped to the glyph with Unicode point 0x6f (UTF-8), which is o, in this font. This is not a problem per se - any PDF viewer can handle it - but it is strange, because all other glyphs that are used are not "cross-mapped". e.g. character 0x63 is mapped to Unicode point 0x63 (which is c), etc.
Now for the reason that Acrobat does the text extraction correctly (except for the space), and the others go wrong. We'll have to delve into the PDF syntax for this:
[p, -17.9, e, -15.1, l, 1.4, l, 8.4, i, -20, m, 5.8, i, 14, st, -17.5, e, 31.2, ,, -20.1, a] TJ
<</ActualText <fffffffeffffffff00640064> >> BDC
5.102 0 Td
[d, -14.2, d] TJ
EMC
That tells a PDF viewer to print p-e-l-l-i- -m-i-st-e- -a on the first line of code, and d-d after that on the fourth line. However, d maps to o, which is apparently only a problem for text extraction. Acrobat does do the text extraction correctly, because there is a content marker /ActualText which says that whatever we write between the BDC and EMC markers must be parsed as dd (0x64,0x64).
So to answer your question: iText does this on the same level as a lot of well-respected viewers, which all ignore the /ActualText marker. Except for Acrobat, which does respect it and overrules the ToUnicode mapping.
And to really answer your question: iText is currently looking into parsing the /ActualText marker, but it will probably take a while before it gets into an official release.
This probably has to do with how the PDF with OCR'd in the first place, rather than with how iTextSharp is parsing the PDF's contents. Try copy/pasting the text from the PDF into Notepad, and see if the "ds -> os" transformation still occurs. If this is the case, you're going to have to do the following when parsing text from this particular PDF:
Identify all occurrences of the string "os".
Decide whether or not the word of which the given "os" instance is a constituent is a valid English/German/Spanish/ word.
If it IS a valid word, do nothing.
If it is NOT a valid word, perform the reverse "os -> ds" transformation, and check against the dictionary in the language of your choice again.

PdfUtilities.convertPdf2Png Create automatic images in My directory

I've written some code to perform OCR on a PDF using Tesseract (Tess4J):
public void DoOCRAnalyse(String From) throws FileNotFoundException {
Tesseract instance = Tesseract.getInstance(); // JNA Interface Mapping
File[] files=PdfUtilities.convertPdf2Png(new File(From));
for (File f:files) {
try {
String result = instance.doOCR(f);
/*String result = instance.doOCR(take File or BufferedImage); */
SearchForSVHC(result,SvhcList);
} catch (TesseractException e) {
System.err.println(e.getMessage());
}
}
}
It recognizes text, which is great, but my problem is that it needs the images to be in a directory on disk. How can I pass a BufferedImage or File to the methode doOCR() without needing the files on disk?
You are passing a File object to doOCR. When you call convertPdf2Png, it invokes GhostScript to convert a PDF file to one or more PNG files. You certainly can delete them after OCR if you want, e.g., by executing f.Delete() in a finally block.

How can I get the current stack trace in Java?

How do I get the current stack trace in Java, like how in .NET you can do Environment.StackTrace?
I found Thread.dumpStack() but it is not what I want - I want to get the stack trace back, not print it out.
You can use Thread.currentThread().getStackTrace().
That returns an array of StackTraceElements that represent the current stack trace of a program.
StackTraceElement[] st = Thread.currentThread().getStackTrace();
is fine if you don't care what the first element of the stack is.
StackTraceElement[] st = new Throwable().getStackTrace();
will have a defined position for your current method, if that matters.
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste + "\n");
}
Thread.currentThread().getStackTrace();
is available since JDK1.5.
For an older version, you can redirect exception.printStackTrace() to a StringWriter() :
StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
Tony, as a comment to the accepted answer, has given what seems to be the best answer which actually answers the OP's question:
Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );
... the OP did NOT ask how to get a String from the stack trace from an Exception. And although I'm a huge fan of Apache Commons, when there is something as simple as the above there is no logical reason to use an outside library.
You can use Apache's commons for that:
String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
On android a far easier way is to use this:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Another solution (only 35 31 characters):
new Exception().printStackTrace();
new Error().printStackTrace();
To get the stack trace of all threads you can either use the jstack utility, JConsole or send a kill -quit signal (on a Posix operating system).
However, if you want to do this programmatically you could try using ThreadMXBean:
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);
for (ThreadInfo info : infos) {
StackTraceElement[] elems = info.getStackTrace();
// Print out elements, etc.
}
As mentioned, if you only want the stack trace of the current thread it's a lot easier - Just use Thread.currentThread().getStackTrace();
I suggest that
Thread.dumpStack()
is an easier way and has the advantage of not actually constructing an exception or throwable when there may not be a problem at all, and is considerably more to the point.
Silly me, it's Thread.currentThread().getStackTrace();
In Java 9 there is a new way:
public static void showTrace() {
List<StackFrame> frames =
StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE )
.walk( stream -> stream.collect( Collectors.toList() ) );
for ( StackFrame stackFrame : frames )
System.out.println( stackFrame );
}
Getting stacktrace:
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
Printing stacktrace (JAVA 8+):
Arrays.asList(ste).forEach(System.out::println);
Printing stacktrage (JAVA 7):
StringBuilder sb = new StringBuilder();
for (StackTraceElement st : ste) {
sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);
To string with guava:
Throwables.getStackTraceAsString(new Throwable())
I have a utility method that returns a string with the stacktrace:
static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
}
And just logit like...
...
catch (FileNotFoundException e) {
logger.config(getStackTrace(e));
}
try {
}
catch(Exception e) {
StackTraceElement[] traceElements = e.getStackTrace();
//...
}
or
Thread.currentThread().getStackTrace()
Maybe you could try this:
catch(Exception e)
{
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
e.printStackTrace(pw);
String errorDetail = writer.toString();
}
The string 'errorDetail' contains the stacktrace.
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
The last element of the array represents the bottom of the stack, which is the least recent method invocation in the sequence.
A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().
loop through StackTraceElement and get your desired result.
for (StackTraceElement ste : stackTraceElements )
{
//do your stuff here...
}
You can use jstack utility if you want to check the current call stack of your process.
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id#]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
I used answers from above and added formatting
public final class DebugUtil {
private static final String SEPARATOR = "\n";
private DebugUtil() {
}
public static String formatStackTrace(StackTraceElement[] stackTrace) {
StringBuilder buffer = new StringBuilder();
for (StackTraceElement element : stackTrace) {
buffer.append(element).append(SEPARATOR);
}
return buffer.toString();
}
public static String formatCurrentStacktrace() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return formatStackTrace(stackTrace);
}
}
For people, who just want to get the current stacktrace to their logs, I would go with:
getLogger().debug("Message", new Throwable());
Cheers
You can also use exception to print stack instead of taking pain of putting new line char:
Exception e = new Exception();
e.setStackTrace(Thread.currentThread().getStackTrace());
loggr.info(e);
This is an old post, but here is my solution :
Thread.currentThread().dumpStack();
More info and more methods there :
http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html