Powershell add type in class in PSM1

1.6k Views Asked by At

In a PS1, this works

class pxInitFailureMessage {
    static [void] Send ([int32]$processID, [String]$title, [string]$message) {
        Add-Type -AssemblyName:System.Windows.Forms
        Add-Type -AssemblyName:System.Drawing
        $balloonTip = New-Object System.Windows.Forms.NotifyIcon
        $balloonTip.icon = [system.drawing.icon]::ExtractAssociatedIcon($(Get-Process -id:$processID | Select-Object -expandProperty:Path))
        $balloonTip.balloonTipIcon = 'Error'
        $balloonTip.balloonTipTitle = $title
        $balloonTip.balloonTipText = $message
        $balloonTip.visible = $true 
        $balloonTip.ShowBalloonTip(0)
        $balloonTip.Dispose
    }
}
[pxInitFailureMessage]::Send($pid, 'Title', 'Message is just some extra text')

But, move that class to a library.PSM1 file, and this in the PS1

Using module '\\Mac\iCloud Drive\Px Tools 4.#\Dev 4.0\#Spikes\Windows7\library.psm1'
[pxInitFailureMessage]::Send($pid, 'Title', 'Message is just some extra text')

And it works in the ISE, but not in the console when run from a shortcut. I get Unable to find type [system.drawing.icon].

Obviously the first Add-Type works, I get no error at New-Object. So why is the second type load failing? I also tried moving the two Add-Type lines out of the class, and into the root of the module file, with the same results. What DOES work is adding those lines to the PS1, between using module (which has to be the first non remarked line) and the call. That works, but then you don't have a self contained class, which seems to suck a bit. What am I misunderstanding here?

How does one make a self contained class that uses .NET types and work with it from a module file?

1

There are 1 best solutions below

0
Gordon On

For anyone interested, the solution I came up with is as follows. In library.PSM1 I have...

class pxInitFailureMessage {
    static [void] Send ([int32]$processID, [String]$title, [string]$message, [System.Drawing.Icon]$icon) {
        Add-Type -AssemblyName:System.Windows.Forms
        $balloonTip = New-Object System.Windows.Forms.NotifyIcon
        $balloonTip.icon = $icon
        $balloonTip.balloonTipIcon = 'Error'
        $balloonTip.balloonTipTitle = $title
        $balloonTip.balloonTipText = $message
        $balloonTip.visible = $true 
        $balloonTip.ShowBalloonTip(0)
        $balloonTip.Dispose
    }
}

And in my scrip I have...

using assembly System.Drawing
Using module '.\library.psm1'

$processIcon = [system.drawing.icon]::ExtractAssociatedIcon($(Get-Process -id:$pID | Select-Object -expandProperty:Path))

[pxInitFailureMessage]::Send($pid, 'Title', 'Message is just some extra text', $processIcon)

The key is that the class IS now self contained, and follows good practice of providing the class with everything it needs, so it doesn't have to go looking outside itself. I could just as easily use my own ICO file for the icon, like so...

$processIcon = [system.drawing.icon]::New('\\Mac\iCloud Drive\Px Tools 4.#\Dev 4.0\Px_Resources\PxIcon.ico')

Again with a literal path in this example.

So, I learned a thing today. Woot.