<# -------------------------------------------------------------------------- UpdateUserWorkstations.ps1 PowerShell script to update the userWorkstations attribute of Active Directory users in bulk from the information in a CSV file. Computer names can be added to and/or removed from the attribute. The corresponding PowerShell property exposed by the Set-ADUser cmdlet is LogonWorkstations. Copyright (c) 2019 Richard L. Mueller Version 1.0 - January 4, 2019 ---------------------------------------------------------------------- You have a royalty-free right to use, modify, reproduce, and distribute this script file in any way you find useful, provided that you agree that the copyright owner above has no warranty, obligations, or liability for such use. The CSV file specifies the users and the workstations to be added to and removed from the userWorkstations attribute. A header line should define the three fields sAMAccountName, AddNames, and RemoveNames. If either AddNames or RemoveNames has more than one computer name, the names must be comma delimited and the entire value should be enclosed in double quotes. -------------------------------------------------------------------------- #> # ============ Modify the values in this section for your situation ========= # Specify the CSV file. $CsvFile = "c:\Scripts\UserWorkstations.csv" # Specify the log file. $LogFile = ".\UpdateUserWorkstation.log" # If $Update is $True, user objects will be updated. Otherwise the script # will only generate the log file without updating users. $Update = $False # ================ End of section to modify ================================= # Script version and date. $Version = "Version 1.0 - January 4, 2019" Write-Host "Please Standby..." Try {Import-Module ActiveDirectory -ErrorAction Stop -WarningAction Stop} Catch { Write-Host "ActiveDirectory module (or DC with ADWS) not found!!" ` -ForegroundColor Red -BackgroundColor Black Write-Host "Script Aborted." -ForegroundColor Red -BackgroundColor Black # Abort the script. Break } # Retrieve all computer sAMAccountNames in the domain. Try { $NTNames = Get-ADComputer -Filter * | sAMAccountName } Catch { Write-Host "Error: AD modules not supported, script aborted." ` -foregroundcolor red -backgroundcolor black Break } # Add information to the log file. Try { Add-Content -Path $LogFile ` -Value "------------------------------------------------" ` -ErrorAction Stop } Catch { Write-Host ` "Error: Logfile $LogFile invalid or protected, script aborted." ` -foregroundcolor red -backgroundcolor black Break } Add-Content -Path $LogFile -Value "UpdateUsersWorkstations.ps1" Add-Content -Path $LogFile -Value "$Version" Add-Content -Path $LogFile -Value "CSV file: $CsvFile" Add-Content -Path $LogFile -Value "Log file: $LogFile" Add-Content -Path $LogFile -Value "Update users: $Update" Add-Content -Path $LogFile -Value "Started: $((Get-Date).ToString())" Add-Content -Path $LogFile ` -Value "------------------------------------------------" # Populate a hash table with the computer names. $SamNames = @{} ForEach ($Item In $NTNames) { $Name = $($Item.sAMAccountName) # Remove any trailing "$" character. If ($Name.EndsWith("$")) { $Name = $Name.SubString(0,$Name.Length - 1) } $SamNames.Add($Name, $True) } # Enumerate the users in the CSV file. $Users = Import-Csv -Path $CsvFile ForEach ($User In $Users) { # Retrieve values from the CSV for this user. $ID = $User.sAMAccountName Add-Content -Path $LogFile -Value "User: $ID" # Convert the Workstations into arrays of computer names. $Add = $User.AddNames Add-Content -Path $LogFile -Value " Computers to add: $Add" If ($Add) {$AddComputers = $Add -Split ","} Else {$AddComputers = $Null} $Remove = $User.RemoveNames Add-Content -Path $LogFile -Value " Computers to remove: $Remove" If ($Remove) {$RemoveComputers = $Remove -Split ","} Else {$RemoveComputers = $Null} # Retrieve the existing value of the userWorkstations attribute # for the user. Try { $Names = (Get-ADUser -Identity $ID -Properties userWorkstations).userWorkstations } Catch { Write-Host "Error: User $ID not found." ` -foregroundcolor red -backgroundcolor black Add-Content -Path $LogFile -Value " User not found!" # Skip this user. Continue } Add-Content -Path $LogFile -Value " Existing value: $Names" # Convert into an array. $arrNames = $Names -Split "," # Convert into a hash table. $CompNames = @{} ForEach ($Item In $arrNames) { If (-Not $CompNames.ContainsKey($Item)) { $CompNames.Add($Item, $True) } } $Changed = $False # Enumerate the computer names in the CSV to be added. ForEach ($Computer In $AddComputers) { $Computer = $Computer.Trim() # Check that the computer object exists in the domain. If ($SamNames.ContainsKey($Computer) -eq $True) { # Make sure the same computer is not to be removed. If ($Remove -NotContains $Computer) { # Make sure existing workstations does not include # this computer. If ($CompNames.ContainsKey($Computer) -eq $False) { # Add this computer name to the list of names. $Changed = $True $CompNames.Add($Computer, $True) } } } Else { Add-Content -Path $LogFile ` -Value " Computer $Computer not found" } } # Enumerate the computer names in the CSV to be removed. ForEach ($Computer In $RemoveComputers) { $Computer = $Computer.Trim() # Make sure existing workstations includes this computer. If ($CompNames.ContainsKey($Computer) -eq $True) { # Remove this computer name from the list of names. $Changed = $True $CompNames.Remove($Computer) } } # Only update the user if there are computer names # to be added or removed. If ($Changed) { If ($CompNames.Count -eq 0) { # Clear userWorkstations. If ($Update) { Set-ADUser -Identity $ID -Clear userWorkstations } Add-Content -Path $LogFile -Value " All values cleared" } Else { # Convert the hash table into a string of comma delimited # computer names. $Names = $CompNames.Keys -Join "," # Update computer names to the new list of names. If ($Update) { Set-ADUser -Identity $ID -LogonWorkstations "$Names" } Add-Content -Path $LogFile -Value " New value: $Names" } } Else { Add-Content -Path $LogFile -Value " No change" } } # Update the log file. Add-Content -Path $LogFile -Value "------------------------------------------------" Add-Content -Path $LogFile -Value $("Finished: " + (Get-Date).ToString()) Write-Host "Done. See log file: $LogFile"