AutoIt meets .NET Common Language Runtime (CLR) Framework

April 27, 2017

CLR : The Common Language Runtime (CLR) is a an Execution Environment .

Common Language Runtime (CLR)’s main tasks are to convert the .NET Managed Code to native code, manage running code like a Virtual Machine, and also controls the interaction with the Operating System.

As part of Microsoft’s .NET Framework, the Common Language Runtime (CLR) is managing the execution of programs written in any of several supported languages.

Allowing them to share common object-oriented classes written in any of the languages.

 

Appdomain : To access the CLR environment you need to create an Appdomain Object.

An AppDomain provides an isolated region in which code runs inside of an existing process.

Application domains provide an isolation boundary for security, reliability, and versioning, and for unloading assemblies.

Application domains are typically created by runtime hosts, which are responsible for bootstrapping the common language runtime before an application is run.

 

CLR Runtime Hosts : When would you use CLR Runtime Hosts.

1. To access .NET Class Libraries :

  • System
  • System.Collections
  • System.Data
  • System.Drawing
  • System.IO
  • System.Text
  • System.Threading
  • System.Timers
  • System.Web
  • System.Web.Services
  • System.Windows.Forms
  • System.Xml

2. Accessing custom build .Net Assemblies :

Some Examples (but there are a ton out there)

  • AutoItX3 – The .NET Assembly for using AutoItX
  • JSonToXML libr.
  • XMLRPC Libr.
  • .NETPDF libr.
  • .NETOCR Libr
  • WInSCP Libr.

    3. To Compile .Net Code into an Assembly at Runtime

    4. To Run C# or VB.net Code at Runtime

    5. To Mix AU3 and .Net functionality in your Application

 

Documentation : Where to find info about CLR hosting

First of all you can find a lot on MSDN relating to .Net CLR Hosting and of course here :

AutoIt .NET CLR Framework

 

Examples : All examples are included in the above thread of the AutoIt forum.

1. To access .NET Class Libraries :

    Example : “System.Text.UTF8Encoding”

    image

    Example : “System.IO.FileInfo”

    image

    Example : “System.Windows.Forms”

    image

 

2. Accessing custom build .Net Assemblies :

    Example : AutoItX3 .NET Assembly using AutoItX

    image

 

3. To Compile .Net Code into an Assembly at Runtime

    Example : Compile Code C# and Code VB

    image

 

4. To Run C# or VB.net Code at Runtime

    Example : Compile Code C# at Runtime

    image

 

5. To Mix AU3 and .Net functionality in your Application

All of the above Examples have a mix of au3 functionality and .Net CLR code

 

This CLR.au3 UDF makes a bridge between .Net and Au3, which give a new dimension to our scripting experience.

Enjoy !


Developing a Console App for running on a Raspberry PI3 using Windows Core IoT – Without Visual Studio

December 31, 2016

I was wondering wondering If we could create an App for running on our Rasberry PI3, where Windows 10 Core IoT is installed.

As you might know regular EXE files don’t run on this windows version, because a RPI3 uses an ARM Architecture.

While a normal Windows is based on x86 or x64 Architecture.

 

Solution : 

Some years back I created a wrapper for the DotNet Compiler and called it Visual Studio Light

I modified this version that was created in AU3 to compile for ARM architecture.

(Just added the PLATFORM Switch for ARM)

 

So next I compiled this simple Console Application :

class HelloCsharp
{
       static void Main()
       {
            System.Console.WriteLine (“Hello World from C#. on ARM Architecture like Raspberry PI3 running Windows 10 Core IoT”);
       }
}


 

image

 

There where some errors popping up, but they seem to be normal.

Because I compiled the exe on a x64 Machine, and the EXE was compiled for and ARM Archtecture.

So it started complaining about this, but don’t worry  Winking smile

Next I copied the EXE for ARM to my RPI3.

image

Logged into a PS session on the RPI3, and it ran without any problems Smile

 

image

 

Enjoy!


Powershell – Using the .Net Charting Controls

January 4, 2015

Picked this up on the internet Smile Great extension to Powershell and .NET

What you need to get started is the

Microsoft Chart Controls for Microsoft .NET Framework 3.5

The Charting Controls documentation is here :

Microsoft Chart Controls for .NET Framework Documentation

image

Once installed you are ready to go, here is an example script showing the top 5 largest files in a directory.

image

If you hit the “Save button” it will save the graph to the desktop.

Here is the script :

CLS

if([Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization") -eq $null)
{
    #Microsoft Chart Controls are not installed
    [void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0,`
    Culture=neutral, PublicKeyToken=b77a5c561934e089")
    [void][System.Windows.Forms.MessageBox]::Show("Microsoft Chart Controls for Microsoft .NET 3.5`
    Framework is required", "Microsoft Chart Controls Required")
    #Open the URL
    [System.Diagnostics.Process]::Start("http://www.microsoft.com/downloads/en/`
    details.aspx?familyid=130F7986-BF49-4FE5-9CA8-910AE6EA442C&displaylang=en");
    return $false
}

# load the appropriate assemblies 
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")

   
# create chart object 
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart 
$Chart.Width = 500 
$Chart.Height = 450
$Chart.Left = 40 
$Chart.Top = 30
   
# create a chartarea to draw on and add to chart 
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea 
$Chart.ChartAreas.Add($ChartArea)


# add data to chart 
$Files = dir $env:USERPROFILE -Recurse -File | sort length  | select -last 5 # | % {"$_.Name " + [math]::Round(($_.Length / 1MB),2)}
$FileNames = @(foreach($File in $Files){$File.Name}) 
$FileSize = @(foreach($File in $Files){[math]::Round(($File.Length / 1MB),2)}) 


[void]$Chart.Series.Add("Data") 
$Chart.Series["Data"].Points.DataBindXY($FileNames, $FileSize)

# add title and axes labels 
[void]$Chart.Titles.Add("Top 5 Files - Descending") 
$ChartArea.AxisX.Title = "File Name" 
$ChartArea.AxisY.Title = "File Size - [MB]"

# Find point with max/min values and change their colour 
$maxValuePoint = $Chart.Series["Data"].Points.FindMaxByValue() 
$maxValuePoint.Color = [System.Drawing.Color]::Red 

$minValuePoint = $Chart.Series["Data"].Points.FindMinByValue() 
$minValuePoint.Color = [System.Drawing.Color]::Green

# change chart area colour 
$Chart.BackColor = [System.Drawing.Color]::Transparent

# make bars into 3d cylinders 
$Chart.Series["Data"]["DrawingStyle"] = "Cylinder"

# display the chart on a form 
$Chart.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right -bor 
                [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left

# sorting the dataset
$Chart.Series["Data"].Sort([System.Windows.Forms.DataVisualization.Charting.PointSortOrder]::Descending, "Y")

# add a save button 
$SaveButton = New-Object Windows.Forms.Button 
$SaveButton.Text = "Save" 
$SaveButton.Top = 500 
$SaveButton.Left = 450 
$SaveButton.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right 
$SaveButton.add_click({$Chart.SaveImage($Env:USERPROFILE + "\Desktop\Chart.png", "PNG")}) 


# save chart to file 
$Chart.SaveImage($Env:USERPROFILE + "\Desktop\Chart.png", "PNG")

$Form = New-Object Windows.Forms.Form 
$Form.Text = "PowerShell Chart" 
$Form.Width = 600 
$Form.Height = 600 
$Form.controls.add($Chart) 
$Form.Add_Shown({$Form.Activate()}) 

$Form.controls.add($SaveButton)

$Form.ShowDialog()

A good way to start is reading here :

http://blogs.technet.com/b/richard_macdonald/archive/2009/04/28/3231887.aspx

You can build some nifty Tools with this ?

image

Enjoy!


Powershell – Output to a GUI

January 4, 2015

Ever wanted to get the output of PowerShell to a GUI.

Well that’s not so difficult, since PS is built on top op .NET you can use the .NET Forms Class for this.

This example will capture your Computer Name, and the Process list and display it is a list box.

CLS

# add a Listbox
$objListBox = New-Object Windows.Forms.Listbox
$objListBox = New-Object System.Windows.Forms.ListBox
$objListBox.Location = New-Object System.Drawing.Size(15,10)
$objListBox.Size = New-Object System.Drawing.Size(550,10)
$objListBox.Height = 400

# add a save button
$oButton = New-Object Windows.Forms.Button
$oButton.Text = "Get Computer Name"
$oButton.Top = 500
$oButton.Left = 350
$oButton.Width = 150
$oButton.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right 

$oButton.add_click({$SaveButton.Text = $env:ComputerName})
$oButton.add_click({$objListBox.Items.Add($env:ComputerName)})

$oButton.add_click({

$sTemp = Get-Process 

$sTemp | % {  $item = $_.ProcessName
$objListBox.Items.Add($item) }

})

# Build the GUI
$Form = New-Object Windows.Forms.Form
$Form.Text = "PowerShell Output"
$Form.Width = 600
$Form.Height = 600 

$Form.Add_Shown({$Form.Activate()}) 

$Form.controls.add($oButton)
$Form.controls.add($objListBox)

$Form.ShowDialog()

rv objListBox, Form, oButton, sTemp, item

When pressing the button it will trigger the actions Winking smile

Enjoy!


ASP.Net Error [im003] – Oracle Error

October 8, 2014

Error [im003] specified driver could not be loaded due to system error  5 (oracle in oracle9i)

I had a strange error when accessing an Oracle database over ODBC using an ASP.NET (4.0 framework) Application running on IIS 6.0.

The ASP.net page could not load the database tables while the ODBC manager gave no errors ?

image

In the eventviewer I saw a lot of ASP.NET 4.0.30319.0 – Event ID 1309

image

This showed definitely a security issue on the Oracle home directory.

image

Solution :

Oracle 9.2 Client software requires that you give the Authenticated User privilege to the Oracle Home by following these steps:

1. Log on to Windows as a user with Administrator privileges.

2. Launch Windows Explorer from the Start Menu and and navigate to the ORACLE_HOME folder. This is typically the “Ora92” folder under the “Oracle” folder (i.e. C:\Oracle\Ora92).

3. Right-click on the ORACLE_HOME folder and choose the “Properties” option from the drop down list. A “Properties” window should appear.

4. Click on the “Security” tab of the “Properties” window.

5. Click on “Authenticated Users” item in the “Name” list (on Windows XP the “Name” list is called “Group or user names”).

6. Clear the “Read and Execute” box in the “Permissions” list under the “Allow” column (on Windows XP the “Permissions” list is called “Permissions for Authenticated Users”).

7. Re-check the “Read and Execute” box under the “Allow” column (this is the box you just unchecked).

8. Click the “Advanced” button and in the “Permission Entries” list make sure you see the “Authenticated Users” listed there with:

·

Permission = Read & Execute

·

Apply To = This folder, subfolders and files

If this is NOT the case, edit that line and make sure the “Apply onto” drop-down box is set to “This folder, subfolders and files”. This should already be set properly but it is important that you verify this.

9. Click the “OK” button until you close out all of the security properties windows. The cursor may present the hour glass for a few seconds as it applies the permissions you just changed to all subfolders and files.

10. Reboot your computer to assure that these changes have taken effect. (no need for this in my case).

11. Re-execute the application and it should now work.

This made it works like a charm !

Reason was that IIS user did not have enough permission on the folders and subfolders ?


Run a .Net Assembly DLL from Memory in PowerShell

September 7, 2014

In my previous post I showed you how to load a .NET Assembly DLL without registering in the GAC.

Using the technique found here you can run the .NET Assembly DLL from Memory !

Run this script from the above site using your new .NET DLL (see my previous post).

CLS

function Out-CompressedDll
{
    [CmdletBinding()] Param (
        [Parameter(Mandatory = $True)]
        [String]
        $FilePath
    )

    $Path = Resolve-Path $FilePath

    if (! [IO.File]::Exists($Path))
    {
        Throw "$Path does not exist."
    }

    $FileBytes = [System.IO.File]::ReadAllBytes($Path)

    if (($FileBytes[0..1] | % {[Char]$_}) -join '' -cne 'MZ')
    {
        Throw "$Path is not a valid executable."
    }

    $Length = $FileBytes.Length
    $CompressedStream = New-Object IO.MemoryStream
    $DeflateStream = New-Object IO.Compression.DeflateStream ($CompressedStream, [IO.Compression.CompressionMode]::Compress)
    $DeflateStream.Write($FileBytes, 0, $FileBytes.Length)
    $DeflateStream.Dispose()
    $CompressedFileBytes = $CompressedStream.ToArray()
    $CompressedStream.Dispose()
    $EncodedCompressedFile = [Convert]::ToBase64String($CompressedFileBytes)

    Write-Verbose "Compression ratio: $(($EncodedCompressedFile.Length/$FileBytes.Length).ToString('#%'))"

    $Output = @"
`$EncodedCompressedFile = @'
$EncodedCompressedFile
'@
`$DeflatedStream = New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(`$EncodedCompressedFile),[IO.Compression.CompressionMode]::Decompress)
`$UncompressedFileBytes = New-Object Byte[]($Length)
`$DeflatedStream.Read(`$UncompressedFileBytes, 0, $Length) | Out-Null
[Reflection.Assembly]::Load(`$UncompressedFileBytes)
"@

    Write-Output $Output
}

# See Example on the site
# Out-CompressedDll .\test.dll | Out-File LoadDll.ps1

Out-CompressedDll "C:\\_\\Apps\\Hello World.dll" | Out-File .\LoadDll.ps1

Invoke-Item ($Env:USERPROFILE+"\LoadDll.ps1")

This will generate a new PS1 Script which will contain the compressed DLL code as a binary string.

image

Add your static method to call whatever you specified in your DLL.

image

Run it to see that is works.

So bottom line is that you don’t need to register in the GAC and don’t need to copy the DLL to your machines in order to run it Smile

Isn’t that great for a scripter !


Powershell run Assembly that is not registered in the GAC

September 5, 2014

As demonstrated in previous posts you can easily compile your own .Net Assemblies.

Using AutoIT to create a Wrapper for compiling an EXE or DLL using .NET.

image

Or  your own COM objects

But now it is time to see once we compiled the Assembly.dll, and how we can run it in PowerShell. Without registering it the GAC !

Here is some example code to create a .Net assembly.dll

Public module HelloWorld

 Sub main()
 Console.WriteLine ("Hello World using Visual Basic Code!")
 Msgbox("Hello World from My DotNET Assembly !")
 End sub
End module

Save this code as a Hello World.vb file.

If you compile it using the above Wrapper, choose the Class Library button to generate the DLL.

Once this is successfully processed you will see the Assembly.dll that is created.

image

Using general .NET practice you would need to register the DLL to the GAC in order to access the Methods and Properties. But for scripters like us this is not practical Winking smile

So we want to distribute the DLL across PC’s and Servers by just copying the file around.

So this example shows you have to access the DLL from within PowerShell.

It pops up a message box and wrote something to the console

image

By the way since PS v3.0 the IDE you can use the intellisense feature on you newly created Assembly.dll

image

 

CLS
# Notice the double backslash !
$filename = "C:\\_\\Apps\\Hello World.dll"
$assembly = [Reflection.Assembly]::Loadfile($filename)

echo '--'
echo $assembly.gettype()
echo '--'
echo $assembly.fullName
echo '--'
echo $assembly.gettypes() | ?{$_.IsPublic} # List Public Functions
echo '--'

# Call the Class / Methods
[HelloWorld]::Main()

# Clean-up
rv assembly, filename

As simple as that, isn’t that great ! 🙂

So one more missing link to make the circle round. What if we could access the .NET Assembly from within Autoit running this PS code that would be just great.

Coming soon stay tuned !

Enjoy!