Samstag, 24. April 2010

WPF Linkcollection for PowerShell

During the last time I played with some ways to present GUI from PowerShell. I spend some time collection links, which I want to share now.

First there are two toolkits between you can select.

WPK which is part of PowerShellPack and Powerboots.

WPK is created by James brundage
and it comes with some examples in the Modules\WPK\Examples folder.

Videos:
A Brief Introduction to using WPF-Containers
Multitouch Fingerpaint in 30 Lines of PowerShell Script

Some blog postings:
Hey, Scripting Guy! Using the Windows Presentation Foundation PowerShell Kit to Create a GUI
PowerShell Picture Viewer using WPF and WPK
Write-Progress & WPK

Test-Spelling

Projects using WPK:
SQLPSX
Try PowerShell (currently only in source not released)


PowerBoots is created by Joel Bennett (Jaykul) of HuddledMasses.org
and when installed, you find the examples in ...\Modules\PowerBoots\Samples\Samples.ps1

Some Blogs about it:
PowerBoots 0.2
PowerShell Picture Viewer using PowerBoots

Jaykuls tagged WPF

Posts Tagged ‘WPF’
PowerBoots: The tutorial walkthrough
PowerBoots: Loading XAML Windows in PowerShell 1.0 or 2.0

Creating GUI with Powershell and WPF was possible without the aid of toolkits, even in the dark adges of CTP 2 and CTP 3. Code from that early time needs to be adopted to run today, but for the curious, you find interessting stuff in it too.
Thanks to Max Trinidad for his post containing a link to the old trasures.

and here is th eearly serie from James Brundage:
Part 1
Part 2
Part 3
Part 4
Part 5
Part 6
Part 7

To make the examples run in PowerShell V2 you need help from the following posts
Windows PowerShell CTP2 to CTP3 Conversion Guide by James Brundage
PowerShell 2.0 CTP3 has arrived! by Oisin Grehan


Look for WPF tag in PowerShell Team Blog

finally you may want to look at some general WPF links
WPF Tutorial by Christian Mosers
WPF and XAML Tutorials by Josh Smith

Now have some fun, exploring WPF by yourself.

Bernd

Freitag, 2. April 2010

PowerShell modules are funny guys (III)

Today I continue to write about some advanced features, you only touch when you are importing some modules and than to remove some of them again.

To demonstate I create two modules, the first to be used as submodule by the second. I call it mod_s
$script:state_s = 0            
Write-host "Executing mod_s"

$mInfo = $MyInvocation.MyCommand.ScriptBlock.Module
$mInfo.OnRemove = { Write-Host "Removing module mod_s" }

function Get-State
{
return $script:state_s
}

function Set-State ($x)
{
$script:state_s = ($x)
}

function Set-ModSUnremovable
{
$mInfo = $MyInvocation.MyCommand.ScriptBlock.Module
$mInfo.AccessMode = "readonly"
}

function Set-ModSremovable
{
$mInfo = $MyInvocation.MyCommand.ScriptBlock.Module
$mInfo.AccessMode = "ReadWrite"
}

Se second is used to import this module, I call it mod_a:
Write-host "Executing mod_a"            
Import-Module mod_s.psm1
Write-host "Old state $(Get-state)"
Set-state 11

function Get-StateA
{
return Get-State
}

function Set-StateA ($x)
{
Set-State $x
}


Now let us see what happens, when I first import mod_s and than mod_a and finally remove mod_s


1]10:33:45 C:\Var\bin (FileSystem)
ipmo mod_s
Executing mod_s

_____________________________________________________________________________________________________
[2]10:33:50 C:\Var\bin (FileSystem)
ipmo mod_a
Executing mod_a
Old state 0

_____________________________________________________________________________________________________
[3]10:33:57 C:\Var\bin (FileSystem)
rmo mod_a
Removing module mod_s

_____________________________________________________________________________________________________
[4]10:34:02 C:\Var\bin (FileSystem)
gmo

ModuleType Name ExportedCommands
---------- ---- ----------------
Script ISECreamBasic {get-AvailableModuleList, Remove-IseMenu, Add-IseMenu}



_____________________________________________________________________________________________________
[5]


Let us remember, that mod_s is removed and the global reference to mod_s is removed.

Next let us keep a referenc to mod_s before removing mod_a:
[1]10:39:04 C:\Var\bin (FileSystem)
ipmo mod_s
Executing mod_s

_____________________________________________________________________________________________________
[2]10:40:52 C:\Var\bin (FileSystem)
$a = gmo mod_s

_____________________________________________________________________________________________________
[3]10:40:58 C:\Var\bin (FileSystem)
ipmo mod_a
Executing mod_a
Old state 0

_____________________________________________________________________________________________________
[4]10:41:03 C:\Var\bin (FileSystem)
rmo mod_a
Removing module mod_s

_____________________________________________________________________________________________________
[5]10:41:07 C:\Var\bin (FileSystem)
$a

ModuleType Name ExportedCommands
---------- ---- ----------------
Script mod_s {Set-ModSUnremovable, Set-State, Set-ModSremovable, Get-State}



_____________________________________________________________________________________________________
[6]10:41:12 C:\Var\bin (FileSystem)
gmo

ModuleType Name ExportedCommands
---------- ---- ----------------
Script ISECreamBasic {get-AvailableModuleList, Remove-IseMenu, Add-IseMenu}



_____________________________________________________________________________________________________
[7]


Here you see, that mod_s doesn't execute its termination code. I get the impression, that they use some sort of reference count to modules and when it drops down to 0. The module gets unloaded from memory.

The fact that the reference to the global scope is removed, by removing a submodul makes it difficult to ensure that some modules are imported.

Lets study Bruce Payette. He has a section Controlling when modules can be unloaded.

Let's try:
[1]10:49:09 C:\Var\bin (FileSystem)
ipmo mod_s
Executing mod_s

_____________________________________________________________________________________________________
[2]10:49:15 C:\Var\bin (FileSystem)
Set-ModSUnremovable

_____________________________________________________________________________________________________
[3]10:49:23 C:\Var\bin (FileSystem)
Set-ModSremovable

_____________________________________________________________________________________________________
[4]10:49:30 C:\Var\bin (FileSystem)
Set-ModSUnremovable

_____________________________________________________________________________________________________
[5]10:49:39 C:\Var\bin (FileSystem)
ipmo mod_a
Executing mod_a
Old state 0

_____________________________________________________________________________________________________
[6]10:49:45 C:\Var\bin (FileSystem)
rmo mod_a
Remove-Module : Unable to remove module 'mod_s' because it is read-only. Use the -force flag to remove r
ead-only modules.
At line:1 char:4
+ rmo <<<< mod_a
+ CategoryInfo : PermissionDenied: (mod_s:PSModuleInfo) [Remove-Module], InvalidOperationE
xception
+ FullyQualifiedErrorId : Modules_ModuleIsReadOnly,Microsoft.PowerShell.Commands.RemoveModuleComman
d


_____________________________________________________________________________________________________
[7]10:49:49 C:\Var\bin (FileSystem)
Set-ModSremovable
The term 'Set-ModSremovable' is not recognized as the name of a cmdlet, function, script file, or operab
le program. Check the spelling of the name, or if a path was included, verify that the path is correct a
nd try again.
At line:1 char:18
+ Set-ModSremovable <<<<
+ CategoryInfo : ObjectNotFound: (Set-ModSremovable:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException


_____________________________________________________________________________________________________
[8]


Anyone not calling this a bug around ?

Bernd

Dienstag, 30. März 2010

PowerShell modules are funny guys (II)

Here I'll focus on the irritating feature. The following script creates 2 modules in your user modul folder.
The second module imports the first module.

Import the first module, then the second. Both modules are imported.
Now remove the second module (that which imports the other too) and both are gone.

$modpath1 = ($env:PSModulepath -split ';')[0]            
mkdir $modpath1\submod -force
mkdir $modpath1\testmod -force



@'
$script:state_s = 0

function Get-State
{
return $script:state_s
}

function Set-State ($x)
{
$script:state_s = ($x)
}
'@
> "$modpath1\submod\submod.psm1"


@'
Import-Module submod.psm1


function Get-StateY
{
return Get-State
}

function Set-StateY ($x)
{
Set-State $x
}
'@
> "$modpath1\testmod\testmod.psm1"

ipmo submod
ipmo testmod
Write-host '------------'
gmo
Write-host '------------'
rmo testmod
gmo


Do you agree, that is to be called a bug?

Bernd

Montag, 29. März 2010

How to Organize Modules you Develop in Projects

Today I want to tell about the ways I organise my modul development.

When you start to develop PowerShell modules it is relative easy. Just add a folder under
(Split-path $profile) + '\Modules'            

say MyMod.
Then put a file MyMod.psm1 into it

Write-host "mymod loaded"


When you type ipmo Mymod, which is the alias for Import-Module you get


mymod loaded


With rmo Mymod , which is the short for Remove-Module you get rid of your module.

To check that it is removed, you can type
gmo or gmo Mymod, which is the alias for Get-Module

Now you shouldn't see it anymore.

Here I'm not going to tell you, what to put into your module file.

Best link for this I know is this post from Bruce Payette.

My focus here is, how to organise your system, when you have written something usefull and uploaded your module to some project.

I guess that you checkout your module from the project to some place, which is not in your modules folders. To ckeck where your system searches for modules just type

$env:PSModulePath -split ';'


Next I tried to be clever. I put the following into my profile:

$env:PSModulePath += ";\D:\MysharedProject\modules"


Now I can load the modules from this project by simple calles of ipmo myModule.

It really took some time to discover that I was too clever.

I'm using ISE for nearly all my PowerShell task and some time ago I discovered the menu New PowerShell Tab with the short-cut CTRL+T.

Each time you invoke this, you get a new PowerShell session and your PowerShell Profiles are executed.

But all these PowerShell session live in your current Windows session and each time the PSModulePath variable of the Windows environment will be modified. It gets longer and longer.

OK here now my final solution, this is the start of my profile.ps1

write-host "================== generall ($env:USERDOMAIN.$env:username) ==========================="            

$AdditionalModulPathes = @(
"D:\someProjectBleedingEdge\Modules"
"D:\someProjectRelease\Modules"
# "D:\MyCopyOfSomeProject\Modules"
)


foreach ($path in ($AdditionalModulPathes| Get-unique) )
{
if (($env:PSModulePath -split ';') -notcontains $path)
{
$env:PSModulePath += ";" + $path
}
}

# $env:PSModulePath -split ';'



Now I modify the evironment only once.
And here is the location, where I select whether I use the stable release, the current development version or my own unpublished work.

I hope this give you some ideas.

Bernd

BTW: ISE-Cream has reached release 0.1
If you are thinking about extending ISE, take a look at it

Donnerstag, 25. März 2010

PowerShell modules are funny guys

Ed Wilson says Windows PowerShell 1.0 was the vision, Windows PowerShell 2.0 is the reality [ from the preface of LeeHolmes Windows PowerShell Cookbook
I dare say PowerShell 2.0 ISE and Modules are still a vision.

When a module depends on a another module like SQLISE on ICECreamBasic or WPK it seems natural
to use within the .psm1 file
import-module ISECreamBasic            
import-module SQLParser
import-module adolib
import-module WPK


When I write a second module OracleIse, I can do similar

import-module ISECreamBasic            
import-module OracleClient
import-module WPK


Seems OK so far.

Next modules can be removed using Remove-module and that fires even an event to do some clean up as removing ISE addons menu items

$mInfo = $MyInvocation.MyCommand.ScriptBlock.Module            
$mInfo.OnRemove = {
Write-Host "$($MyInvocation.MyCommand.ScriptBlock.Module.name) removed on $(Get-Date)"
Remove-IseMenu OracleIse
}


Now emove on of these modules an see, which modules are left using

get-module            


You see, that the removed modul removed the modules imported within too, without tribute to the fact that the other module depends on WPK and ISECreamBasic too.

Conclusion. Better do not use import-module to import module from within your modules. Import the needed modules in advance.

Have some fun trying to find work arounds for this issue.

Bernd

Removing a specific Item from a Powershell ISE Addon menu

Well in ISECreamBasic I had written the function Remove-IseMenu to remove Toplevel menus.
Thanks to Shay Levi and Jaykul it became a nice advanced function with parametersets.

You can find the code in the ISE-Cream project

Just when I finished writing the header comments Ravi wanted to use the function not restricted to toplevel menu items.

First attemps tried to search the tree, but there can be more subitems with the same name hidden in the menu structure. To get it clear I designed the following function, which requires the complete path to the item to delete:

function Remove-IseMenuItem {            

$submenu = $psise.CurrentPowerShellTab.AddOnsMenu.Submenus

for ($j = 0; $j -lt $args.count; $j++)
{
$name = $args[$j]
$count = $submenu.count
#Write-host "arg0: $name $count"
for ($i = 0; $i -lt $submenu.count; $i++)
{
$found = $false
if ($Submenu[$i].DisplayName -eq $name)
{
#Write-host "found toplevel menu $name"
$found = $True
if ( $j -eq ($args.count - 1))
{
Write-host 'Removing'
$null = $submenu.remove($Submenu[$i])
}
else
{
$submenu = $Submenu[$i].submenus
}
break
}
}
if (! $found)
{
Write-host "Menuitem not found"
break
}

}
}

Remove-IseMenuItem Edit Pad

# Remove-Child $Submenu[$i] $Name | out-null



But this looks like an old PowerShell V1 coding style. It doesn't check that all arguments are strings. Please can someone show me, how to set up a PowerShell V2 advanced function parameter declaration for this.

Sonntag, 14. März 2010

ISE and PowerShell Modules

The last days searched a bit the current links about PowerShell modules.

There are the two new links by
Bruce Payette

http://dotnetslackers.com/articles/net/Converting-a-PowerShell-Script-into-a-Module.aspx
http://dotnetslackers.com/articles/net/Converting-a-PowerShell-Script-into-a-Module-part2.aspx

and in PowerShellPack there are lots of examples.

When you have a script module, that is one with a .psm1 file, it is easy to create a personal variant of it, be just copying it to a new folder within PSmodulePath and rename its
.psm1 file to correspond to the new foldername.

There might be .psd1 and .ps1xml files which require similar and further adaptions. The modules I'm working on don't have them.

But being modules that extend ISE, they use the addons menu and the current defacto standard to build such menus is the use of the Add-IseMenu from ISEpack.

The original version from James Brundage has some shortcomings, but I succeeded in writing a compatible extension, which you find in ISE-Cream. The main advantage, is that it only warns when shortcut keys are used and just builds the menu ignoring them.

That makes it easy to copy a module, rename the top menu name in one of them and load them side by side.

At first the menus look good, but when you try them, they seem to use the function from the last imported module.
When 2 modules export the same function name, the name is rebound to the function from the last imported module. Usually menus call their functions just by name and do not hard weir the modulename into the call.
In the end both menus call the functions from the last imported module.

Of course you can take the risk and edit the modul into all function calls, but that is a lot of work and seems error phrone.
Ignorant to the possibility to prefix the calls with the module name, I added a module parameter to the ICE-Cream version of Add-IseMenu, so that I have to set it at a single point.

Whenever I see the following code:
import-module IsePack          

I replace it with
if (! (test-path function:Add-IseMenu ) ) {import-module IsePack }          
Did I mention, that in the ISE-Cream version, you can predefine the order of the entries?


Bernd

PS:
I noticed, that undersores in modulnames will not be displayed. Better don't use them