0 votes

Hello

We are looking to optimize one of our most used scripts. The script is kinda slow when working against a domain containing over 15 terminal servers. We are using the same script against several domains, therefore we can not specify the names or ou's of the servers.

So if anyone has any suggestions on how to make this script work faster, it would be greatly appreciated!

Import-Module Adaxes

$credentialDirectoryPath = "C:\Credentials" 

$targetUserName = "%username%"
# Get name of the user's domain
$domainName = $Context.GetObjectDomain("%distinguishedName%")

# Get credentials for the domain
if(!(Test-Path -Path $credentialDirectoryPath))
{
    $Context.LogMessage("The credentials folder was not found. Make sure that $credentialDirectoryPath exists.", "Error") 
    return
}
$directory = Get-ChildItem -Path $credentialDirectoryPath -Filter $domainName
if(!$directory)
{
    $Context.LogMessage("The credentials folder for domain $domainName was not found.", "Error") 
    return
}

# Read credentials for the domain from the file
$file = Get-ChildItem -Path $directory.FullName
if(!$file)
{
    $Context.LogMessage("The credentials file for domain $domainName was not found.", "Error") 
    return
}

$userName = (Get-Content -Path $file.FullName)[0]
$passwordEncryptedString = (Get-Content -Path $file.FullName)[1]
$password = ConvertTo-SecureString -String $passwordEncryptedString
$credential = New-Object System.Management.Automation.PsCredential($userName,$password)

# Get all computers from the user's domain
$computers = Get-AdmComputer -Filter {(Enabled -eq $True) -and (operatingSystem -like "*Server*") -and (name -like "*MF*" -or name -like "*ctx*" -or name -like "*xap*" -or name -like "*TS*")} `
    -AdaxesService localhost -Server $domainName

# Create a remote PowerShell session
$session = New-PSSession $file.Name -Authentication Negotiate -Credential $credential 
foreach ($computer in $computers) {
    $result = Invoke-Command -Session $session -ArgumentList $computer, $targetUserName -Scriptblock {
        param($computer, $targetUserName)
        Import-Module PSTerminalServices
        try
        {
            $session = Get-TSSession -ComputerName $computer.DNSHostName -UserName $targetUserName
            if($session) 
            {
                return "User has a " + $session.State + " session on " + $computer.Name
            }
        }
        catch
        {
            continue
        }
    }
    if($result)
    {
        $Context.LogMessage($result, "Information")
    }
}
Remove-PSSession $session
by (960 points)
0

Hello,

We've given our script guy the task to test the script and see whether it is possible to improve it. I'll update the post as soon as he comes up with something.

1 Answer

0 votes
by (216k points)

Hello,

Our script guy has come up with a certain performance improvement. However, keep in mind that often the time required for a script to run depends on your environment. In this particular case the performance of the script may depend on whether all of the computers that are polled are available. If some of the computers are unavailable (e.g. powered off), the script will still try to connect to them, and this involves the standard timeout required to identify that the computer is down.

Here's the updated version of the script. Instead of using the Invoke-Command cmdlet in a foreach loop, it passes an array of computers to the Invoke-Command cmdlet, and only connection to the computers is performed in the foreach loop.

Import-Module Adaxes

$credentialDirectoryPath = "C:\Credentials"

$targetUserName = "%username%"
# Get name of the user's domain
$domainName = $Context.GetObjectDomain("%distinguishedName%")

# Get credentials for the domain
if(!(Test-Path -Path $credentialDirectoryPath))
{
    $Context.LogMessage("The credentials folder was not found. Make sure that $credentialDirectoryPath exists.", "Error")
    return
}
$directory = Get-ChildItem -Path $credentialDirectoryPath -Filter $domainName
if(!$directory)
{
    $Context.LogMessage("The credentials folder for domain $domainName was not found.", "Error")
    return
}

# Read credentials for the domain from the file
$file = Get-ChildItem -Path $directory.FullName
if(!$file)
{
    $Context.LogMessage("The credentials file for domain $domainName was not found.", "Error")
    return
}

$userName = (Get-Content -Path $file.FullName)[0]
$passwordEncryptedString = (Get-Content -Path $file.FullName)[1]
$password = ConvertTo-SecureString -String $passwordEncryptedString
$credential = New-Object System.Management.Automation.PsCredential($userName,$password)

# Get all computers from the user's domain
$computers = Get-AdmComputer -Filter {(Enabled -eq $True) -and (operatingSystem -like "*Server*") -and (name -like "*MF*" -or name -like "*ctx*" -or name -like "*xap*" -or name -like "*TS*")} `
    -AdaxesService localhost -Server $domainName

# Create a remote PowerShell session
$session = New-PSSession $file.Name -Authentication Negotiate -Credential $credential
$result = Invoke-Command -Session $session -ArgumentList $computers, $targetUserName -Scriptblock {
    param($computers, $targetUserName)
    Import-Module PSTerminalServices

    $sessionsInfo = @()
    foreach($computer in $computers)
    {
        try
        {
            $session = Get-TSSession -ComputerName $computer.DNSHostName -UserName $targetUserName 
            if($session)
            {
                $sessionsInfo += "User has a " + $session.State + " session on " + $computer.Name
            }
        }
        catch
        {
            continue
        }
    }
    return $sessionsInfo
}
Remove-PSSession $session

if($result -eq $NULL)
{
    $Context.LogMessage("No session information for the user.", "Information") # TODO: modify me
    return
}

foreach($sessionInfo in $result)
{
    $Context.LogMessage($sessionInfo, "Information")
}
0

Thank you very much!

We added a bit to the script to avoid offline servers, as per your suggestion. These two together made the script execute about 15 sec faster :)

Here is the complete script:

Import-Module Adaxes

$credentialDirectoryPath = "C:\Credentials"

$targetUserName = "%username%"
# Get name of the user's domain
$domainName = $Context.GetObjectDomain("%distinguishedName%")

# Get credentials for the domain
if(!(Test-Path -Path $credentialDirectoryPath))
{
    $Context.LogMessage("The credentials folder was not found. Make sure that $credentialDirectoryPath exists.", "Error")
    return
}
$directory = Get-ChildItem -Path $credentialDirectoryPath -Filter $domainName
if(!$directory)
{
    $Context.LogMessage("The credentials folder for domain $domainName was not found.", "Error")
    return
}

# Read credentials for the domain from the file
$file = Get-ChildItem -Path $directory.FullName
if(!$file)
{
    $Context.LogMessage("The credentials file for domain $domainName was not found.", "Error")
    return
}

$userName = (Get-Content -Path $file.FullName)[0]
$passwordEncryptedString = (Get-Content -Path $file.FullName)[1]
$password = ConvertTo-SecureString -String $passwordEncryptedString
$credential = New-Object System.Management.Automation.PsCredential($userName,$password)

# Get all computers from the user's domain
$computers = Get-AdmComputer -Filter {(Enabled -eq $True) -and (operatingSystem -like "*Server*") -and (name -like "*MF*" -or name -like "*ctx*" -or name -like "*xap*" -or name -like "*TS*")} `
    -AdaxesService localhost -Server $domainName

# Create a remote PowerShell session
$session = New-PSSession $file.Name -Authentication Negotiate -Credential $credential
$result = Invoke-Command -Session $session -ArgumentList $computers, $targetUserName -Scriptblock {
    param($computers, $targetUserName)
    Import-Module PSTerminalServices

    $sessionsInfo = @()
    foreach($computer in $computers)
    {    
    $online = Test-Connection -Cn $computer.DNSHostName -BufferSize 16 -Count 1 -ea 0 -quiet
    if($online){
        try
        {
            $session = Get-TSSession -ComputerName $computer.DNSHostName -UserName $targetUserName 
            if($session)
            {
                $sessionsInfo += "User has a " + $session.State + " session on " + $computer.Name
            }
        }
        catch
        {
            continue
        }
      }
    }
    return $sessionsInfo
}
Remove-PSSession $session

if($result -eq $NULL)
{
    $Context.LogMessage("User has no active sessions", "Information") 
    return
}

foreach($sessionInfo in $result)
{
    $Context.LogMessage($sessionInfo, "Information")
}
0

Hello,

Well, we think that this is as much performance gain as you can get in this case. Thank you for your update on the script. ;)

Related questions

0 votes
1 answer

Is there a way to open the Reset Password window for a user after creation via a custom command? We don't want to send the password via email and don't want the ... m wondering if there is a command that will open the password reset dialog box after creation.

asked May 22 by ajmilic (130 points)
0 votes
0 answers

Hi All, after the update to v.3.17.23627.0 some script in our enviroment doesn't works. Before the update all works. below an example for condition true: ... $Context.ConditionIsMet = $StrtMonth.AddDays(7*($FindNthDay-1)) -eq $datetopatch Can you help me?

asked May 19 by Simone.Vailati (500 points)
0 votes
1 answer

I moved adaxes to a new virtual server (2022), upgraded powershell, and upgraded to 2025.1 so working through script issues. This script retrieves the last reboot for ... (' + $RebootTime.Days + ') days ago.' $Context.LogMessage($logmessage, "Information")

asked Apr 30 by jbadry (450 points)
0 votes
1 answer

Hi, Situation: Imagine we have a forest consisting of 3 domains (1 root domain and 2 sub domains) in a single forest At the moment we installed Adaxes service in the root domain ... "enterprise admins" group (We wouldn't want to do that...) Any other ideas?

asked Apr 10 by dper (40 points)
0 votes
1 answer

Hi, I am wondering how cloud connections should be handled across scripts for things to run as smooth as possible. For example, if I disconnect from Graph in ... ) $null = Connect-MicrosoftTeams -AccessTokens @($graphToken, $teamsToken) } Best regards, Martin

asked Mar 14 by Martin (170 points)
3,699 questions
3,383 answers
8,549 comments
549,745 users