Add user Notes field stamping with computer name and login timestamp
This commit is contained in:
+49
-28
@@ -1,19 +1,20 @@
|
|||||||
#Requires -Version 5.1
|
#Requires -Version 5.1
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Sets the Active Directory computer object's "Managed By" attribute to the currently logged-in user.
|
Sets the AD computer's "Managed By" to the logged-in user, and stamps the
|
||||||
|
computer name into the user's "Notes" field.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Designed to run as a GPO User Logon Script. On each login, it resolves the current
|
Designed to run as a GPO User Logon Script. On each login it:
|
||||||
user and computer in AD, then stamps the user's Distinguished Name into the computer
|
1. Sets the computer object's "managedBy" attribute to the user's DN
|
||||||
object's "managedBy" attribute.
|
2. Sets the user object's "info" attribute (Notes / Telephones tab) to the computer name
|
||||||
|
|
||||||
PREREQUISITES:
|
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)
|
- 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).
|
can WRITE the "managedBy" attribute on Computer objects in the relevant OU(s).
|
||||||
See README.md for delegation instructions.
|
- 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
|
.NOTES
|
||||||
Deploy via: GPO > User Configuration > Policies > Windows Settings > Scripts > Logon
|
Deploy via: GPO > User Configuration > Policies > Windows Settings > Scripts > Logon
|
||||||
@@ -29,7 +30,6 @@ function Write-Log {
|
|||||||
param([string]$Message, [string]$Level = "INFO")
|
param([string]$Message, [string]$Level = "INFO")
|
||||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||||
$entry = "[$timestamp] [$Level] $Message"
|
$entry = "[$timestamp] [$Level] $Message"
|
||||||
# Rotate log if oversized
|
|
||||||
if ((Test-Path $LogFile) -and ((Get-Item $LogFile).Length / 1KB -gt $MaxLogSizeKB)) {
|
if ((Test-Path $LogFile) -and ((Get-Item $LogFile).Length / 1KB -gt $MaxLogSizeKB)) {
|
||||||
Remove-Item $LogFile -Force -ErrorAction SilentlyContinue
|
Remove-Item $LogFile -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,7 @@ function Write-Log {
|
|||||||
$currentUser = $env:USERNAME
|
$currentUser = $env:USERNAME
|
||||||
$computerName = $env:COMPUTERNAME
|
$computerName = $env:COMPUTERNAME
|
||||||
$userDomain = $env:USERDOMAIN
|
$userDomain = $env:USERDOMAIN
|
||||||
|
$loginTimestamp = Get-Date -Format "yyyy-MM-dd HH:mm"
|
||||||
|
|
||||||
Write-Log "Script started. User=$userDomain\$currentUser, Computer=$computerName"
|
Write-Log "Script started. User=$userDomain\$currentUser, Computer=$computerName"
|
||||||
|
|
||||||
@@ -59,21 +60,30 @@ try {
|
|||||||
Write-Log "AD module not available. Falling back to ADSI/DirectorySearcher." "WARN"
|
Write-Log "AD module not available. Falling back to ADSI/DirectorySearcher." "WARN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Helper: build the notes string ──────────────────────────────────────────
|
||||||
|
$notesValue = "Last logon: $computerName ($loginTimestamp)"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($useADModule) {
|
if ($useADModule) {
|
||||||
# ── AD Module path ──────────────────────────────────────────────────
|
# ── AD Module path ──────────────────────────────────────────────────
|
||||||
$userObj = Get-ADUser -Identity $currentUser -ErrorAction Stop
|
$userObj = Get-ADUser -Identity $currentUser -Properties info -ErrorAction Stop
|
||||||
$computerObj = Get-ADComputer -Identity $computerName -ErrorAction Stop
|
$computerObj = Get-ADComputer -Identity $computerName -Properties managedBy -ErrorAction Stop
|
||||||
|
|
||||||
$currentManagedBy = (Get-ADComputer -Identity $computerName -Properties managedBy).managedBy
|
# — Set computer ManagedBy ——
|
||||||
|
if ($computerObj.managedBy -eq $userObj.DistinguishedName) {
|
||||||
if ($currentManagedBy -eq $userObj.DistinguishedName) {
|
|
||||||
Write-Log "ManagedBy already set to $currentUser. No change needed."
|
Write-Log "ManagedBy already set to $currentUser. No change needed."
|
||||||
exit 0
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
Set-ADComputer -Identity $computerName -ManagedBy $userObj.DistinguishedName -ErrorAction Stop
|
Set-ADComputer -Identity $computerName -ManagedBy $userObj.DistinguishedName -ErrorAction Stop
|
||||||
Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$($userObj.DistinguishedName)'"
|
Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$($userObj.DistinguishedName)'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# — Set user Notes (info attribute) ——
|
||||||
|
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 {
|
} else {
|
||||||
# ── ADSI fallback (no module required) ──────────────────────────────
|
# ── ADSI fallback (no module required) ──────────────────────────────
|
||||||
@@ -83,9 +93,9 @@ try {
|
|||||||
$searcher = New-Object DirectoryServices.DirectorySearcher
|
$searcher = New-Object DirectoryServices.DirectorySearcher
|
||||||
$searcher.SearchRoot = [ADSI]"LDAP://$domainDN"
|
$searcher.SearchRoot = [ADSI]"LDAP://$domainDN"
|
||||||
|
|
||||||
# Find the user DN
|
# Find the user
|
||||||
$searcher.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=$currentUser))"
|
$searcher.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=$currentUser))"
|
||||||
$searcher.PropertiesToLoad.Add("distinguishedName") | Out-Null
|
$searcher.PropertiesToLoad.AddRange(@("distinguishedName", "info"))
|
||||||
$userResult = $searcher.FindOne()
|
$userResult = $searcher.FindOne()
|
||||||
|
|
||||||
if (-not $userResult) {
|
if (-not $userResult) {
|
||||||
@@ -94,11 +104,10 @@ try {
|
|||||||
}
|
}
|
||||||
$userDN = $userResult.Properties["distinguishedname"][0]
|
$userDN = $userResult.Properties["distinguishedname"][0]
|
||||||
|
|
||||||
# Find the computer DN
|
# Find the computer
|
||||||
$searcher.Filter = "(&(objectCategory=computer)(sAMAccountName=$computerName$))"
|
$searcher.Filter = "(&(objectCategory=computer)(sAMAccountName=$computerName$))"
|
||||||
$searcher.PropertiesToLoad.Clear()
|
$searcher.PropertiesToLoad.Clear()
|
||||||
$searcher.PropertiesToLoad.Add("distinguishedName") | Out-Null
|
$searcher.PropertiesToLoad.AddRange(@("distinguishedName", "managedBy"))
|
||||||
$searcher.PropertiesToLoad.Add("managedBy") | Out-Null
|
|
||||||
$computerResult = $searcher.FindOne()
|
$computerResult = $searcher.FindOne()
|
||||||
|
|
||||||
if (-not $computerResult) {
|
if (-not $computerResult) {
|
||||||
@@ -108,7 +117,7 @@ try {
|
|||||||
|
|
||||||
$computerDN = $computerResult.Properties["distinguishedname"][0]
|
$computerDN = $computerResult.Properties["distinguishedname"][0]
|
||||||
|
|
||||||
# Check current value
|
# — Set computer ManagedBy ——
|
||||||
$currentManagedBy = $null
|
$currentManagedBy = $null
|
||||||
if ($computerResult.Properties["managedby"].Count -gt 0) {
|
if ($computerResult.Properties["managedby"].Count -gt 0) {
|
||||||
$currentManagedBy = $computerResult.Properties["managedby"][0]
|
$currentManagedBy = $computerResult.Properties["managedby"][0]
|
||||||
@@ -116,18 +125,30 @@ try {
|
|||||||
|
|
||||||
if ($currentManagedBy -eq $userDN) {
|
if ($currentManagedBy -eq $userDN) {
|
||||||
Write-Log "ManagedBy already set to $currentUser. No change needed."
|
Write-Log "ManagedBy already set to $currentUser. No change needed."
|
||||||
exit 0
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
# Set the attribute via ADSI
|
|
||||||
$computerEntry = [ADSI]"LDAP://$computerDN"
|
$computerEntry = [ADSI]"LDAP://$computerDN"
|
||||||
$computerEntry.Put("managedBy", $userDN)
|
$computerEntry.Put("managedBy", $userDN)
|
||||||
$computerEntry.SetInfo()
|
$computerEntry.SetInfo()
|
||||||
|
|
||||||
Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$userDN'"
|
Write-Log "SUCCESS: Set ManagedBy on '$computerName' to '$userDN'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# — Set user Notes (info attribute) ——
|
||||||
|
$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 {
|
} catch {
|
||||||
Write-Log "FAILED to set ManagedBy: $($_.Exception.Message)" "ERROR"
|
Write-Log "FAILED: $($_.Exception.Message)" "ERROR"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user