Click here to Skip to main content
Licence LGPL3
First Posted 29 Sep 2011
Views 23,976
Downloads 198
Bookmarked 19 times

Threading in PowerShell

By | 14 Feb 2012 | Article
This article presents you some capabilities of PowerShell like the usage of .NET Framework 4.0 and .NET threading.

Introduction

PowerShell is a great scripting language providing access to the complete .NET Framework. Most people out there forget that PowerShell is not a programming language and seems to be limited in some ways. But what should one do if she or he is not allowed to use a real programming language? What if you are only allowed to provide a script in contrast to a binary that is precompiled to e.g., IL, ByteCode, PCode, or even compiled as it is the case of C, C++? The answer ... one option is to use PowerShell. I'd like to demonstrate to you the dynamicity and flexibility of PowerShell.

But before introducing my thoughts, I want to provide you with some PowerShell internals.

PowerShell internals

PowerShell has been written in C++ 6.0. This information can be retrieved by using Microsoft's dumpbin tool and looking for the "msvcrt.dll" binary. MSVCRT is the C++ runtime for Visual C++ version 4.2 to 6.0. The versions before and after have used differently named DLLs for each version (e.g., msvcr70.dll, msvcr100.dll, etc.).

PowerShell imports

That information gives us the great knowledge that PowerShell.exe itself hasn't been written in .NET. But how does PowerShell cooperate with .NET?

The answer is simple. PowerShell uses the CorBindToRuntimeEx function of mscoree.dll.

CorBindToRuntimeEx in PowerShell

HRESULT CorBindToRuntimeEx (
        [in]  LPWSTR    pwszVersion, 
        [in]  LPWSTR    pwszBuildFlavor, 
        [in]  DWORD     flags, 
        [in]  REFCLSID  rclsid, 
        [in]  REFIID    riid, 
        [out] LPVOID*   ppv
);

There is nearly no difference between .NET 2.0 and 4.0 in this point except that:

  • MSCorEE.idl has been replaced by MSCorEE.h,
  • flags has been renamed to startupFlags, and
  • the function has been marked as deprecated in .NET 4.0.

More information can be found here: http://msdn.microsoft.com/en-us/library/99sz37yh(v=VS.100).aspx.

That's the reason why one has more problems using .NET 4.0 code in PowerShell than .NET 2.0.

By the way, using .NET 4.0 is possible in PowerShell, but you have to define your own host or change some Registry settings or config files, because PowerShell.exe and the ISE have been compiled against .NET 2.0. E.g.:

reg add hklm\software\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1
reg add hklm\software\wow6432node\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1

The above Registry changes will allow PowerShell to use .NET 4.0.

Attention

Attention! Modifying the .NET Framework Registry settings may affect the whole system. Please consider modifying the configuration files instead.

The same applies to the ISE by changing powershell_ise.exe.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <startup>
  <supportedRuntime version="v4.0.30319" />
 </startup>
</configuration>

You can even change powershell.exe.config ($pshome\) as follows:

<?xml version="1.0"?> 
<configuration> 
    <startup useLegacyV2RuntimeActivationPolicy="true"> 
        <supportedRuntime version="v4.0.30319"/> 
        <supportedRuntime version="v2.0.50727"/> 
    </startup> 
</configuration>

Or you can write your own PowerShell host:

using System;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;
namespace PowerShell40
{
    class Program
        {
            static int Main(string[] args)
            {
                return ConsoleShell.Start
                    (
                        RunspaceConfiguration.Create(),
                        "Windows PowerShell .NET 4.0 Enabled",
                        string.Empty,
                        args
                    );
            }
    }
}

In order to compile your .NET 4.0 console application, you need to add a reference to the Microsoft.PowerShell.ConsoleHost and System.Management.Automation assemblies, which can be found under %programfiles%\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0.

Diving deeper - Threading

As shown in the previous section, neither are you limited to any runtime version in PowerShell nor are you limited in threading capabilities, as I'll show you now.

PowerShell 2.0 provides some kind or some sort of jobs, which enable you to run background jobs. This might be useful, for example, if you have a number of computers and want to get some information for each via PowerShell. There are millions of scenarios where threading is useful.

Even for such a simple command, PowerShell will create a new process, a new runspace, and communicate via IPC via the "host" process:

start-job { gwmi win32_process }

Another example in detail:

start-job { get-process }

will use an IPC channel with WinRM to run, and doesn't require administrative permissions.

The second one:

invoke-command -scriptblock {get-process} -computer localhost -asjob

uses both HTTP and WinRM and needs administrative rights.

PowerShell in the task manager

This might be considered as overkill. Moreover, you do not have the ability to control the jobs via .NET mechanisms.

For that reason, I've provided a simple library that makes it possible to start threads over .NET, no second process will be created, the communication effort needed is much lower, and the CPU doesn't explode if you have a complex task.

Method #1

function CreateThreadStart ([ScriptBlock]$scriptBlock)
{
    $ps_s=$scriptBlock.GetPowerShell()
    $smi=($ps_s.gettype().getmethods()| ? {$_.name -eq "Invoke"})[0]$fp = 
                                           $smi.methodhandle.getfunctionpointer
    $ts=new-object threading.threadstart $ps_s,$fp
    return $ts
}

function CreateThread ([ScriptBlock]$scriptBlock)
{
    return new-object threading.thread (CreateThreadStart $scriptBlock)
}

This method is quite simple and does nothing else to get a pointer to a function and creates an object of type System.Threading.ThreadStart.

But you are limited because PowerShell (i.e., the GetPowerShell() method) will only allow to pass one argument in the script block.

This will work:

[System.Threading.Thread] $thread = (CreateThread {Get-Service})
$thread.Start()

This won't:

# Error: "Can only convert a script block that contains exactly one pipeline 
  or command. Expressions or control structures aren't permitted. Make sure t
  he script block contains exactly one pipeline or command."
[System.Threading.Thread] $thread = (CreateThread {Get-Service;Get-Service})
$thread.Start()

Method #2

Creating your own PSHost and PSHostUserInterface.

This can be done by creating your own .NET DLL. If you have problems with possible audits etc., or you are only allowed to script, then use PowerShell's Add-Type and you'll be able to do everything in PowerShell you can imagine. The script is only an example (therefore not perfect) and has been written to demonstrate some capabilities of .NET and PowerShell interaction.

How to include the PowerShell library

Library is maybe the wrong word; it' just a script that can be included for simplicity. Just put the following code at the start of your main script or directly after the param section (if applicable), to include the Threading.ps1 script or lib, for example:

[array]$loads = "Threading.ps1"
foreach ($load in $loads)
{
    If (!($loadedlibs -like "*$load*"))
       {
           . (Join-Path (Split-Path -parent 
             ($MyInvocation.MyCommand.Definition)) 
              -childpath "$($load)")
    }
}

[System.Guid]$guid = StartThread -scriptBlock { Write "Application"; Sleep 2; 
                         Write "Application 2"; Get-Service; }
GetThreadOutput
Start-Job {Sleep 2000}
StopThread

The example output:

Application
Application 2

Status   Name               DisplayName
------   ----               ----------- 
Stopped  aspnet_state       ASP.NET State Service
Stopped  COMSysApp          COM+ System Application
Running  CryptSvc           Cryptographic Services
Running  CscService         Offline Files
Running  DcomLaunch         DCOM Server Process Launcher
Stopped  defragsvc          Disk Defragmenter
Running  Dhcp               DHCP Client
Running  Dnscache           DNS Client
...

Id   Name   State    HasMoreData   Location    Command
--   ----   -----    -----------   --------    -------
3    Job3   Running  True          localhost   Sleep 2000
True

That's it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

About the Author

Oliver Kohl DSc


OMantl Software Entwicklung e.U.
Austria Austria

Member

http://www.omantl.at

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 5 PinmemberViktor1224565:46 18 Feb '12  
GeneralMy vote of 5 PinmemberViktor1224565:46 18 Feb '12  
GeneralMy vote of 5 PinmemberGuru11112356634336:02 22 Oct '11  
GeneralWow Pinmemberjon123883:20 11 Oct '11  
AnswerRe: Wow PinmemberOliver Mantl DSc3:24 11 Oct '11  
GeneralWarning about registry settings Pinmemberpigwin3211:27 2 Oct '11  
AnswerRe: Warning about registry settings PinmemberOliver Mantl DSc3:23 11 Oct '11  
SuggestionMy vote of 5 PinmemberFilip D'haene20:18 29 Sep '11  
GeneralRe: My vote of 5 PinmemberOliver Mantl DSc0:14 30 Sep '11  
AnswerRe: My vote of 5 PinmemberOliver Mantl DSc0:36 30 Sep '11  
GeneralMy vote of 5 Pinmemberscriptingguy6:12 29 Sep '11  
AnswerRe: My vote of 5 PinmemberOliver Mantl DSc6:18 29 Sep '11  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120517.1 | Last Updated 14 Feb 2012
Article Copyright 2011 by Oliver Kohl DSc
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid