0

I am trying to build a messaging system that is launched by scheduled task, and will eventually allow me to send messages to users before triggering software update jobs.

I have the UserMessage script basically working...

class PxMessage {

    static [PxMessage] $instance
    static [windows.forms.notifyIcon] $balloon
    static [drawing.icon] $defaultIcon

    static [PxMessage] GetInstance($processID) {
        if ([PxMessage]::instance -eq $null) {
            [PxMessage]::instance = [PxMessage]::new()
            #[void][reflection.assembly]::LoadWithPartialName('Windows.Forms')

            [PxMessage]::balloon = [windows.forms.notifyIcon]::New()
            [PxMessage]::defaultIcon = [drawing.icon]::ExtractAssociatedIcon($(Get-Process -id:$processID | Select-Object -expandProperty:path))
        }
        return [PxMessage]::instance
    }

    [Void] SendMessage ([String]$title, [String]$message, [String]$messageIcon, [String]$icon) {
        if ($icon) {
            [PxMessage]::balloon.icon = [drawing.icon]::ExtractAssociatedIcon($icon) # must be a local path
        } else {
            [PxMessage]::balloon.icon = [PxMessage]::defaultIcon
        }
        [PxMessage]::balloon.balloonTipTitle = $title
        [PxMessage]::balloon.balloonTipText = $message
        [PxMessage]::balloon.balloonTipIcon = $messageIcon
        [PxMessage]::balloon.visible = $true 
        [PxMessage]::balloon.ShowBalloonTip(0)
        [void][PxMessage]::balloon.Dispose
    }
}

$message = [PxMessage]::GetInstance($pid)
$message.SendMessage('Title', 'Message', 'Info', 'C:\PxIcon.ico')

This works when run in the ISE, and it works when I run it in the console from another script using & "\\Mac\iCloud Drive\Px Tools\Dev 4.0\#Spikes\ScheduledTasks\UserMessage.ps1".

However, when I set up a scheduled task like this...

$runTime = (get-Date) + (New-TimeSpan -seconds:1)
$action = New-ScheduledTaskAction -execute:'powershell.exe' -argument:'-NonInteractive -NoLogo -NoProfile -noExit -executionPolicy Bypass -File "\\Mac\iCloud Drive\Px Tools\Dev 4.0\#Spikes\ScheduledTasks\UserMessage_class.ps1"'
$trigger = New-ScheduledTaskTrigger -once -at:$runTime
$settings = New-ScheduledTaskSettingsSet
$task = New-ScheduledTask -action:$action -trigger:$trigger -settings:$settings
Register-ScheduledTask -taskName:'Px Tools' -inputObject:$task

I get the error Unable to find type [Windows.Forms.NotifyIcon]. Is there some interaction with Scheduled Tasks that causes problems with loading assemblies?

I know that [reflection.assembly]::LoadWithPartialName has been deprecated, and I found this which outlines some options. I tried [reflection.assembly]::LoadFrom("C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll"), with the same results.

Gordon
  • 6,257
  • 6
  • 36
  • 89

1 Answers1

0

Did you load the assemblies like so:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

Or as indicated here:

Add-Type -AssemblyName System.Windows.Forms
DarkLite1
  • 13,637
  • 40
  • 117
  • 214
  • I've tried both ways. The first throws the error, the second has no error, but also the code doesn't work. I do wonder, if I am using the type in the Static property definition, but prior to the required assembly being loaded, how would that work? – Gordon Oct 29 '19 at 15:44
  • You can also do `using assembly system.drawing`. – js2010 Oct 29 '19 at 17:00
  • @js2010, how would one do that. I tried it exactly as you have it, both in the class before and after the static declarations, and in the GetInstance method, in place of what I had before and at the beginning of the method. All are tagged as wrong (red underline). Even putting them at the top of the script file didn't work (no errors, but also no balloon tip), and that would not result in the class being self contained, which I would think is doable. – Gordon Oct 29 '19 at 19:59
  • 1
    This works for me in 5.1: `using assembly system.windows.forms; using namespace system.windows.forms; [messagebox]::show('hi')` – js2010 Oct 29 '19 at 20:10