4

I am new to c# and I have a doubt about using a WinForm to complete a batch file with the arguments received by the form, execute the batch and create the specific files.

What I have:

WinForm -> 2 string variables (ip and user)

Batch file -> creating a .rdp file and its shortcut on the desktop with a personalized icon (the batch works when launched manually)

My problem is that the code works for the first time but if I try to change the variables the process doesn´t run and the files are not overwritten with the new information and I have an error saying I don´t have access.

WinForm code:

    private void ok_Click(object sender, EventArgs e)
    {
        string ipText, userText, defaultFile, rdpFile;
        ipText = this.ipOutput.Text;
        userText = this.userOutput.Text;
        defaultFile = "C:\\TerminalServer\\RDbatch.cmd";
        rdpFile = "C:\\TerminalServer\\RD Arbeitsplatz.rdp";

        Console.WriteLine("IP : " + ipText + "; USER : " + userText);

        Process p = null;        

        try
        {
            p = new Process();
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.StartInfo.FileName = defaultFile;
            p.StartInfo.Arguments = String.Format("{0} {1}", ipText, userText);
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.Start();
            p.WaitForExit();
        }
        catch(Exception ex)
        {
            Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
        }         

    }

Batch File Code

@echo off

REM Change this by remming out desktop or all users desktop as you wish
REM Make sure that all entries below have " " around them as present

rem set Location="AllUsersDesktop"
set Location="C:\Users\Default\Desktop"

set DisplayName=""
set filename="C:\TerminalServer\RD Arbeitsplatz.rdp"

REM point to an ICO file or an icon within an existing EXE
rem set icon="C:\TerminalServer\rohwerderLogo.ico"
set icon="C:\TerminalServer\rohwerderLogo.ico, 0"

set WorkingDir="C:\TerminalServer"

del %filename% 2>NUL

(echo screen mode id:i:2
echo use multimon:i:0
echo desktopwidth:i:1920
echo desktopheight:i:1080
echo session bpp:i:32
echo winposstr:s:0,3,0,0,800,600
echo compression:i:1
echo keyboardhook:i:2
echo audiocapturemode:i:0
echo videoplaybackmode:i:1
echo connection type:i:7
echo networkautodetect:i:1
echo bandwidthautodetect:i:1
echo displayconnectionbar:i:1
echo disable wallpaper:i:0
echo allow font smoothing:i:0
echo allow desktop composition:i:0
echo disable full window drag:i:1
echo disable menu anims:i:1
echo disable themes:i:0
echo disable cursor setting:i:0
echo bitmapcachepersistenable:i:1
echo full address:s:%1
echo audiomode:i:0
echo redirectprinters:i:1
echo redirectcomports:i:0
echo redirectsmartcards:i:1
echo redirectclipboard:i:1
echo redirectposdevices:i:0
echo drivestoredirect:s:
echo username:s:%2
echo autoreconnection enabled:i:1
echo authentication level:i:2
echo prompt for credentials:i:0
echo negotiate security layer:i:1
echo remoteapplicationmode:i:0
echo alternate shell:s:
echo shell working directory:s:
echo gatewayhostname:s:
echo gatewayusagemethod:i:4
echo gatewaycredentialssource:i:4
echo gatewayprofileusagemethod:i:0
echo promptcredentialonce:i:0
echo gatewaybrokeringtype:i:0
echo use redirection server name:i:0
echo rdgiskdcproxy:i:0
echo kdcproxyname:s:
) > %filename%
attrib %filename% +r
echo Y|cacls %filename% /E /P %username%:r

REM Make temporary VBS file to create shortcut
REM Then execute and delete it

set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs"

echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT%
echo sLinkFile = "%USERPROFILE%\Desktop\RD Arbeitsplatz.lnk" >> %SCRIPT%
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT%
echo oLink.TargetPath = "C:\TerminalServer\RD Arbeitsplatz.rdp" >> %SCRIPT%
echo oLink.IconLocation = "C:\TerminalServer\rohwerderLogo.ico" >> %SCRIPT%
echo oLink.Save >> %SCRIPT%

cscript /nologo %SCRIPT%
rem del %SCRIPT% 2>NUL

I was thinking of launching the process code if the file didn´t exist and if exist overwriting it but I am not sure how to go from here.

galactica15
  • 43
  • 1
  • 6
  • You didn't post any C# code that deals with files, just a call to start another process. That other process then starts *another* script that tries to create a shortcut. Why not create the shortcut directly in your C# code? – Panagiotis Kanavos Aug 10 '18 at 07:46
  • In any case, if a file is in use you can't overwrite it. You didn't post the full exception, as returned by `Exception.ToString()` so one can only guess what the exception was or which line threw it. The full exception contains the call stack which would show *which* call ended up throwing an exception – Panagiotis Kanavos Aug 10 '18 at 07:48
  • I suspect this should be a duplicate of [Create a shortcut on desktop](https://stackoverflow.com/questions/4897655/create-a-shortcut-on-desktop) – Panagiotis Kanavos Aug 10 '18 at 07:50
  • @PanagiotisKanavos Like I said I am new to c# and I created the batch file before deciding to use the WinForm. – galactica15 Aug 10 '18 at 07:51
  • Without the full exception we can't help. There's no file access code in the C# snippet. – Panagiotis Kanavos Aug 10 '18 at 07:54
  • Are you trying to create a `vbs` script that creates the shortcut *in the batch*? First, that's just as easy to do in C#, eg with `File.WriteAllText`. Second, there's probacly a *single* Powershell line that can create a desktop shortcut – Panagiotis Kanavos Aug 10 '18 at 07:56
  • @PanagiotisKanavos The application didn´t stop so there isn't really an exception. I only have a message in the console output saying Access Denied. – galactica15 Aug 10 '18 at 07:56
  • What are you trying to do in the first place? Create a script that creates shortcuts? Or create the shortcuts themselves? I already posted a link that shows how to create the shortcuts – Panagiotis Kanavos Aug 10 '18 at 07:58
  • @PanagiotisKanavos ok but stil that´s not really the problem here. The batch works and the shortcut is created. I just want to recreate the rdp file and shortcut when the exe is launched with a new ip and user. – galactica15 Aug 10 '18 at 08:00
  • Like if the .rdp file already exists then when the batch is executed, the variables user and ip in the rdp file should be updated – galactica15 Aug 10 '18 at 08:03
  • That *is* the problem here. If the *batch* tries to overwrite an RDP or vbs file that's in use, it won't be allowed to. If you generate the rdp or vbs file in the batch you have *two* layers between the C# code and the file. At this point you don't even know *which* file is causing the problem. `vbs`? `rdp`? Are you going to add error handling in the *batch*? – Panagiotis Kanavos Aug 10 '18 at 08:03
  • Put the code in C# to check the exception at least. – Panagiotis Kanavos Aug 10 '18 at 08:05
  • Your batch file creates a file, then changes its attributes and ACL to read-only. Of course you cannot overwrite it! Make sure the read-only atteibute is cleared, and the ACL allows you to write to the file before trying to overwrite it. – dumetrulo Aug 10 '18 at 11:35
  • @dumetrulo yeah I noticed that sometime later after creating the post. I changed it and everything is working now. I forgot to update the post to let you guys know. Thanks, Panagiotis Kanavos as well for your help. – galactica15 Aug 13 '18 at 08:55

1 Answers1

1

I would recommend trying to fulfill your task in a C# only, here is some code with my comments in order to get you going. Let us know what exception it causes by adding a try/catch block around the method call.

 ** Required usings **
 using System.IO;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.ComTypes;
 using System.Security.AccessControl;

        // Usage of the method
        // (CommonDesktopDirectory = All Users Desktop or DesktopDirectory = Current user desktop)
        CreateRdpFile(Environment.SpecialFolder.CommonDesktopDirectory,
            @"C:\TerminalServer\rohwerderLogo.ico", 
            "127.0.0.1",
            Environment.UserName
        );


    public void CreateRdpFile(Environment.SpecialFolder locationOfShortcut, string iconPath, string ip, string userName)
    {
        // The fileName of the rdp file to create
        var rdpFileName = @"C:\TerminalServer\RD Arbeitsplatz.rdp";

        // Your filecontents, note that we're concatenation the ip and userName from the methods arguments
        var rdpFileContent =
@"screen mode id:i:2
use multimon:i:0
desktopwidth:i:1920
desktopheight:i:1080
session bpp:i:32
winposstr:s:0,3,0,0,800,600
compression:i:1
keyboardhook:i:2
audiocapturemode:i:0
videoplaybackmode:i:1
connection type:i:7
networkautodetect:i:1
bandwidthautodetect:i:1
displayconnectionbar:i:1
disable wallpaper:i:0
allow font smoothing:i:0
allow desktop composition:i:0
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1
full address:s:" + ip + @"
audiomode:i:0
redirectprinters:i:1
redirectcomports:i:0
redirectsmartcards:i:1
redirectclipboard:i:1
redirectposdevices:i:0
drivestoredirect:s:
username:s:"+ userName +@"
autoreconnection enabled:i:1
authentication level:i:2
prompt for credentials:i:0
negotiate security layer:i:1
remoteapplicationmode:i:0
alternate shell:s:
shell working directory:s:
gatewayhostname:s:
gatewayusagemethod:i:4
gatewaycredentialssource:i:4
gatewayprofileusagemethod:i:0
promptcredentialonce:i:0
gatewaybrokeringtype:i:0
use redirection server name:i:0
rdgiskdcproxy:i:0
kdcproxyname:s:";

        // Open a filestream, load that into a streamWriter
        using (var fileStream = File.Open(rdpFileName, FileMode.Create))
        using(var streamWriter = new StreamWriter(fileStream))
        {
            // Write the contents of the string created above
            streamWriter.Write(rdpFileContent); 
        }
        // fileStream and streamWriter automatically closed because of using block


        // Get a FileSecurity object that represents the
        // current security settings.
        FileSecurity fSecurity = File.GetAccessControl(rdpFileName);

        // Add the FileSystemAccessRule to the security settings. (Allow read for user from argument)
        fSecurity.AddAccessRule(new FileSystemAccessRule(userName, FileSystemRights.Read, AccessControlType.Allow));

        // Build the shortcut path
        var shortcutPath = Path.Combine(Environment.GetFolderPath(locationOfShortcut), "RD Arbeitsplatz.lnk");

        IShellLink link = (IShellLink)new ShellLink();
        // Setup shortcut information
        link.SetDescription("My Description");
        link.SetPath(rdpFileName);
        link.SetIconLocation(iconPath);

        // Save it
        var file = (IPersistFile)link;
        file.Save(shortcutPath, false);
    }

    #region Imported code to prevent additional assembly references
    [ComImport]
    [Guid("00021401-0000-0000-C000-000000000046")]
    internal class ShellLink
    {
    }

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("000214F9-0000-0000-C000-000000000046")]
    internal interface IShellLink
    {
        void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, int fFlags);
        void GetIDList(out IntPtr ppidl);
        void SetIDList(IntPtr pidl);
        void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
        void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
        void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
        void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
        void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
        void GetHotkey(out short pwHotkey);
        void SetHotkey(short wHotkey);
        void GetShowCmd(out int piShowCmd);
        void SetShowCmd(int iShowCmd);
        void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
        void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
        void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
        void Resolve(IntPtr hwnd, int fFlags);
        void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
    }
    #endregion
Fixation
  • 969
  • 6
  • 12