diff --git a/Set-ComputerManagedBy.ps1 b/Set-ComputerManagedBy.ps1 new file mode 100644 index 0000000..a7f9323 --- /dev/null +++ b/Set-ComputerManagedBy.ps1 @@ -0,0 +1,134 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Sets the Active Directory computer object's "Managed By" attribute to the currently logged-in user. + +.DESCRIPTION + Designed to run as a GPO User Logon Script. On each login, it resolves the current + user and computer in AD, then stamps the user's Distinguished Name into the computer + object's "managedBy" attribute. + + PREREQUISITES: + - The RSAT ActiveDirectory PowerShell module must be installed on client machines, + OR the script can fall back to ADSI/DirectorySearcher (no module needed). + - 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). + See README.md for delegation instructions. + +.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" + # Rotate log if oversized + 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 + +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" +} + +try { + if ($useADModule) { + # ── AD Module path ────────────────────────────────────────────────── + $userObj = Get-ADUser -Identity $currentUser -ErrorAction Stop + $computerObj = Get-ADComputer -Identity $computerName -ErrorAction Stop + + $currentManagedBy = (Get-ADComputer -Identity $computerName -Properties managedBy).managedBy + + if ($currentManagedBy -eq $userObj.DistinguishedName) { + Write-Log "ManagedBy already set to $currentUser. No change needed." + exit 0 + } + + Set-ADComputer -Identity $computerName -ManagedBy $userObj.DistinguishedName -ErrorAction Stop + Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$($userObj.DistinguishedName)'" + + } else { + # ── ADSI fallback (no module required) ────────────────────────────── + $rootDSE = [ADSI]"LDAP://RootDSE" + $domainDN = $rootDSE.defaultNamingContext + + $searcher = New-Object DirectoryServices.DirectorySearcher + $searcher.SearchRoot = [ADSI]"LDAP://$domainDN" + + # Find the user DN + $searcher.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=$currentUser))" + $searcher.PropertiesToLoad.Add("distinguishedName") | Out-Null + $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 DN + $searcher.Filter = "(&(objectCategory=computer)(sAMAccountName=$computerName$))" + $searcher.PropertiesToLoad.Clear() + $searcher.PropertiesToLoad.Add("distinguishedName") | Out-Null + $searcher.PropertiesToLoad.Add("managedBy") | Out-Null + $computerResult = $searcher.FindOne() + + if (-not $computerResult) { + Write-Log "Could not find computer '$computerName' in AD." "ERROR" + exit 1 + } + + $computerDN = $computerResult.Properties["distinguishedname"][0] + + # Check current value + $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." + exit 0 + } + + # Set the attribute via ADSI + $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" + exit 1 +} + +exit 0