Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 187
  • Last Modified:

Can I use powershell to generate list of users who logged in to computers in AD

hello, I need to gather a list of computers, users who log into the computers and service tags(dell tags). Last logged on time would be helpful as well.

I am trying to clean up my asset management system as well as AD while trying to avoid going around all 200+ computers

It is ok if the dell service/system tag is not possible to obtain the service tag, but the computers and their respective users will be needed.

The users do NOT use roaming profiles. They all log on to their dedicated workstations.

Is there any script I am over looking out there that can help me out here?

Many thanks.
t
0
tobe1424
Asked:
tobe1424
3 Solutions
 
Niten KumarPrincipal Systems AdministratorCommented:
Try the powershell script below.



# Applies to: Computers
#
# Description: This script searches for a specific, logged on user on all or
# specific Computers by checking the process "explorer.exe" and its owner.
#
# ********************************************************************************

#Set variables
$progress = 0

#Get Admin Credentials
Function Get-Login {
Clear-Host
Write-Host "Please provide admin credentials (for example DOMAIN\admin.user and your password)"
$Global:Credential = Get-Credential
}
Get-Login

#Get Username to search for
Function Get-Username {
      Clear-Host
      $Global:Username = Read-Host "Enter username you want to search for"
      if ($Username -eq $null){
            Write-Host "Username cannot be blank, please re-enter username!"
            Get-Username
      }
      $UserCheck = Get-ADUser $Username
      if ($UserCheck -eq $null){
            Write-Host "Invalid username, please verify this is the logon id for the account!"
            Get-Username
      }
}
Get-Username

#Get Computername Prefix for large environments
Function Get-Prefix {
      Clear-Host
      $Global:Prefix = Read-Host "Enter a prefix of Computernames to search on (CXX*) use * as a wildcard or enter * to search on all computers"
      Clear-Host
}
Get-Prefix

#Start search
$computers = Get-ADComputer -Filter {Enabled -eq 'true' -and SamAccountName -like $Prefix}
$CompCount = $Computers.Count
Write-Host "Searching for $Username on $Prefix on $CompCount Computers`n"

#Start main foreach loop, search processes on all computers
foreach ($comp in $computers){
      $Computer = $comp.Name
      $Reply = $null
        $Reply = test-connection $Computer -count 1 -quiet
        if($Reply -eq 'True'){
            if($Computer -eq $env:COMPUTERNAME){
                  #Get explorer.exe processes without credentials parameter if the query is executed on the localhost
                  $proc = gwmi win32_process -ErrorAction SilentlyContinue -computer $Computer -Filter "Name = 'explorer.exe'"
            }
            else{
                  #Get explorer.exe processes with credentials for remote hosts
                  $proc = gwmi win32_process -ErrorAction SilentlyContinue -Credential $Credential -computer $Computer -Filter "Name = 'explorer.exe'"
            }                  
                  #If $proc is empty return msg else search collection of processes for username
            if([string]::IsNullOrEmpty($proc)){
                  write-host "Failed to check $Computer!"
            }
            else{      
                  $progress++                  
                  ForEach ($p in $proc) {                        
                        $temp = ($p.GetOwner()).User
                        Write-Progress -activity "Working..." -status "Status: $progress of $CompCount Computers checked" -PercentComplete (($progress/$Computers.Count)*100)
                        if ($temp -eq $Username){
                        write-host "$Username is logged on $Computer"
                        }
                  }
            }      
      }
}
write-host "Search done!"
1
 
get-ADuser -F ($_.Name -eq "Todd")Systems AdministratorCommented:
Copy below and place in Windows Powershell ISE.  I just did it and it works.  Read my remarks. Replace in caps the name of your domain controller.  I have it in caps where you change it.   Also rem $Comps pipeline if you decide to use the parameter of this script and replace the loop from $comps to $Computername.





<#Run this funcion under Windows Powershell ISE.  Depending on your environment.  This goes through  every
 computer, and takes a while.  If you decide to use the paramenter Computername, then remove the remarks of
the paramenter.  And just type in an array of machines.  That goes faster...E.g. Get-loggedOnUser -computername -server1,server2,computer1
#>


# Pipeline version otherwise use parameter and rem this out
$Comps =  Get-ADComputer -Filter * -Server YOURDOMAINCONTROLLER -Properties * |select -ExpandProperty  name

function Get-LoggedOnUser {
#Requires -Version 2.0            
 <# [CmdletBinding()]            
 Param            
   (                      
    [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
    [String[]$ComputerName
   )#End Param
#>  

Begin            
{            
 Write-Host "`n Checking Users . . . "
 $i = 0            
}#Begin          
Process            
{
    $Comps | Foreach-object {
    $Computer = $_
    try
        {
            $processinfo = @(Get-WmiObject -class win32_process -ComputerName $Computer -EA "Stop")
                if ($processinfo)
                {    
                    $processinfo | Foreach-Object {$_.GetOwner().User} |
                    Where-Object {$_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM"} |
                    Sort-Object -Unique |
                    ForEach-Object { New-Object psobject -Property @{Computer=$Computer;LoggedOn=$_} } |
                    Select-Object Computer,LoggedOn
                }#If
        }
    catch
        {
            "Cannot find any processes running on $computer" | Out-Host
        }
     }#Forech-object(Comptuters)      
           
}#Process
End
{

}#End

}#Get-LoggedOnUser
1
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 
David Johnson, CD, MVPOwnerCommented:
work in progress script
function Get-ComputerUser {
#Requires -Version 3.0            
 [CmdletBinding()]            
 Param            
   (                      
    [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
    [String[]]$ComputerName
   )#End Param
 Write-Host ("`n Checking Users . . . on Computer:" + $ComputerName)
 $path = '\\'+$ComputerName + '\c$\Users\'
  Get-ChildItem -Path $path -Directory | Select-Object -Property Name, LastWriteTime
 }#Foreach-object(Computers)      
}
}#Get-LoggedOnUser 
function get-staleADusers
{
 [CmdletBinding()]            
 Param            
   (                      
    [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
    [String]$domain = 'domain.mydom.com',
   [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
 [int]$DaysInactive = 90,
   [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
 [string]$csvoutputfile = 'OLD_User.csv'
)
    $time = (Get-Date).Adddays(-($DaysInactive))
    # Get all AD User with lastLogonTimestamp less than our time and set to enable
    Get-ADUser -Filter {LastLogonTimeStamp -lt $time -and enabled -eq $true} -Properties LastLogonTimeStamp |
    select-object -Property Name,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} | export-csv -Path $csvoutputfile -NoTypeInformation
}
function get-stalecomputers{

            
 [CmdletBinding()]            
 Param            
   (                      
    [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
    [String]$domain = 'domain.mydom.com',
   [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
 [int]$DaysInactive = 90,
   [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
 [string]$csvoutputfile = 'Stale_Computers.csv'
)
    $time = (Get-Date).Adddays(-($DaysInactive))
    # Get all AD User with lastLogonTimestamp less than our time and set to enable
    Get-ADComputer -Filter {LastLogonTimeStamp -lt $time -and enabled -eq $true} -Properties LastLogonTimeStamp |
    select-object -Property Name,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} | export-csv -Path $csvoutputfile -NoTypeInformation
}


$DCS = get-ADDomainController
foreach($dc in $DCS){
$Comps =  Get-ADComputer -Filter * -Server $dc.name -Properties * |select -ExpandProperty  name
foreach ($computer in $Comps) {
$userlist = Get-ComputerUser -ComputerName $computer
}
get-staleAdUsers
get-stalecomputers

Open in new window


what I intend to do is having the computer and checking the users directory which is updated everytime the user logs on and export a list of old users.  The previous scripts depended upon the 'user' actually being logged into the machine under test or the machine being online at the time of the test
1
 
get-ADuser -F ($_.Name -eq "Todd")Systems AdministratorCommented:
Yes, that is true, My script output is based on if logged in at the time,.
0
 
tobe1424Author Commented:
Thanks for the feedback! I will give this a shot a soon as I get to the office
0
 
tobe1424Author Commented:
Apologies for the late reply folks.

I edit the script as per your instructions. However, when I run the script via dos or powershell, it seems to process but nothing is generated. I simply end up at another dos/power shell prompt
0
 
tobe1424Author Commented:
Am I missing something? Is it possible to generate a csv or at least list the results?

Many thanks
0
 
get-ADuser -F ($_.Name -eq "Todd")Systems AdministratorCommented:
I'm sure I confused you on trying to show to different types of accessing data.  My fault.  This one is to search your domain of anyone logged in.  (At the time you run it).  Otherwise it will fail.  Place this script in ISE.  Run once to load the function.  Then type the function name.  Get-LoggedOnUser.  Example:   PS C:\powershell\Get-LoggedOnUser

It will search and write to the host.  If you want to go to csv, change "Out-Host to Export-Csv C:\yourpath\YourFile.csv. Also change your DC name to your own.  Its in CAPS where to change.  



<#Run this funcion under Windows Powershell ISE.  Depending on your environment.  This goes through  every
  computer, and takes a while.  If you decide to use the paramenter Computername, then remove the remarks of
 the paramenter.  And just type in an array of machines.  That goes faster...E.g. Get-loggedOnUser -computername -server1,server2,computer1
 #>


 # Pipeline version otherwise use parameter and rem this out
 $Comps =  Get-ADComputer -Filter * -Server -YOURDCNAME -Properties * |select -ExpandProperty  name

 function Get-LoggedOnUser {
 #Requires -Version 2.0            
  <# [CmdletBinding()]            
  Param             
    (                       
     [Parameter(Mandatory=$true,
                Position=0,                          
                ValueFromPipeline=$true,            
                ValueFromPipelineByPropertyName=$true)]            
     [String[]$ComputerName
    )#End Param
 #>   

 Begin            
 {            
  Write-Host "`n Checking Users . . . "
  $i = 0            
 }#Begin          
 Process            
 {
     $Comps | Foreach-object {
     $Computer = $_
     try
         {
             $processinfo = @(Get-WmiObject -class win32_process -ComputerName $Computer -EA "Stop")
                 if ($processinfo)
                 {    
                     $processinfo | Foreach-Object {$_.GetOwner().User} | 
                     Where-Object {$_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM"} |
                     Sort-Object -Unique |
                     ForEach-Object { New-Object psobject -Property @{Computer=$Computer;LoggedOn=$_} } | 
                     Select-Object Computer,LoggedOn
                 }#If
         }
     catch
         {
             "Cannot find any processes running on $computer" | Out-Host
         }
      }#Forech-object(Comptuters)       
             
 }#Process
 End
 {

 }#End

 }#Get-LoggedOnUser 

Open in new window

0
 
get-ADuser -F ($_.Name -eq "Todd")Systems AdministratorCommented:
This one is for an array, that you can just type computer names in, because the parameter is -computername.  Run this script once to load the function,  they type Get-LoggedOnUser and then it will ask for a computer name.  Type as many as you like.  Once finished just push enter and it will find the computers you typed in.   (If they are logged in).   This is by computername so nothing to change.  

function Get-LoggedOnUser {
#Requires -Version 2.0            
[CmdletBinding()]            
 Param             
   (                       
    [Parameter(Mandatory=$true,
               Position=0,                          
               ValueFromPipeline=$true,            
               ValueFromPipelineByPropertyName=$true)]            
    [String[]]$ComputerName
   )#End Param

Begin            
{            
 Write-Host "`n Checking Users . . . "
 $i = 0            
}#Begin          
Process            
{
    $ComputerName | Foreach-object {
    $Computer = $_
    try
        {
            $processinfo = @(Get-WmiObject -class win32_process -ComputerName $Computer -EA "Stop")
                if ($processinfo)
                {    
                    $processinfo | Foreach-Object {$_.GetOwner().User} | 
                    Where-Object {$_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM"} |
                    Sort-Object -Unique |
                    ForEach-Object { New-Object psobject -Property @{Computer=$Computer;LoggedOn=$_} } | 
                    Select-Object Computer,LoggedOn
                }#If
        }
    catch
        {
            "Cannot find any processes running on $computer" | Out-Host
        }
     }#Forech-object(Computers)       
            
}#Process
End
{

}#End

}#Get-LoggedOnUser

Open in new window

0
 
get-ADuser -F ($_.Name -eq "Todd")Systems AdministratorCommented:
On the 1st script to search whole domain, what I mean by fail is that is will just report back "Cannot find any processes running on PCNAME".  It will continue to search until it has searched all ADcomputers.
0
 
tobe1424Author Commented:
Thanks again!

Searching the whole domain seems more like what I need to do. But I will try both of them.

Cheers
0
 
get-ADuser -F ($_.Name -eq "Todd")Systems AdministratorCommented:
Lastly I wrote this for a person that needed who was last logged in for a certain amount of days.  This is from the LastLogon attribute in the ADUser Object.  I deleted the filter of a date -10 days last logged in.  This is in HTML format.  So it will email it to you.  Change the information under "This information you need about your SMTP server" that I have remarked out.  I capitalized what to change.  But notice I had to filter it a different way, otherwise it gives every user.  (Even disabled, ExchangeHealth, etc)  We have our EmployeeID entered for all active users.  Take the Where-Object {$_.EmployeeID -ne $null} if you don't have their ID entered.  Or change to -eq, doesn't matter.  This will search Active Directory of the last successful logon in AD.  Change the selection of what you need as well.  He needed manager, EmployeeID, office, etc.  If you want in a CSV, read instruction in the remarks at the bottom of the script.  



# Get date values
 $Date = Get-Date
 [String]$Year = $Date.Year
 [String]$Month = $Date.Month
 [String]$Day = $Date.Day
 
 # Pad the date parts with leading 0's
 If ( $Month.ToString().Length -lt 2 ) { $Month = '0' + $Month }
 If ( $Day.ToString().Length -lt 2 ) { $Day = '0' + $Day }



# This is information you need about your SMTP server

$SMTPServer = "MAIL.DOMAIN.COM"
$messageSubject = "All Domain Users"
$smtpfrom = "ANYNAME.DOMAIN.COM"
$smtpto = "VALIDEMAILADDRESS@DOMAIN.COM"
$message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto
$message.Subject = $messageSubject
$message.IsBodyHTML = $true

<# 
    Convert to HTML  You can go to this site to find more color names.
    I use what I can see well. http://www.w3schools.com/colors/colors_names.asp
#>

$a = "<style>"
$a = $a + "BODY{background-color:peachpuff;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 2px;padding: 1px;border-style: solid;border-color: black;background-color:lightgray: text-align;right}"
$a = $a + "TD{border-width: 2px;padding: 1px;border-style: solid;border-color: black;background-color:whitesmoke}"
$a = $a + "</style>"

<# 
    Here is the amount of days.  I picked 10.  You can change the -gt to whatever you want.
    Keep in mind I get a lot of dates of the year 1600.  I think thats because they never logged in.
    Also, because of Exchange I get all the Exchange HealthMailboxes, etc.  But my Domain is 
    in theprocess of cleaning up bad accounts.
    You can limit it by OU and use -searchbase for a specific OU
    Or what I did, and only
#> 

$AllUsers = get-aduser -filter *  -properties DisplayName,lastlogon,Manager,EmployeeID,office | Where-Object {$_.EmployeeID -ne $null} `
             |sort-object lastlogon `
             |select name,DisplayName,@{Exp={([datetime]::FromFileTime($_.lastlogon))};label="Last logon time"} `
             ,@{n="Manager Name";e={(Get-ADUser -Identity $_.Manager -properties DisplayName).DisplayName}},employeeID,office


            
            
<#  
    If you need to export to CSV by the date of the file place what I have below to the $allUsers variable
    Then put -attacments at the end of H1> and the path you exported it too
  
    |export-csv "C:\powershell\Scripts\lastlogon-audit_$Year$Month$Day.csv" -NoTypeInformation -Delimiter ";"
#>


$message.Body = $AllUsers | ConvertTo-HTML -head $a -body "<H1>Users Logged In Times From AD</H1>"

$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($message)

Open in new window

1
 
tobe1424Author Commented:
Thanks guys
0

Featured Post

Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now