X++ run a process with user credentials

When you want to run for example a command prompt from within the X++ language, you can use the following code :
Let’s assume that the following parameters were passed to the method :

  • FileName : “C:\windows\system32\cmd.exe”
  • Arguments : “”
  • RunAsAdmin : true
  • UseShellExecute : true
  • WaitForExit : false

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
static void runWindowsProcess(  FileName    _fileName
                            ,   str         _arguments
                            ,   boolean     _runAsAdmin         = false
                            ,   boolean     _useShellExecute    = false
                            ,   boolean     _waitForExit        = false)
{
    System.Diagnostics.ProcessStartInfo processStartInfo;
    System.Diagnostics.Process          process;
    System.OperatingSystem              operatingSystem;
    System.Version                      operatingSystemVersion;
    System.Exception                    ex;
    int                                 major;
    Boolean                             start;
    ;
 
    try
    {
        // Assert CLRInterop permission
        new InteropPermission(InteropKind::ClrInterop).assert();
 
        // BP deviation documented
        processStartInfo    = new System.Diagnostics.ProcessStartInfo(_fileName, _arguments);
 
        // BP deviation documented
        process             = new System.Diagnostics.Process();
 
        // Get an instance of the System.OperatingSystem class
        operatingSystem         = System.Environment::get_OSVersion();
 
        // Get the OS version number
        operatingSystemVersion  = operatingSystem.get_Version();
 
        // If admin rights asked
        if(_runAsAdmin)
        {
            major = operatingSystemVersion.get_Major();
 
            // Get the major part of the version number (Starting from Windows Vista)
            if(major >= 6)
            {
                // Start using the runAs property which will prompt for administrator credentials
                processStartInfo.set_Verb('runas');
            }
        }
 
        // Use the system shell to execute the process
        processStartInfo.set_UseShellExecute(_useShellExecute);
 
        // Attach the starting information to the process
        process.set_StartInfo(processStartInfo);
 
        // Start the process and wait for it to complete
        start = process.Start();
 
        // Wait for the process to finish
        if(_waitForExit)
        {
            process.WaitForExit();
        }
 
        // Revert permission
        CodeAccessPermission::revertAssert();
    }
    catch(Exception::CLRError)
    {
        // BP Deviation documented
        ex = ClrInterop::getLastException();
 
        while (ex != null)
        {
            error(ex.ToString());
 
            ex = ex.get_InnerException();
        }
 
        throw error(strFmt("@HEL270", _fileName));
    }
}

Warning: count(): Parameter must be an array or an object that implements Countable in /customers/5/2/1/ksaelen.be/httpd.www/wordpresses/dynamicsaxblog/wp-includes/class-wp-comment-query.php on line 399

6 thoughts on “X++ run a process with user credentials

  1. I am trying to encrypt file to be .gpg file.

    So you made a good example how to use processstartinfo. But How can I pass command line into cmd.exe in x++?? My code is as the blow:

    psi = new System.Diagnostics.ProcessStartInfo(“C:\windows\system32\cmd.exe”);
    // Start using the runAs property which will prompt for administrator credentials
    psi.set_Verb(‘runas’);

    // psi.set_WorkingDirectory(filePath);

    psi.set_FileName(strfmt(@’gpg’)); //
    //GPG –help in CMD.exe
    // [option -o -r] related topic first before [command – e – k etc.] file
    // sCommandLine = “| gpg -o “” +
    // outputFileNameFullPath + “” –decrypt “” +
    // @”C:\Program Files\GNU\GnuPG\test.txt.gpg” + “””;
    sCommandLine = strfmt(@”%1%2%3%4%5%6″,
    ” gpg -r “,
    receiptId,
    ” -o “”,
    strfmt(@”%1″,outputFileNameFullPath),
    “” -e “”,
    strfmt(@”%1″,_fileName));

    psi.set_Arguments(strfmt(“”%1″”, sCommandLine));

    psi.set_CreateNoWindow(True);
    psi.set_UseShellExecute(false);
    psi.set_RedirectStandardInput(true);
    psi.set_RedirectStandardOutput(true);
    psi.set_RedirectStandardError(true);

    process.set_StartInfo(psi);
    process.Start();
    process.WaitForExit(); — dead here, always crash AX..

  2. Hi jzeng,

    I cannot give you the right code right now (@home and left my laptop @work) but I will try and do this tomorrow. Sure as hell funny that actually today I needed this again to start the WCF Trace Viewer from within Dynamics.
    There I needed to pass an argument also so the clue here is to use the set argument method. (psi.set_args or arguments)

    But I will try and remember to send you the code tomorrow (or even better, within 11 hours :-) )

    kind regards,
    Kenny

  3. Hi jzeng,

    Here is the code I wrote to start something with arguments. Hope this helps!

    ///
    /// Opens the WCF trace viewer tool and opens the log file
    ///
    ///
    /// Uses the System.Diagnostics.Process and System.Diagnostics.ProcessStartInfo to start the trace viewer
    ///
    private void openTraceViewerTool()
    {
    FilePath editorPath;
    System.Diagnostics.Process process;
    System.Diagnostics.ProcessStartInfo startInfo;
    ;

    // Get the executable file of the trace viewer we want to start
    editorPath = RDSWCFTraceViewerToolStarter::getTraceViewerPath();

    // Create a new process instance
    process = new System.Diagnostics.Process();

    // Build an information object to start the process with the
    startInfo = process.get_StartInfo();

    // Pass the executable to the start info
    startInfo.set_FileName(editorPath);

    // Pass the config file to the Trace Viewer
    startInfo.set_Arguments(strfmt(‘”%1″‘, this.parmLogFileName()));

    // Open the Trace Viewer
    process.Start();
    }

  4. I found I had two problem.

    1st is filePath. Then I add
    pathloc = System.IO.Path::GetDirectoryName(fileExecutable);

    Then now that error msg saying ‘can’t find file specified’ is gone. And windows can pop up that gpp.exe window.

    The 2nd problem comes, that gpg.exe is not executable program. When I mannully click that C:Program files (x86) GnuPTGPGgpg.exe, that is not executable, it is saying
    ”gpg: Go ahead and type your message …

    so my textErr now is
    “gpg: can’t execute ‘gpg -r gppkeyid -o file.gpg -e file.txt”.

    Godish, what that hell GPG software… it just can be run under cmd.exe.

    I know how to run cmd.exe via system.diagnostic.process startinfo, but how to make console process in x++ to run cmd??

  5. pathloc = System.IO.Path::GetDirectoryName(fileExecutable);
    psi.set_WorkingDirectory(strfmt(@”%1″, pathloc));

    I found problem. I saw a lot of developer was stacking here because of this problem.

    .NET in AX should find file path via system.IO.Path to get directory, and pull this directory when set working directory. If directly pull fileExecutable path into working directory, then system 32 exception always pop up…and saying it can’t find specified file.

    Now my programming come to command line, and for GPG, I still can’t get result sucessfully, when I move “” or some @, info log saying usage[option][filename], later on saying gpg:can’t open ‘-e file.name’ etc..

    So my programming is stacking at command line now.

  6. thank you, my coding working already…. encryption (gnupg ) my file and upload to FTP server in DMZ – done… cheers…

Leave a Comment Yourself

Your email address will not be published. Required fields are marked *