We are working with some legacy code that accesses a shared drive by the letter (f:\ for example). Using the UNC notation is not an option. Our Java wrapper app will run as a service, and as the first step, I would like to map the drive explicitly in the code. Has anyone done this?
Consider executing the DOS command that maps a network drive as in the following code:
String command = "c:\\windows\\system32\\net.exe use f: \\\\machine\\share /user:user password";
Process p = Runtime.getRuntime().exec(command);
...
See details on net use command:
The syntax of this command is:
NET USE
[devicename | *] [\\computername\sharename[\volume] [password | *]]
[/USER:[domainname\]username]
[/USER:[dotted domain name\]username]
[/USER:[username#dotted domain name]
[/SMARTCARD]
[/SAVECRED]
[[/DELETE] | [/PERSISTENT:{YES | NO}]]
NET USE {devicename | *} [password | *] /HOME
NET USE [/PERSISTENT:{YES | NO}]
You can use JCIFS
http://jcifs.samba.org/src/docs/api/jcifs/smb/SmbFile.html
or if you want higher level API and support for other protocols like FTP, Zip and others:
http://commons.apache.org/vfs/filesystems.html
Both options are pure Java and cross platform.
I think the easiest way is to use the Runtime.getRuntime().exec() method and call the "net use" command.
For example:
try {
// Execute a command without arguments
String command = "C:\\Windows\\system32\\net.exe use F: \\\\server\\share /user:user password";
Process child = Runtime.getRuntime().exec(command);
} catch (IOException e) {
}
Related
consider the following java program:
class PrintName{
public static void main(String[] args){
System.out.println("Hi " + args[0]);
}
}
Now I just compile and execute it from console (I'm on Ubuntu server):
~$:javac PrintName.java
~$:java PrintName "Fernando"
I get the next output:
Hi Fernando
I know there are commands like 'yes' in Linux, with which I can get infinite stream of data. My idea is to do something like this:
yes "Fernando" | java PrintName >> my_file.txt
I want to be able to pass "infinite" Fernando's to my program and have it run infinitely many times, then be able to manipulate the STDO to redirect to some file.
I don't know if I explained it clearly, sorry for my poor handling of the English language. Thank you very much for your time.
This is where you want the xargs command:
yes Fernando | xargs java PrintName
xargs takes each line of stdin, and passes it as command line arguments to the given command.
To redirect it to a file, you can wrap that in a grouping construct:
{ yes Fernando | xargs java PrintName; } >> my_file.txt
Is there a way to use the MS Speech utility from command line? I can do it on a mac, but can't find any reference to it on Windows XP.
My 2 cents on the topic, command line one-liners:
on Win using PowerShell.exe
PowerShell -Command "Add-Type –AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('hello');"
on Win using mshta.exe
mshta vbscript:Execute("CreateObject(""SAPI.SpVoice"").Speak(""Hello"")(window.close)")
on OSX using say
say "hello"
Ubuntu Desktop (>=2015) using native spd-say
spd-say "hello"
on any other Linux
refer to How to text-to-speech output using command-line?
commandline function using google TTS (wget to mp3->mplayer)
command using google with mplayer directly:
/usr/bin/mplayer -ao alsa -really-quiet -noconsolecontrols "http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=Hello%20World&tl=en";
on Raspberry Pi, Win, OSX (or any remote) using Node-Red
npm i node-red-contrib-sysmessage
There's a nice open source program that does what you're asking for on Windows called Peter's Text to Speech available here: http://jampal.sourceforge.net/ptts.html
It contains a binary called ptts.exe that will speak text from standard input, so you can run it like this:
echo hello there | ptts.exe
Alternatively, you could use the following three line VBS script to get similar basic TTS:
'say.vbs
set s = CreateObject("SAPI.SpVoice")
s.Speak Wscript.Arguments(0), 3
s.WaitUntilDone(1000)
And you could invoke that from the command line like this:
cscript say.vbs "hello there"
If you go the script route, you'll probably want to find some more extensive code examples with a variable timeout and error handling.
Hope it helps.
There's also Balabolka: http://www.cross-plus-a.com/bconsole.htm
It has a command line tool balcon.exe. You can use it like this:
List voices:
balcon.exe -l
Speak file:
balcon.exe -n "IVONA 2 Jennifer" -f file.txt
Speak from the command-line:
balcon.exe -n "IVONA 2 Jennifer" -t "hello there"
More command line options are available. I tried it on Ubuntu with SAPI5 installed in Wine. It works just fine.
If you can't find a command you can always wrap the System.Speech.Synthesis.SpeechSynthesizer from .Net 3.0 (Don't forget to reference "System.Speech")
using System.Speech.Synthesis;
namespace Talk
{
class Program
{
static void Main(string[] args)
{
using (var ss = new SpeechSynthesizer())
foreach (var toSay in args)
ss.Speak(toSay);
}
}
}
There is a powershell way also:
Create a file called speak.ps1
param([string]$inputText)
Add-Type –AssemblyName System.Speech
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
$synth.Speak($inputText);
Then you can call it
.\speak.ps1 "I'm sorry Dave, I'm afraid I can't do that"
rem The user decides what to convert here
:input
cls
echo Type in what you want the computer to say and then press the enter key.
echo.
set /p text=
rem Making the temp file
:num
set num=%random%
if exist temp%num%.vbs goto num
echo ' > "temp%num%.vbs"
echo set speech = Wscript.CreateObject("SAPI.spVoice") >> "temp%num%.vbs"
echo speech.speak "%text%" >> "temp%num%.vbs"
start temp%num%.vbs
pause
del temp%num%.vbs
goto input
pause
Your best approach is to write a small command line utility that will do it for you. It would not be a lot of work - just read text in and then use the ms tts library.
Another alternative is to use Cepstral. It comes with a nice command line utility and sounds light years better than the ms tts.
When I run the following command as the root user in the Centos 7 Linux terminal, it produces 57 lines of output:
journalctl --output=json-pretty UNIT=firewalld.service
So how do I change the code below to successfully call this from Java without having to leave my password in a file?
Here is my attempt. When I execute the following code, the console only outputs exit: 1:
String s;
Process p;
try {
p = Runtime.getRuntime().exec("journalctl --output=json-pretty UNIT=firewalld.service");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
Edit
When I add the following:
BufferedReader br2 = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((s = br2.readLine()) != null)
System.out.println("error line: " + s);
The following output gets generated:
error line: No journal files were found.
error line: Failed to get realtime timestamp: Cannot assign requested address
Is the problem related to permissions? When I run journalctl --output=json-pretty UNIT=firewalld.service as root from the Linux terminal, I get the 57 lines of output. But when I run journalctl --output=json-pretty UNIT=firewalld.service as a normal user, the terminal tells me that no files were found. I do not want to put my root password in Java code.
Is there some other way to call journalctl from Java without having to leave the system root password in a file?
You can add your (normal) user to the group systemd-journal using usermod -a -G systemd-journal <username>. Logout and login to it for the change to take effect. This gives your user access to the system journal files without giving it complete root privileges.
The group may be different for different operating system setups. You can simply take a look at which group the journal files belong to, by using ls -l /var/log/journal/ or ls -l /run/systemd/journal/ if /var/log/journal/ does not exist.
I have tried this in Centos LiveCD, and the group the files belonged to was root. So you can add the user to group root, which is not the same as giving it full root permissions.
Nevertheless, I suppose a better route to go would be to set ACLs on the journal files to allow a particular group to access them, because the root group may have access to a little bit too much. The manual for systemd-journald.service gives this example ACL modification command, that grants read access to the journal to wheel and adm:
setfacl -Rnm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal/
Although the manual page for journalctl tells you that adding a user to systemd-journal should allow them to access all journals, that doesn't work on CentOS 7. I have initially worked around this by doing:
chmod +s /usr/bin/journalctl
But that gives everyone access to the journals and that might not be what you want.
As #RealSkeptic pointed out the man page for systemd-journald.service indicates that additional access rights can be given to groups to read the journal (and states as well that adding a user to systemd-journal should be enough). Combining that information you can do
sudo setfacl -Rnm g:systemd-journal:rx,d:g:systemd-journal:rx /run/log/journal/
and after that adding the user to the systemd-journal group, as per the man pages, is enough to allow access to the journals:
sudo usermod -a -G systemd-journal your_user_name
Is it feasible to check queue depth(MQ) using any scripts? [No restrictions on the language]. The plan is to look at non-Java solutions.
I do understand that it is achievable in Java using MQQueueManager but that would need the usage of client API. Hence checking for any alternate options or better practices.
InquireQueue at http://www.capitalware.biz/mq_code_perl_python.html looks similar[but looks a bit outdated]
Didn't Google give you a recent blog posting I wrote called "How to Clear a MQ Queue from a Script or Program" at http://www.capitalware.biz/rl_blog/?p=1616
Just change the MQSC "clear" command to "current depth" (CURDEPTH).
i.e.
DIS QL(TEST.*) CURDEPTH
Does nobody use google anymore ?
PyMQI, an open-source Python extension for WebSphere MQ
http://metacpan.org/pod/MQSeries::Queue
my %qattr = $queue->Inquire( qw(MaxMsgLength MaxQDepth) );
The perl mqseries is very complete. Below is some sample code. (Part of the credit for the sample probably goes to someone else, but it has been floating around my drive for years.) The code connects to the queue manager specified by the command line, if not supplied, it will connect to the default queue manager. It then inquires about the queue name passed in, specifically, the current depth of that queue. This is displayed to the user. This code can easily be modified to display other queue properties. Furthermore, MQINQ can be used to inquire about the attributes of other objects, not just queues.Here is the subset sample code:
use MQSeries;
my $quename = $ARGV[0];
my $quemgrname = $ARGV[1];
my $Hconn = MQCONN($qmgrname, $CompCode, $Reason);
print"MQCONN reason:$Reason\n";
my $ObjDesc = { ObjectType => MQOT_Q, ObjectName => $qname };
my $Options = MQOO_INQUIRE | MQOO_SET | MQOO_FAIL_IF_QUIESCING;
my $Hobj = MQOPEN($Hconn,$ObjDesc,$Options,$CompCode,$Reason);
print"MQOPEN reason:$Reason\n";
my $tst = MQINQ($Hconn,$Hobj,$CompCode,$Reason,MQIA_CURRENT_Q_DEPTH);
print"Depth of $qname is: $tst\n";
MQCLOSE($Hconn,$Hobj,$COptions,$CompCode,$Reason);
print"MQCLOSE reason:$Reason\n";
MQDISC($Hconn,$CompCode,$Reason);
print"MQDISC reason:$Reason\n";
If you are logged in using MQM user on linux and want to have a quick check on queues with messages in them .. here is a quickfix ..
echo "dis ql(*) CURDEPTH" | runmqsc <QMGRNAME> | grep -v '(0' | grep -v 'AMQ'
this will give you a command line output and you can schedule the same command in crontab if needed directly ( without having to save a script for it )
I know its not neat but may be the quickest of solutions.
There's the many JVM based scripting/ish languages that give you access to Java classes. Some need a thin glue layer, some need nothing at all.
Groovy
Jython
Scala
Clojure
etc.
I have some java components that sometimes die and the only way I know is when a user compains they've gotten an error.
What I've done on our monitoring systems is count the amount of java processes running on the server. If a component dies, I get alerted that the java threshold is below normal and I log in to find out which one of the java components died. It works, but I think it could be refined to which component died and be able to start the java process remotely.
So what I was thinking is writing a Powershell script that is executed from the monitoring system. I think I have most of the 'one liner' but need a little more help getting me to the finish line, as I think this script doesn't need to be elaborate.
What I have so far is:
$theProcess = Get-WmiObject win32_process -Filter "name like '%java%'" | select commandLine
The output of this command gives me all the parameters sent to the JVM, including the name of the component, lets call the component "COMP_Number1", and usually there are 5 java component processes running, so the name of the components are "COMP_Number2", "COMP_Number3", and so on.
My question is: Given the output of $theProcess, how do I check all the java processes to validate that all of the components are running? And if not, which one is not running?
Much Appreciated!
TT
You can do something like this:
$components = #("COMP_Number1","COMP_Number2")
$theProcess | %{
$p = $_
$running = $components | ?{$p.commandline -match $_}
$notrunning = $components | ?{ $running -notcontains $_ }
}
$notrunning
If you can use WMI on the the server you can use WMI events to detects the processes that are stopped.
Register-WMIEvent -Query "SELECT * FROM Win32_ProcessStopTrace WHERE ProcessName like 'notepad%'" -Action {Write-Host "kind of notepad process is died"; Write-Host $args}
Here you'll detect notepad.exe die and also notepad++.exe.
You can use Get-EventSubscriber to retreive events you suscribe to and Unregister-Event To unsuscribe.
The script block is considered as a job, so be carefull to import all the modules you need inside.
The script block receive two parameters :
1) System.Management.ManagementEventWatcher
2) System.Management.EventArrivedEventArgs
Here are the parameters of $args[1].newevent :
ExitStatus Property System.UInt32 ExitStatus {get;set;}
ParentProcessID Property System.UInt32 ParentProcessID {get;set;}
ProcessID Property System.UInt32 ProcessID {get;set;}
ProcessName Property System.String ProcessName {get;set;}
SECURITY_DESCRIPTOR Property System.Byte[] SECURITY_DESCRIPTOR {get;set;}
SessionID Property System.UInt32 SessionID {get;set;}
Sid Property System.Byte[] Sid {get;set;}
Exemple :
Register-WMIEvent -Query "SELECT * FROM Win32_ProcessStopTrace WHERE ProcessName like 'notepad%'" -Action {Write-Host "$($args[1].newevent.ProcessName) process is died"}
$components = #("COMP_Number1","COMP_Number2")
$running = #()
do {
Get-WmiObject win32_process -Filter "name like '%java%'" | select commandLine | Foreach-Object {
$running += ($_.commandLine -replace ".*(COMP_Number\d).*",'$1')
}
if ($running.Count -lt $components.Count) {
Compare-Object ($running | Sort-Object) ($components | Sort-Object)
}
$running = #()
Start-Sleep 50000
} until (1 -lt 0)
The regexp most certainly needs work on. You might add some other warning method (e-mail?) or even try to automatically restart the missing process in the if statement.