http://deployhappiness.com/find-out-what-computer-a-user-logged-into/#comment-5068
I won't reprint it here but the jist is by using a logon/logoff VB script, and a GPO, you can populate a field in the Active Directory record of each PC in a domain.
That part works really well. After that you would need to search AD for the username to identify the PC.
What I've done is created a PowerShell script with a GUI to do it for you. Now, it's not finished yet, but it does work. The code below is dirty and as soon as I get it the way I want I'll update this posting, but for now, it works pretty well. Don't complain about bugs,I know it has them, I'm working on it. And, yes, I have no doubt some things could be done better or more efficiently, feel free to post improvements.
What it has (or will have):
- Self relocates to c:/scripts and drops an icon on the current users desktop for future launches
- Self relocation is optional
- Colorized output
- GUI driven for simplicity
- Various levels of debugging options
- Reports items located in both AD "Description" field, and "Managed By" field.
Watch for word wrapping...
<#======================================================================================
File Name : Find-User.ps1
Original Author : Kenneth C. Mazie (kcmjr AT kcmjr.com)
:
Description : Will locate the PC a user
is currently logged on to.
:
Notes : Normal operation is with
no command line options. Requires PowerShell AD module.
:
Warnings :
:
Legal : Public Domain. Modify and
redistribute freely. No rights reserved.
: SCRIPT PROVIDED "AS
IS" WITHOUT WARRANTIES OR GUARANTEES OF
: ANY KIND. USE AT YOUR OWN
RISK. NO TECHNICAL SUPPORT PROVIDED.
:
Credits : Code snippets and/or ideas
came from many sources including but
: not limited to the following:
:
http://deployhappiness.com/find-out-what-computer-a-user-logged-into/#comment-5068
:
https://stackoverflow.com/questions/2688547/muliple-foreground-colors-in-powershell-in-one-command
:
Last Update by : Kenneth C. Mazie
Version History : v1.0 - 04-11-14 - Original
Change History : v1.1 - 00-00-00 -
:
=======================================================================================#>
clear-host
#-------------------------------[
Begin ]---------------------------------------#>
$Debug1 = $false
#--[ Set to true to have extra messages to console during run
$Debug2 = $false
#--[ Set to true to have extra messages to console during run
$CurrentVersion = "1.0"
if (!(Get-Module -Name ActiveDirectory)){Import-Module ActiveDirectory}
$ErrorActionPreference = "SilentlyContinue"
$TargetPath = "C:\Scripts"
#--[ Where the script "should" live
$ScriptFullName = ($MyInvocation.MyCommand).Name #--[ EX:
script.ps1
$ScriptFullPath = ($MyInvocation.MyCommand).Path #--[ EX:
C:\Scripts\script.ps1
$ScriptHomeDir = split-path -parent $ScriptFullPath #--[ EX:
C:\Scripts, where the script resides
$ScriptWorkingDir = $pwd.path
#--[ EX: C:\Scripts or C:\temp, where the script executes from
$ScriptShortName = [system.io.path]::GetFilenameWithoutExtension($ScriptFullPath) #--[ EX: script (no extention)
$osv = [environment]::osversion.VersionString #--[ Get Windows
version, not required, just for convenience
$windir = [System.Environment]::ExpandEnvironmentVariables("%WINDIR%") #--[ Get %windir% environment
variable
#$windir = $env:windir
#--[ Alternate format
$Home = [System.Environment]::ExpandEnvironmentVariables("%USERPROFILE%") #--[ Get %userprofile% environment
variable
$ThisComputer1 = [System.Net.Dns]::GetHostName() #--[ NOTE: No
reason for both forms, just because.
$ThisComputer2 = $env:COMPUTERNAME
$Relocate = $false
#--[ Change to $true to enable automatic relocation of the script
Function LocateUser {
Param ([string]$TargetUser)
$TargetUserSAM = $Null
$TargetUserName = $Null
$ResultA = @()
$ResultB = @()
$FullArray = @()
$SubArray = @()
$Computers = Get-ADComputer -Filter * -Properties
ManagedBy,Description | Select Name, ManagedBy, Description | Sort -Property Name
If ($TargetUser.contains(" ")){
#--[ Get name or ID depending on what uer entered.
[string]$TargetUserSAM = (Get-ADUser -Filter "Name -eq
'$TargetUser'" | Select-Object name, samaccountname).samaccountname
[string]$TargetUserName = $TargetUser.ToUpper()
}Else{
[string]$TargetUserName = (Get-ADUser -Filter "samAccountName
-eq '$TargetUser'" | Select-Object name, samaccountname).name
[string]$TargetUserSAM = $TargetUser.ToUpper()
}
If ($TargetUserName -eq ""){$TargetUserName = "UNKNOWN"}
$TargetUser = (Get-Culture).TextInfo.ToTitleCase($TargetUser.ToLower())
If ($Debug2){Write-Host "Checkpoint 1:
TUname= " $TargetUserName "
TUsam=" $TargetUserSAM " TU=" $TargetUser}
ForEach ($Computer in $Computers){ #--[ Sort
through AD Computers, extract ManagedBy and Description ]--
$ManagedBy = ""
$ManagedBy = (((($Computer.managedby).split(",")).split("="))[1]).ToUpper()
$Description = ""
$Description = ($Computer.description).ToUpper()
#If ($Debug2){Write-Host
"Checkpoint 2: Comp=" $Computer.name
" ManagedBy=" $ManagedBy
" Description="$Description }
#--[ computer, description, & who is its manager in AD
If ($Debug2){color-Write Checkpoint 2: -Red
Comp = $Computer.name -Yellow
LoggedOn = $ManagedBy -Green Description = $Description } #--[ computer, description, & who is
its manager in AD
$SubArray = $Computer.name,$ManagedBy,$Description
$FullArray += ,$SubArray #--[ Fullarray will contain
Computer,ManagedBy,Description ]--
}
$count = $FullArray.count
# write-host "B = "
$ResultA.count
# write-host "A = "
$ResultB.count
$ResultA += $TargetUserName + "
(" + $TargetUserSAM + ")`n`nLogged on to:`n"
$ResultB += "Assigned to:
`n" #$TargetUserName + "
(" + $TargetUserSAM + ")`n"
While ($count -gt 0){
#If ($Debug2){Write-Host "Checkpoint
3: $count DetectedUser=" $FullArray[$count][1]
" TargetUser="
$TargetUserName
"PC-Descr="
$Description}
If ($Debug2){$FullArrayCount1 = $FullArray[$count][1];color-Write
Checkpoint 3: -Magenta $count -Yellow DetectedUser = $FullArrayCount1 -Cyan
TargetUser = $TargetUserName -Green PC-Descr = $Description}
If ($FullArray[$count][1] -eq $TargetUserName){
# If ($Debug2){Write-Host
"Checkpoint 4:
FAcount$count-0=" $FullArray[$count][0] " FAcount$count-1=" $FullArray[$count][1] " User="
$TargetUser }
$ResultA += $FullArray[$count][0] + "`n"
}
If ($FullArray[$count][2] -eq $TargetUserName){
$ResultB += $FullArray[$count][0] + "`n"
}#write-host $Description}
#If ($Debug2){$FullArrayCount1 =
$FullArray[$count][1];$X = $count-1;Write-Host "Checkpoint 5: FullArrayCount $X = " $FullArrayCount1}
$count --
}
If ($Debug2){$x = $ResultA.count;color-Write Checkpoint 6: -Red ResultACount = $x (includes
target)}
If ($Debug2){color-Write -Red ResultBCount = $ResultB.count (includes
target)}
#write-host "A = " $ResultA.count
#write-host "B = " $ResultB.count
#write-host $ResultA[0]
$ResultA[1]
#write-host $ResultB[0]
$ResultB[1]
If ($ResultA.count -eq 2){ #-[ If results plus target > 2 then display
multiples ]--
$objLabel.Text = "Results
for: $ResultA[0]" #--[ Overwrite the text with the
username ]--
$objLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$objLabel.Refresh()
$objForm.Controls.remove($objTextBox)
#--[ Add Result 1 Lable ]--
If ($Debug1){Write-Host "Adding
result label 1"}
$objResult1 = New-Object System.Windows.Forms.Label
$objResult1.Location = New-Object System.Drawing.Size(10,50)
$objResult1.Size = New-Object System.Drawing.Size(315,20)
$objResult1.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$objResult1.Text = "Currently
logged onto: " + $ResultA[1]
$objForm.Controls.Add($objResult1)
#--[ Add Result 2 Label ]--
If ($ResultB[1] -eq $Null){$Assigned = "N/A"}Else{$Assigned = $ResultB[1]}
If ($Debug1){Write-Host "Adding
result label 2"}
$objResult2 = New-Object System.Windows.Forms.Label
$objResult2.Location = New-Object System.Drawing.Size(10,70)
$objResult2.Size = New-Object System.Drawing.Size(315,20)
$objResult2.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$objResult2.Text = "Assigned
to: $Assigned"
$objForm.Controls.Add($objResult2)
}ElseIf ($ResultA.count -gt 2){
$objTextBox.Enabled = $false
$objTextBox.Text = " ... More Than One Found ... "
$objTextBox.Refresh()
# $objForm.close()
[System.Windows.Forms.MessageBox]::Show("$ResultA
`n $ResultB","Multiple Logons Found")
# $objTextBox.Text = " ... More Than One Found ... "
}Else{
$objTextBox.Text = " ...... NOT FOUND
...... "
$objTextBox.Refresh()
}
If ($Debug1){Write-Host "Adding
locate another"}
#$objResult1.Text = "Currently
logged onto: "
$objProcessButton.Text = "Locate
Another"
$objProcessButton.tabindex = 1
#$objTextBox.Text = " "
$objTextBox.Enabled = $false
$objTextBox.Refresh()
$objProcessButton.Add_Click({$objTextBox.Text = " ...... RELOADING
...... ";$objTextBox.Refresh();ResetGUI})
# $objCloseButton.Location = new-object
System.Drawing.Size(($ButtonLeft+60),$ButtonTop)
#
$objForm.Controls.Remove($objProcessButton)
$TargetUserSAM = $Null
$TargetUserName = $Null
$Result.Clear()
$FullArray.Clear()
$SubArray.Clear()
$IterationResult.Clear()
$TargetUser = $False
} #--[ End LocateUser Function ]--
function color-Write
{
$allColors = ("-Black", "-DarkBlue","-DarkGreen","-DarkCyan","-DarkRed","-DarkMagenta","-DarkYellow","-Gray",
"-Darkgray","-Blue", "-Green", "-Cyan", "-Red", "-Magenta", "-Yellow", "-White")
$foreground = (Get-Host).UI.RawUI.ForegroundColor
#
current foreground
$color = $foreground
[bool]$nonewline = $false
$sofar = ""
$total = ""
foreach($arg in $args)
{
if ($arg -eq "-nonewline") {
$nonewline = $true
}elseif ($arg -eq "-foreground"){
if ($sofar) { Write-Host $sofar -foreground $color -nonewline }
$color = $foregrnd
$sofar = ""
}elseif ($allColors -contains $arg){
if ($sofar) { Write-Host $sofar -foreground $color -nonewline }
$color = $arg.substring(1)
$sofar = ""
}else{
$sofar += "$arg "
$total += "$arg "
}
}
Write-Host $sofar -foreground $color -nonewline:$nonewline
}
Function ResetGUI {
$objForm.Close()
$objForm.Dispose()
CreateGUI
}
Function IsThereText{
if ($objTextBox.Text.Length -ne 0){
$objProcessButton.Enabled = $true
}else{
$objProcessButton.Enabled = $false
}
}
Function Relocate {#--------------------[
Assure things run from C:\scripts ]----------------------
If ($Relocate = False){Break}
If (!($ScriptHomeDir -eq $TargetPath)){
#--[ Paths are NOT same ]--
If (!(Test-Path -path $TargetPath)){New-Item $TargetPath -type directory} #--[ Does target path exist? If not, create it ]--
If (!(Test-Path "$TargetPath\ScriptFullName" -pathType Leaf )){Copy-Item $ScriptFullPath $TargetPath\$ScriptFullName} #--[ Is the
script there? If not, copy it there ]--
If (!(Test-Path -path "$Profile\Desktop\$ScriptShortName.lnk")){
$WshShell = New-Object -comObject WScript.Shell #--[ Place a
shortcut on the desktop of current user
$Shortcut = $WshShell.CreateShortcut("$Profile\Desktop\$ScriptShortName.lnk")
$Shortcut.TargetPath = 'powershell.exe'
$Shortcut.Arguments = "-WindowStyle
Hidden –Noninteractive -NoLogo -Command
`"$TargetPath\$ScriptFullName`""
$Shortcut.Save()
If ($Debug1){If (!(Test-Path -path "$Profile\Desktop\$ScriptShortName.lnk")){write-host "FAILED to
create icon"}}
}
iex -command "$Profile\Desktop\$ScriptShortName.lnk" #--[ re-invoke
the script from the new location ]--
#Remove-Item
$MyINvocation.InvocationName #--[
Delete the old copy of this script ]--
EXIT
#--[ Force termination ]--
}Else{ #--[ Paths ARE
good, script exists, OK to execute ]--
#if (!(Test-Path
"$ScriptPath\ThisScriptName")) #--[ an
optional additional check ]--
}
}
Function CreateGUI{
#--------------------------[
Create The GUI ]-----------------------------------
[void] [reflection.assembly]::loadwithpartialname("System.Windows.Forms")
[void] [reflection.assembly]::loadwithpartialname("System.Drawing")
[int]$Width = (Get-WmiObject -Class Win32_DesktopMonitor | Select-Object
ScreenWidth,ScreenHeight).ScreenWidth
[int]$FormWidth = 350
[int]$FormHeight = 170
[int]$Center = ($Width / 2)
[int]$ButtonLeft = 55
[int]$ButtonTop = 99
#--[ Create Form ]--
If ($Debug1){Write-Host "Creating
form"}
$objForm = new-object System.Windows.Forms.form
$objForm.Text = "User
Locatinator. v$CurrentVersion"
$objForm.size = new-object System.Drawing.Size($FormWidth,$FormHeight)
$objForm.minimumSize = New-Object System.Drawing.Size($FormWidth,$FormHeight)
$objForm.maximumSize = New-Object System.Drawing.Size($FormWidth,$FormHeight)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $true
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter"){$TargetUser=$objTextBox.Text;$objTextBox.Text = " ...... Working
......";$objTextBox.Refresh();LocateUser $TargetUser}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape"){$objForm.Close()}})
#--[ Add Form Lable ]--
If ($Debug1){Write-Host "Creating
label 1"}
$objFormLabelBox = new-object System.Windows.Forms.Label
$objFormLabelBox.Font = new-object System.Drawing.Font("New Times
Roman",9,[System.Drawing.FontStyle]::Bold)
$objFormLabelBox.Location = new-object System.Drawing.Size(3,5)
$objFormLabelBox.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$objFormLabelBox.size = new-object System.Drawing.Size(325,20)
$objFormLabelBox.Text = "This tool
will locate the PC a user is logged on to:"
$objForm.Controls.Add($objFormLabelBox)
#--[ Add Form Lable ]--
If ($Debug1){Write-Host "Creating
label 2"}
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Point(25,25)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Enter the
First && Last Name, or Logon ID of the user:"
$objLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$objForm.Controls.Add($objLabel)
#--[ Add Text Input Box ]--
If ($Debug1){Write-Host "Creating
input box"}
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(78,58)
$objTextBox.Size = New-Object System.Drawing.Size(175,20)
$objTextBox.TabIndex = 0
$objTextBox.add_TextChanged({IsThereText})
$objForm.Controls.Add($objTextBox)
#--[ Add LOCATE Button ]--
If ($Debug1){Write-Host "Adding
LOCATE button"}
$objProcessButton = new-object System.Windows.Forms.Button
$objProcessButton.Location = new-object System.Drawing.Size($ButtonLeft,$ButtonTop)
$objProcessButton.Size = new-object System.Drawing.Size(100,25)
$objProcessButton.Enabled = $false
$objProcessButton.Text = "Locate
The User"
$objProcessButton.tabindex = 1
$objForm.Controls.Add($objProcessButton)
$objProcessButton.Add_Click({$TargetUser=$objTextBox.Text;$objTextBox.Text = " ...... Working
......";$objTextBox.Refresh();LocateUser $TargetUser})
#--[ Add STOP Button ]--
If ($Debug1){Write-Host "Adding
STOP button"}
$objCloseButton = new-object System.Windows.Forms.Button
$objCloseButton.Location = new-object System.Drawing.Size(($ButtonLeft+125),$ButtonTop)
$objCloseButton.Size = new-object System.Drawing.Size(100,25)
$objCloseButton.Text = "Cancel/Close"
$objCloseButton.Add_Click({$objForm.close()})
$objCloseButton.tabindex = 2
$objForm.Controls.Add($objCloseButton)
#--[ Open Form ]--
If ($Debug1){Write-Host "Opening
form"}
$objForm.topmost = $true
$objForm.Add_Shown({$objForm.Activate();$objTextBox.Focus})
[void]$objForm.ShowDialog()
}
CreateGui
Not working for me. Not returning any results and users I know are logged in.
ReplyDeleteDid you put the logon/logoff script in place on your domain? The entire process relies on that being in place and functioning. I use this script myself at work and it does work (at least for me). I won't deny that there are still bugs in it but the basic functionality is working when I run it. You can verify that that data is in place in AD by viewing a users settings with the advanced option on so you can see the attribute editor. Assuming the user is currently logged on, the PC they logged onto should be listed in the "managedBy" attribute. If not that data is not being written to AD.
ReplyDelete