Running XSharper

XSharper has many command line options to run, debug and compile scripts.

Getting help

It's difficult to remember all XSharper options. It's even more difficult to remember all XSharper actions and parameters. And it's impossible to remember all classes in .NET framework.

Yes, there is Internet, and MSDN, and Visual Studio, but I often find myself in a situation I need a brief piece of help. Command syntax perhaps. Exact parameter order. Fast.

To get help about XSharper command line options:

xsharper /?

To list all XSharper built-in actions:

xsharper /? *

To learn about a specific XSharper built-in action:

xsharper /? print
xsharper /? service

To print all loaded .NET types with type matching *Con*:

xsharper /? *Con*

To print all public methods and properties of a specific .NET type:

xsharper /? Console
xsharper /? System.IO.IOException
xsharper /? XS.ScriptContext

Scripts in files

To run hello.xsh just

xsharper hello.xsh

Same, but disable output to info stream:

xsharper hello.xsh //quiet

Same as above, but also copy script output to a file (it will be still displayed in the console)

xsharper hello.xsh //log x.txt

Require script elevation if the current user is not an administrator:

xsharper hello.xsh //requireAdmin

Run code from a URL (signature validation is forced)
To run hello.xsh just

xsharper hello.xsh

Same, but disable output to info stream:

xsharper hello.xsh //quiet

Same as above, but also copy script output to a file (it will be still displayed in the console)

xsharper hello.xsh //log x.txt

Require script elevation if the current user is not an administrator:

xsharper hello.xsh //requireAdmin

Run code from a URL (signature validation is forced)

xsharper http://xsharper.com/lib/hash.xsh

Same, but using a shorter syntax

xsharper #/hash.xsh 

Register XSharper as default handler of .xsh files

xsharper #/register

Configuration files

.NET programs are crazy about configuration files. Many popular frameworks put lots and lots of program data, and even program logic into XML configuration files. While I'm not a big fan of replacement of code verified during compile time with code verified only on runtime, and System.Configuration namespace is a huge beast that takes hundreds of milliseconds to load even on a decent machine, the configuration files do have their legitimate uses.

A big problem with scripting languages is that configuration files are usually loaded by .NET looking at the executable name and location. Not a problem for compiled XSharper scripts. For interpreted scripts, however, the executable is always xsharper.exe and .NET will expect to find its .config file in the binary directory, not where your script is located.

To solve this problem for interpreted scripts, XSharper allows to explicitly specify what configuration file should be used via //config parameter:

C:\>xsharper myscript.xsh //config script-app.config

To make the config madness complete, the script itself may reside in the configuration file (template may be produced via //genconfig):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="xsharper" type="XSharper.Core.ScriptSectionHandler,XSharper.Core" />
  </configSections>
  <!--  Connection strings  -->
  <connectionStrings>
    <add name="mydb" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=mydb;Integrated Security=True;" />
  </connectionStrings>
  <!-- ** XSharper script ** -->
  <xsharper engineVersion="0.9.1057.0" id="WAIT" xmlns="http://www.xsharper.com/schemas/1.0">
    <print>Hello!</print>
  </xsharper>
</configuration>

This can be executed by providing . (dot) as script name:

C:\>xsharper . //config my.config 
Hello!

Inline scripts

XSharper can run scripts directly from command line, which is often faster than dealing with files, and replaces interactive mode. There are three special switches:

/// <expression> (Run)

Evaluate expression from /// until the end of the line. By default it is treated as a piece of C# code:

C:\>xsharper /// Console.Write("Hello,world")
Hello,world

Usually it's a good idea to wrap everything into double quotes (so <, > and " characters are not interpreted by command line interpreter).

XSharper command-line processing code replaces ` (back quote) with " in the expression to keep it simpler. In the unfortunate event you do need the ` character, just use "\x60" in C# code, or (char)0x60 in XSharper multi-expressions (there is no escaping there).

C:\>xsharper /// "for (int i=0;i<5;++i) Console.WriteLine(`Hello,world`+i)"
Hello,world0
Hello,world1
Hello,world2
Hello,world3
Hello,world4

Print ASCII table of the first 96 printable characters (by generating array of bytes and calling XSharper.Core.Utils.ToHexDump on it):

C:\>xsharper ///p "XS.Utils.ToHexDump(Enumerable.Range(32,128-32).Select(x=>(byte)x).ToArray(),16,32,true)"
00000020  20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F   !"#$%&'()*+,-./
00000030  30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F  0123456789:;<=>?
00000040  40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F  @ABCDEFGHIJKLMNO
00000050  50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F  PQRSTUVWXYZ[\]^_
00000060  60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F  `abcdefghijklmno
00000070  70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F  pqrstuvwxyz{|}~⌂

If the expression starts with < it is treated as XML

xsharper /// "<print>Hello, world!</print>"

Finally, if the expression starts with =, it is treated as interpreted multi-expression with relaxed rules

C:\>xsharper /// "=c.writeline(2+(int)"6"+{1,2,'oops'}.length)"
11

Quotes and command line arguments in inline scripts

Aside of protecting from the wrongdoings of Windows command processor, if the first character of the expression is ", only the string inside the quotes is considered to be a script, and the rest are treated as arguments that can be accessed via ${=$argv[0]}, ${=$argv[1]} and so on. This looks a bit confusing but allows writing simple one liners with arguments.

For example, display the length of file passed as first argument:

C:\>xsharper /// "c.Print(`Length is ${=new FileInfo($argv[0]).Length}`)" C:\Windows\win.ini
Length is 569

If the first character is not ", expression is evaluated until the end of the line:

C:\>xsharper /// c.WriteLine("Hello"); c.WriteLine("World");
Hello
World

Additional assemblies

Also, additional assemblies may be specified in the command line as an assembly name, or DLL path. Multiple names may be specified in comma or semicolon separated list.

Load the image specified in the first command line argument and copy it to clipboard:

C:\>xsharper //ref system.windows.forms;system.drawing /// "=System.Windows.Forms.Clipboard.SetImage(system.drawing.Image.FromFile($argv[0]))" C:\bitmap.png

Actually the code above may be shortened via prefixing assembly names with @, which adds assembly names into default namespace (does the right thing for Windows.Forms, System.Diagnostics where namespace matches assembly name):

C:\>xsharper //ref @System.Windows.Forms;@System.Drawing /// "=Clipboard.setImage(Image.fromFile($arg[0]))" C:\bitmap.png

And now, with one more parameter, we produce a complete utility img2clipboard (more about it in Compiling scripts):

C:\>xsharper //genexe img2clipboard.exe //ref @System.Windows.Forms;@System.Drawing  /// "=Clipboard.setImage(Image.fromFile($arg[0]))" 

///p <expression> (Print)

Evaluate expression (either C#, or multi-expression if starts with =) that returns value, and write the value with WriteLine .

Read c:\windows\win.ini and print each line within [[ ... ]]:

C:\> xsharper ///p "string.Join(`\n\r`,(from x in c.ReadLines (@`c:\windows\win.ini`) select `[[`+x+`]]`).ToArray())"
[[[Mail]]]
[[MAPI=1]]
...

Print first 64 bytes of explorer.exe as HEX dump:

C:\>xsharper ///p "=.ToHexDump(.ReadBytes((.Expand('${% WINDIR %}\explorer.exe')),0,64),16,null,true)"
4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00  MZ?.........yy..
B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ?.......@.......
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 00 00 00 00 00 E0 00 00 00  ............a...

///# <expression> (Dump)

Evaluate expression (either C#, or multi-expression if starts with =) that returns value, and dump the value.

xsharper ///# ={1,2,3}
(int[])  array[3] { /* #1, 01e6fa8e */
  [0] = (int)  1 (0x1)
  [1] = (int)  2 (0x2)
  [2] = (int)  3 (0x3)
}

Using standard input

In some special cases it may be useful to read script from standard input, instead of the command line. In that case specify - (minus) instead of the expression.

echo "Hello, world" | xsharper ///p -

Debugging scripts

You are on a machine via Remote Desktop, there is no Visual Studio in sight, nor you can install, nor you want to install anything, and script does not work. What's next?

Enable script debug output (you'll need DebugView for Windows to see the output)

xsharper hello.xsh //debug

If //debug is specified, if script fails with exception, a complete error message is produced. For example, there is a script:
You are on a machine via Remote Desktop, there is no Visual Studio in sight, nor you can install, nor you want to install anything, and script does not work. What's next?

Enable script debug output (you'll need DebugView for Windows to see the output)

xsharper hello.xsh //debug

If //debug is specified, if script fails with exception, a complete error message is produced. For example, there is a script:

<print newline="false">Enter an expression:</print>
<set expr="${=c.ReadLine()}" />
<print outTo="^debug">Expression: ${expr}</print>
<print>Result: ${=c.Eval($expr)}</print>

which when executed attempts to divide by 0:

C:\xsharper eval.xsh
Enter an expression: (50+20)/0
Error: Attempted to divide by zero.

C:\xsharper eval.xsh //debug
Enter an expression: (50+20)/0
Error: System.DivideByZeroException: Attempted to divide by zero.
   at XSharper.Core.EvalHelper.runAgainstObject(Object obj, Type objType, String func, Array a, RunFlags flags, Object& retVal)
   at XSharper.Core.Operations.OperationCall.Eval(IEvaluationContext context, Stack`1 stack)
   at XSharper.Core.Operations.OperationExpression.Eval(IEvaluationContext context, Stack`1 stack)
   at XSharper.Core.Operations.OperationVariableAccess.Eval(IEvaluationContext context, Stack`1 stack)
   at XSharper.Core.ScriptContext.EvaluateMulti(ParsingReader r)
   at XSharper.Core.ScriptContext.expandVars(TransformRules rules, String s)
   at XSharper.Core.ScriptContext.Transform(Object source, TransformRules rules)
   at XSharper.Core.ValueBase.GetTransformedValueStr()
   at XSharper.Core.Print.execute()
   at XSharper.Core.ScriptContext.<>c__DisplayClass13.<Execute>b__12()
   at XSharper.Core.ScriptContext.RunOnStack(ScriptOperation operation, IScriptAction action, ScriptExecuteMethod method)
At script location:
  [Executing] print(value="Result: ${=c.Eval($expr)}")
  [Executing] xsharper(location="C:\eval.xsh")

To enable debug output and print it to console there is //debugc switch (debugc= debug to console)

C:\>xsharper eval.xsh //debugc 
Enter an expression: 4+5

Expression: 4+5
Result: 9

Same, but enable debug output and print it to console, including script engine details, is done via //verbose:

C:\>xsharper eval.xsh //debugc //verbose
# OpenStream> Reading from file C:\eval.xsh
# Context> Executing script C:\eval.xsh with isolation High
Enter an expression: 4+5

Expression: 4+5
Result: 9

Same, as above, but also trace lines of code as they execute

xsharper hello.xsh //debugc //verbose //trace
C:\>xsharper eval.xsh //debugc //verbose //trace
# OpenStream> Reading from file C:\eval.xsh
# @ [Loading] xsharper(location="C:\eval.xsh")
# @ [Initializing] xsharper(location="C:\eval.xsh")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> print(newLine="False", value="Enter an expression:")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> set(name="expr", ="${=c.ReadLine()}")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> print(outTo="^debug", value="Expression: ${expr}")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> print(value="Result: ${=c.Eval($expr)}")
# @ [Compiling] xsharper(location="C:\eval.xsh")
# Context> Executing script C:\eval.xsh with isolation High
# @ [ParsingArguments] xsharper(location="C:\eval.xsh")
# @ [Executing] xsharper(location="C:\eval.xsh")
# @ [Executing] xsharper(location="C:\eval.xsh") >> print(newLine="False", value="Enter an expression:")
Enter an expression:
@ [Executing] xsharper(location="C:\eval.xsh") >> set(name="expr", ="${=c.ReadLine()}")
4+5
# @ [Executing] xsharper(location="C:\eval.xsh") >> print(outTo="^debug", value="Expression: ${expr}")
# Expression: 4+5
# @ [Executing] xsharper(location="C:\eval.xsh") >> print(value="Result: ${=c.Eval($expr)}")
Result: 9

Measure script execution time, display exit code and ask for a key press before exit

xsharper #/hash //wait

Using ToDump

Using the previous steps you may determine where the program throws an exception, how execution goes, how to print debug messages etc.

It is as important to see variables defined at critical script points. Of couse, can use the usual ToString method, but it often produces rather useless results for complex objects.

XSharper has a few special methods for converting objects variables:

Shortcut name Full method name Description
.ToDump Dump.ToDump Convert a .NET object graph to string
.ToDumpAll ScriptContext.ToDumpAll Convert all defined XSharper variables to string (a filter may be specified to dump only some variables
.Dump ContextWriter.Dump Shortcut for ContextWriter.WriteDump.ToDump(object))
.Dump ScriptContext.Dump Shortcut for Out.Write(Dump.ToDump(object))

What it all means is easier to demonstrate:

<set a="Hello" />
<set b="${=new DirectoryInfo('c:\windows')}" />
<set c="${=new string[] { 'This', 'is','a','string','array'}  }" />
<print outTo="^bold">Dumping a to standard output</print>
<eval>c.Dump($a);</eval>
<print outTo="^bold">Dumping b to error output</print>
<eval>c.Error.Dump($b);</eval>
<print outTo="^bold">Dumping b and c to info</print>
<eval>c.Out.WriteLine(c.ToDumpAll('b;c*'))</eval>

prints

Dumping a to standard output
(string) "Hello"
Dumping b to error output
(DirectoryInfo) { /* #1, 03553390 */
  Name = (string) "windows"
  Parent = (DirectoryInfo) "" /* ToString */
  Exists = (bool) true
  Root = (DirectoryInfo) "c:\" /* ToString */
  FullName = (string) "c:\windows"
  Extension = (string) ""
  CreationTime = (DateTime) 2009-03-03T08:30:25.3750000-05:00
  CreationTimeUtc = (DateTime) 2009-03-03T13:30:25.3750000Z
  LastAccessTime = (DateTime) 2009-12-10T13:12:37.1088672-05:00
  LastAccessTimeUtc = (DateTime) 2009-12-10T18:12:37.1088672Z
  LastWriteTime = (DateTime) 2009-12-07T19:51:20.7933162-05:00
  LastWriteTimeUtc = (DateTime) 2009-12-08T00:51:20.7933162Z
  Attributes = (FileAttributes) [Directory] /* 0x00000010 */
}
Dumping b and c to info
b  = (DirectoryInfo) "c:\windows" /* ToString */
c  = (string[]) "System.String[]" /* ToString */

Compiling scripts

XSharper requires no installation. Sometimes this is not good enough.

Imagine a situation when you wrote a script that needs to be used by someone else. It is an inconvenience to explain to users of your script all the prerequisites, from where to download what, and how to specify command line parameters, and alike. It can go wrong and it will.

It is also an inconvenience to distribute an MSI or setup.exe, that may require admin rights, will have to be launched, and then users will need to dive into c:\program files (x86)\your-application\something.bat (that will launch xsharper.exe yourscript.xsh) . Nor you want to distribute a bunch of DLLs and .config files for "XCopy deployment" which used to be a popular buzz-word when .NET was introduced.

Simple single .EXE , that just works, is the best option here. It's very simple with XSharper too.

For the purpose of demonstration, let's the hello.xsh script be

    <while maxLoops="3">
        <print>Hello, World</print>
    </while>

Compile script into .EXE

This operation is as simple as (hello.exe is actually optional and may be skipped)

C:\>xsharper hello.xsh //genexe hello.exe
Generating C# source code...
Compiling hello.exe...
Executable saved to hello.exe...

Now there is a single hello.exe, which can be run as

C:\>hello
Hello, World
Hello, World
Hello, World

//genexe produces a Windows console executable but a Windows executable may be produced instead. There will be no console output in this case though.

C:\>xsharper //genwinexe windir.exe //ref System.Windows.Forms /// "System.Windows.Forms.MessageBox.Show(`Hello. Your windows directory is `+c.GetEnv(`WinDir`))"

and that produces windir.exe, which if executed displays
Windir Screen shot

Generate C# code

What C# code does XSharper generate and compile?

R:\>xsharper hello.xsh //gencs hello.cs
Generating C# source code...
C# source code saved to hello.cs ...

In the produced file you would see something like

using System;
...

namespace Generated33c26cc8138342a98ec9f8d43ef8af14 {

    // Generated XSharper script class
    public class Hello
    {
        XS.Script _script;
        public XS.Script Script { get { return _script; } }
        
        public object Run(XS.ScriptContext context, IEnumerable<string> args)
        {
            context.Initialize(_script);
            return context.ExecuteScript(_script, args);
        }
        
        public Hello()
        {
            _script=new XS.Script((System.Diagnostics.Process.GetCurrentProcess().MainModule!=null)?System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName:null   ){
				Parameters = new List<XS.CommandLineParameter>() ,
				Items = new List<XS.IScriptAction> {
					new XS.While(){
						MaxCount = 3,
						Items = new List<XS.IScriptAction> {
							new XS.Print(){
								Value = @"Hello, World"
							}
						} 
					}
				} 
			};
        }
        #region -- Code snippets --
        
        #endregion -- Code snippets --
    }
}

You may control the name of the generated class and namespace via //namespace and //class parameters, which come handy if the generated code is included into another project.

Note that using the new C# 3.0 syntax makes the generated code relatively readable, yet it's possible to revert back to a less readable, but slightly faster, C# 2.0 notation with //forcenet20 parameter.

Producing complete C# code

//gencs parameter by default produces only script source code, without any boiler plate code. void static Main and all the whistles may be added by //main option, which is added automatically when .EXE files are produced.

It's also possible to produce full and complete source code, including all needed DLLs, icons, manifests and a batch file to build it:

C:\>xsharper hello.xsh //genexe //codeout c:\hello
Generating C# source code...
Compiling hello.exe...
Executable saved to hello.exe ...

C:\>dir c:\hello
 Volume in drive C has no label.
 Volume Serial Number is 4832-7B26

 Directory of c:\hello

01/09/2009  07:39 PM    <DIR>          .
01/09/2009  07:39 PM    <DIR>          ..
01/09/2009  07:39 PM               562 compile_hello.bat
01/09/2009  07:39 PM            46,839 hello.cs
01/09/2009  07:39 PM             1,496 manifest.xml
01/09/2009  07:39 PM             4,150 xsh.ico
01/09/2009  07:39 PM           378,880 XSharper.Core.dll
01/09/2009  07:39 PM           161,782 XSharper.Core.dll.gz
               6 File(s)        593,709 bytes
               2 Dir(s)  12,089,413,632 bytes free

compile_hello.bat will invoke C# compiler and produce the very same hello.exe .

Get script out of the code

Another not-so-hypothetical situation. Once upon a time you wrote a useful script hello.xsh that just works, which was compiled into to an executable.

Now, 18 months later, it does not work anymore because it has Hello, World hardcoded into it, yet now the missing exclamation sign was detected and Hello, World! must be there instead. Source code of the original utility is, well, somewhere. Long deleted from your hard-drive, perhaps it's on one of those backup discs of the late year, on that shelf, or may be the other, oh well...

Writing from scratch is possible but no volunteers. There is an option to use Reflector to decompile the code into a Visual Studio project, that can be then compiled and run. That's again something to download and install.

With XSharper there is a better way. Just run the hello.exe with //save:

C:\> hello.exe //save hello.cs
C:\>type hello.cs
<?xml version="1.0" encoding="utf-8"?>
<xsharper xmlns="http://www.xsharper.com/schemas/1.0">
  <while maxCount="3">
    <print>Hello, World</print>
  </while>
</xsharper>

Another use of the //save option is to provide a way out of too long command lines. For example, there is a fine command line piece that prints first 64 bytes of explorer.exe:

C:\>xsharper ///p "=.ToHexDump(.ReadBytes((.Expand('${% WINDIR %}\explorer.exe')),0,64),16,null,true)"
4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00  MZ?.........yy..
B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ?.......@.......
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 00 00 00 00 00 E0 00 00 00  ............a...

Now it needs to be converted into a more generic program that accepts a command-line parameter with the filename to be dumped. Instead of writing everything from scratch, the script may be saved into a file:

C:>xsharper //save dumpheader.xsh ///p "=.ToHexDump(.ReadBytes((.Expand('${% WINDIR %}\explorer.exe')),0,64),16,null,true)"
Saving script to dumpheader.xsh ...
Script file dumpheader.xsh saved...

And now it can be easily changed to use a command line parameter instead:

<?xml version="1.0" encoding="utf-8"?>
<xsharper engineVersion="0.9.1057.0" netVersion="3.5" id="generated" xmlns="http://www.xsharper.com/schemas/1.0">
  <param name="filename" required="true">Filename</param>
  <eval>c.WriteLine(.ToHexDump(.ReadBytes($filename,0,64),16,null,true))</eval>
</xsharper>

Utilities

There are 4 essential utilities included with XSharper: display version info, zip files, unzip archive, and to download a file from URL. They are not replacements for real zip/unzip/wget utilities, but do provide sufficient functionality for many scenarios and batch scripts w/o the need to download and install additional tools.

These utilities are actually XSharper scripts embedded into xsharper.exe, and source code can be seen/modified by adding //save parameter to command lines (e.g. xsharper //zip //save zip.xsh) .

Version info

Display version info and Xsharper's environment variables.

C:\> xsharper //version
XSharper v.0.9.1051.0 DeltaX Inc. Copyright (c) 2006-2009

Environment:
====================
Operating system    : Microsoft Windows NT 5.2.3790 Service Pack 2
.NET Framework      : 2.0.50727, 3.0, 3.5
Current directory   : R:\
Privileges          : Administrator
XSharper executable : c:\util\XSharper.exe
Configuration file  : c:\util\XSharper.exe.config (does not exist)

Environment variables:
=======================
XSH_PATH            :
XSH_REF             :
XSH_COLORS          :

ZIP

Store C:\Hello directory into a .ZIP archive C:\hello.zip:

R:\>xsharper //zip c:\hello.zip c:\Hello
Compressing c:\Hello => c:\hello.zip ...
  c:\Hello\app.config
  c:\Hello\compile_hello.bat
  c:\Hello\dumpheader.xsh
  c:\Hello\hello.cs
  c:\Hello\hello.exe
  c:\Hello\hello.pdb
  c:\Hello\manifest.xml
  c:\Hello\x.cs
  c:\Hello\xsh.ico
  c:\Hello\XSharper.Core.dll
  c:\Hello\XSharper.Core.dll.gz
Completed

There are many additional parameters available, for recursive compression, password protection, to help with hidden files & directories etc. Run xsharper //zip /? for more details.

UnZIP

Extract C:\hello.zip to C:\Hello2 (created if does not exist):

C:\>xsharper //unzip c:\hello.zip c:\hello2
Extracting c:\hello.zip => c:\hello2\ ...
  c:\hello2\app.config
  c:\hello2\compile_hello.bat
  c:\hello2\dumpheader.xsh
  c:\hello2\hello.cs
  c:\hello2\hello.exe
  c:\hello2\hello.pdb
  c:\hello2\manifest.xml
  c:\hello2\x.cs
  c:\hello2\xsh.ico
  c:\hello2\XSharper.Core.dll
  c:\hello2\XSharper.Core.dll.gz
Completed

Run xsharper //unzip /? for more details.

Download a file

wget it is not. Simply download data from the specified URL and save it to a file. If filename is not specified, file is saved to the current directory.

C:\>xsharper //download http://www.xsharper.com/xsharper.exe
Downloading http://www.xsharper.com/xsharper.exe => C:\xsharper.exe ...
...
Completed. 343040 bytes downloaded.

Vista/Windows7 UAC

In Vista and Windows 7, at least by default, even administrator does not have administrative privileges all the time. If something administrative needs to be done, user must explicitly put on his admin's hat and launch an "elevated" process, which will then have administrative privileges.

If a program needs to perform an administrative action on Vista/W7, it must contain a special XML resource called manifest, to indicate that the program must be "elevated" before execution.

This manifest may (and will be) embedded when XSharper script is compiled with //requireAdmin parameter. Then, when the script is executed, Vista/Windows7 will produce an elevation screen.

Alternatively, the option may be specified in the script itself:

<xsharper id="admin-tool" requireAdmin="admin">
...
</xsharper>

Either way, if this script is executed under Vista/Windows7, it will produce:

UAC Screenshot1

As you see, it's possible to see from this screen which script has requested the privilege. If access is granted, XSharper reuses the original console instead of spawning the new one, thus not breaking batch files which rely on user output:

What's interesting is that in interactive mode, where script is not compiled, there are two xsharper processes running in this scenario: one w/o administrative rights, that spawned a new elevated one, which talks back to the original process via .NET remoting.

Miscellaneous

Upgrade XSharper in-place
To check if you run the latest version of XSharper, and automatically upgrade if you don't, run

C:\>xsharper //upgrade
XSharper v.0.9.1057.0 DeltaX Inc. Copyright (c) 2006-2009
Currently executing R:\xsharper.exe
Checking the latest XSharper version...
The latest available version is 0.9.1057.0
Installed XSharper version is up to date.

Display execution time and exit code
If you run XSharper through Start Menu -> Run ( or through keyboard via Windows + R ), when script terminates, its window disappears by default.

To make the window stay, display execution time & exit code use //wait parameter:

C:\>xsharper hello.xsh  //wait
Hello, World
Hello, World
Hello, World
Completed in 00:00:00.2778342 with exit code=0. Press Enter to close...

Generate sample script
Just to produce a sample XSharper script that does, well, does not do anything really:

C:\>xsharper //gensample 
sample.xsh created.

Likewise, a configuration file may be created:

C:\>xsharper //genconfig
app.config created.