2017-07-10 2 views
0

J'ai écrit un script qui affinera les utilisateurs qui sont déconnectés ou qui ont un temps d'inactivité supérieur à 60 minutes. J'ai déjà mis en place ces paramètres et le filtre fonctionne bien, cependant; Au lieu de déconnecter l'utilisateur spécifique dans ce serveur, le script déconnecte le serveur comme entierDéconnecter l'utilisateur du serveur en utilisant l'ID de session

J'utilise deux autres fonctions, dont une que j'ai ajoutée directement dans le script. l'autre vient de Get-LoggedOnUser.ps1 Le Disconnect-LoggedOnUser et Get-LoggedOnUser sont destinés à fonctionner ensemble. J'ai gardé les instructions pour le script de déconnexion. J'ai inclus mon script complet dans ce GitHub gist

Toute aide ou suggestion est grandement appréciée! Tout le code correspondant ci-dessous:

Description 
-----------  
This command dot sources the script to ensure the Disconnect-LoggedOnUser function is available in your current PowerShell session 

.EXAMPLE 
Disconnect-LoggedOnUser -ComputerName server01 -Id 5 

Description 
----------- 
Disconnect session id 5 on server01 

.EXAMPLE 
.\Get-LoggedOnUser.ps1 -ComputerName server01,server02 | Where-Object {$_.UserName -eq 'JaapBrasser'} | Disconnect-LoggedOnUser -Verbose 

< script #My #>

<# 
    .SYNOPSIS 
     Convert output from CMD's 'query.exe user' to usable objects. 

    .DESCRIPTION 
     Take the text based output returned by 'query.exe user' and convert it to objects that can be manipulated in PowerShell. 

    .PARAMETER Name 
     Computer name to run query.exe against. 

    .EXAMPLE 
     PS C:\> Convert-QueryToObjects -Name server01 
     ComputerName Username SessionState SessionType 
     ------------ -------- ------------ ----------- 
     server01  bobsmith Disconnected 
     server01  janedoe Active  tcp-rdp 
#> 


function Disconnect-LoggedOnUser { 
<# 
.SYNOPSIS 
Function to disconnect a RDP session remotely 

.DESCRIPTION 
This function provides the functionality to disconnect a RDP session remotely by providing the ComputerName and the SessionId 

.PARAMETER ComputerName 
This can be a single computername or an array where the RDP sessions will be disconnected 

.PARAMETER Id 
The Session Id that that will be disconnected 

.NOTES 
Name: Disconnect-LoggedOnUser 
Author: Jaap Brasser 
DateUpdated: 2015-06-03 
Version: 1.0 
Blog: http://www.jaapbrasser.com 

.LINK 
http://www.jaapbrasser.com 

.EXAMPLE 
. .\Disconnect-LoggedOnUser.ps1 

Description 
-----------  
This command dot sources the script to ensure the Disconnect-LoggedOnUser function is available in your current PowerShell session 

.EXAMPLE 
Disconnect-LoggedOnUser -ComputerName server01 -Id 5 

Description 
----------- 
Disconnect session id 5 on server01 

.EXAMPLE 
.\Get-LoggedOnUser.ps1 -ComputerName server01,server02 | Where-Object {$_.UserName -eq 'JaapBrasser'} | Disconnect-LoggedOnUser -Verbose 

Description 
----------- 
Use the Get-LoggedOnUser script to gather the user sessions on server01 and server02. Where-Object filters out only the JaapBrasser user account and then disconnects the session by piping the results into Disconnect-LoggedOnUser while displaying verbose information. 
#> 
    param(
     [Parameter(
      Mandatory, 
      ValueFromPipeline, 
      ValueFromPipelineByPropertyName, 
      Position=0 
     )] 
     [string[]] 
      $ComputerName, 
     [Parameter(
      Mandatory, 
      ValueFromPipelineByPropertyName 
     )] 
     [int[]] 
      $Id 
    ) 

    begin { 
     $OldEAP = $ErrorActionPreference 
     $ErrorActionPreference = 'Stop' 
    } 

    process { 
     foreach ($Computer in $ComputerName) { 
      $Id | ForEach-Object { 
       Write-Verbose "Attempting to disconnect session $Id on $Computer" 
       try { 
        rwinsta $_ /server:$Computer 
        Write-Verbose "Session $Id on $Computer successfully disconnected" 
       } catch { 
        Write-Verbose 'Error disconnecting session displaying message' 
        Write-Warning "Error on $Computer, $($_.Exception.Message)" 
       } 
      } 
     } 
    } 

    end { 
     $ErrorActionPreference = $OldEAP 
    } 
} 






function Convert-QueryToObjects 
{ 
    [CmdletBinding()] 
    [Alias('QueryToObject')] 
    [OutputType([PSCustomObject])] 
    param 
    (
     [Parameter(Mandatory = $false, 
        ValueFromPipeline = $true, 
        ValueFromPipelineByPropertyName = $true, 
        Position = 0)] 
     [Alias('ComputerName', 'Computer')] 
     [string] 
     $Name = $env:COMPUTERNAME 
    ) 

    Process 
    { 
     Write-Verbose "Running query.exe against $Name." 
     $Users = query user /server:$Name 2>&1 

     if ($Users -like "*No User exists*") 
     { 
      # Handle no user's found returned from query. 
      # Returned: 'No User exists for *' 
      Write-Error "There were no users found on $Name : $Users" 
      Write-Verbose "There were no users found on $Name." 
     } 
     elseif ($Users -like "*Error*") 
     { 
      # Handle errored returned by query. 
      # Returned: 'Error ...<message>...' 
      Write-Error "There was an error running query against $Name : $Users" 
      Write-Verbose "There was an error running query against $Name." 
     } 
     elseif ($Users -eq $null -and $ErrorActionPreference -eq 'SilentlyContinue') 
     { 
      # Handdle null output called by -ErrorAction. 
      Write-Verbose "Error action has supressed output from query.exe. Results were null." 
     } 
     else 
     { 
      Write-Verbose "Users found on $Name. Converting output from text." 

      # Conversion logic. Handles the fact that the sessionname column may be populated or not. 
      $Users = $Users | ForEach-Object { 
       (($_.trim() -replace ">" -replace "(?m)^([A-Za-z0-9]{3,})\s+(\d{1,2}\s+\w+)", '$1 none $2' -replace "\s{2,}", "," -replace "none", $null)) 
      } | ConvertFrom-Csv 

      Write-Verbose "Generating output for $($Users.Count) users connected to $Name." 

      # Output objects. 
      foreach ($User in $Users) 
      { 
       Write-Verbose $User 
       if ($VerbosePreference -eq 'Continue') 
       { 
        # Add '| Out-Host' if -Verbose is tripped. 
        [PSCustomObject]@{ 
         ComputerName = $Name 
         Username = $User.USERNAME 
         SessionState = $User.STATE.Replace("Disc", "Disconnected") 
         SessionType = $($User.SESSIONNAME -Replace '#', '' -Replace "[0-9]+", "") 
         IdleTime = $User.'IDLE TIME' 
         ID = $User.ID 
         LogonTime =$User.'Logon Time' 
        } | Out-Host 
       } 
       else 
       { 
        # Standard output. 
        [PSCustomObject]@{ 
         ComputerName = $Name 
         Username = $User.USERNAME 
         SessionState = $User.STATE.Replace("Disc", "Disconnected") 
         SessionType = $($User.SESSIONNAME -Replace '#', '' -Replace "[0-9]+", "") 
         IdleTime = $User.'IDLE TIME' 
         LogonTime = $User.'Logon Time' 
         ID = $User.ID 
        } 
       } 
      } 
     } 
    } 
} 


$Servers = Get-Content 'H:\demo\computernames.txt' 
$Queries = foreach ($Server in $Servers) { 
    #Query each server that pings, save it in a variable for reuse 
    if (Test-Connection $Server -Count 1 -Quiet) { 
     Convert-QueryToObjects $Server -ErrorAction SilentlyContinue 
    } 
} 

#Open servers are ones that responded to the query. 
$Queries | 
    Select-Object -ExpandProperty ComputerName -Unique | 
    Out-File 'H:\demo\session\openservers.txt' 

#Use the saved query information, filter with Where-Object, loop over to disconnect. 
$Queries | 
    Where-Object { ($_.SessionState -eq 'Disconnected') -or (($_.IdleTime -like "*:*") -and ($_.IdleTime -gt "00:59"))} | 
    ForEach-Object { 
     Disconnect-LoggedOnUser -ComputerName $_.ComputerName -Id $_.ID -Verbose 
    } 
+2

Il fait exactement ce que vous lui dites. 'H: \ WindowsPowerShell \ Get-LoggedOnUser.ps1 -ComputerName $ Serveur | Disconnect-LoggedOnUser -Verbose 'n'est pas filtré avec' Where-Object' à tous. Donc va tout déconnecter. – BenH

+0

@BenH Je voulais dire que j'ai essayé d'ajouter 'Where-Object {$ _. ID -eq' $ Id '}' mais ça ne semble pas fonctionner. est-ce que je m'approche mal? merci – russell

+1

L'utilisation de guillemets simples ne permet pas l'évaluation des variables. Mais cela ne résout qu'une seule pièce, l'autre pièce est d'où vous obtenez «$ ID». – BenH

Répondre

2

Le problème est que H:\WindowsPowerShell\Get-LoggedOnUser.ps1 -ComputerName $Server| Disconnect-LoggedOnUser -Verbose n'est pas filtré avec Where-Object. Vous devez donc enregistrer les informations sur les sessions des utilisateurs à déconnecter, puis utiliser ces informations filtrées pour les déconnecter.

Voici une façon de l'aborder, commentaires en ligne.

$Servers = Get-Content 'H:\demo\computernames.txt' 
$Queries = foreach ($Server in $Servers) { 
    #Query each server that pings, save it in a variable for reuse 
    if (Test-Connection $Server -Count 1 -Quiet) { 
     Convert-QueryToObjects $Server -ErrorAction SilentlyContinue 
    } 
} 

#Open servers are ones that responded to the query. 
$Queries | 
    Select-Object -ExpandProperty ComputerName -Unique | 
    Out-File 'H:\demo\session\openservers.txt' 

#Use the saved query information, filter with Where-Object, loop over to disconnect. 
$Queries | 
    Where-Object { ($_.SessionState -eq 'Disconnected') -or (($_.IdleTime -like "*:*") -and ($_.IdleTime -gt "00:59"))} | 
    ForEachObject { 
     Disconnect-LoggedOnUser -ComputerName $_.ComputerName -Id $_.ID -Verbose 
    } 
+0

merci pour cela, j'ai ajouté votre script dans mon programme, cependant; il ne semble pas circuler à travers tous les serveurs et ne le fait que pour l'un d'entre eux (le dernier) que j'ai collé dans votre code exactement comme décrit. J'ai mis à jour mon code dans le github gist [trouvé ici] (https://gist.github.com/ruslive109/59673e6785230d156d5f6a4d0134152b) merci – russell

+0

@russell Excuses, mon code enregistrait sur $ Requêtes chaque boucle de $ Serveur J'ai mis à jour ma réponse pour remédier à la question – BenH

+0

merci encore! y at-il de toute façon je peux aussi avoir les variables énumérées comme avant? au lieu de simplement l'état de déconnexion. merci – russell