PSRdSessions.psm1

<#
    Connect Method void Connect(Cassia.ITerminalServicesSession target, string password, bool synchronous), void ITerminalServicesSession.Connect(Cassi...
    Disconnect Method void Disconnect(), void Disconnect(bool synchronous), void ITerminalServicesSession.Disconnect(), void ITerminalServicesSession.Disc...
    Equals Method bool Equals(System.Object obj)
    GetHashCode Method int GetHashCode()
    GetProcesses Method System.Collections.Generic.IList[Cassia.ITerminalServicesProcess] GetProcesses(), System.Collections.Generic.IList[Cassia.ITerminalS...
    GetType Method type GetType()
    Logoff Method void Logoff(), void Logoff(bool synchronous), void ITerminalServicesSession.Logoff(), void ITerminalServicesSession.Logoff(bool sync...
    MessageBox Method void MessageBox(string text), void MessageBox(string text, string caption), void MessageBox(string text, string caption, Cassia.Remo...
    StartRemoteControl Method void StartRemoteControl(System.ConsoleKey hotkey, Cassia.RemoteControlHotkeyModifiers hotkeyModifiers), void ITerminalServicesSessio...
    StopRemoteControl Method void StopRemoteControl(), void ITerminalServicesSession.StopRemoteControl()
#>

Function Open-RdSession {
    <#
    .SYNOPSIS
        Function to connect an RDP session without the password prompt
    .DESCRIPTION
        This function provides the functionality to start an RDP session without having to type in the password
    .PARAMETER ComputerName
        This can be a single computername or an array of computers to which RDP session will be opened
    .PARAMETER User
        The user name that will be used to authenticate
    .PARAMETER Password
        The password that will be used to authenticate
    .PARAMETER Credential
        The PowerShell credential object that will be used to authenticate against the remote system
    .PARAMETER Admin
        Sets the /admin switch on the mstsc command: Connects you to the session for administering a server
    .PARAMETER RDG
        Sets the /g parameters as Remote Desktop Gateaway
    .PARAMETER MultiMon
        Sets the /multimon switch on the mstsc command: Configures the Remote Desktop Services session monitor layout to be identical to the current client-side configuration
    .PARAMETER FullScreen
        Sets the /f switch on the mstsc command: Starts Remote Desktop in full-screen mode
    .PARAMETER Public
        Sets the /public switch on the mstsc command: Runs Remote Desktop in public mode
    .PARAMETER Width
        Sets the /w:<width> parameter on the mstsc command: Specifies the width of the Remote Desktop window
    .PARAMETER Height
        Sets the /h:<height> parameter on the mstsc command: Specifies the height of the Remote Desktop window

    .NOTES
        Name: Open-RdSession
        Author: Jaap Brasser
        DateUpdated: 2016-10-28
        Version: 1.2.5
    .LINK
        https://gallery.technet.microsoft.com/scriptcenter/Connect-Mstsc-Open-RDP-2064b10b
    .EXAMPLE
        A remote desktop session to server01 will be created using the credentials of contoso\jaapbrasser
        Open-RdSession -ComputerName server01 -User open\jdoe -cred (Get-CredentialByRegistry (whoami))
    #>

    [cmdletbinding(SupportsShouldProcess,DefaultParametersetName='UserPassword')]
    param (
        [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
        [Alias('CN')]
            [string[]]     $ComputerName,
        [Parameter(ParameterSetName='UserPassword',Mandatory=$true)]
        [Alias('U','NtAccountName')] 
            [string]       $User = (whoami.exe),
        [Parameter(ParameterSetName='UserPassword',Mandatory=$true)]
        [Alias('P')] 
            [string]       $Password,
        [Parameter(ParameterSetName='Credential',Mandatory=$true)]
        [Alias('C')]
            [PSCredential] $Credential = $null,
        [Alias('A')]
            [switch]       $Admin,
        [Alias("g")]
            [string]       $RDG,
        [Alias('MM')]
            [switch]       $MultiMon,
        [Alias('F')]
            [switch]       $FullScreen,
        [Alias('Pu')]
            [switch]       $Public,
        [Alias('W')]
            [int]          $Width,
        [Alias('H')]
            [int]          $Height,
        [Alias('WT')]
            [switch]       $Wait
    )

    begin {
        [string]$MstscArguments = ''
        switch ($true) {
            {$Admin}      {$MstscArguments += '/admin '}
            {$RDG}        {$MstscArguments += "/g:$RDG "}
            {$MultiMon}   {$MstscArguments += '/multimon '}
            {$FullScreen} {$MstscArguments += '/f '}
            {$Public}     {$MstscArguments += '/public '}
            {$Width}      {$MstscArguments += "/w:$Width "}
            {$Height}     {$MstscArguments += "/h:$Height "}
        }

        if ($Credential) {
            $User     = $Credential.UserName
            $Password = $Credential.GetNetworkCredential().Password
        }
    }
    process {
        foreach ($Computer in $ComputerName) {
            $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
            $Process = New-Object System.Diagnostics.Process
            
            # Remove the port number for CmdKey otherwise credentials are not entered correctly
            if ($Computer.Contains(':')) {
                $ComputerCmdkey = ($Computer -split ':')[0]
            } else {
                $ComputerCmdkey = $Computer
            }

            $ProcessInfo.FileName    = "$($env:SystemRoot)\system32\cmdkey.exe"
            $ProcessInfo.Arguments   = "/generic:TERMSRV/$ComputerCmdkey /user:$User /pass:$($Password)"
            $ProcessInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
            $Process.StartInfo = $ProcessInfo
            if ($PSCmdlet.ShouldProcess($ComputerCmdkey,'Adding credentials to store')) {
                [void]$Process.Start()
            }

            $ProcessInfo.FileName    = "$($env:SystemRoot)\system32\mstsc.exe"
            $ProcessInfo.Arguments   = "$MstscArguments /v $Computer"
            $ProcessInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Normal
            $Process.StartInfo       = $ProcessInfo
            if ($PSCmdlet.ShouldProcess($Computer,'Connecting mstsc')) {
                [void]$Process.Start()
                if ($Wait) {
                    $null = $Process.WaitForExit()
                }
            }
        }
    }
}
function Convert-RdSession {
    <#
        .SYNOPSIS
            Converti un objet cassia.session en PSObject
        .DESCRIPTION
            retourne la session sous une forme efficiante pour interpretation
        .PARAMETER Sessions
            Cassia.Session
        .EXAMPLE
            $RDSessions = [Cassia.TerminalServicesManager]::new().GetRemoteServer('vdiv03')
            $RDSessions.Open()
            $RDSessions.GetSessions() | Convert-RdSession -DetailsTimeOut 10 -ResolveIp
        .NOTES
            Alban LOPEZ 2018
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$Sessions, # [Cassia.Impl.TerminalServicesSession]
        [int]$DetailsTimeOut,
        [switch]$ResolveIp
    )
    begin {
        $Count = 0
        $UnResolvableIP = @()
        $poolstart = (get-date)
        # $NtAccount = New-Object System.Security.Principal.NTAccount #
    }
    process {
        foreach ($Session in $Sessions) {
            if($Session -is [Cassia.Impl.TerminalServicesSession]){
                # $start = (get-date)
                $Count++
                $duree = $("$($Session.IdleTime)").split(':')
                #$NtAccountName = $Session.UserAccount
                [hashtable]@{
                    ComputerName = $Session.server.ServerName
                    SessionID = "$($Session.SessionID)"
                    State = "$($Session.ConnectionState)"
                    Sid = [string]$(if($Session.UserAccount){
                        try {
                            New-Object System.Security.Principal.NTAccount($Session.UserAccount).Translate([System.Security.Principal.SecurityIdentifier]).Value
                        } catch {
                            Write-LogStep -prefixe "L.$($_.InvocationInfo.ScriptLineNumber) %caller%" "Recuperation SID [$($Session.UserAccount)] ","$_" Error
                        }
                    }else{'-'})
                    NtAccountName = [string]$Session.UserAccount
                    IPAddress = [string]$(
                        # write-verbose "$IP : $($Session.SessionID) - $(((get-date)-$start).TotalSeconds)"
                        if($Session.WindowStationName -eq 'Console') {
                            # sur la session console sera affiche l'ip du serveur
                            [string][System.Net.Dns]::GetHostAddresses($Session.server.ServerName).IPAddressToString
                        } else {
                            # write-color $Session.UserAccount, $Session.RemoteEndPoint.Address, $Session.ClientIPAddress,$(if($Session.RemoteEndPoint.Address -match $Session.ClientIPAddress){' === '}else{' XXX '}) -fore cyan,magenta,yellow,red
                            if($Session.RemoteEndPoint.Address -and $Session.ClientIPAddress){
                                # si il y a les 2 IP on prefere ClientIPAddress, car l'autre et bizare avec les Platines
                                $IP ="$($Session.ClientIPAddress)/$($Session.RemoteEndPoint.Address)"
                            } elseif ($Session.RemoteEndPoint.Address -and $Session.RemoteEndPoint.Address -notmatch '^127\.0\.\d+\.\d+') {
                                $IP = $Session.RemoteEndPoint.Address -replace('(.+):\d*','$1')
                            } else {
                                $IP = $Session.ClientIPAddress
                            }
                            if ($IP -eq [string][System.Net.Dns]::GetHostAddresses($Session.server.ServerName).IPAddressToString) {
                                'HTML5-Direct'
                            } elseif ($IP -match '^10\.12\d\.\d+\.\d+' -and $UnResolvableIP -notcontains $IP) {
                                if ($ResolveIp) {
                                    # Write-LogStep "Tentative de resolution IP-TSG ", $IP wait
                                    $(
                                        try {
                                            $fqdn = (Get-DnsClientCache -data $IP -ea Stop).name | Sort-Object -Unique
                                            $fqdn
                                            # Write-LogStep "Get-DnsClientCache [$IP]", $fqdn OK
                                        } catch {
                                            try {
                                                $fqdn = (Resolve-DnsName $IP -Server ($Session.server.ServerName.split('.')[-2..-1] -join('.')) -ea Stop).nameHost
                                                $fqdn
                                                # Write-LogStep "Resolve-DnsName [$IP]", $fqdn OK
                                                Test-TcpPort $fqdn -port 135 -Quick | Out-Null # permet de rensegner le cacheDNS
                                            } catch {
                                                try {
                                                    $fqdn = [System.Net.Dns]::gethostentry($IP).HostName
                                                    $fqdn
                                                    # Write-LogStep "[Net.Dns]::gethostentry($IP)", $fqdn OK
                                                    Test-TcpPort $fqdn -port 135 -Quick | Out-Null # permet de rensegner le cacheDNS
                                                } catch {
                                                    $IP
                                                    $UnResolvableIP += $IP
                                                    Write-LogStep   `
                                                    -messages '',$_ Error
                                                }
                                            }
                                        }
                                        "TSG:$IP"
                                    ) -join(", `n")
                                } else {
                                    "TSG:$IP"
                                }
                            } elseif ($IP -match '^172\.16\.\d+\.\d+') {
                                'HTML5-HAProxy'
                            } else {
                                $IP
                            }
                        }
                        # write-verbose "$IP : $($Session.SessionID) - $(((get-date)-$start).TotalSeconds)"
                        )
                    ClientName = "$($Session.ClientName)"
                    Protocole = $(
                        switch -Regex ($Session.WindowStationName) {
                            '^Session' { 'Flexy-RDP' }
                            '^RDP' { 'WinTS-RDP' }
                            '^ICA' { 'Citrix-ICA' }
                            '^Console' {'VMWare-Console'}
                            Default {$Session.WindowStationName}
                        }
                    )
                    ClientBuildNumber = "$($Session.ClientBuildNumber)" # [System.DateTime]
                    LoginTime = $( if ("$($Session.LoginTime)") {$Session.LoginTime.ToString()} else {"-"})
                    DisconnectTime = $( if ("$($Session.DisconnectTime)") {$Session.DisconnectTime.ToString()} else {"-"})
                    ConnectTime = $( if ("$($Session.ConnectTime)") {$Session.ConnectTime.ToString()} else {"-"})
                    Inactivite = if($duree){"$($duree[0].replace('.','j '))h $($duree[1])m $($duree[2].split('.')[0])s"}else{$null}
                    Screen = "$($Session.ClientDisplay.HorizontalResolution)*$($Session.ClientDisplay.VerticalResolution) / $($Session.ClientDisplay.BitsPerPixel)Bits"
                    Process = $( if ($DetailsTimeOut -and (((get-date)-$poolstart).TotalSeconds -lt $DetailsTimeOut)) {$Session.getprocesses().ProcessName} )
                    # Timer = ((get-date)-$start).TotalSeconds
                }
            } elseif ($Session) {
                # [hashtable]
                $Session
            }
        }
    }
    end {
        Write-LogStep "Collecte terminee [$($Session.server.ServerName)] ", "[$($Count) RdChannels]" OK
    }
}
function Get-RdComputer {
    <#
        .SYNOPSIS
            Construis l'object destiner a interoger les sessions TS
        .DESCRIPTION
            Retourne un object Cassia qui pourra etre utiliser et reutiliser par la suite
        .PARAMETER TSRemoteServer
            Computer cassia connector [Cassia.Impl.TerminalServer]
        .PARAMETER CassiaErrorServer
            Object issue de la fonction Get-RdComputer, mais incompatible pour la suite
        .PARAMETER ComputerName
            Fqdn de l'ordinateur a interoger, si il est fournis seul les autres parametre (IP, Port...) seront calcule
        .PARAMETER IP
            Adresse IP
        .PARAMETER Port22
            Etat du port Tcp-IP 22, si fourni il ne sera pas reteste
        .PARAMETER Port135
            Etat du port Tcp-IP 135, si fourni il ne sera pas reteste
        .PARAMETER Port445
            Etat du port Tcp-IP 445, si fourni il ne sera pas reteste
        .EXAMPLE
            contruis le handler Cassia pour vdiv03 et vdiv05
            'vdiv03', 'vdiv05' | Get-RdComputer
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'cassia')]
            [Cassia.Impl.TerminalServer]$TSRemoteServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'CassiaError')]
            [hashtable]$CassiaErrorServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'Simple')]
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$ComputerName = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$IP = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port22 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port135 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port445 = $null
    )
    begin {
        $TSManager = New-Object Cassia.TerminalServicesManager # [Cassia.TerminalServicesManager]::new()
        $SrvList = @()
        $PipeStart = (get-date)
    }
    process {
        $ThisStart = (get-date)
        # Write-Object $PSCmdlet.ParameterSetName -foreGroundColor DarkBlue
        try {
            switch($PSCmdlet.ParameterSetName){
                'cassia' {
                    $TSRemoteServer.Open()
                    if($TSRemoteServer.IsOpen){
                        $TSRemoteServer
                    } else {
                        $IP = '-'
                        $State = 'Connexion Failed'
                        Throw '[Cassia.TerminalServicesManager] Connexion Failed !'
                    }
                }
                'Simple' {
                    try{
                        $IP = [string][System.Net.Dns]::GetHostAddresses($ComputerName).IPAddressToString
                        [PSCustomObject]@{
                            ComputerName = $ComputerName
                            IP           = $IP
                            Port22       = (Test-TcpPort $ComputerName -port 22 -Confirm -Quick)
                            Port135      = (Test-TcpPort $ComputerName -port 135 -Confirm -Quick)
                            Port445      = (Test-TcpPort $ComputerName -port 445 -Confirm -Quick)
                        } | Get-RdComputer
                    } catch {
                        $IP = '-'
                        $State = 'HS'
                        Throw '[Pas de resolution DNS]'
                    }
                }
                'Dragonfly' {
                    if ($IP -like '*.*.*.*') {
                        if ($Port135 -and $Port445) {
                            $TSRemoteServer = $TSManager.GetRemoteServer($ComputerName)
                            $TSRemoteServer.Open()
                            if($TSRemoteServer.IsOpen){
                                $TSRemoteServer
                            } else {
                                $State = 'Connexion Failed'
                                Throw '[Cassia.TerminalServicesManager] Connexion Failed !'
                            }
                        } elseif ($Port22) {
                            $State = 'Linux'
                            Throw '[Impossible de lister les Sessions]'
                        } else {
                            # [Cassia.Impl.TerminalServicesSession]::new($TSRemoteServer,0)
                            $State = 'HS'
                            Throw '[Tcp-Ip Down]'
                        }
                    }
                }
                'CassiaError' {
                    $CassiaErrorServer
                }
            }
        } catch {
            Write-LogStep -prefixe "L.$($_.InvocationInfo.ScriptLineNumber) %caller%" "Collecte des Sessions [$computerName] ","$_" Error
            # [PSCustomObject]
            [hashtable]@{
                ComputerName = $ComputerName
                SessionID = '-'
                State = $State
                Sid = '-'
                NtAccountName = $null
                IPAddress = $IP
                ClientName = '-'
                Protocole = '-'
                ClientBuildNumber = '-'
                LoginTime = '-'
                DisconnectTime = "Error L.$($_.InvocationInfo.ScriptLineNumber): $_"
                ConnectTime = '-'
                Inactivite = "$(((get-date)-$ThisStart).TotalSeconds) Sec"
                Screen = '-'
                Process = $null
            }
        }
    }
    end {
        # Write-LogStep 'Collecte des RdHandler ', "Duree $(((get-date)-$PipeStart).TotalSeconds) Sec" ok
    }
}
function Get-RdSession {
    <#
        .SYNOPSIS
            Interroge des serveurs a la recherche de session
        .DESCRIPTION
            retourne une liste d'entree relative au session et serveur
        .PARAMETER TSRemoteServer
            Computer cassia connector [Cassia.Impl.TerminalServer]
        .PARAMETER CassiaErrorServer
            Object issue de la fonction Get-RdComputer, mais incompatible pour la suite
        .PARAMETER ComputerName
            Fqdn de l'ordinateur a interoger, si il est fournis seul les autres parametre (IP, Port...) seront calcule
        .PARAMETER IP
            Adresse IP
        .PARAMETER Port22
            Etat du port Tcp-IP 22, si fourni il ne sera pas reteste
        .PARAMETER Port135
            Etat du port Tcp-IP 135, si fourni il ne sera pas reteste
        .PARAMETER Port445
            Etat du port Tcp-IP 445, si fourni il ne sera pas reteste
        .PARAMETER Identity
            filtre ID ou NtAccountName
        .EXAMPLE
            Se connecte a 2 user et cherche la session 6 sur chacun d'entre eux
            'vps.opt2','vdiv03' | Get-RdComputer | Get-RdSession -Identity 6
        .EXAMPLE
            se connecte au vdiv03 et cherche la session '*\user'
            Get-RdComputer vdiv03 | Get-RdSession -Identity '*\user'
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [cmdletbinding(DefaultParameterSetName='ComputerName')]
    param (
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'cassia')]
            [Cassia.Impl.TerminalServer]$TSRemoteServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'CassiaError')]
            [hashtable]$CassiaErrorServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'Simple')]
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$ComputerName = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$IP = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port22 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port135 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port445 = $null,
        [alias('SessionId','NtAccountName','UserAccount')]
        [Parameter(ParameterSetName = 'cassia')]
        [Parameter(ParameterSetName = 'CassiaError')]
        [Parameter(ParameterSetName = 'Simple')]
        [Parameter(ParameterSetName = 'Dragonfly')]
            $Identity = $null
    )
    begin {
        $PipeStart = (get-date)
    }
    process {
        # Write-Object $PSCmdlet.ParameterSetName -foreGroundColor red
        switch($PSCmdlet.ParameterSetName){
            'cassia' {
                $TSRemoteServer.Open()
                if($TSRemoteServer.IsOpen){
                    try {
                        if($Identity -is [int]){
                            $TSRemoteServer.GetSession($Identity)
                        } elseif($Identity -is [string]){
                            $TSRemoteServer.GetSessions() | Where-Object{$_.UserAccount -like $Identity}
                        } else {
                            $TSRemoteServer.GetSessions()
                        }
                    # } catch [System.Runtime.InteropServices.ExternalException] {
                        # Write-LogStep 'Collecte des RdSession ', $_ Error
                    } catch {
                        [hashtable]@{
                            ComputerName = $TSRemoteServer.servername
                            SessionID = '-'
                            State = 'HS'
                            Sid = '-'
                            NtAccountName = $null
                            IPAddress = $null
                            ClientName = '-'
                            Protocole = '-'
                            ClientBuildNumber = '-'
                            LoginTime = '-'
                            DisconnectTime = "Error L.$($_.InvocationInfo.ScriptLineNumber): $_"
                            ConnectTime = '-'
                            Inactivite = '-'
                            Screen = '-'
                            Process = $null
                        }
                        Write-LogStep "Collecte refuser [$($TSRemoteServer.servername)]", $_ Error
                    }
                }
            }
            'Simple' {
                $ComputerName | Get-RdComputer | Get-RdSession -Identity $Identity
            }
            'Dragonfly' {
                [PSCustomObject]@{
                    ComputerName = $ComputerName
                    IP           = $IP
                    Port22       = $Port22
                    Port135      = $Port135
                    Port445      = $Port445
                } | Get-RdComputer | Get-RdSession -Identity $Identity
            }
            'CassiaError' {
                $CassiaErrorServer
            }
        }
    }
    end {
        Write-LogStep 'Collecte des RdSession ', "Duree $(((get-date)-$PipeStart).TotalSeconds) Sec" ok
    }
}
function Stop-RdSession {
    <#
        .SYNOPSIS
            Ferme une ou plusieurs sessions distante
        .DESCRIPTION
            Retourne les objects sessions qui ont appliqué le logOff()
        .PARAMETER TSRemoteServer
            Computer cassia connector [Cassia.Impl.TerminalServer]
        .PARAMETER CassiaErrorServer
            Object issue de la fonction Get-RdComputer, mais incompatible pour la suite
        .PARAMETER ComputerName
            Fqdn de l'ordinateur a interoger, si il est fournis seul les autres parametre (IP, Port...) seront calcule
        .PARAMETER IP
            Adresse IP
        .PARAMETER Port22
            Etat du port Tcp-IP 22, si fourni il ne sera pas reteste
        .PARAMETER Port135
            Etat du port Tcp-IP 135, si fourni il ne sera pas reteste
        .PARAMETER Port445
            Etat du port Tcp-IP 445, si fourni il ne sera pas reteste
        .PARAMETER Identity
            filtre ID ou NtAccountName
        .EXAMPLE
            Stop-RdSession
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'cassia')]
            [Cassia.Impl.TerminalServicesSession]$TerminalServicesSession = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'CassiaError')]
            [hashtable]$CassiaErrorServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'Simple')]
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$ComputerName = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$IP = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port22 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port135 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port445 = $null,
        [alias('SessionId','NtAccountName','UserAccount')]
        [Parameter(ParameterSetName = 'CassiaError')]
        [Parameter(ParameterSetName = 'Simple')]
        [Parameter(ParameterSetName = 'Dragonfly')]
            $Identity
    )
    begin {
        $Targets = @()
    }
    process {
        # Write-Object $PSCmdlet.ParameterSetName
        switch($PSCmdlet.ParameterSetName){
            'cassia' {
                $Targets += $TerminalServicesSession
            }
            'Simple' {
                $ComputerName | Get-RdComputer | Get-RdSession -Identity $Identity | Stop-RdSession
            }
            'Dragonfly' {
                [PSCustomObject]@{
                    ComputerName = $ComputerName
                    IP           = $IP
                    Port22       = $Port22
                    Port135      = $Port135
                    Port445      = $Port445
                } | Get-RdComputer | Get-RdSession -Identity $Identity | Stop-RdSession
            }
            'CassiaError' {
                $CassiaErrorServer
            }
        }
    }
    end {
        foreach ($Target in $Targets) {
            try {
                $Target.Logoff()
                $Target
                Write-LogStep "Fermeture de session [$($Target.Server.ServerName):$($Target.SessionId)]","$([string]$Target.UserAccount)" OK
            } catch {
                Write-LogStep "Fermeture de session ",$PSBoundParameters Error
            }
        }
    }
}
function Send-RdSession {
    <#
        .SYNOPSIS
            envoy un Message a une session distante
        .DESCRIPTION
            [Descriptif en quelques lignes]
        .PARAMETER TSRemoteServer
            Computer cassia connector [Cassia.Impl.TerminalServer]
        .PARAMETER CassiaErrorServer
            Object issue de la fonction Get-RdComputer, mais incompatible pour la suite
        .PARAMETER ComputerName
            Fqdn de l'ordinateur a interoger, si il est fournis seul les autres parametre (IP, Port...) seront calcule
        .PARAMETER IP
            Adresse IP
        .PARAMETER Port22
            Etat du port Tcp-IP 22, si fourni il ne sera pas reteste
        .PARAMETER Port135
            Etat du port Tcp-IP 135, si fourni il ne sera pas reteste
        .PARAMETER Port445
            Etat du port Tcp-IP 445, si fourni il ne sera pas reteste
        .PARAMETER Identity
            filtre ID ou NtAccountName
        .PARAMETER Title
            Title en haut du PopUp
        .PARAMETER Message
            Corp du PopUp
        .PARAMETER Footer
            Signature en bas du message
        .EXAMPLE
            liste toutes les sessions Open sur vdiv05 puis envoy un message
            'vdiv05' | Get-RdSession -identity 'open\*' | send-RdSession -Message 'Merci de fermer vos session'
        .EXAMPLE
            liste toutes les sessions cecaf sur vdiv05 puis envoy un message
            $sessions = 'vdiv05' | Get-RdSession -identity '*alopez'
            $sessions | Send-RdSession -Message 'Merci de fermer vos session'
            start-sleep -s 30
            $sessions | Stop-RdSession
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'cassia')]
            [Cassia.Impl.TerminalServicesSession]$TerminalServicesSession = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'CassiaError')]
            [hashtable]$CassiaErrorServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'Simple')]
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$ComputerName = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$IP = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port22 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port135 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port445 = $null,
        [alias('SessionId','NtAccountName','UserAccount')]
        [Parameter(ParameterSetName = 'CassiaError')]
        [Parameter(ParameterSetName = 'Simple')]
        [Parameter(ParameterSetName = 'Dragonfly')]
            $Identity,
        [string] $Title = 'Message de votre support',
        [string] $Message = '...',
        [string] $Footer = "$(whoami), Coaxis-Asp (0825 82 82 57)"
    )
    begin {
        $Targets = @()
    }
    process {
        # Write-Object $PSCmdlet.ParameterSetName -fore DarkMagenta
        switch($PSCmdlet.ParameterSetName){
            'cassia' {
                $Targets += $TerminalServicesSession
            }
            'Simple' {
                $Targets += $ComputerName | Get-RdComputer | Get-RdSession -Identity $Identity # | Send-RdSession -Title $Title -Message $Message -Footer $Footer
            }
            'Dragonfly' {
                $Targets += [PSCustomObject]@{
                    ComputerName = $ComputerName
                    IP           = $IP
                    Port22       = $Port22
                    Port135      = $Port135
                    Port445      = $Port445
                } | Get-RdComputer | Get-RdSession -Identity $Identity # | Send-RdSession -Title $Title -Message $Message -Footer $Footer
            }
            'CassiaError' {
                $CassiaErrorServer
            }
        }
    }
    end {
        foreach ($Target in ($Targets | Where-Object{$_.UserAccount})) {
            try {
                $Target.MessageBox("$Message`n`n$Footer",$Title)
                $Target
                Write-LogStep "Message en session [$($Target.Server.ServerName):$($Target.SessionId)]","$([string]$Target.UserAccount)" OK
            } catch {
                Write-LogStep "Message en session ",$PSBoundParameters Error
            }
        }
    }
}
function Request-RdSession {
    <#
        .SYNOPSIS
            Pose une Question Yes/No a une session distante
        .DESCRIPTION
            Fais apparaitre une PopUp avec la quetion et la possibilité de repondre par oui / non
        .PARAMETER TSRemoteServer
            Computer cassia connector [Cassia.Impl.TerminalServer]
        .PARAMETER CassiaErrorServer
            Object issue de la fonction Get-RdComputer, mais incompatible pour la suite
        .PARAMETER ComputerName
            Fqdn de l'ordinateur a interoger, si il est fournis seul les autres parametre (IP, Port...) seront calcule
        .PARAMETER IP
            Adresse IP
        .PARAMETER Port22
            Etat du port Tcp-IP 22, si fourni il ne sera pas reteste
        .PARAMETER Port135
            Etat du port Tcp-IP 135, si fourni il ne sera pas reteste
        .PARAMETER Port445
            Etat du port Tcp-IP 445, si fourni il ne sera pas reteste
        .PARAMETER Identity
            filtre ID ou NtAccountName
        .PARAMETER Title
            Title en haut du PopUp
        .PARAMETER Message
            Corp du PopUp
        .PARAMETER Footer
            Signature en bas du message
        .PARAMETER TimeOut
            Delais pour repondre
        .EXAMPLE
            liste toutes les sessions Open sur vdiv05 puis envoy un message
            'vdiv05' | Get-RdSession -identity 'open\*' | Request-RdSession -Message 'Etes vous majeur ?' | ft UserName,request,answer
        .EXAMPLE
            liste toutes les sessions cecaf sur vdiv05 puis envoy un message
            $sessions = 'vdiv05' | Get-RdSession -identity '*alopez'
            $sessions | Request-RdSession -title 'interdi au mineur' -Message 'Etes vous majeur ?'
            $sessions | ?{$_.answer -like 'no'} | Stop-RdSession
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'cassia')]
            [Cassia.Impl.TerminalServicesSession]$TerminalServicesSession = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'CassiaError')]
            [hashtable]$CassiaErrorServer = $null,
        [Parameter(ValueFromPipeline = $true,  Mandatory = $true, ParameterSetName = 'Simple')]
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$ComputerName = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            [string]$IP = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port22 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port135 = $null,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory = $true, ParameterSetName = 'Dragonfly')]
            $Port445 = $null,
        [alias('SessionId','NtAccountName','UserAccount')]
        [Parameter(ParameterSetName = 'CassiaError')]
        [Parameter(ParameterSetName = 'Simple')]
        [Parameter(ParameterSetName = 'Dragonfly')]
            $Identity,
        [string] $Title = 'Message de votre support',
        [string] $Message = '...',
        [string] $Footer = "$(whoami), Coaxis-Asp (0825 82 82 57)",
        [int] $TimeOut = 60
    )
    begin {
        $Targets = @()
    }
    process {
        # Write-Object $PSCmdlet.ParameterSetName -fore DarkMagenta
        switch($PSCmdlet.ParameterSetName){
            'cassia' {
                $Targets += $TerminalServicesSession
            }
            'Simple' {
                $Targets += $ComputerName | Get-RdComputer | Get-RdSession -Identity $Identity # | Request-RdSession -Title $Title -Message $Message -Footer $Footer
            }
            'Dragonfly' {
                $Targets += [PSCustomObject]@{
                    ComputerName = $ComputerName
                    IP           = $IP
                    Port22       = $Port22
                    Port135      = $Port135
                    Port445      = $Port445
                } | Get-RdComputer | Get-RdSession -Identity $Identity # | Request-RdSession -Title $Title -Message $Message -Footer $Footer
            }
            'CassiaError' {
                $CassiaErrorServer
            }
        }
    }
    end {
        foreach ($Target in ($Targets | Where-Object{$_.UserAccount})) {
            try {
                Write-LogStep "Question en session [$($Target.Server.ServerName):$($Target.SessionId)]",$Target.UserAccount wait
                $ClickOn = $Target.MessageBox(
                            "$Message`n`n$Footer", $Title,
                            [Cassia.RemoteMessageBoxButtons]::YesNo,
                            [Cassia.RemoteMessageBoxIcon]::Warning,
                            [Cassia.RemoteMessageBoxDefaultButton]::Button2,
                            [Cassia.RemoteMessageBoxOptions]::TopMost,
                            [timespan]::FromSeconds($TimeOut),
                            $true)
                $Target | Add-Member -Name Request -Value $Message -MemberType NoteProperty
                $target | Add-Member -Name Answer -Value $ClickOn -MemberType NoteProperty
                switch ($ClickOn){
                    'Timeout' {
                        Write-LogStep $Message,"L'utilisateur n'as pas repondu dans le [$timeOut Sec]" Error
                    }
                    Default {
                        Write-LogStep $Message,"Reponce l'utilisateur [$ClickOn]" ok
                    }
                }
            } catch {
                Write-LogStep "Question en session ",$PSBoundParameters Error
                Write-Host $_ -fore Red
            }
            $Target
        }

        # void MessageBox(string text)
        # void MessageBox(string text, string caption)
        # void MessageBox(string text, string caption, Cassia.RemoteMessageBoxIcon icon),
        # Cassia.RemoteMessageBoxResult MessageBox(string text,
        # string caption,
        # Cassia.RemoteMessageBoxButtons buttons,
        # Cassia.RemoteMessageBoxIcon icon,
        # Cassia.RemoteMessageBoxDefaultButton defaultButton,
        # Cassia.RemoteMessageBoxOptions options,
        # timespan timeout,
        # bool synchronous)
        # void ITerminalServicesSession.MessageBox(string text)
        # void ITerminalServicesSession.MessageBox(string text, string caption)
        # void ITerminalServicesSession.MessageBox(string text, string caption, Cassia.RemoteMessageBoxIcon icon)
        # # Cassia.RemoteMessageBoxResult ITerminalServicesSession.MessageBox('string text',
        # 'string caption',
        # [Cassia.RemoteMessageBoxButtons]::AbortRetryIgnore,
        # [Cassia.RemoteMessageBoxIcon]::Warning,
        # [Cassia.RemoteMessageBoxDefaultButton]::Button2,
        # [Cassia.RemoteMessageBoxOptions]::TopMost,
        # 3,
        # $true)
    }
}


# Export-ModuleMember -Function Convert-RdSession, Get-RdSession
Write-LogStep 'Chargement du module ',$PSCommandPath ok