$Users = GC "Desktop\Master.txt"
foreach ($user in $users) {
$userobj = $(try {Get-ADUser $user} catch {$Null})
If ($userobj -ne $Null) {
Write-Host "$User Exists"
} else {
Write-Host "$User Doesn't Exist"
}}
I am using this code to check if a user exists in AD. Later on this notepad file is processed to delete the users that are on the file. I was going to see if it was possible that I can remove the users off the list that don't exist. Is there a command to remove the line from the Notepad file that has the names on if the user doesn't exist in AD
Write a function to test just a single user:
function Test-ADUser {
param($Identity)
try {
$null = Get-ADUser #PSBoundParameters -ErrorAction Stop
# user must exist if we reached this point
return $true
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]{
return $false
}
}
Now you can use Where-Object to filter the list from the text file based on what the function determines:
# Read list from file, filter out usernames that don't exist
$filteredList = Get-Content "Desktop\Master.txt" |Where-Object { Test-ADUser -Identity $_ }
# Write filtered data back to disk
$filteredList |Set-Content "Desktop\Master.txt" -Force
Related
Looking to get some help with my powershell script. Basically have a script that I use to bulk edit fields in Azure AD for multiple users and it works fine. I tried to use it for editing custom attributes for multiple users via Exchange Online and it is not working. I'm guessing it does not work the same for EO. The goal here is to pull a csv that has 2 columns (the users emails address "userprincipalname", and one column for the value I want to add for "customattribute1") Any help is appreciated.
# Connect to ExchangeOnline
Connect-ExchangeOnline
# Get CSV content
$CSVrecords = Import-Csv C:\pathtofile.csv
# Create arrays for skipped and failed users
$SkippedUsers = #()
$FailedUsers = #()
# Loop trough CSV records
foreach ($CSVrecord in $CSVrecords) {
$upn = $CSVrecord.UserPrincipalName
$user = Get-Mailbox -Filter "userPrincipalName eq '$upn'"
if ($user) {
try{
$user | Set-Mailbox -customattribute1 $CSVrecord.customattribute1
} catch {
$FailedUsers += $upn
Write-Warning "$upn user found, but FAILED to update."
}
}
else {
Write-Warning "$upn not found, skipped"
$SkippedUsers += $upn
}
}
I think there could be 2 points that leads fail to set customattribute1.
The filter expression should be : "userPrincipalName -eq '$upn'"
Seems I can't find the -Delimiter param while you import your .CSV file which will lead to unbale to pull column value correctly.
Try the code below that works perfectly for me:
Connect-ExchangeOnline
$SkippedUsers = #()
$FailedUsers = #()
$CSVrecords = Import-Csv "C:\Users\Administrator\Desktop\test.csv" -Delimiter ","
foreach($CSVrecord in $CSVrecords ){
$upn = $CSVrecord.UserPrincipalName
$user = Get-Mailbox -Filter "userPrincipalName -eq '$upn'"
if ($user) {
try{
$user | Set-Mailbox -customattribute1 $CSVrecord.customattribute1
} catch {
$FailedUsers += $upn
Write-Warning "$upn user found, but FAILED to update."
}
}
else {
Write-Warning "$upn not found, skipped"
$SkippedUsers += $upn
}
}
My test .csv file:
After run the PS command, try to get customattribute1 of my test user:
Let me know if you have more questions.
I have an existing script which does the job of checking if a given user exists in AD or not. But I'm unable to export the result in csv file. Please help.
Clear-Host
$UserList = gc .\Output_userInfo.csv
$outputFilePath = "D:\Input\User&Group_Output.csv"
foreach ($u in $UserList) {
try {
$ADUser = Get-ADUser -Identity $u -ErrorAction Stop
}
catch {
if ($_ -like "Cannot find an object with identity: '$u'") {
"User '$u' does not exist." | Export-Csv .\notexists.csv -NoTypeInformation -Force
}
else {
"An error occurred: $_"
} continue
}
"User '$($ADUser.SamAccountName)' exists." |
Export-Csv .\notexists.csv -NoTypeInformation -Force
}
$UserList = gc C:\temp\Output_userInfo.csv #use full path instead. .\ is relative path and could cause issues if you are not careful
$outputFilePath = "D:\Input\User&Group_Output.csv"
$finalResult = foreach ($u in $UserList)
{
#CSV takes data in a table format. So best to replicate that with a PS Cusotm object that can easily be represented ina table format.
$obj = [PSCustomObject]#{
UserName = $u
Status = ""
}
try
{
$ADUser = Get-ADUser -Identity $u -ErrorAction Stop
$obj.Status = "Exists"
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
{
$obj.Status = "Does not Exist"
}
catch
{
$obj.Status = $_.Exception.Message
}
$obj
}
$finalResult | Export-Csv -Path $outputFilePath -NoTypeInformation -Force
If you are wondering how I knew the error type used in the 1st catch, you can find it by simulating an error [in this case, get-aduser blah would do it since such a user does not exist]. Then you can expand the last error message with select * as shown and look at the exception type. Alternately, you could also try to read the documentation but I don't have that kind of patience.
Need to write a script to take an input file (text) list of names, check if it exists in AD, and create new computers.
The requirements are as follows -
Computer names are based on the users name (input from file)
Names must be 15 characters (for name resolution)
if the truncated name doesnt exist, create a computer object in specific OU with the truncated name.
If the truncated name does exist, append -# and test to see if it exists until it finds one that doesnt, then create new computer object with that name.
At the end I will need to output the results to an array but I haven't started adding that yet since this doesn't work.
So I finally got the "else" part but the if part at the beginning does not work.
$users = get-content C:\scriptdata\VMS.txt
$OU = ************
foreach ($user in $users)
{
$cleanname = if ($user.Length -gt 15) { $user.Substring(0, 15) } else { $user }
$exist = (get-adcomputer $cleanname) -eq $null
if ((get-adcomputer $cleanname) -like "get-adcomputer : Cannot find an object with identity")
{
New-ADComputer -Name $cleanname -Path "$OU" -SAMAccountName $cleanname -confirm
}
else
{
$count=0
DO{
$count++
$cleanname13 = if ($user.Length -gt 13) { $user.Substring(0, 13) } else { $cleanname }
$cleannamedash = $cleanname13 + '-' + "$count"
}
UNTIL ((get-adcomputer $cleannamedash | out-null) -eq $null)
New-ADComputer -Name $cleannamedash -Path "$OU" -SAMAccountName $cleannamedash -confirm
}
}
currently works for -# but not for those that dont exist at all.
Have a look at Naming conventions in Active Directory for computers, domains, sites, and OUs.
You'll find that there is more to a valid computer name than just the length.
Mind that the New-ADComputer cmdlet creates a new computer object, but does not join a computer to a domain.
Something like this should work (untested)
$computers = Get-Content C:\scriptdata\VMS.txt | Where-Object { $_ -match '\S'}
$OU = ************
foreach ($name in $computers) {
$newName = ($name -creplace '[\\/:*?"<>|.]','').Substring(0, 15)
try {
$computer = Get-ADComputer -Filter "Name -eq '$newName'" -PassThru -ErrorAction Stop
}
catch {
$computer = $null
}
if ($computer) {
# a computer with that name already exists, create a new name by adding a dash and two digit number
$count = 0
$name12 = $newName.Substring(0, 12) # we're going to add three characters
# get an array of computernames that are like the one you want to create
$existingComputers = Get-ADComputer -Filter "Name -like '$name12-*'" | Select-Object -ExpandProperty Name
do {
$newName = '{0}-{1:00}' -f $name12, ++$count
}
until ($existingComputers -notcontains $newName -or $count -gt 99)
if ($count -gt 99) {
$newName = '{0}-XX' -f $name12
throw "Cannot create computer $newName because all index numbers 00..99 are taken.."
}
}
# use splatting, because New-ADComputer has MANY parameters
$props = #{
'Name' = $newName
'Path' = $OU
'SamAccountName' = $newName
'Enabled' = $true
'Confirm' = $true
}
Write-Host "Creating computer '$newName'"
New-ADComputer #props
}
I assume you mean that this is the line that's not working:
if ((get-adcomputer $cleanname) -like "get-adcomputer : Cannot find an object with identity")
And even this doesn't work:
$exist = (get-adcomputer $cleanname) -eq $null
The reason is the same in both cases: If the computer doesn't exist, then Get-ADComputer throws an exception and the comparison is never done.
There is a good article about this here, but in short, the solution is to catch the exception. For you, it would look something like this:
try {
$computer = Get-ADComputer $cleanname
# If we get here, we know it exists
# You can put your loop here and just keep looping until Get-ADComputer throws an exception
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
{
# Whatever you last tried doesn't exist. Create it here.
}
I'm trying to create a script that will pull a list of group members from AD and run a foreach loop to determine when the last time each user logged into any given domain controller. I got some of the code for the measure-latest function here . I would like to have the script run through the foreach loop and print the samAccountName (username) and last login time stamp (measure-latest) for each user in the group, but so far have not been able to get it working. I think I've got something wrong in logic but i can't seem to figure it out. Any help is appreciated, thank you.
# Get a list of last login times for a group of users
# Script Requires Quest Cmdlet features: https://support.software.dell.com/activeroles-server/download-new-releases
Add-PSSnapin Quest.ActiveRoles.ADManagement
# filter out $nulls and produce the latest of them
function Measure-Latest {
BEGIN { $latest = $null }
PROCESS {
if (($_ -ne $null) -and (($latest -eq $null) -or ($_ -gt $latest))) {
$latest = $_
}
}
END { $latest }
}
# Get list of group users by username
Get-ADGroupMember -identity "Domain Admins" | select samAccountName | Export-csv -path C:\Scripts\UserInformationByGroup\Groupmembers.csv -NoTypeInformation
# Get list of users from group, assign user value
$userlist = import-csv C:\Scripts\UserInformationByGroup\Groupmembers.csv
$user = $userlist | Select samAccountName
# Loop through list of users and print Username ------ Last Login time
foreach ($user in $userlist) {
Get-QADComputer -ComputerRole DomainController | foreach {
(Get-QADUser -Service $_.Name -SamAccountName $user).LastLogon
} | Measure-Latest $samAccountName | out-file -filepath C:\Scripts\UserInformationByGroup\userListLastLogin.txt -append
}
I should mention that when I run the script like this, and just enter each username manually it works and prints the last login time:
Add-PSSnapin Quest.ActiveRoles.ADManagement
function Measure-Latest {
BEGIN { $latest = $null }
PROCESS {
if (($_ -ne $null) -and (($latest -eq $null) -or ($_ -gt $latest))) {
$latest = $_
}
}
END { $latest }
}
Get-QADComputer -ComputerRole DomainController | foreach {
(Get-QADUser -Service $_.Name -SamAccountName USER_NAME_HERE).LastLogon
} | Measure-Latest
This part of the pipeline makes no sense:
| Measure-Latest $samAccountName |
Since nothing is assigned to the variable $samAccountName
You'll need to add pipeline support to your Measure-Latest function, like so:
function Measure-Latest {
[CmdletBinding]
param(
[parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
$LastLogon
)
# rest of the script (begin-process-end blocks) goes here
}
And now you can pipe the LastLogon values directly to the function:
(Get-QADUser -SamAccountName $user).LastLogon |Measure-Latest | Out-File #or whatever
Thanks to the ValueFromPipelineByPropertyName flag, you can now also pipe the entire object to the function:
Get-QADUser -SamAccountName $user | Measure-Latest
Because the parameter name ($LastLogon) matches that property anyways
In addition to that, I would probably change the logic a bit, so that you don't perform 1 LDAP query per DC per user. If you have 5 Domain Controllers and 200 users, that's now 1000 individual queries to the directory service.
You could simply retrieve ALL the users from each DC, in a single query, using the -LdapFilter parameter with Get-QADUser:
$LDAPClauses = #()
foreach($user in $userlist){
$LDAPClauses += "(samaccountname={0})" -f $user
}
# The | in an LDAP filter means logical OR
$LDAPFilter = "(&(LastLogon=*)(|$(-join($LDAPClauses))))"
Now you can run just a single query per DC:
Get-QADUser -LdapFilter $LDAPFilter
and it'll retrieve all the users in $userlist that has a LastLogon attribute value on that specific DC (you're not really interested in $null-values anyways, right?)
I have a script which loops through a list of users (samaccountname):
# Read usersfile to variable
$users = get-content ("users.txt")
# Get current time
$now = $(get-date -uformat "%H:%M %d/%m/%Y")
# Loop through list of users
foreach($user in $users) {
# Disable user
Disable-QADUser $user
# Set informative description
Set-QADuser $user -Description "Disabled $now"
# Delete all groupmemberships except "domain users"
Get-QADGroup -Containsmember $user | where-object { $_.name -ne 'domain users'} | Remove-QADGroupmember
# Move to "disabled users" group
move-QADObject $user -NewParentContainer 'contosoc.com/Disabled users'
# Hide from addresslist
Set-Mailbox -identity $user -HiddenFromAddressListsEnabled $true
# Moving mailbox to disabled users database
Move-Mailbox -Identity $user -TargetDatabase "myserver\mydb" -BadItemLimit 50 -Confirm:$False
}
I would like to:
Suppress output from the different cmdlets and only show "$user is OK!" if all is ok and log success to a logfile.txt
Display "Error!" and the command that failed if not ok. And output the complete error msgs to a separate logfile.
I've been thinking about doing a if(!cmdlettorun) { write-host "Error!" } But I'm thinking that there must be a better way.
How should I do error handling in a proper fashion so I minimize the displayed output but still let me see it if desirable?
For suppressing cmlet output you can pipe to out-null or precede the command with:
[void](.. your cmdlets..)
a good way for your goal is using a tray-catch-finally code like in this minimized code:
$a = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"
foreach($user in $users) {
try
{
... yours code ...
$JobStatus = "OK"
}
catch [exception]
{
$("Error catched: " + $_.Exception.GetType().FullName) | out-file c:\file.log
$("Error catched: " + $_.Exception.Message) | out-file c:\file.log -append
$JobStatus = "not OK"
continue;
}
finally
{
write-host "$user is $JobStatus!"
}
$ErrorActionPreference = $a
}
For some hint to use try-catch-finally read here