param(
    $ServerNameSource, #Numeric script config parameter: 1 = Parameter ServerNames list / 2 = Parameter InputFile / 3 = LDAP query with name-prefix / 4 = LDAP query with filter on OU / 5 = LDAP query with name-prefix and OU filter
    $ServerNames, #depending on ServerNameSource (1) - a simple, coma separated list of server names e.g. @("server1", "server2", "server3")
    $ServerNamesInputFile, #depending on ServerNameSource (2) - path and name of a file that holds the server names, one servername per line - e.g.: "C:\servernames.txt"
    $ServerNamesLDAPnameFilter, #depending on ServerNameSource (3 and/or 5) - name search string - can hold wildcards (*) e.g.: "RDS*"
    $ServerNamesLDAPOUFilter, #depending on ServerNameSource (4 and/or 5) - e.g.: "OU=RDS hosts,DC=domain,DC=local"
    $SubstractSessionsPerHost = 2, #substract this amount of sessions per host - due to e.g. two RDS listeners (would make 2 sessions) or additional e.g. 1x ICA listener (would make 3 sessions) etc...
    $UseWMI = $false #use WMI - if not set it will use QWINSTA by default: enable with: $true
)
 
#function to convert a string to proper XML and write it as output/screen
Function WriteXmlToScreen ([xml]$xml) #just to make it clean XML code...
{
    $StringWriter = New-Object System.IO.StringWriter;
    $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter;
    $XmlWriter.Formatting = "indented";
    $xml.WriteTo($XmlWriter);
    $XmlWriter.Flush();
    $StringWriter.Flush();
    Write-Output $StringWriter.ToString();
}
 
$ServerNameList;
 
If ($ServerNameSource -gt 0 -and $ServerNameSource -lt 6) {
 
    Switch ($ServerNameSource) {
        1 {
            $ServerNameList = $ServerNames;
        }
        2 {
            $ServerNameList = Get-Content $ServerNamesInputFile;
        }
        3 {
            $ServerNameList = (Get-ADComputer -LDAPFilter "(name=$ServerNamesLDAPnameFilter)" | Select Name).Name;
        }
        4 {
            $ServerNameList = (Get-ADComputer -Filter "*" -SearchBase $ServerNamesLDAPOUFilter | Select Name).Name;
        }
        5 {
            $ServerNameList = (Get-ADComputer -LDAPFilter "(name=$ServerNamesLDAPnameFilter)" -SearchBase $ServerNamesLDAPOUFilter | Select Name).Name;
        }
    }
} Else {
    Write-Output "Missing Parameter or wrong value for: ServerNameSource";
    Exit;
}
  
#if the array holds entries
If ($ServerNameList.Count -gt 0) {
 
    $SessionsTotal = 0;
    $SessionsActive = 0;
    $ServersNotReached = 0;
 
    #go through the list
    ForEach ($ServerName in $ServerNameList) {
        #try to connect - on error jump to catch
        Try {
            $FoundTotal = 0;
            $FoundActive = 0;
            
            
            If ($UseWMI -eq $false) {
                #less control in theory - due to reformatting and searching through the results
                #single execution of the query / command
                $QWinstaResults = qwinsta /server $ServerName | ForEach-Object {
                        $_.Trim() -replace "\s+",","
                    } | ConvertFrom-Csv -Header "SessionName","UserName","ID","State","Type","Device"; #we add manual headers here, since this otherwise can cause issues with the filter later on
                $FoundTotal = $QWinstaResults.Count-1;  #if we use QWINSTA we need to substract one more session from the results
                $FoundActive = ($QWinstaResults | ? { $_.State -eq "Active" }).Count;
            } else {            
                #more control - but might run slower
                #in theory you can invoke all server-names at once, but then you need to run through the table and you lose some control over what was reached and what wasn't - first run might always be slowest depending on amount of servers
                $FoundTotal = (Get-WmiObject -Query "SELECT TotalSessions FROM Win32_TerminalService" -ComputerName $ServerName | Select TotalSessions).TotalSessions;
                $FoundActive = (Get-WmiObject -Query "SELECT ActiveSessions FROM Win32_PerfFormattedData_LocalSessionManager_TerminalServices" -ComputerName $ServerName | Select ActiveSessions).ActiveSessions;
            }
 
            #SessionsTotal might need a substract depending on the parameter input
            $FoundTotal = $FoundTotal - $SubstractSessionsPerHost;
            #we need to avoid that the substractions is negative, to avoid false substraction
            If ($FoundTotal -le 0){
                $FoundTotal = 0;
            }
            
            #we now add the results to the current counters
            $SessionsTotal += $FoundTotal;
            $SessionsActive += $FoundActive;
        } Catch {
            $ServersNotReached += 1;
        } Finally {
            #nothing to do here
        }
    }
 
    #Lets put together the results
    $PRTGstring="<prtg>
        <result>
     <channel>Total Servers checked</channel>
        <value>" +  $ServerNameList.Count + "</value>
     </result>
        <result>
     <channel>Total Servers responded</channel>
        <value>" + ($ServerNameList.Count - $ServersNotReached)  + "</value>
     </result>
        <result>
     <channel>Total Servers not reached</channel>
        <value>$ServersNotReached</value>
     </result>
        <result>
     <channel>Total Sessions found</channel>
        <value>$SessionsTotal</value>
     </result>
        <result>
     <channel>Total Sessions active</channel>
        <value>$SessionsActive</value>
     </result>
        </prtg>"
 
    #we call the function WriteXmlToScreen to transform the $PRTGstring to XML and output it 
    WriteXmlToScreen "$PRTGstring"
 
} Else {
    Write-Output "Parameter Error or List did not contain any names / no server names found"
    Exit;
}