#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