Sintez.Module.RDS.psm1

function Install-SintezRDSModuleServer {


<#
    .Synopsis
    Add/Remove settings for RDS module on server side.
 
    .Description
    Add/Remove user/group to RDP-Tcp administrator group settings on server side (ONLY RDSH servers).
 
    This script MUST be started as local Administrator.
  
    .Parameter Domain
    -Domain [-D] - Domain name. For domain.com it should be just DOMAIN.
 
    .Parameter Group
    -Group [-G] - Group of users who allow to connect (shadow) to the user session.
 
    .Parameter Remove
    -Remove [-R] - Clear all custom groups in RDP security settings (reset param).
 
    .Parameter View
    -View [-V] - Show all groups from RDP security settings tab.
 
    .Parameter RDSH
    -RDSH [-SH] - Remote host
 
    .Parameter Cred
    -Cred [-C] - Credentials switch. Enforce credential form.
 
    .Example
    # Add RDS security group with administrator rights (Shadow, Logoff, Disconnect and etc.):
    Install-SintezRDSModuleServer -Domain DOMAIN -Group rds_support_team
 
    .Example
    # Clear all custom groups in RDP security settings:
    Install-SintezRDSModuleServer -R
 
    .Example
    # Clear all custom groups in RDP security settings (Remotely):
    Install-SintezRDSModuleServer -R -H RDSH1,RDSH2,RDSH3 -C
 
    .Example
    # Show all groups in RDP-Tcp security settings:
    Install-SintezRDSModuleServer -View -H RDSH1,RDSH2,RDSH3
 
    .LINK
    http://www.heavenbay.ru/app/sintez/help/module/rds#installserver
#>



    [CmdletBinding()]
    Param(
        [alias("SH")]
        [array]$RDSH,

        [alias("D")]
        [string]$Domain,
    
        [alias("G")]
        [string]$Group,

        [alias("R")]
        [switch]$Remove,
        [alias("V")]
        [switch]$View,
        [alias("C")]
        [switch]$Cred
    )

    $ErrorActionPreference = "stop"

    if (!$RDSH) {[array]$RDSH = $ENV:COMPUTERNAME}

    if ($Cred -eq $true) {
        [PSCredential]$Cred = Get-Credential
    } else {
        [PSCredential]$Cred = [System.Management.Automation.PSCredential]::Empty
    }

    if ($Remove -eq $true) {
        foreach ($SH in $RDSH) {
            Write-Host ""
            Write-Host "Server is $SH`:"
            Try {
                ((gwmi -ComputerName $SH -Credential $Cred -Namespace "root\CIMV2\TerminalServices" -Class Win32_TSPermissionsSetting).where({$_.TerminalName -eq "RDP-Tcp"})).RestoreDefaults() | Out-Null
                If (!$Error) {Write-Host "Done" -BackgroundColor Black -ForegroundColor Green}
            }
            Catch [System.Management.Automation.MethodInvocationException] {
                Write-Host "Check that RDS-RD-Server role is installed on this PC." -BackgroundColor Black -ForegroundColor Red
            }
            Catch [System.Runtime.InteropServices.COMException] {
                Write-Host "RDSH is unavailable. Probably wrong IP/FQDN or firewall issues." -BackgroundColor Black -ForegroundColor Red
            }
            Catch [System.UnauthorizedAccessException] {
                Write-Host "Access to a remote broker is denided. Start cmdlet with a key '-C' to set the right credentials." -BackgroundColor Black -ForegroundColor Red
                Write-Host ""
                Break
            }

        }

        Write-Host ""
        Write-Host "Complited!"
        Write-Host ""
        break
    }

    if ($View -eq $true) {
        foreach ($SH in $RDSH) {
            Write-Host ""
            Write-Host "Server is $SH`:"
            Try {
                $v = ((gwmi -ComputerName $SH -Credential $Cred -Namespace "root\CIMV2\TerminalServices" -Class Win32_TSPermissionsSetting).where({$_.TerminalName -eq "RDP-Tcp"})).StringSecurityDescriptor
                [regex]::matches($v, "S-1-5-\d+-\d+-\d+-\d+-\d+").Groups.Value | %{Write-Host (New-Object System.Security.Principal.SecurityIdentifier($_)).Translate([System.Security.Principal.NTAccount]).Value -ForegroundColor Yellow -BackgroundColor Black}
            }
            Catch [System.Management.Automation.PSArgumentException] {
                Write-Host "There are no groups." -ForegroundColor Yellow -BackgroundColor Black
            }
            Catch [System.Runtime.InteropServices.COMException] {
                Write-Host "RDSH is unavailable. Probably wrong IP/FQDN or firewall issues." -BackgroundColor Black -ForegroundColor Red
            }
            Catch [System.UnauthorizedAccessException] {
                Write-Host "Access to a remote broker is denided. Start cmdlet with a key '-C' to set the right credentials." -BackgroundColor Black -ForegroundColor Red
                Write-Host ""
                Break
            }

        }

        Write-Host ""
        Write-Host "Complited!"
        Write-Host ""
        break
    }

    $Group = $Domain + "\" + $Group
    foreach ($SH in $RDSH) {
        Write-Host ""
        Write-Host "Server is $SH`:"
        Try {
            ((gwmi -ComputerName $SH -Credential $Cred -Namespace "root\CIMV2\TerminalServices" -Class Win32_TSPermissionsSetting).where({$_.TerminalName -eq "RDP-Tcp"})).AddAccount($Group,2) | Out-Null
            If (!$Error) {Write-Host "Done" -BackgroundColor Black -ForegroundColor Green}
        }
        Catch [System.Runtime.InteropServices.COMException] {
            Write-Host "RDSH is unavailable. Probably wrong IP/FQDN or firewall issues." -BackgroundColor Black -ForegroundColor Red
        }
        Catch [System.Management.Automation.MethodInvocationException] {
            Write-Host "Wrong domain/group. Please restart script with right params." -ForegroundColor Red -BackgroundColor Black
            Break
        }
        Catch [System.UnauthorizedAccessException] {
            Write-Host "Access to a remote broker is denided. Start cmdlet with a key '-C' to set the right credentials." -BackgroundColor Black -ForegroundColor Red
            Write-Host ""
            Break
        }
    }

    Write-Host ""
    Write-Host "Complited!"
    Write-Host ""

}

function Install-SintezRDSModuleClient {


<#
    .Synopsis
    Add/Remove settings for RDS module on client PC.
 
    .Description
    Add/Remove registry tree "rdsmc" and .js file (WINDIR)
    for SINTEZ App RDS module on client PC.
 
    This script MUST be started as local Administrator.
  
    .Parameter Remove
    -Remove [-R] - Uninstall changes.
 
    .Example
    # Install RDS module settings:
    Install-SintezRDSModuleClient
 
    .Example
    # Uninstall RDS module settings:
    Install-SintezRDSModuleClient -Remove
 
    .LINK
    http://www.heavenbay.ru/app/sintez/help/module/rds#installclient
#>



    [CmdletBinding()]
    Param(
        [switch]$Remove
    )

    $win = $ENV:SYSTEMROOT
    $winjs = $win -replace "\\","\\"
    $RegPath = "HKLM:\SOFTWARE\Classes\rdsmc"
    $ErrorActionPreference = "stop"

    if ($Remove -eq $true) {

        Try {
            Remove-Item -Path $RegPath -Force -Recurse
        }
        Catch [System.Security.SecurityException] {
            Write-Host "Please, start new powershell session with local administrator rights and execute the cmdlet again." -BackgroundColor Black -ForegroundColor Red
            Write-Host ""
            Break
        }
        Catch [System.Management.Automation.ItemNotFoundException] {
            Write-Host "Registry: no item. Skipped..." -BackgroundColor Black -ForegroundColor Yellow
        }

        Try {
            Remove-Item -Path "$win\SnitezRDSMC.js" -Force
        }
        Catch [System.Management.Automation.ItemNotFoundException] {
            Write-Host "JS file: no item. Skipped..." -BackgroundColor Black -ForegroundColor Yellow
        }

        Write-Host ""
        Write-Host "Complited" -BackgroundColor Black -ForegroundColor Green
        Write-Host ""
        break
    }

    Try {
        New-Item -Path $RegPath -Value "URL:Remote Desktop Connection Management Console" -Force | Out-Null
    }
    Catch [System.Security.SecurityException] {
        Write-Host "Please, start new powershell session with local administrator rights and execute the cmdlet again." -BackgroundColor Black -ForegroundColor Red
        Write-Host ""
        Break
    }

    New-ItemProperty -Path $RegPath -Name "URL Protocol" -Force | Out-Null
    New-Item -Path "$RegPath\DefaultIcon" -Value "$win\System32\mstsc.exe" -Force | Out-Null
    New-Item -Path "$RegPath\shell\open\command" -Value "wscript.exe $win\SnitezRDSMC.js %1" -Force | Out-Null
    
    [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("
        dmFyIHN0ckFyZ3M9KFdTY3JpcHQuQXJndW1lbnRzKDApKQp2YXIgcHJlZml4PSdyZHNtYzovLycKc3RyQXJncz1zdHJBcmdzLnJlcGxhY2UocHJlZml4LCAn
        JykKc3RyQXJncz1zdHJBcmdzLnNwbGl0KCcvJykKdmFyIHNoZWxsID0gbmV3IEFjdGl2ZVhPYmplY3QoIldTY3JpcHQuU2hlbGwiKQppZiAoc3RyQXJnc1sw
        XSA9PSAic2hhZG93IikgewogICAgdmFyIGFwcD0nJVdJTkRJUiVcXHN5c3RlbTMyXFxtc3RzYy5leGUnCiAgICBzaGVsbC5FeGVjKGFwcCArICIgL3Y6IiAr
        IHN0ckFyZ3NbMV0gKyAiIC9zaGFkb3c6IiArIHN0ckFyZ3NbMl0gKyAiIC9jb250cm9sIC9ub2NvbnNlbnRwcm9tcHQiKQp9IGVsc2UgaWYgKHN0ckFyZ3Nb
        MF0gPT0gIm1zcmEiKSB7CiAgICB2YXIgYXBwPSclV0lORElSJVxcc3lzV09XNjRcXG1zcmEuZXhlJzsKICAgIHNoZWxsLkV4ZWMoYXBwICsgIiAvb2ZmZXJS
        QSAiICsgc3RyQXJnc1sxXSkKfSBlbHNlIGlmIChzdHJBcmdzWzBdID09ICJSRFAiKSB7CiAgICB2YXIgYXBwPSclV0lORElSJVxcc3lzdGVtMzJcXG1zdHNj
        LmV4ZSc7CiAgICBzaGVsbC5FeGVjKGFwcCArICIgL3Y6IiArIHN0ckFyZ3NbMV0pCn0gZWxzZSB7CiAgICBhbGVydCgnU29tZXRoaW5nIGdvZXMgd3Jvbmch
        Jyk7Cn0K
    "
)) | Out-File -FilePath "$win\SnitezRDSMC.js" -Force 

    Write-Host ""
    Write-Host "Complited!" -BackgroundColor Black -ForegroundColor Green
    Write-Host ""
}

function Start-RDSConnect {


<#
    .Synopsis
    Start RDS console.
 
    .Description
    Used for getting user list and starting RDP connection.
  
    .Parameter Broker
    Broker [B] - RDCB FQDN. Ex.: RDCB1.domain.com
 
    .Parameter Credential
    Credential [C] - Connection credentials switch. No params are needed.
 
    .Example
    # Start console with credentials prompt:
    Start-RDSConnect -B RDCB1.domain.com -C
 
    .Example
    # Start console without credentials prompt:
    Start-RDSConnect -Broker RDCB1.domain.com
 
    .LINK
    http://www.heavenbay.ru/app/sintez/help/module/rds#console
#>



    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true)]
        [alias("B")]
        [string]$Broker,
    
        [alias("C")]
        [switch]$Cred

    )

    if ($Cred -eq $true) {
        [PSCredential]$Cred = Get-Credential
    } else {
        [PSCredential]$Cred = [System.Management.Automation.PSCredential]::Empty
    }

    $col = @{}
    $newCol = @{}
    
    Try {
        Get-WmiObject -Credential $Cred -ComputerName $Broker -Query "SELECT Alias, Name FROM Win32_RDSHCollection" -Namespace root\CIMv2\rdms | %{$col.Add($_.alias, $_.name)}
    }
    Catch [System.UnauthorizedAccessException] {
        Write-Host "Access to a remote broker is denided. Start cmdlet with a key '-C' to set the right credentials." -BackgroundColor Black -ForegroundColor Red
        Write-Host ""
        Break
    }
    Catch [System.Runtime.InteropServices.COMException] {
        Write-Host "Broker is unavailable. Probably wrong IP/FQDN or firewall issues." -BackgroundColor Black -ForegroundColor Red
        Write-Host ""
        Break
    }

    Get-WmiObject -Credential $Cred -ComputerName $Broker -Query "SELECT Name, CollectionAlias FROM Win32_RDSHServer" -Namespace root\CIMv2\rdms | %{$newCol.Add(($_.Name),$col[$_.CollectionAlias])}

    function getStateName([int]$StateId)
    {
      [string]$rez = "###";
      switch ($StateId)
      {
        0 {$rez = "Active"}
        1 {$rez = "Active, Minimized"}
        2 {$rez = "Query"}
        3 {$rez = "Shadow"}
        4 {$rez = "Disconnected"}
        5 {$rez = "Idle"}
        6 {$rez = "Listen"}
        7 {$rez = "Reset"}
        8 {$rez = "Down"}
        9 {$rez = "Init"}
        default {$rez = "Invalid State"}
      }
      return $rez
    }

    function SessionAction {
        Param (
            [parameter(ValueFromPipelineByPropertyName)]
            [int[]]$SID,

            [parameter(ValueFromPipelineByPropertyName)]
            [string[]]$UserName,

            [parameter(ValueFromPipelineByPropertyName)]
            [string[]]$Host
        )

        Begin {
            $Sessions = @()
        }
        Process {
            $Sessions += "$UserName;$SID;$Host"
        }
        End {
            If ($Sessions.Count -le 0) {
                Write-Host ""
                Write-Host "No sessions. Do nothing."
                Write-Host ""
            }
            ElseIf ($Sessions.Count -eq 1) {
                start-process rdsmc://shadow/$Host/$SID
            }
            Else {
                Write-Host "It's a bad idea to start 100500 RDP sessions. I limit them to 2." -BackgroundColor Black -ForegroundColor Yellow
                Write-Host ""

                foreach($S in $Sessions[0..1]) {
                    [int]$SID = $S.Split(";")[1]
                    [string]$Host = $S.Split(";")[2]
                    start-process rdsmc://shadow/$Host/$SID
                }
            }
        }
    }

    Get-WmiObject -Credential $Cred -ComputerName $Broker -Namespace "root\CIMv2" -Query "SELECT UserName,IdleTime,CreateTime,HostServer,DomainName,SessionState,UnifiedSessionID FROM Win32_SessionDirectorySessionEx" `
    | Select UserName,`
    @{Label="SID";Expression={$_.UnifiedSessionID}},`
    @{Label="Host";Expression={$_.HostServer}},`
    @{Label="Activity";Expression={getStateName($_.SessionState)}},`
    @{Label="Collection";Expression={$newCol[$_.HostServer]}},`
    @{Label="Creation Time";Expression={[datetime]::ParseExact(($_.CreateTime -replace "\..*",""),"yyyyMMddHHmmss", $null)}},`
    @{Label="Domain";Expression={$_.DomainName}},`
    @{Label="Idle";Expression={"{0:N0}" -f ([timespan]::frommilliseconds($_.IdleTime)).TotalMinutes}} `
    | Out-GridView -PassThru -Title "RDS Sessions" `
    | SessionAction
}

Export-ModuleMember -Function "Install-SintezRDSModuleServer", "Install-SintezRDSModuleClient", "Start-RDSConnect"