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

I have made a deprovision custom command. I cannot change the attribute directReports, so was thinking - i could take the people in the directReports field of the manager ... (and its subordinates) that im running the deprovision custom command from. Any tips?

asked Mar 21 by EdgarsABG (50 points)
0 votes
2 answers

Hi team, we are using a lot of custom PowerShell Scripts in our rules and actions. Is there a way to see and search through them? Are they saved somewhere in a readable ... some paths and would like to avoid to open every rule and check every PS action. Thanks

asked Mar 6 by wintec01 (1.1k points)
0 votes
1 answer

I'm trying to implement the script on https://www.adaxes.com/script-repository/changes-in-group-membership-including-changes-made-by-3rd-party-tools-s289.htm. I added my ... is set to run hourly on Domain Admins, and Exchange Admin "group" objects. Thanks

asked Feb 26 by stevehalvorson (110 points)
0 votes
1 answer

Hello, I am wanting to write a script to have Adaxes add/remove all authorized DHCP Servers in the domain to a certain security group weekly. Dynamically adding and removing ... you have a better soulution then PS, then let me know. Thanks in advance!

asked Feb 8 by NewTechSolutions (20 points)
0 votes
1 answer

Hi All, I am currently using the 30 day free trial of Adaxes and seeing if we can use it to achieve our method of user provisioning. I am looking into server-side ... variable value within an SQL query Can this be achieved? Any help is much appreciated, Thanks

asked Feb 1 by Lewis (40 points)
3,343 questions
3,044 answers
7,766 comments
544,956 users