Files
ad-managed-by-logon/Set-ComputerManagedBy.ps1

182 lines
6.9 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Sets the AD computer's "Managed By" to the logged-in user, and stamps the
computer name into the user's "Notes" field.
.DESCRIPTION
Designed to run as a GPO User Logon Script. On each login it:
1. Sets the computer object's "managedBy" attribute to the user's DN
2. Sets the user object's "info" attribute (Notes / Telephones tab) to the computer name
Each operation runs independently - if one fails the other still runs.
PREREQUISITES:
- AD permissions must be delegated so that Authenticated Users (or Domain Users)
can WRITE the "managedBy" attribute on Computer objects in the relevant OU(s).
- Users can write their own "info" attribute by default (Personal Information
property set). No extra delegation needed for the Notes field.
- RSAT AD module is optional; the script falls back to ADSI if unavailable.
.NOTES
Deploy via: GPO > User Configuration > Policies > Windows Settings > Scripts > Logon
Filename: Set-ComputerManagedBy.ps1
#>
# -- Configuration ------------------------------------------------------------
$LogFile = "$env:TEMP\Set-ComputerManagedBy.log"
$MaxLogSizeKB = 256
# -- Logging helper ------------------------------------------------------------
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$entry = "[$timestamp] [$Level] $Message"
if ((Test-Path $LogFile) -and ((Get-Item $LogFile).Length / 1KB -gt $MaxLogSizeKB)) {
Remove-Item $LogFile -Force -ErrorAction SilentlyContinue
}
Add-Content -Path $LogFile -Value $entry -ErrorAction SilentlyContinue
}
# -- Gather environment --------------------------------------------------------
$currentUser = $env:USERNAME
$computerName = $env:COMPUTERNAME
$userDomain = $env:USERDOMAIN
$loginTimestamp = Get-Date -Format "yyyy-MM-dd HH:mm"
Write-Log "Script started. User=$userDomain\$currentUser, Computer=$computerName"
# -- Skip if local/non-domain login --------------------------------------------
if ($userDomain -eq $computerName) {
Write-Log "Local login detected (domain = computername). Skipping." "WARN"
exit 0
}
# -- Try AD module first, fall back to ADSI ------------------------------------
$useADModule = $false
try {
Import-Module ActiveDirectory -ErrorAction Stop
$useADModule = $true
Write-Log "Using ActiveDirectory PowerShell module."
} catch {
Write-Log "AD module not available. Falling back to ADSI/DirectorySearcher." "WARN"
}
# -- Build the notes string ----------------------------------------------------
$notesValue = "Last logon: $computerName ($loginTimestamp)"
# -- Resolve user and computer DNs --------------------------------------------
$userDN = $null
$userObj = $null
$computerDN = $null
if ($useADModule) {
try {
$userObj = Get-ADUser -Identity $currentUser -Properties info -ErrorAction Stop
$userDN = $userObj.DistinguishedName
} catch {
Write-Log "Could not find user '$currentUser' in AD: $($_.Exception.Message)" "ERROR"
exit 1
}
try {
$computerObj = Get-ADComputer -Identity $computerName -Properties managedBy -ErrorAction Stop
$computerDN = $computerObj.DistinguishedName
} catch {
Write-Log "Could not find computer '$computerName' in AD: $($_.Exception.Message)" "ERROR"
}
} else {
$rootDSE = [ADSI]"LDAP://RootDSE"
$domainDN = $rootDSE.defaultNamingContext
$searcher = New-Object DirectoryServices.DirectorySearcher
$searcher.SearchRoot = [ADSI]"LDAP://$domainDN"
# Find the user
$searcher.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=$currentUser))"
$searcher.PropertiesToLoad.AddRange(@("distinguishedName", "info"))
$userResult = $searcher.FindOne()
if (-not $userResult) {
Write-Log "Could not find user '$currentUser' in AD." "ERROR"
exit 1
}
$userDN = $userResult.Properties["distinguishedname"][0]
# Find the computer
$searcher.Filter = "(&(objectCategory=computer)(sAMAccountName=$computerName$))"
$searcher.PropertiesToLoad.Clear()
$searcher.PropertiesToLoad.AddRange(@("distinguishedName", "managedBy"))
$computerResult = $searcher.FindOne()
if (-not $computerResult) {
Write-Log "Could not find computer '$computerName' in AD." "ERROR"
} else {
$computerDN = $computerResult.Properties["distinguishedname"][0]
}
}
# -- Task 1: Set computer ManagedBy (separate try/catch) -----------------------
if ($computerDN -and $userDN) {
try {
if ($useADModule) {
if ($computerObj.managedBy -eq $userDN) {
Write-Log "ManagedBy already set to $currentUser. No change needed."
} else {
Set-ADComputer -Identity $computerName -ManagedBy $userDN -ErrorAction Stop
Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$userDN'"
}
} else {
$currentManagedBy = $null
if ($computerResult.Properties["managedby"].Count -gt 0) {
$currentManagedBy = $computerResult.Properties["managedby"][0]
}
if ($currentManagedBy -eq $userDN) {
Write-Log "ManagedBy already set to $currentUser. No change needed."
} else {
$computerEntry = [ADSI]"LDAP://$computerDN"
$computerEntry.Put("managedBy", $userDN)
$computerEntry.SetInfo()
Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$userDN'"
}
}
} catch {
Write-Log "FAILED to set ManagedBy: $($_.Exception.Message)" "ERROR"
}
} else {
Write-Log "Skipping ManagedBy - computer object not found." "WARN"
}
# -- Task 2: Set user Notes (separate try/catch) -------------------------------
if ($userDN) {
try {
if ($useADModule) {
if ($userObj.info -eq $notesValue) {
Write-Log "User notes already current. No change needed."
} else {
Set-ADUser -Identity $currentUser -Replace @{info = $notesValue} -ErrorAction Stop
Write-Log "SUCCESS: Set Notes on '$currentUser' to '$notesValue'"
}
} else {
$currentNotes = $null
if ($userResult.Properties["info"].Count -gt 0) {
$currentNotes = $userResult.Properties["info"][0]
}
if ($currentNotes -eq $notesValue) {
Write-Log "User notes already current. No change needed."
} else {
$userEntry = [ADSI]"LDAP://$userDN"
$userEntry.Put("info", $notesValue)
$userEntry.SetInfo()
Write-Log "SUCCESS: Set Notes on '$currentUser' to '$notesValue'"
}
}
} catch {
Write-Log "FAILED to set Notes: $($_.Exception.Message)" "ERROR"
}
}
Write-Log "Script finished."
exit 0