Thursday, October 14, 2021

Retrieve Local Administrators from Multiple Computers

 A forum user asked for assistance with a PowerShell script that would read a list of servers from a text file and then either show the list of users in the local administrator groups on each server.

The script below, Get-LocalMembers, takes things a bit further. While it will default to the local administrators group, you can supply any number of groups to the script. It even supports wildcards! By default, the results are displayed on the console, but can also export the results as a .csv file.

The script takes 2 parameters (both optional):

Computers

A list of computers to query. The list may be provided as a parameter to the script, or read from a text file. Default: localhost

Groups

A list of local groups to query on each of the computers. Wildcards are support (see examples below). Default: Administrators

Examples

Get-LocalMembers

    Retrieves the members of the default group (Administrators) on the default computer(localhost).

Get-LocalMembers -Computers (Get-Content -Path "c:\temp\computers.txt")

    Will retrieve the members of the Administrators group on all the computers in the file computers.txt.

Get-LocalMembers -groups 'Remote*','Admin*'

    Will retrieve the members of the Administrators, Remote Desktop Users and Remote Management Users groups on localhost.

Get-LocalMembers | Export-Csv -Path "c:\reports\GroupMembers.csv" -NoTypeInformation

    Retrieves the members of the default group (Administrators) on the default computer(localhost) and exports them to the specified .csv file.

Function Get-LocalMembers {
<#
.SYNOPSIS
    Gets the members of one or more local groups of the specified computer(s) 
    and optionally outputs the results to a CSV file.

.PARAMETER Computers
    Specifies the computers to query.
    Can be a string or a list retrieved from a file via Get-Content (see examples).
    Default: $env:computername (localhost)

.PARAMETER Groups
    Specifies the groups to query. Supports wildcards. 
    Can be a string or a list retrieved from a file via Get-Content (see examples).
    (e.g. Remote* will enumerate both Remote Desktop Users and Remote Management Users)
    Default: Administrators

.EXAMPLE
    Get-LocalMembers
    Retrieves the members of the default group (Administrators) on the default computer(localhost)

.EXAMPLE
    Get-LocalMembers -Computers (Get-Content -Path "c:\temp\computers.txt")
    Will retrieve the members of the Administrators group on all the computers in the file computers.text

.EXAMPLE
    Get-LocalMembers -groups 'Remote*'
    Will retrieve the members of the Remote Desktop Users and Remote Management Users groups on localhost

.EXAMPLE
    Get-LocalMembers | Export-Csv -Path "c:\reports\GroupMembers.csv" -NoTypeInformation

.LINK
    Heavily modified from script: https://gallery.technet.microsoft.com/223cd1cd-2804-408b-9677-5d62c2964883
#>

    Param(
        [string[]]$Computers,
        [string[]]$Groups
    )

    # defaults
    if ($Computers -eq $null) {
        $Computers = $env:COMPUTERNAME
    }
    if ($Groups -eq $null) {
        $groups = 'Administrators'
    }

    # testing the connection to each computer via ping before executing the script
    foreach ($computer in $Computers) {
        if (Test-Connection -ComputerName $computer -Quiet -count 1) {
            $livePCs += $computer
        } else {
            Write-Host ('Computer {0} is unreachable.' -f $computer) -ForegroundColor DarkRed -BackgroundColor White
        }
    }

    $list = new-object -TypeName System.Collections.ArrayList

    # cycle through each computer in the list
    foreach ($computer in $livePCs) {

        # cycle through each group in the list
        foreach($groupToTest in $groups) {
            $err = @()
            $admins = @(Get-WmiObject -Class win32_groupuser -ComputerName $computer -EA SilentlyContinue -EV err | 
                Where-Object {$_.groupcomponent -like "*`"$($groupToTest)`""})

            if ($err.Count -gt 0) {
                $errMsg =  $err[0].Exception.Message
                Write-Host ('Error accessing WMI on {0} ... {1}' -f $computer, $err[0].Exception.Message) `
                            -ForegroundColor DarkRed -BackgroundColor White
            } else {
               if ($admins.Count -gt 0) {
                    # get the group name
                    $null =  $admins[0].Groupcomponent -match '.+Domain\=(.+)\,Name\=(.+)$'
                    $group = $matches[2].trim('"')

                    # get the members of the group
                    $aAdmins = @() 
                    foreach ($admin in $admins) {
                        $null = $admin.partcomponent -match '.+Domain\=(.+)\,Name\=(.+)$' 
                        $null = $matches[1].trim('"') + '\' + $matches[2].trim('"') + "`n"
                        $aAdmins += $matches[1].trim('"') + '\' + $matches[2].trim('"')
                    }
                    $obj = New-Object -TypeName PSObject -Property @{
                        Computer = $computer
                        Group    = $group
                        Members  = ($aAdmins -join ',')
                    }
                    $null = $list.add($obj)
                }
            }
        }
    }
    $list | select computer, group, members
}

Sam Jacobs is the Director of Technology at Newtek Technology Systems (formerly IPM), the longest standing Citrix Platinum Partner on the East Coast. With more than 30 years of IT consulting, Sam is a NetScaler and StoreFront customizations and integrations industry expert. He holds Microsoft and Citrix certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. He is one of the top Citrix support Forum contributors, and has earned industry praise for the tools he has developed to make NetScaler, StoreFront and Web Interface easier to manage for administrators and more intuitive for end users. Sam became a Citrix Technology Professional (CTP) in 2015, and can be reached at: sjacobs@newtekone.com or on Twitter at: @WIGuru.


Sunday, September 12, 2021

Log Off Idle Citrix Sessions

The simple PowerShell snippet below will log off any session that has been idle for more than the specified number of hours.


# sessions that have been idle for longer than 
# the below number of hours will be logged off
$maxIdleHours = 24

# load the Citrix snapin
Add-PSSnapin Citrix*

# function to calculate the number of hours
# that a session has been idle
Function Get-IdleHours {
    param ([TimeSpan] $IdleTime)
    ($IdleTime.Days * 24) + $IdleTime.Hours
}

# get sessions that are idle
$sessions = @(Get-Brokersession | ? IdleDuration -ne $null)

# cycle through the list, and log off sessions that
# have been idle for > the specified number of hours
foreach ($sess in $sessions) {
    if ((Get-IdleHours($sess.IdleDuration)) -gt $maxIdleHours) {
        Stop-BrokerSession $sess
    }
}


Sam Jacobs is the Director of Technology at Newtek Technology Systems (formerly IPM), the longest standing Citrix Platinum Partner on the East Coast. With more than 30 years of IT consulting, Sam is a NetScaler and StoreFront customizations and integrations industry expert. He holds Microsoft and Citrix certifications, and is the editor of TechDevCorner.com, a technical resource blog for IT professionals. He is one of the top Citrix support Forum contributors, and has earned industry praise for the tools he has developed to make NetScaler, StoreFront and Web Interface easier to manage for administrators and more intuitive for end users. Sam became a Citrix Technology Professional (CTP) in 2015, and can be reached at: sjacobs@newtekone.com or on Twitter at: @WIGuru.