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

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)
0 votes
1 answer

Hi again, the script here needs a small change In the last catch area, it has to be $messageEncodingName, otherwise the output will show nothing for default as the value is empty : ) catch { $messageEncodingName = "UTF-8 (default)" }

asked Mar 11 by wintec01 (1.8k points)
0 votes
1 answer

I am trying to create a Script power Shell for creating users with a South American standard. I need to use the first part of firstname + the ... .TargetObject.Put("userPrincipalName", $userPrincipalName) # Aplica as mudanças $Context.TargetObject.SetInfo()

asked Feb 21 by victor.motta (20 points)
0 votes
1 answer

We are using the below snippet to grab the email of a single custom attribute object. Can I get guidance on the best way to modify this to get all the emails of each ... "The user specified in parameter 'MyParameter' has no email address. ", "Information") }

asked Dec 23, 2024 by msheppard (790 points)
3,677 questions
3,361 answers
8,494 comments
549,328 users