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;
}