none
[HELP] Dynamic multi object and events creation RRS feed

  • Question

  • i´m trying to create objects and events based on a .xlsx file. my script need to teste connection with the computers listed on .xlsx

    My script create a Tray Icon alert if any computer is off-line dynamically.

    My trouble is when/how i create these NotifyIcons and its Events dynamically. i´m including and configuring this objects in another matriz, but i think is not working because the -action cant distinguish who is calling the event (I THINK!).

    for while my script still not test if connection is ok, i know is simple but iam testing yet.

    Notes:

    -i need use the register-objectevent because my user will do another things while the script do the job :D

    -i think my script have another problems because that´s my first script in powershell and iam just a newbie

    - i dont know if what im trying to do is the better form to do what i want... see?

    -sorry my english ;)

    all my script below:

    CLS
    
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    
    $Caminho     = "C:\Users\dvsilva\Documents\Projeto Balanças/"
    $Documento   = "Relação Unidades.xlsx"
    
    $Arquivo     = $Caminho + $Documento
    $ValoresExcel = New-Object 'object[]' 5
    $Qtd_Colunas = 1
    $Qtd_Linhas = 1
    
    ###start to read .xlsx###
    $Excel = New-Object -ComObject "Excel.Application"
    $Workbook = $Excel.workbooks.open($Arquivo)
    $Sheet = $workbook.Worksheets.Item(1)
     
    ###clean the .xlsx###
    $range = $excel.Range("A2","AZ500")
    $range.Interior.ColorIndex = 0
    
    ##Conting columns and Lines of .xlsx
    while ($Sheet.Cells.Item(1,$Qtd_Colunas).Text -ne ""){$Qtd_Colunas++}
    while ($Sheet.Cells.Item($Qtd_Linhas,1).Text -ne ""){ $Qtd_Linhas++}
    
    ###Creating and populating the matriz for output
    $Matriz = New-Object 'object[,]' $Qtd_Linhas,$Qtd_Colunas
    $Matriz = ,@()
    for ($ContL = 1; $ContL -lt $Qtd_Linhas+1; $ContL++) {
        for ($ContC = 0; $ContC -lt $Qtd_Colunas; $ContC++) {
            $ValoresExcel[$ContC] = $Sheet.Cells.Item($ContL+1,$ContC+1).Text
        }
        $Matriz += ,@($ValoresExcel)
    }
    #closing .xlsx
    $Excel.Quit()
    stop-process -ProcessName Excel
    
    #Outputing the matriz of .excel content in table mode with 12 characters each column
    for ($ContL = 1; $ContL -lt $Qtd_Linhas; $ContL++) {
        for ($ContC = 0; $ContC -lt $Qtd_Colunas; $ContC++) {
    
                #if not lower and greater, i need just the 12 firsts characters
                if (($Matriz[$ContL][$ContC] |% {($_ | Measure-Object -Character).Characters}) -gt 15){
                    $Matriz[$ContL][$ContC] = $Matriz[$ContL][$ContC].Substring(0,15)
                }
    
                #if lower then 12 charaters, input some blank spaces (" ")
                elseif (($Matriz[$ContL][$ContC] |% {($_ | Measure-Object -Character).Characters}) -lt 15){
                    while (($Matriz[$ContL][$ContC] |% {($_ | Measure-Object -Character).Characters}) -lt 15) {
                        $Matriz[$ContL][$ContC] = $Matriz[$ContL][$ContC] + ' '
                    }
                }
                ##if is 12, do nothing
        }
    }
    #outputing
    ($Matriz)|% { $_ -join "`t"} | Format-Table
        
    ######start of the action#######
    $MatrizNotify = New-Object 'object[,]' ($Qtd_Linhas-1),3
    $MatrizNotify = ,@()
    
    #unregistering all events
    Get-EventSubscriber -Force | Unregister-Event -Force                                                                                                                       
    
    #repetion structure for create the objects and event.... my trouble start here :D :D :D
    for ($cont =1; $cont -lt $Qtd_Linhas-1; $cont++){
        $pc = $Matriz[$cont][2].Replace(" ","")+"DB01"
                
                #creating all objects in the matriz
                $MatrizNotify += ,@((New-Object System.Windows.Forms.NotifyIcon),                         # NotifyIcon  = $MatrizNotify[$cont][0].
                                    (New-Object System.Windows.Forms.ContextMenu),                        # ContextMenu = $MatrizNotify[$cont][1].
                                    (New-Object System.Windows.Forms.MenuItem),                           # MenuItem    = $MatrizNotify[$cont][2].
                                    $pc)
    
                #my events
                register-objectevent -InputObject $MatrizNotify[$cont][0] -EventName BalloonTipClicked -SourceIdentifier $pc".objNotifyIcon.BalloonTipClicked" -MessageData $MatrizNotify[$cont][0] -Action     {
                                                                                                                                                                      $sender.Dispose()
                                                                                                                                                                     } | Out-Null
    
                register-objectevent -InputObject $MatrizNotify[$cont][0] -EventName Disposed -SourceIdentifier $pc".objNotifyIcon.Disposed" -MessageData $MatrizNotify[$cont][0] -Action  {
                                                                                                                                                 Remove-Event $pc".objNotifyIcon.BalloonTipClicked" -ea SilentlyContinue
                                                                                                                                                 Remove-Event $pc".objNotifyIcon.Disposed"          -ea SilentlyContinue
                                                                                                                                                 Remove-Event $pc".objNotifyIcon.MouseDoubleClick"  -ea SilentlyContinue
                                                                                                                                                 Remove-Event $pc".MenuItem.Click"                  -ea SilentlyContinue
                                                                                                                                                 Unregister-Event -SourceIdentifier $pc".objNotifyIcon.BalloonTipClicked" -ea SilentlyContinue
                                                                                                                                                 Unregister-Event -SourceIdentifier $pc".objNotifyIcon.Disposed"          -ea SilentlyContinue
                                                                                                                                                 Unregister-Event -SourceIdentifier $pc".objNotifyIcon.MouseDoubleClick"  -ea SilentlyContinue
                                                                                                                                                 Unregister-Event -SourceIdentifier $pc".MenuItem".Click                  -ea SilentlyContinue                                                                                                                       
                                                                                                                                                 Get-EventSubscriber -Force | Unregister-Event -Force                                                                                                                       
                                                                                                                                                 $sender.Dispose()
                                                                                                                                                 $sender.Dispose()
                                                                                                                                                } | Out-Null
    
                register-objectevent -InputObject $MatrizNotify[$cont][0] -EventName MouseDoubleClick -SourceIdentifier $pc".objNotifyIcon.MouseDoubleClick" -MessageData $MatrizNotify[$cont][0] -Action  {
                                                                                                                                                                 $sender.ShowBalloonTip(2000)
                                                                                                                                                                } | Out-Null
                
                register-objectevent -InputObject $MatrizNotify[$cont][2] -EventName Click -SourceIdentifier $pc".MenuItem.Click" -MessageData $MatrizNotify[$cont][2] -Action {
                                                                                                                                     $sender.Dispose()
                                                                                                                                    } | Out-Null
    
                #Object properties
                $MatrizNotify[$cont][0].Icon = "C:\Users\dvsilva\Documents\Projeto Balanças\icons\icon_Alert.ico"
                $MatrizNotify[$cont][0].BalloonTipIcon = "Error" 
                $MatrizNotify[$cont][0].BalloonTipText = "Servidor $pc não está respondendo. Clique para fechar a notificação." 
                $MatrizNotify[$cont][0].BalloonTipTitle = "$pc não alcansado"
                $MatrizNotify[$cont][0].ContextMenu = $MatrizNotify[$cont][1]
                $MatrizNotify[$cont][0].ContextMenu.MenuItems.AddRange($MatrizNotify[$cont][2])
                $MatrizNotify[$cont][0].Visible = $True
                $MatrizNotify[$cont][2].Text = "Sair"
    
                $MatrizNotify[$cont][0].ShowBalloonTip(2000)
                
    
    }

    Tuesday, February 16, 2016 12:54 PM

Answers

  • The following demonstrates how to get the identity of the sender.

    Add-Type -AssemblyName System.Windows.Forms
    $ni = New-Object System.Windows.Forms.NotifyIcon
    $ni.Visible=$true
    $ni.Icon = [System.Drawing.SystemIcons]::Information
    $cm = New-Object System.Windows.Forms.ContextMenu
    $ni.ContextMenu = $cm
    $cm.Name='cm1'
    $mi = New-Object System.Windows.Forms.MenuItem
    $mi.Name='meuitem1'
    $mi.Text='My menu item'
    $cm.MenuItems.Add($mi)
    
    $clicked={
    	#https://msdn.microsoft.com/en-us/library/system.management.automation.pseventargs_members%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
    	Write-Host 'Menu Item Clicked' -fore green
    	Write-Host $Event.TimeGenerated -fore Blue -back white
    	Write-Host $Event.Sender.Text -fore black -back white
    }
    $evt=Register-ObjectEvent $ni Click -sourceIdentifier clicked -Action $clicked
    
    $ni.BalloonTipTitle='This is a Balloon Title'
    $ni.BalloonTipText='This is the message in the balloon tip'
    $ni.BalloonTipIcon='Error'
    $ni.Visible=$True 
    #$ni.ShowBalloonTip(2000)

    We can also event on the context menu and aggregate all clicks.


    \_(ツ)_/


    • Marked as answer by DaniloVSilva Thursday, February 18, 2016 12:04 PM
    • Edited by jrv Friday, March 4, 2016 8:44 PM
    Tuesday, February 16, 2016 7:57 PM

All replies

  • and the structure of my .xlsx is:

    Unidade IP Sigla Número
    Unidade 51 10.0.0.30. BVR 51
    Unidade 4 17.0.0. BRA 4
    Unidade 325 12.0.0. BWS 325

    Tuesday, February 16, 2016 1:09 PM
  • Kt is probably this line:

     $MatrizNotify[$cont][0].ContextMenu.MenuItems.AddRange($MatrizNotify[$cont][2])

    AddRange requires an array or collection.

    Also:
    $MatrizNotify[$cont][2]

    What is this?  Try it at a prompt to see what it evaluates to.

    I recommend simplifying the code. 

    It is unlikely that anyone can reproduce this easily so you will have to isolate the issue more completely.


    \_(ツ)_/


    • Edited by jrv Tuesday, February 16, 2016 6:09 PM
    Tuesday, February 16, 2016 6:08 PM
  • Here is how to event individual menu items.  Copy and paste into PS CLI and it should work as expected.

    Add-Type -AssemblyName System.Windows.Forms
    $ni = New-Object System.Windows.Forms.NotifyIcon
    $ni.Visible=$true
    $ni.Icon = [System.Drawing.SystemIcons]::Information
    $cm = New-Object System.Windows.Forms.ContextMenu
    $ni.ContextMenu = $cm
    $cm.Name='cm1'
    $mi = New-Object System.Windows.Forms.MenuItem
    $mi.Name='mi1'
    $mi.Text='My menu item'
    $cm.MenuItems.Add($mi)
    
    $clicked={Write-Host 'Menu Item Clicked' -fore green}
    $event=Register-ObjectEvent $mi Click -sourceIdentifier clicked -Action $clicked
    
    $ni.BalloonTipTitle='This is a Balloon Title'
    $ni.BalloonTipText='This is the message in the balloon tip'
    $ni.BalloonTipIcon='Error'
    $ni.Visible=$True 
    #$ni.ShowBalloonTip(2000)
    


    \_(ツ)_/

    Tuesday, February 16, 2016 7:43 PM
  • The following demonstrates how to get the identity of the sender.

    Add-Type -AssemblyName System.Windows.Forms
    $ni = New-Object System.Windows.Forms.NotifyIcon
    $ni.Visible=$true
    $ni.Icon = [System.Drawing.SystemIcons]::Information
    $cm = New-Object System.Windows.Forms.ContextMenu
    $ni.ContextMenu = $cm
    $cm.Name='cm1'
    $mi = New-Object System.Windows.Forms.MenuItem
    $mi.Name='meuitem1'
    $mi.Text='My menu item'
    $cm.MenuItems.Add($mi)
    
    $clicked={
    	#https://msdn.microsoft.com/en-us/library/system.management.automation.pseventargs_members%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
    	Write-Host 'Menu Item Clicked' -fore green
    	Write-Host $Event.TimeGenerated -fore Blue -back white
    	Write-Host $Event.Sender.Text -fore black -back white
    }
    $evt=Register-ObjectEvent $ni Click -sourceIdentifier clicked -Action $clicked
    
    $ni.BalloonTipTitle='This is a Balloon Title'
    $ni.BalloonTipText='This is the message in the balloon tip'
    $ni.BalloonTipIcon='Error'
    $ni.Visible=$True 
    #$ni.ShowBalloonTip(2000)

    We can also event on the context menu and aggregate all clicks.


    \_(ツ)_/


    • Marked as answer by DaniloVSilva Thursday, February 18, 2016 12:04 PM
    • Edited by jrv Friday, March 4, 2016 8:44 PM
    Tuesday, February 16, 2016 7:57 PM
  • Kt is probably this line:

     $MatrizNotify[$cont][0].ContextMenu.MenuItems.AddRange($MatrizNotify[$cont][2])

    AddRange requires an array or collection.

    Also:
    $MatrizNotify[$cont][2]

    What is this?  Try it at a prompt to see what it evaluates to.

    I recommend simplifying the code. 

    It is unlikely that anyone can reproduce this easily so you will have to isolate the issue more completely.


    \_(ツ)_/


    in the $MatrizNotify[$cont][2] i have a MenuItem created here:

    #creating all objects in the matriz
                $MatrizNotify += ,@((New-Object System.Windows.Forms.NotifyIcon),                         # NotifyIcon  = $MatrizNotify[$cont][0].
                                    (New-Object System.Windows.Forms.ContextMenu),                        # ContextMenu = $MatrizNotify[$cont][1].
                                    (New-Object System.Windows.Forms.MenuItem),                           # MenuItem    = $MatrizNotify[$cont][2].
                                    $pc)
    i will do some trataments in my code to explain my problem. thx for reply

    Wednesday, February 17, 2016 4:21 PM
  • i'am doing this, but i need to create X number of NotifyIcons (the X number can be 1 or 10 or 200), beacuse that i'm using a dynamical method... i put the NotifyIcon, ContextMenu and MenuItem in a Matriz each time i execute the FOR structure for future i can manage they. Using the mentioned method i will just create one, correct? they will override

    Really our difference, excluding the FOR structure, is i dont do the tratment of the -Action parameter on a "function" like u tell me to do ($clicked), can be the problem?

    Thx for help :D


    • Edited by DaniloVSilva Wednesday, February 17, 2016 4:36 PM
    Wednesday, February 17, 2016 4:26 PM
  • The following demonstrates how to get the identity of the sender.

    Add-Type -AssemblyName System.Windows.Forms
    $ni = New-Object System.Windows.Forms.NotifyIcon
    $ni.Visible=$true
    $ni.Icon = [System.Drawing.SystemIcons]::Information
    $cm = New-Object System.Windows.Forms.ContextMenu
    $ni.ContextMenu = $cm
    $cm.Name='cm1'
    $mi = New-Object System.Windows.Forms.MenuItem
    $mi.Name='meuitem1'
    $mi.Text='My menu item'
    $cm.MenuItems.Add($mi)
    
    $clicked={
    	#https://msdn.microsoft.com/en-us/library/system.management.automation.pseventargs_members%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
    	Write-Host 'Menu Item Clicked' -fore green
    	Write-Host $Event.TimeGenerated -fore Blue -back white
    	Write-Host $Event.Sender.Text -fore black -back white
    }
    $evt=Register-ObjectEvent $mi Click -sourceIdentifier clicked -Action $clicked
    
    $ni.BalloonTipTitle='This is a Balloon Title'
    $ni.BalloonTipText='This is the message in the balloon tip'
    $ni.BalloonTipIcon='Error'
    $ni.Visible=$True 
    #$ni.ShowBalloonTip(2000)

    We can also event on the context menu and aggregate all clicks.


    \_(ツ)_/

    i have a question, i need to set the Register-objectEvent in a Variable like you do in $evt?

    i think the $sender is the answer i need :D

    thx, testing.... :)

    Wednesday, February 17, 2016 4:29 PM
  • Here is a more complete example of how to use multiple menu items with one action.

    function Add-NIMenuItem {
    	param (
    		$name,
    		$text,
    		$message
    	)
    	$clicked = {
    		#https://msdn.microsoft.com/en-us/library/system.management.automation.pseventargs_members%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
    		Write-Host 'Menu Item Clicked' -fore green
    		Write-Host $Event.TimeGenerated -fore Blue -back white
    		Write-Host $Event.Sender.Name -fore black -back white
    		Write-Host $Event.Sender.Parent.Name -fore black -back white
    		Write-Host $Event.MessageData -fore black -back white
    		($Event.MessageData).Invoke()
    	}
    	$mi = New-Object System.Windows.Forms.MenuItem
    	$mi.Name = $name
    	$mi.Text = $text
    	$cm.MenuItems.Add($mi)
    	[void](Register-ObjectEvent $mi Click -sourceIdentifier $name -Action $clicked -MessageData $message)
    }
    
    Add-Type -AssemblyName System.Windows.Forms
    $ni = New-Object System.Windows.Forms.NotifyIcon
    $ni.Icon = [System.Drawing.SystemIcons]::Information
    
    $cm = New-Object System.Windows.Forms.ContextMenu
    $ni.ContextMenu = $cm
    $cm.Name='contextmenu1'
    
    Add-NIMenuItem 'menuitem1' 'My menu item 1' 'Extra message data 1'
    Add-NIMenuItem 'menuitem2' 'My menu item 2' 'Extra message data 2'
    
    $ni.Visible = $true
    
    

    If you need to associate more data then put in in a dictionary and use the munuitem name to retrieve it.

    $dict=@{ menuitem1=@{....};menuitem2=@{....}}  etc.
    $data=$dict[$sender.Name]


    \_(ツ)_/

    Wednesday, February 17, 2016 7:25 PM
  • the $sender solve my problem.

    Thx Jrv.

    Thursday, February 18, 2016 12:05 PM
  • Good luck.

    \_(ツ)_/

    Thursday, February 18, 2016 1:12 PM