I recently had an issue where I needed the ability to identify the PC(s) where a user was logged into. I found part of the answer here:
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