SysTrayHost/SysTrayHost.ps1


class SysTrayHost {

    hidden [System.Drawing.Bitmap]                  $_systrayBitmap         = $null
    hidden [System.Drawing.Bitmap]                  $_powershellBitmap      = $null
    hidden [System.Drawing.Bitmap]                  $_cloudBitmap           = $null
    hidden [System.Drawing.Bitmap]                  $_hierarchyBitmap       = $null
    hidden [System.Drawing.Bitmap]                  $_folderBitmap          = $null
    hidden [System.Drawing.Bitmap]                  $_sharepointBitmap      = $null

    hidden [System.Windows.Forms.NotifyIcon]        $_systray               = $null
    hidden [System.Windows.Forms.ContextMenuStrip]  $_contextmenu           = $null

    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemOperations    = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemEcoSystem     = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemShell         = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemShellVerbose  = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemScheduler     = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemProfile       = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemLib           = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemCache         = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemDocs          = $null
    hidden [System.Windows.Forms.ToolStripMenuItem] $_menuitemExit          = $null

    hidden [System.Collections.ArrayList]           $_processes             = [System.Collections.ArrayList]::new()
    hidden [System.Collections.ArrayList]           $_hiddenprocesses       = [System.Collections.ArrayList]::new()

    hidden $_procId                 = $null
    hidden [Boolean]                                $_procHide              = $false
    hidden [Boolean]                                $_procTerminate         = $false

    hidden $_command                = $null
    hidden $_filter                 = $null
    hidden [System.Collections.Stack]               $_nodesStack            = $null

    hidden $_pipeSysTray                                       = $null
    hidden $_pipeExplorer                                      = $null
    hidden $_pipeCustomizer                                    = $null
    hidden $_explorer               = $null
    hidden $_customizer             = $null

    #--------------------
    # Constructor
    #--------------------
    SysTrayHost() {
        $this._systrayBitmap        = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Images\icons8-engineering-50.png")
        $this._powershellBitmap     = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Images\icons8-powershell-filled-50.png")
        $this._cloudBitmap          = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Images\icons8-clouds-30.png")
        $this._hierarchyBitmap      = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Images\icons8-hierarchy-32.png")
        $this._folderBitmap         = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Images\icons8-folder-48.png")
        $this._sharepointBitmap     = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Images\icons8-microsoft-sharepoint-48.png")

        $this.initializeControls()
        $this.buildFormLayout()
        $this.initializePipes()
        if([boolean]($global:SRxEnv.Program.EnabledExplorer)) { $this.newExplorer() }
    }
    hidden [void] initializeControls() {
        $this._systray              = [System.Windows.Forms.NotifyIcon]::new()
        $this._contextmenu          = [System.Windows.Forms.ContextMenuStrip]::new()
        $this._menuitemShell        = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemOperations   = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemEcoSystem    = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemShell        = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemShellVerbose = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemScheduler    = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemProfile      = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemLib          = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemCache        = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemDocs         = [System.Windows.Forms.ToolStripMenuItem]::new()
        $this._menuitemExit         = [System.Windows.Forms.ToolStripMenuItem]::new()
    
    }
    hidden [void] buildFormLayout() {
        #
        # _systray
        #
        $this._systray.Icon = [System.Drawing.Icon]::FromHandle($this._systrayBitmap.GetHicon())
        $this._systray.Text = $global:SRxEnv.DefaultSettings.EcoSystem.SysTrayUI.ts_Title #
        $this._systray.Visible = $global:SRxEnv.Program.EnabledSysTray
        $this._systray.Tag = $this
        $this._systray.add_MouseDown({
            param($source, $e)        
            $_this = $source.Tag

            $connected = Get-SRxIsConnected
            $_this._menuitemOperations.Enabled = $connected
            $_this._menuitemEcoSystem.Enabled = $connected
            $_this._menuitemShell.Enabled = $connected
            $_this._menuitemShellVerbose.Enabled = $connected
            $_this._menuitemScheduler.Enabled = $false 
            $_this._menuitemLib.Enabled = $connected
        }) 
        $this._systray.add_DoubleClick({
            param($source, $e)        
            $_this = $source.Tag

            $_this.newExplorer()
        })     
        $this._systray.add_MouseMove({
            param($source, $e)        
            $_this = $source.Tag

            if( Get-SRxIsConnected ) { $_this._systray.Text = "$($global:SRxEnv.DefaultSettings.EcoSystem.SysTrayUI.ts_Title) - $($global:SRxEnv.Tenancy.TermGroupName)" }
            else                     { $_this._systray.Text = "$($global:SRxEnv.DefaultSettings.EcoSystem.SysTrayUI.ts_Title) - offline"   }
        }) 

        $this._contextmenu.Items.Add($this._menuitemOperations) 
        $this._contextmenu.Items.Add($this._menuitemEcoSystem)
        $this._contextmenu.Items.Add("-")
        $this._contextmenu.Items.Add($this._menuitemShell)
        $this._contextmenu.Items.Add($this._menuitemShellVerbose)
        $this._contextmenu.Items.Add("-")
        $this._contextmenu.Items.Add($this._menuitemScheduler)
        $this._contextmenu.Items.Add("-")
        $this._contextmenu.Items.Add($this._menuitemProfile)
        $this._contextmenu.Items.Add($this._menuitemLib)
        $this._contextmenu.Items.Add($this._menuitemCache)
        $this._contextmenu.Items.Add("-")
        $this._contextmenu.Items.Add($this._menuitemDocs)
        $this._contextmenu.Items.Add("-")
        $this._contextmenu.Items.Add($this._menuitemExit)

        $this._systray.ContextMenuStrip = $this._contextmenu        
        #
        # _menuitemOperations
        #
        $this._menuitemOperations.Text = "Operations"
        #$this._menuitemOperations.DefaultItem = $true
        $this._menuitemOperations.Image = $this._hierarchyBitmap
        $this._menuitemOperations.Tag = $this
        $this._menuitemOperations.add_Click({
            param($source, $e)        
            $_this = $source.Tag

            $_this.newExplorer() 
        })
        #
        # _menuitemEcoSystem
        #
        $this._menuitemEcoSystem.Text = "EcoSystem"
        $this._menuitemEcoSystem.Tag = $this
        $this._menuitemEcoSystem.Image = $this._sharepointBitmap
        $this._menuitemEcoSystem.add_Click({ 
            param($source, $e)
            #$_this = $source.Tag
            #try { $global:_EcoSystem.Invoke( $_this ) } catch { Write-Host ($_.Exception.Message) }
            if( Get-SRxIsConnected ) { 
                $str = $global:SRxEnv.DefaultSettings.EcoSystem.ts_URL
                $str = $str.replace('{tenancy}', $global:SRxEnv.Tenancy.Name)
                $ecosystemURL = $str.replace('{ecosystem}', $global:SRxEnv.Tenancy.EcoSystem)
                Start-Process $ecosystemURL | Out-Null
            } 
        })
        #
        # _menuitemShell
        #
        $this._menuitemShell.Text = "Shell"
        $this._menuitemShell.Image = $this._powershellBitmap
        $this._menuitemShell.Tag = $this
        $this._menuitemShell.add_Click({ 
            param($source, $e)
            $_this = $source.Tag       
            try { $global:_Shell.Invoke( $_this ) }  catch   { Write-Host ($_.Exception.Message)  } 
        })
        #
        # _menuitemShellVerbose
        #
        $this._menuitemShellVerbose.Text = "Shell Verbose"
        $this._menuitemShellVerbose.Tag = $this
        $this._menuitemShellVerbose.Image = $this._powershellBitmap
        $this._menuitemShellVerbose.add_Click({  
            param($source, $e)
            $_this = $source.Tag       
            try { $global:_Shell_Verbose.Invoke( $_this ) }  catch   { Write-Host ($_.Exception.Message)  } 
        })
        #
        # _menuitemScheduler
        #
        $this._menuitemScheduler.Text = "Scheduler"
        $this._menuitemScheduler.Tag = $this
        $this._menuitemScheduler.add_Click({ _Scheduler })
        #
        # _menuitemProfile
        #
        $this._menuitemProfile.Text = "O365 connection"
        $this._menuitemProfile.Image = $this._cloudBitmap
        $this._menuitemProfile.Tag = $this
        $this._menuitemProfile.add_Click({ 
            param($source, $e)
            $_this = $source.Tag       
            try { $global:_Profile.Invoke( $_this ) }  catch   { Write-Host ($_.Exception.Message)  }              
        })
        #
        # _menuitemLib
        #
        $this._menuitemLib.Text = "PowerShell Library"
        $this._menuitemLib.Image = $this._folderBitmap
        $this._menuitemLib.Tag = $this
        $this._menuitemLib.add_Click({  Start-Process explorer $(Join-Path $global:SRxEnv.paths.SRxRoot "Lib") })
        #
        # _menuitemCache
        #
        $this._menuitemCache.Text = "Local cache"
        $this._menuitemCache.Image = $this._folderBitmap
        $this._menuitemCache.Tag = $this
        $this._menuitemCache.add_Click({ 
            param($source, $e)
            $_this = $source.Tag       
            try { $global:_Cache.Invoke( $_this ) }  catch   { Write-Host ($_.Exception.Message)  }                                        
        })
        #
        # _menuitemDocs
        #
        $this._menuitemDocs.Text = "Help"
        $this._menuitemDocs.Tag = $this
        $this._menuitemDocs.add_Click({ 
            param($source, $e)
            $_this = $source.Tag       
            try { $global:_Docs.Invoke( $_this ) }  catch   { Write-Host ($_.Exception.Message)  }                           
        })
        #
        # _menuitemExit
        #
        $this._menuitemExit.Text = "Quit"
        $this._menuitemExit.Tag = $this
        $this._menuitemExit.add_Click({ 
            param($source, $e)
            $_this = $source.Tag       
            $_this.Close()
        })
    }
    hidden [void] initializePipes() {

        $this._pipeSysTray   = New-SRxPipeServer -PipeName "pipe-Shell"  -DoEvents $true
        $this._pipeSysTray.Caller = $this
        $this._pipeSysTray.OnMessage($this._onSysTrayMessage)
        $this._pipeSysTray.OnClose({
            $_this = $($args[0]).Caller           
            if($_this._procTerminate) { 
                $_this.terminateProcesses( $false)
                $_this._procTerminate = $false
            }
        })

        $this._pipeExplorer = New-SRxPipeServer -PipeName "pipe-Explorer"  -DoEvents $false 
        $this._pipeExplorer.Caller = $this
        $this._pipeExplorer.OnMessage($this._onExplorerMessage)
        $this._pipeExplorer.OnClose({
            $_this = $($args[0]).Caller
            #Powershell window was closed interactively by user
            if( $_this._explorer ) { 
                $_this._explorer.Complete() 
            }
        })

        $this._pipeCustomizer = New-SRxPipeServer -PipeName "pipe-Customizer"  -DoEvents $false 
        $this._pipeCustomizer.Caller = $this
        $this._pipeCustomizer.OnMessage($this._onCustomizerMessage)
        $this._pipeCustomizer.OnClose({
            $_this = $($args[0]).Caller
            #Powershell window was closed interactively by user
            if( $_this._customizer ) { 
                $_this._customizer.Complete() 
            }
        })
    }
    hidden [void] startPowerShell($arguments) {
        if( $this._command.ts_HideWindow ) {
            [System.Diagnostics.Process]$proc = Start-Process PowerShell -WindowStyle Minimized -ArgumentList $arguments -PassThru
            $this._hiddenprocesses.Add($proc)                            
            $this._procId = $proc.Id                       
            $this._procHide = $true
        }
        else {
            [System.Diagnostics.Process]$proc = Start-Process PowerShell -WindowStyle Normal -ArgumentList $arguments -PassThru
            $this._processes.Add($proc) 
            $this._procId = $proc.Id  
            $this._procHide = $false
        }
    }
    hidden [void] newExplorer() {
        try {
            if( $global:SRxEnv.Tenancy.TermGroupID -ne "") {
                if( -not $this._explorer) {
                    Write-Host "new schema explorer"

                    $sgroupName = Remove-SRxStringSpecialCharacter -String $global:SRxEnv.Tenancy.TermGroupName
                    $schema = $global:SRxEnv.CachePath + "\Profiles\" + $sgroupName + "\termSet.xml"

                    Connect-SRxProvisioningDatabase_JSON 

                    $this._explorer = Explorer -schema $schema -source $($global:SRxEnv.Paths.SRxRoot)
                    $this._explorer.Caller = $this
                    
                    $this._explorer.OnCommand({
                        $_this = $($args[0]).Caller
                        $_this._command  = $($args[1])
                        $_this._procId = $null
                        $_this.startPowerShell($($args[2]))
                    })
                    $this._explorer.OnClose({ 
                        $_this = $($args[0]).Caller
                        $_this.terminateProcesses( $true)
                        $_this._explorer = $null 
                        if( -not [boolean]($global:SRxEnv.Program.EnabledSysTray) ) {   $_this.Close() }
                    })
                    $this._explorer.OnCancel({ 
                        $_this = $($args[0]).Caller
                        $_this.terminateProcesses( $false)
                        $_this._pipeExplorer.Close()
                    })
                    $this._explorer.OnHideProcess({ 
                        $_this = $($args[0]).Caller
                        $_this._procHide = $($args[1])
                        #https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
                        if($_this._procHide) { $null = [Win32Functions.Win32Windows]::ShowWindowAsync((Get-Process -PID $($_this._procId)).MainWindowHandle, 2) }
                        else                 { $null = [Win32Functions.Win32Windows]::ShowWindowAsync((Get-Process -PID $($_this._procId)).MainWindowHandle, 10) }
                    })
                    $this._explorer.OnTemplateCommand({
                        $_this = $($args[0]).Caller
                        $_this._customizer = $_this._explorer
                        #$_this._command = $($args[1])
                        #$_this._nodesStack = $_this._command.nodesStack

                    })
                    $this._explorer.OnTemplateClose({
                        $_this = $($args[0]).Caller
                        $_this._customizer = $null
                    })
                    #Write-Host "----- _explorer.OnEnableSysTray -----"
                    $this._explorer.OnEnableSysTray({
                        $_this = $($args[0]).Caller
                        $enabled = [boolean]$($args[1])
                        $_this._systray.Visible = $enabled
                        $global:SRxEnv.Program.EnabledSysTray = $enabled
                        $global:SRxEnv.PersistCustomProperty("Program", $global:SRxEnv.Program)
                    })

                    $this._explorer.Run()                        
                }
                else {
                    Write-Host "activate schema explorer"
                    $this._explorer.Activate()
                }
            }    
        }
        catch {
            Write-Host($_.Exception.Message) 
            Write-Host($_.Exception) 
        } 
    }
    hidden [void] terminateProcesses([boolean]$all) {

        function terminateProcs ($procs) {
            if($procs.Count -gt 0) {
                for( [int]$i = $($procs.Count - 1); $i -ge 0; $i--) {
                    $proc = $procs[$i]
                    Write-Host "Stop-Process $($proc.Id)"
                    Stop-Process $proc
                    [void]$procs.RemoveAt($i)    
                }
            }
        }
        if( $all) {
            terminateProcs($this._hiddenprocesses)
            terminateProcs($this._processes)
        }
        else {
            #
            $procs = $this._hiddenprocesses
            if($procs.Count -gt 0) {
                for( [int]$i = $($procs.Count - 1); $i -ge 0; $i--) {
                    $proc = $procs[$i]
                    [boolean]$isMinimized = [Win32Functions.Win32Windows]::IsIconic((Get-Process -PID $($proc.Id)).MainWindowHandle)
                    if( -not $isMinimized) {
                        Write-Host "Don't terminate Process $($proc.Id)"
                        $this._processes.Add($proc)
                        [void]$procs.RemoveAt($i)    
                    }
                }
            }
            terminateProcs($procs)
        }
    }
    hidden [System.Management.Automation.ScriptBlock] $_onSysTrayMessage = {
        try {
            $message    = $($args[1])
            $pipe       = $($args[0])
            $_this      = $pipe.Caller

            #Write-Host "[this] $ths"
            Write-Host "[server] $($pipe.GetPipeName()) received ($($message.GetType().Name)) from client: $message"

            if( $($message.GetType().Name) -eq "String") {  
                #Write-Host "switch [string]"
                #string
                #Write-Host "[server] $($pipe.GetPipeName()) received (text) from client: $message"
                switch($message) {
                    "Terminate"     {   $_this.Close() }
                    "Receive"       {   $pipe.Write("Hello client !") }
                    "getObject"     {   $obj = [PSCustomObject]@{
                                            ts_Environment = "Production"
                                            ts_Title       = "Title"
                                        }
                                        $pipe.Write($obj)    
                                    }
                    "Get-Command"   {   if($_this._command) {
                                            $pipe.Write($_this._command)
                                            $_this._command = $null
                                        }
                                        else { $pipe.Write([pscustomobject]$false) }    
                                    } 
                    "Get-NodeStack" {   <#if($_this._customizer) {
                                            if($_this._nodesStack) {
                                                $pipe.Write($_this._nodesStack)
                                                $_this._nodesStack = $null
                                            }
                                            else { $pipe.Write([pscustomobject]$false) }
                                        }
                                        #>

                                        if($_this._customizer ) { #$_this._customizer === $_this._explorer
                                            Write-Host "_this._procId = $($_this._procId)"
                                            $ns = $_this._customizer.NodesPack( $_this._procId)

                                            if($ns) { 
                                                Write-Host ($ns | FT | Out-String)
                                                $pipe.Write($ns) 
                                            }
                                            else    {
                                                Write-Host ("no nodestack available") 
                                                $pipe.Write([pscustomobject]$false) 
                                            }    #explor will pause process $_this._procId
                                        }
                                        else {
                                            $exit ="invalid"
                                            Write-Host ("invalid")
                                            $pipe.Write([pscustomobject]$exit) 
                                        }  
                                    } 
                    "Complete"      {
                                        if( $_this._explorer ) { 
                                            $pipe.Write([pscustomobject]$true)
                                            $_this._explorer.Complete() 
                                            #terminateChildProcesses -all $false
                                            #$pipe.Restart()
                                        }
                                        else {
                                            $exit ="invalid"
                                            $pipe.Write([pscustomobject]$exit) 
                                        }  
                                    }
                    default         {   $pipe.Write([pscustomobject]$false) }                         
                }
            }
            else {
                #Write-Host "[server] $($pipe.GetPipeName()) received (pscustomobject) from client:"
                Write-Host ( $message | Format-Table | Out-String )
                
                Write-Host "$($message.ts_ControlFile)"
                
                if( $message.ts_ControlFile ) {
                    switch($message.ts_ControlFile) 
                    {
                        "Open-Explorer"     {                                                  
                                                $_this.newExplorer() #-command $command
                                                $pipe.Write([pscustomobject]$true)
                                            }
                        "Open-Customizer"   {                                                  
                                                $_this._explorer.ShowCustomizer($true)
                                                $_this._customizer = $_this._explorer
                                                $pipe.Write([pscustomobject]$true)
                                            }
                        "Update-Customizer" {
                                                if($_this._customizer) {
                                                    $_this._customizer.SetFilter2($message.filter)
                                                    $_this._customizer.StatusBar("Ready")
                                                    $pipe.Write([pscustomobject]$true)
                                                }
                                                else { 
                                                    #$pipe.Write([pscustomobject]$false)
                                                    $exit ="invalid"
                                                    $pipe.Write([pscustomobject]$exit) 
        
                                                }

                                            }
                        "Complete-Explorer"      {
                                                if( $_this._explorer ) { 
                                                    Connect-SRxProvisioningDatabase_JSON
                                                    $_this._explorer.Complete() 
                                                    [boolean]$isMinimized = [Win32Functions.Win32Windows]::IsIconic((Get-Process -PID $($_this._procId)).MainWindowHandle)
                                                    Write-Host ("Complete pid = $($_this._procId) Window Minimized = $isMinimized")
                                                    #Write-Host ("Complete - startup window hidden = $($_this._procHide)")

                                                    if($_this._procHide -and $isMinimized) { $_this._procTerminate = $true } 
                                                    $_this._procHide = $false
                                                    $_this._procId = $null
                                                
                                                    $pipe.Write([pscustomobject]$true)
                                                }
                                                else {
                                                    $exit ="invalid"
                                                    $pipe.Write([pscustomobject]$exit) 
                                                }  
                                            }
        
                        "Status-Explorer"   {
                                                if( $_this._explorer ) {                                                     
                                                    $_this._explorer.StatusBar($message.ts_Title) 
                                                    $pipe.Write([pscustomobject]$true)                                            
                                                }
                                                else { $pipe.Write([pscustomobject]$false)  }  
                                            } 
                        "Status-Customizer" {
                                                if( $_this._customizer ) {                                                     
                                                    $_this._customizer.StatusBar($message.ts_Title) 
                                                    $pipe.Write([pscustomobject]$true)                                            
                                                }
                                                else { $pipe.Write([pscustomobject]$false)  }  
                                            }                            

                        default             {  
                                                $exit ="invalid"
                                                $pipe.Write([pscustomobject]$exit)         
                                            }                             
                    }
                }
                else {
                    Write-Host ( $message | Format-List | Out-String )
                    $pipe.Write([pscustomobject]$true)    
                }
            }
        }
        catch {
            Write-Host($_.Exception.Message) 
            Write-Host($_.Exception) 
        } 
    }   
    hidden [System.Management.Automation.ScriptBlock] $_onExplorerMessage = {
        $message    = $($args[1])
        $pipe       = $($args[0])
        $_this      = $pipe.Caller

        Write-Host "[server] $($pipe.GetPipeName()) received ($($message.GetType().Name)) from client: $message"
        if( $_this._explorer ) {  $_this._explorer.StatusBar($message)  }

        $pipe.Write([pscustomobject]$true)
    }
    hidden [System.Management.Automation.ScriptBlock] $_onCustomizerMessage = {
        $message    = $($args[1])
        $pipe       = $($args[0])
        $_this      = $pipe.Caller

        Write-Host "[server] $($pipe.GetPipeName()) received ($($message.GetType().Name)) from client: $message"
        if( $_this._customizer ) {  $_this._customizer.StatusBar($message)  }
        
        $pipe.Write([pscustomobject]$true)
    }
    [void] Run2() {
        # Create an application context for it to all run within.
        # This helps with responsiveness, especially when clicking Exit.
        $appContext = New-Object System.Windows.Forms.ApplicationContext
        [void][System.Windows.Forms.Application]::Run($appContext)
    }
    [void] Close() {
        if($this._pipeSysTray)      { $this._pipeSysTray.Dispose() }
        if($this._pipeExplorer)     { $this._pipeExplorer.Dispose() }
        if($this._pipeCustomizer)   { $this._pipeCustomizer.Dispose() }

        $this._systray.Visible = $false
        [System.Windows.Forms.Application]::Exit() #close any opened forms

        $this._systray.dispose()
        #$window.Close()
        #[System.Diagnostics.Process]::CloseMainWindow()
        [int]$pid = [System.Diagnostics.Process]::GetCurrentProcess().Id 
        Stop-Process $pid
    }
}