PowerShell – .NET Scripting how to ?

August 7, 2014

Late Binding for .Net

Just as ‘Late Binding’ for COM objects. We can use the same ‘Late Binding’ approach for .Net Scripting, like PowerShell.

Since PowerShell is built on top of .Net we can use .NET Framework’s Reflection API’s.

.NET Framework’s Reflection API’s allows you to fetch type (assembly) information at runtime programmatically. We can also achieve late binding by using .NET Reflection.

At runtime, the Reflection mechanism uses the PE file to read information about the assembly. Reflection enables you to use code that is not available at compile time.

It can be used effectively to find all types in an assembly and/or dynamically invoke methods in an assembly. This includes information about the type, properties, methods, and events of an object.

The System.Reflection namespace and the System.Type class plays a very important role in .NET Reflection.

You can read more interesting stuff in this article.

http://www.codeproject.com/Articles/55710/Reflection-in-NET

Now move back to PowerShell

Add-Type versus Reflection. In the early versions of PowerShell there was no option. You had to use the .NET Reflection method to load assemblies.

Both allow you to hook into the power of the .NET Framework as well as any Assemblies DLL you build.

As of Powershell V2.0 the This allows you to tap into the power of the .NET framework as well as any DLLs/Assemblies you build. was introduced.

Let’s see some differences :

In PowerShell Version 1 that cmdlet is not available so you need to use the one of the Load* static methods found in System.Reflection.Assembly.

[Reflection.Assembly]::Load Loads an assembly
[Reflection.Assembly]::LoadFile Loads the contents of an assembly file on the specified path
[Reflection.Assembly]::LoadFrom Loads an assembly given its file name or path
[Reflection.Assembly]::LoadWithPartialName Loads an assembly from the application directory or from the global assembly cache using a partial name

Reflection vs Add-Type Example here :

CLS
$null = [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$date = [Microsoft.VisualBasic.Interaction]::InputBox('What is your birthday?')
$days = (New-TimeSpan -Start $date).Days
"You are $days days old."

# Using the Add-Type cmdlet:
Add-Type -AssemblyName Microsoft.VisualBasic<br>$date = [Microsoft.VisualBasic.Interaction]::InputBox('What is your birthday?')

$days = (New-TimeSpan -Start $date).Days
"You are $days days old."

Both will have the same result. More interesting to read over here  :

http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

Last but not least you can also call a .Net Class directly.

Example calling a .Net Class directly  :

CLS
# .NET Version
if ([System.IO.Directory]::GetParent("C:\windows") -ne $null)
{
# do something interesting
$NETDirInfo = New-Object System.IO.directoryInfo -ArgumentList "C:\windows"

echo "NETDirInfo"
$NETDirInfo.Parent

# PS Version
if ((test-path c:\windows) -eq $true)
	# do something interesting
	$PSDirInfo = Get-ItemProperty c:\windows
	echo "PSDirInfo"
	$PSDirInfo.Parent
}

image

As you can see both have the same result 🙂

More in-depth reading here :

http://www.dougfinke.com/blog/index.php/2010/08/29/how-to-load-net-assemblies-in-a-powershell-session/

I hope this can help clear some mist ?

So now it is time to find out which Assemblies, Classes, Method, Properties etc. are at your disposal.

Example to get Assembly information

This will list a all of the Assemblies Class information

[appdomain]::currentdomain.GetAssemblies() | % {$_.gettypes()} | sort basetype

image

http://blogs.technet.com/b/heyscriptingguy/archive/2012/07/22/use-powershell-to-find-and-to-explore-net-framework-classes.aspx

Different Approach using New-Object

Last but not least you can access the Assembly Methods & Properties using the New-Object –> Get-Member #-static for static members only

ClS
New-Object -com scripting.filesystemobject | Get-Member

image

Not handy so we need some extra Tools read here

Enjoy !


Programming skills are not the same as Technical skills ?

July 1, 2014

Being a Developer does not require that you have good Technical and Protocol skills alone these days.

First of all you need to master many Technologies, that are best fit to support the Business scenario’s and requirements.

Technologies in a Windows Environment are piling up each year.

You should know what is :
WPF Windows Presentation Foundation
MCF Windows Communication Foundation
WWF Windows Workflow Foundation
– WIF Windows Identity Framework
– WMF Windows Management Framework
WSE Web Service Enhancements
– WEF Windows Entity Framework

Depending if the requirement is a Client Side application or a Web Based Server Side Business Solution.
You would need to pick either one of them or even a mix of both.

You would at least need to learn what CLR (Common Runtime Language) is. And what is IL- CLR- CTS-CLS-and-GIT.

Or DLR is not the same as CLR

Maybe a bit too much all together for scripters. Confused smile

But let’s have a quick overview of which kind of Technologies we can pick from.

.NET (versions 1 to 4.x) versus Java(Script)

Application Architecture
Object Oriented Programming
Service Oriented programming

Web Oriented Architecture
XML                      – JSON
* XML/A                  – AJAX
* CAML                    – DOM
* XAML (mobile)
– CSS (3)               – SOAP
– HTML (5)             – REST
Java(Script)         – Web API / ASMX

Enterprise Data Architecture
SQL (AZURE)
OLAP
Odata
OLEDB / ADO.NET
LINQ
SQL / MDX

Server Side Technology
AD
ASP.Net
IIS
SharePoint

Client Side Technology
Powershell
Webmatrix / Razor
SQLite.Net / LDF databases

Programming Technology
.Net Framework
* Assemblies / Classes / Objects
* .Net Reflection (late binding)
* .Net Reflection.EMIT ?
* Model View Controller (MV)

– JavaScript Libraries

* SP.Core.js
* SP.js
* JQuery.js
* Node.js
* KnockOut.js
* Angular.js
* …

Most of these Technologies you can access using smart Scripting Techniques.

I am trying to give some examples on in this Blog whenever possible.

Bottom line is that in this ever changing IT world keeping up and learning new Technologies is a necessity.

For some amongst us this is fun for others this is a real challenge 🙂

 


PowerShell – Using Windows Script Component

November 3, 2014

Windows Script Component (WSC) goes a long way back. This technique is almost 15 years old, dating from Windows 2000.

But you can still use it, even by the latest Powershell version. Smile

Find here more information about what WSC is.

In short WSC gives you the possibility to create COM objects on the fly. Which you can register as normal COM objects exposing you methods and properties.

image

As you can see the WSC files show up with different Icon. If you right click it you see extra shortcut menu’s.

image

Register will register you COM object in the registry if you filled up the WSC file with the proper XML sections. The same as you would use the regsvr32.exe command line tool.

Or you can just run functions as is, without registering.

WSC supports VBScript / JScript and PerlScript.

Let’s give an example on how to access the object from within PS.

1. Create a simple WSC file.

image

<?xml version=”1.0″?>
<component id=”mywsc”>
<public>
<method name=”test”/>
</public>

</component>

 

This simple example will display a Message Box with a text as parameter, when invoked using PS.

image

You need to use the .Net [system.runtime.interopservices.marshal]::BindToMoniker to connect to the WSC object.

As you can see I use the following prefix syntax “script:…” in order to call the WSC object on the fly.

This will avoid you to register the COM object on your system. Which makes it extremely flexible. You can now adjust the WSC code on the fly and run it. As well as copy it on multiple machines without any admin overhead.

The InvokeMember has 5 parameters, which explain themselves :

1. “Test” is the name of the WSC VBScript function to call.

2. $im holds the BindingFlags method

3. Not used

4. Variable that holds the references to the WSC Object

5. Used to send across the Parameter(s) to the WSC function.

Here is the full code with some helper calls in between.

 

CLS

$test = [system.runtime.interopservices.marshal]::BindToMoniker("script:C:\_\Apps\_PowerShell\_Advanced Examples\_WSC Examples\Test.wsc")

$isObj = [system.runtime.interopservices.marshal]::IsComObject($test)

write-host $isObj

Write-host " "

Write-host "Get-Type" 

$test.GetType()

$param = "Hello World ! -&gt; From PowerShell to WSC"

$im = [System.Reflection.BindingFlags]::InvokeMethod

$test.GetType().psobject.BaseObject.InvokeMember("test", $im, $null, $test, $param)

$ret1 = [System.Runtime.InteropServices.Marshal]::GetIDispatchForObject($test)

$ret2 = [System.Runtime.InteropServices.Marshal]::GetIUnknownForObject($test)

$uObj = [System.Runtime.InteropServices.Marshal]::GetUniqueObjectForIUnknown($ret2)

$Obj = [System.Runtime.InteropServices.Marshal]::GetObjectForIUnknown($ret2) # refers back to $WSC COM object returns the GUID

write-host " "

#[System.Runtime.InteropServices.Marshal]::Release($test)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($test)

write-host "5. "  $ret1 $ret2 $uObj $obj

write-host " "

[System.Runtime.InteropServices.Marshal]::AreComObjectsAvailableForCleanup()

write-host " "

[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()

rv test, im, param, isObj, ret1, ret2, uobj, obj

[System.GC]::Collect()

Enjoy!


PowerShell – Run a .Net Assembly DLL from in Memory

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 !