Dynamics AX 2009: How to FTP from a batch job on an AOS - dynamics-ax-2009

After quite a few searches for ways to FTP files in AX, I was happy to discover the WinInet class, which is more or less just a wrapper for the .DLL of the same name. I thought my problems were solved! I was not aware, however, that the class had a major Achilles heel -- it doesn't run in batch (on a server).
Can anybody point me in the right direction? Specifically, I want to upload (FTP put) a file to another server in a server-run batch job (running as a service user with admin rights to the file in question). Anybody?

There is another example of using .NET classes for FTP in Axaptapedia. It is different enough from 10p's example code to take a look...
In my own experience I ended up writing and then calling a bat file from the command line to pass in ftp commands as we needed to use a special FTP client! Here are two examples of using shell scripting - Net Time && Run a Process.

Use .NET classes in AX, e.g. following code logs into the FTP server and renames the file there:
str ftpHostName = 'ftp.microsoft.com'; // without "ftp://", only name
str username = 'myloginname';
str password = 'mypassword';
str oldname = 'oldfilename';
str newname = 'newfilename';
System.Net.Sockets.Socket socket;
System.Net.Dns dns;
System.Net.IPHostEntry hostEntry;
System.Net.IPAddress[] addresses;
System.Net.IPAddress address;
System.Net.IPEndPoint endPoint;
void sendCommand(str _command)
{
System.Text.Encoding ascii;
System.Byte[] bytes;
;
ascii = System.Text.Encoding::get_ASCII();
bytes = ascii.GetBytes(_command + '\r\n');
socket.Send(bytes, bytes.get_Length(), System.Net.Sockets.SocketFlags::None);
}
;
socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily::InterNetwork, System.Net.Sockets.SocketType::Stream, System.Net.Sockets.ProtocolType::Tcp);
hostEntry = System.Net.Dns::GetHostEntry(ftpHostName);
addresses = hostEntry.get_AddressList();
address = addresses.GetValue(0);
info(address.ToString());
endPoint = new System.Net.IPEndPoint(address, 21);
socket.Connect(endPoint);
sendCommand(strfmt("USER %1", username));
sendCommand(strfmt("PASS %1", password));
sendCommand(strfmt("RNFR %1", oldname));
sendCommand(strfmt("RNTO %1", newname));
This is just an example but feel free to use any standard FTP command slightly mpdifying this code. Let me know if the concept is unclear.

Related

Multiple script commands through SSH on Juniper OS

My question is concerning networking equipments, especially Juniper OS.
I would like to execute a lot of commands through SSH on the switch.
And not manually, with a script.
But, when I push a command through SSH (example : 'configure') to manipulate software configuration, it changes the prompt indeed.
And the next command, available only in this level of configuration, doesn't work, because the level up is for sure not registrated since last command, so new command = come back to inital prompt.
Example in Ruby with net/ssh :
ssh = Net::SSH.start("X.X.X.X", LOGIN, :password => PASSWORD)
ssh.exec!("configure") # -> Entering configuration mode
ssh.exec!("set system services telnet") # -> error: unknown command: set
ssh.close
On Juniper ILC, there isn't '&' or ';' to add mutlipe commands.
Is it possible to insert a carriage return in this kind of command and then put all commands in one request ?
Otherwise how can I execute several commands, keeping the link between them ?
Thanks in advance.
Ok, the only solution I found is to concatenate the instructions into one connection.
Example :
ssh.exec!('configure;
set system services telnet;
delete system services web-management;
set system login class READ permissions view-configuration;
set system login class READ allow-commands show;
...
commit;')
Hope this will help somebody, don't hesitate to improve it !
I know it's about Ruby but i hope my investigation results in Java could be useful. I used construction like this in eBay/parallec(i think in JSch it'll work too) :
public static void sshVmWithPassword() {
ParallelClient pc = new ParallelClient();
pc.prepareSsh().setTargetHostsFromString(HOST)
.setSshCommandLine("show version;\nshow log")
.setSshUserName(USERNAME)
.setSshPassword(PASSWORD)
.execute(new ParallecResponseHandler() {
public void onCompleted(ResponseOnSingleTask res,
Map<String, Object> responseContext) {
System.out.println("Responose:" + res.toString()
+ " host: " + res.getHost()
+ " errmsg: " + res.getErrorMessage());
}
});
pc.releaseExternalResources();
}

Perl Script to Monitor URL Using proxy credentials?

Please help on the following code, this is not working in our environment.
use LWP;
use strict;
my $url = 'http://google.com';
my $username = 'user';
my $password = 'mypassword';
my $browser = LWP::UserAgent->new('Mozilla');
$browser->credentials("172.18.124.11:80","something.co.in",$username=>$password);
$browser->timeout(10);
my $response=$browser->get($url);
print $response->content;
OUTPUT :
Can't connect to google.com:80 (timeout)
LWP::Protocol::http::Socket: connect: timeout at C:/Perl/lib/LWP/Protocol/http.p m line 51.
OS: windows XP
Regards, Gaurav
Do you have a HTTP proxy at 172.18.124.11? I assume LWP is not using the proxy. You might want to use env_proxy => 1 with the new() call.
You also have a mod-perl2 tag in this question. If this code runs inside mod-perl2, it's possible that the http_proxy env variable is not visible to the code. You can check this eg. by printing $browser->proxy('http').
Or just set the proxy with $browser->proxy('http', '172.18.124.11');
Also, I assume you don't have use warnings on, because new() takes a hash, not just a string. It's a good idea to always enable warnings. That will save you lots of trouble.

FTP copy a file to another place in same FTP

I need to upload same file to 2 different place in same FTP. Is there a way to copy the file on the FTP to the other place instead of upload it again? Thanks.
There's no standard way to duplicate a remote file over the FTP protocol. Some FTP servers support proprietary or non-standard extensions for this though.
Some FTP clients do support the remote file duplication. Either using the extensions or via a temporary local copy of the remote file.
For example WinSCP FTP client does support the duplication using both drag&drop and menu/keyboard command:
It supports the SITE CPFR/CPTO FTP extension (supported for example by the ProFTPD mod_copy module)
It falls back to an automatic duplication via a local temporary copy, if the above extension is not available.
(I'm the author of WinSCP)
Another workaround is to open a second connection to the FTP server and make the server upload the file to itself by piping a passive mode data connection to an active mode data connection. This solution is shown in the answer by #SaadAchemlal. This is basically use of FXP protocol, but for one server. Though many FTP servers will reject this, as they wont allow data connection to/from an address different to the client's.
Side note: people often confuse move with copy. In case you actually want to move, then that's a completely different question. Moving file on FTP is widely supported.
I don't think there's a way to copy files without downloading and re-uploading, at least I found nothing like this in the List of FTP commands and no client I have seen so far supported something like this.
Yes, the FTP protocol itself can support this in theory. The FTP RFC 959 discusses this in section 5.2 (see the paragraph starting with "When data is to be transferred between two servers, A and B..."). However, I don't know of any client that offers this sort of dual server control operation.
Note that this method could transfer the file from the FTP server to itself using its own network, which won't be as fast as a local file copy but would almost certainly be faster than downloading and then reuploading the file.
I can copy files between remote folders in Linux based systems.
In my particular case, I'm using very common file manager PCManFM:
Menu "Go" --> "Connect to server"
FTP Login info, etc
Open new tab in PCManFM
Connect to same server
Copy from tab to tab...
It's a bit slow, so I guess that it could be downloading and uploading back the files, but it's done automatically and very user-friendly.
The code below makes the FTP server to upload the file to itself (using loopback connection). It needs the FTP server to allow both passive and active connection mode.
If you want to understand the ftp commands here is a list of them : List of ftp commands
function copyFile($filePath, $newFilePath)
{
$ftp1 = ftp_connect('192.168.1.1');
$ftp2 = ftp_connect('192.168.1.1');
ftp_raw($ftp1, "USER ftpUsername");
ftp_raw($ftp1, "PASS mypassword");
ftp_raw($ftp2, "USER ftpUsername");
ftp_raw($ftp2, "PASS mypassword");
$res = ftp_raw($ftp2, "PASV");
$addressAndPort = substr($res[0], strpos($res[0], '(') + 1);
$addressAndPort = substr($addressAndPort, 0, strpos($addressAndPort, ')'));
ftp_raw($ftp1, "CWD ." . dirname($newFilePath));
ftp_raw($ftp2, "CWD ." . dirname($filePath));
ftp_raw($ftp1, "PORT ".$addressAndPort);
ftp_raw($ftp1, "STOR " . basename($newFilePath));
ftp_raw($ftp2, "RETR " . basename($filePath));
ftp_raw($ftp1, "QUIT");
ftp_raw($ftp2, "QUIT");
}
I managed to do this by using WebDrive to mount the ftp as a local folder, then "download" the files using filezilla directly to the folder. It was a bit slower than download normally is, but you dont need to have the space on your hdd.
Here's another workaround using PHP cUrl to execute a copy request on the server by feeding parameters from the local machine and reporting the outcome:
Local code:
In this simple test routine, I want to copy the leaning tower photo to the correct folder, Pisa:
$ch = curl_init();
$data = array ('pic' => 'leaningtower', 'folder' => 'Pisa');
curl_setopt($ch, CURLOPT_URL,"http://travelphotos.com/copypic.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
Server code (copypic.php):
On the remote server, I have simple error checking. On this server I had to mess with the path designation, i.e., I had to use "./" for an acceptable path reference, so you may have to tinker with it a bit.
$pic = $_POST["pic"];
$folder = $_POST["folder"];
if (!$pic || !$folder) exit();
$sourcePath = "./unsortedpics/".$pic.".jpg";
$destPath = "./sortedpics/".$folder."/".$pic.".jpg";
if (!file_exists($sourcePath )) exit("Source file not found");
if (!is_dir("./sortedpics/".$folder)) exit("Invalid destination folder");
if (!copy($sourcePath , $destPath)) exit("Copy not successful");
echo "File copied";
You can do this from C-Panel.
Log into your C-Panel.
Go into file manager.
Find the file or folder you want to duplicate.
Right-click and chose Copy.
Type in the new director you want to copy to.
Done!
You can rename the file to be copied into the full path of your wanted result.
For example:
If you want to move the file "file.txt" into the folder "NewFolder" you can write it as
ftp> rename file.txt NewFolder/file.txt
This worked for me.

Why is the read-only attribute set (sometimes) for files created by my service?

NOTE: This is a complete re-write of this question. I'd previously conflated some ACL issues with the problem I'm hunting, which is probably why there were no answers.
I have a windows service that uses the standard open/close/write routines to write a log file (it reads stuff from a pipe and stuffs it into the log). A new log file is opened each day at midnight. The system is Windows XP Embedded.
The service runs as the Local System service (CreateService with NULL for the user).
When the service initially starts up, it creates a log file and writes to it with no problems. At this point everything is OK, and you can restart the service (or the computer) with no issues.
However, at midnight (when the day changes), the service creates a new log file and writes to it. The funny thing is, this new log file has the 'read only' flag set. That's a problem because if the service (or the computer) restarts, the service can no longer open the file for writing.
Here's the relevant information from the system with the problem having already happened:
Directory of C:\bbbaudit
09/16/2009 12:00 AM <DIR> .
09/16/2009 12:00 AM <DIR> ..
09/16/2009 12:00 AM 437 AU090915.ADX
09/16/2009 12:00 AM 62 AU090916.ADX
attrib c:\bbbaudit\*
A C:\bbbaudit\AU090915.ADX <-- old log file (before midnight)
A R C:\bbbaudit\AU090916.ADX <-- new log file (after midnight)
cacls output:
C:\ BUILTIN\Administrators:(OI)(CI)F
NT AUTHORITY\SYSTEM:(OI)(CI)F
CREATOR OWNER:(OI)(CI)(IO)F
BUILTIN\Users:(OI)(CI)R
BUILTIN\Users:(CI)(special access:)
FILE_APPEND_DATA
BUILTIN\Users:(CI)(IO)(special access:)
FILE_WRITE_DATA
Everyone:R
C:\bbbaudit BUILTIN\Administrators:(OI)(CI)F
NT AUTHORITY\SYSTEM:(OI)(CI)F
CFN3\Administrator:F
CREATOR OWNER:(OI)(CI)(IO)F
Here's the code I use to open/create the log files:
static int open_or_create_file(char *fname, bool &alreadyExists)
{
int fdes;
// try to create new file, fail if it already exists
alreadyExists = false;
fdes = open(fname, O_WRONLY | O_APPEND | O_CREAT | O_EXCL);
if (fdes < 0)
{
// try to open existing, don't create new file
alreadyExists = true;
fdes = open(fname, O_WRONLY | O_APPEND);
}
return fdes;
}
I'm having real trouble figuring out how the file is getting that read-only flag on it. Anyone who can give me a clue or a direction, I'd greatly appreciate it.
Compiler is VC 6 (Yea, I know, it's so far out of date it isn't funny. Until you realize that we're just now upgraded to XPE from NT 3.51).
The Microsoft implementation of open() has an optional third argument 'pmode', which is required to be present when the second argument 'oflag' includes the O_CREAT flag. The pmode argument specifies the file permission settings, which are set when the new file is closed for the first time. Typically you would pass S_IREAD | S_IWRITE for pmode, resulting in an ordinary read/write file.
In your case you have specified O_CREAT but omitted the third argument, so open() has used whatever value happened to be on the stack at the third argument position. The value of S_IWRITE is 0x0080, so if the value in the third argument position happened to have bit 7 clear, it would result in a read-only file. The fact that you got a read-only file only some of the time, is consistent with stack junk being passed as the third argument.
Below is the link for the Visual Studio 2010 documentation for open(). This aspect of the function's behaviour has not changed since VC 6.
http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx
Well, I have no idea what the underlying problem is with the 'open' APIs in this case. In order to 'fix' the problem, I ended up switching to using the Win32 APIs for file management (CreateFile, WriteFile, CloseHandle).

Send mail from a Windows script

I would like to send mail from a script on a Windows Server 2003 Standard Edition. I think the server setup is pretty much out of the box.
The mail server is an Exchange one, and when you're on the internal network you can use plain old SMTP. I have done it from my machine with Perl, but unfortunately Perl is not available on the server.
Is there an easy way of doing this from a .bat-file or any other way that doesn't require installing some additional software?
Edit:
Thanks for the quick replies. The "blat" thingie would probably work fine but with wscript I don't have to use a separate binary.
I didn't see PhiLho's post the first time I edited and selected an answer. No need for me to duplicate the code here.
Just save the script to a file, say sendmail.vbs, and then call it from the command prompt like so:
wscript sendmail.vbs
It is possible with Wscript, using CDO:
Dim objMail
Set objMail = CreateObject("CDO.Message")
objMail.From = "Me <Me#Server.com>"
objMail.To = "You <You#AnotherServer.com>"
objMail.Subject = "That's a mail"
objMail.Textbody = "Hello World"
objMail.AddAttachment "C:\someFile.ext"
---8<----- You don't need this part if you have an active Outlook [Express] account -----
' Use an SMTP server
objMail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
' Name or IP of Remote SMTP Server
objMail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = _
"smtp.server.com"
' Server port (typically 25)
objMail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objMail.Configuration.Fields.Update
----- End of SMTP usage ----->8---
objMail.Send
Set objMail=Nothing
Wscript.Quit
Update: found more info there: VBScript To Send Email Using CDO
By default it seems it uses Outlook [Express], so it didn't worked on my computer but you can use a given SMTP server, which worked fine for me.
If the server happened (I realize how old this question is) to have Powershell v2 installed, the CmdLet Send-MailMessage would do this in one line.
Send-MailMessage [-To] <string[]> [-Subject] <string> -From <string> [[-Body] <string>] [[-SmtpServer] <string>] [-Attachments <string[]>] [-Bcc <string[]>] [-BodyAsHtml] [-Cc <string[]>] [-Credential <PSCredential>] [-DeliveryNotficationOption {None | OnSuccess | OnFailure | Delay | Never}] [-Encoding <Encoding>] [-Priority {Normal | Low | High}] [-UseSsl] [<CommonParameters>]
I don't know if dropping a binary alongside the .bat file counts as installing software, but, if not, you can use blat to do this.
If you have outlook/exchange installed you should be able to use CDONTs, just create a mail.vbs file and call it in a batch file like so (amusing they are in the same dir)
wscript mail.vbs
for the VBScript code check out
http://support.microsoft.com/kb/197920
http://www.w3schools.com/asp/asp_send_email.asp
forget the fact they the two links speak about ASP, it should work fine as a stand alone script with out iis.
I think that you'll have to install some ActiveX or other component what could be invoked from WScript, such as:
http://www.activexperts.com/ActivEmail/
and:
http://www.emailarchitect.net/webapp/SMTPCOM/developers/scripting.asp
Otherwise, you'll have to write the entire SMTP logic (if possible, not sure) in WScript all on your own.
Use CDONTS with Windows Scripting Host (WScript)
Is there a way you send without referencing the outside schema urls.
http://schemas.microsoft.com/cdo/configuration/
That is highly useless as it can't be assumed all boxes will have outside internet access to send mail internally on the local exchange. Is there a way to save the info from those urls locally?

Resources