Below I have a PS command to get some useful user info. I want also have the input from a csv file with PC names. How can I give everything the same format?
The colon after PC name is not the same as I've got from the output from get-aduser. Can someone advise me what to do?
Example of what I've got
Clear-Host
do {
write-Host " Enter the user ID: " -ForegroundColor Cyan -NoNewline
$UserName = Read-Host
Write-Host ""
Get-ADUser -Identity $Username -Properties * | Select-Object DisplayName, mail, LastLogonDate, LastBadPasswordAttempt, AccountExpirationDate, PasswordLastSet , OfficePhone, Department, Manager
$Processes = Import-CSV 'C:\Users\w0vlnd\Desktop\Powershells\Computers in a specific workgroup or domain.csv'
$processes | where "User ID" -like $Username | Select-Object "PC name"
net user $Username /domain | find "Password expires"
net user $Username /domain | find "Password changeable"
write-host "`n"
} while ($Username -notcontains $Processes)
You can construct an object that merges the AD User with the information coming from your CSV and the information from net user. Here is an example of how you can approach it:
$csv = Import-CSV 'path\to\csvhere.csv'
$ADprops = #(
'DisplayName'
'mail'
'LastLogonDate'
'LastBadPasswordAttempt'
'AccountExpirationDate'
'PasswordLastSet'
'OfficePhone'
'Department'
'Manager'
)
$filter = #(
$ADprops
#{
Name = 'PC Name'
Expression = { $pcName }
}, #{
Name = 'Password Changeable'
Expression = { $changeable }
}, #{
Name = 'Password Expires'
Expression = { $expires }
}
)
Clear-Host
do
{
Write-Host " Enter the user ID: " -ForegroundColor Cyan -NoNewline
$UserName = Read-Host
Write-Host ""
$pcName = $csv.Where({ $_."User ID" -match $Username })."PC Name"
$expires, $changeable = net user $Username /domain |
Select-String -Pattern 'Password Changeable|Password Expires' |
ForEach-Object { ($_ -split '\s{2,}')[1] }
Get-ADUser -Identity $Username -Properties $ADprops |
Select-Object $filter
} while ($csv.'User ID' -notcontains $Username)
Related
I'm having issues trying to have my script read and apply the AD groups with my script. Right now, it's just posting what's in my script, but I would like to have the script read what's in my .txt file and use it with the rest of my script.
$filePath = "C:\Users\UserName\Downloads\ADGroupList.txt"
Get-Content -Path $filePath
Get-ADGroup -filter {Name -like "$filePath" } -Properties managedBy |
ForEach-Object {
$managedBy = $_.managedBy;
if ($managedBy -ne $null)
{
$manager = (get-aduser -Identity $managedBy -Properties emailAddress);
$managerName = $manager.Name;
$managerEmail = $manager.emailAddress;
}
else
{
$managerName = 'N/A';
$managerEmail = 'N/A';
}
Write-Output $_; } |
Select-Object #{n='Group Name';e={$_.Name}}, #{n='Managed By Name';e={$managerName}}, #{n='Managed By Email';e={$managerEmail}}
Export-Csv -Path "C:\Users\UserName\Documents\ADGroupManagerList.csv"
The easiest way is to loop over the group names you have in the ADGroupList.txt file (assuming this is a list of group names, each on a separate line)
$filePath = "C:\Users\UserName\Downloads\ADGroupList.txt"
# just loop over the group names you have in the text file and capture the output
$result = Get-Content -Path $filePath | ForEach-Object {
$group = Get-ADGroup -Filter "Name -like '$_'" -Properties managedBy
# create an object pre filled in when no manager was found
$obj = [PsCustomObject]#{
'Group Name' = $group.Name
'Managed By Name' = 'N/A'
'Managed By Email' = 'N/A'
}
# test if the ManagedBy is populated
if (-not [string]::IsNullOrWhiteSpace($group.ManagedBy)) {
# try to use the DN in property ManagedBy to find the manager
try {
$manager = Get-ADUser -Identity $group.ManagedBy -Properties EmailAddress -ErrorAction Stop
$obj.'Managed By Name' = $manager.Name
$obj.'Managed By Email' = $manager.EmailAddress
}
catch {
Write-Warning "No user found for '$($group.ManagedBy)'.. Please check AD."
}
}
# output the object so it gets collected in variable $result
$obj
}
# write the file
$result | Export-Csv -Path "C:\Users\UserName\Documents\ADGroupManagerList.csv" -NoTypeInformation
For workaround you can use this powershell script to get the mangedBy of groups.
Get-ADGroup -filter * -Properties managedBy |
ForEach-Object {
$managedBy = $_.managedBy;
if ($managedBy -ne $null)
{
$manager = (get-aduser -Identity $managedBy -Properties emailAddress);
$managerName = $manager.Name;
$managerEmail = $manager.emailAddress;
}
else
{
$managerName = 'N/A';
$managerEmail = 'N/A';
}
Write-Output $_; } |
Select-Object #{n='Group Name';e={$_.Name}}, #{n='Managed By Name';e={$managerName}}, #{n='Managed By Email';e={$managerEmail}}
After adding the code
$ip = (nslookup $pcName | Select-String Address | Where-Object
LineNumber -eq 5).ToString().Split(' ')[-1]
It will not give any result when the user has NO pc name assigned to his User ID. The script doesn't run and it's giving a blank result. It works when the user has a PC name assigned to his user id.
The same when the user ID cannot be found due to typo or something else. There I want to prompt the user to give in the correct user ID and restart the script. I'm trying to figure it out how it can be done but I don't find the correct way to do it.
Thanks in advance for your help!
$csv = Import-CSV 'C:\Users\ADMIN\Desktop\Powershells\Computers in a specific workgroup or domain.csv'
$ADprops = #(
'DisplayName'
'Mail'
'LastBadPasswordAttempt'
'AccountExpirationDate'
'PasswordLastSet'
)
$filter = #(
$ADprops
#{
Name = 'Password Changeable'
Expression = { $changeable }
}, #{
Name = 'Password Expires'
Expression = { $expires }
}, #{
Name = 'Last logon'
Expression = { $lastlogon }
}, #{
Name = 'PC Name'
Expression = { $pcName }
}, #{
Name = 'Address'
Expression = { $ip }
}
)
Clear-Host
do
{
Write-Host " Enter the user ID: " -ForegroundColor Cyan -NoNewline
$UserName = Read-Host
Write-Host ""
$pcName = $csv.Where({ $_."User ID" -match $Username })."PC Name"
$ip = (nslookup $pcName | Select-String Address | Where-Object LineNumber -eq 5).ToString().Split(' ')[-1]
$expires, $changeable = net user $Username /domain |
Select-String -Pattern 'Password Changeable|Password Expires|Last logon'|
ForEach-Object { ($_ -split '\s{2,}')[1] }
Get-ADUser -Identity $Username -Properties $ADprops |
Select-Object $filter
} while ($Username -notcontains $Processes)
When testing your code I notice that when you provide the function nsloockup with empty string value the function is stucked. What I suggest is to add a check on the $pcName variable as follow:
$pcName = $csv.Where({ $_."User ID" -match $Username })."PC Name"
if([string]::IsNullOrEmpty($pcName)){
continue;
}
I'm trying to create kind of a solution to create thousands of accounts in AD add them to specific group or for service accounts add them to specific OU. Keep a log of what was done and what the errors are.
The script ingest a csv file with the following headers.
SamAccountName,name,password,ou,domain,isAdded
$Domain = [system.directoryservices.activedirectory.domain]::GetCurrentDomain().Name
$NewUserADGroup = 'Print Operators'
$NewUsersList = Import-Csv .\bulk_user1.csv | Where-Object{$_.domain -like "$Domain"}
$NewUsersList | ForEach-Object{
$NewUserAttributes = #{
SamAccountName = $_.SamAccountName
name = $_.name
#path = $_.parentou
#UserPrincipalName = $_."samAccountName" + "#lovely.Local"
AccountPassword = (convertto-securestring "$NewUsersList.password" -AsPlainText -Force)
Enabled = $true
#Server = $dcname
#isAdded = $Issue
}
try{
#Create new User and add to specific group
New-ADUser $NewUserAttributes
Add-ADGroupMember -Identity $NewUserADGroup -Members $_.SamAccountName
#Delete Specific User
#Remove-ADUser -Identity $_.SamAccountName
}catch{
Write-Warning $_
$Issue = $_.ToString()
}
$count = $count + 1
Write-Host $_.SamAccountName " " $_.Name " " $_.SamAccountName.Enabled " Total:" $NewUsersList.Count + "Processed:" $count
$NewUserAttributes| Select-Object -Property SamAccountName,name,AccountPassword,Enabled,isAdded | Export-Csv ".\$Domain.NewAccountsCreatedStatus.csv"
}
I'm getting the following error:
WARNING: The name provided is not a properly formed account name
When I look at the variable
$NewUserAttributes
I do see the name and the value:
Name Value
---- -----
Enabled True
name bfmbsngfilexfer2
AccountPassword System.Security.SecureString
SamAccountName bfmbsngfilexfer2
As promised, below a rewrite of your code.
I have inserted comments to hopefully explain what the code does:
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().Name
$NewUserADGroup = 'Print Operators'
$successCount = 0
$NewUsersList = Import-Csv .\bulk_user1.csv | Where-Object { $_.domain -eq $Domain } | ForEach-Object {
# capture the human readable password for output use
$password = $_.password
$userParams = #{
SamAccountName = $_.SamAccountName
Name = $_.name
Path = $_.parentou
UserPrincipalName = '{0}#lovely.Local' -f $_.SamAccountName
AccountPassword = ConvertTo-SecureString $_.password -AsPlainText -Force
Enabled = $true
#Server = $dcname
}
try{
# Create new User and add to specific group
$user = New-ADUser #userParams -PassThru -ErrorAction Stop
Add-ADGroupMember -Identity $NewUserADGroup -Members $user -ErrorAction Stop
# add the 'isAdded' element to the $userParams hashtable
$userParams['isAdded'] = $true
$successCount++
}
catch{
Write-Warning $_.Exception.Message
$userParams['isAdded'] = $false
}
# output a PsCustomObject with values taken from the Hashtable
# AccountPassword is a SecureString, which will be of no use to you..
# Output the human readable password instead so you can inform the new users.
[PsCustomObject]$userParams | Select-Object SamAccountName, Name,
#{Name = 'Password'; Expression = {$password}},
Enabled, isAdded
}
# output
# use '#($NewUsersList)' to force it as array, so the Count property is accurate
if (#($NewUsersList).Count) {
Write-Host ('Processed: {0} Succeeded: {1}' -f $NewUsersList.Count, $successCount) -ForegroundColor Green
$NewUsersList | Export-Csv ".\$Domain.NewAccountsCreatedStatus.csv" -NoTypeInformation
}
else {
Write-Host 'No users successfully processed!' -ForegroundColor Red
}
I am writing a powershell script to disable users due to the fact that we get a list of them everyday and it is monotonous. I paste the list from the ticket into a csv formatted as Lastname, Firstname then run my script with imports the list, serches ad and ask if you want to disable if it finds them. Here is the code...
# Set variables
$Import = "C:\Scripts\Support Files\Users_To_Disable.csv"
$Export = "C:\Scripts\Support Files\Disabled_Users_Output.txt"
# Import user list
$Users = Import-CSV $Import
foreach ($User in $Users)
{
# Set user variables
$LastName = $User.("Surname")
$FirstName = $User.("GivenName")
# Use user variables from list to search ad
$UserName = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
# What to do if it finds nothing
If ($UserName -eq $Null)
{
Write-Host $LastName, $FirstName NA -ForegroundColor Yellow
Write-Output "$LastName, $FirstName NA" | Out-File $Export -Append
}
# What to do if it finds a user
Else
{
# Ask for user input
Write-Host $LastName, $FirstName Found -ForegroundColor Green
Write-Host UserName = $UserName -ForegroundColor Green
DO {
$Disable = Read-Host "Do you want to disable user? (Y/N)"
If($Disable -eq "Y")
{
# Disable the user
Disable-ADAccount -Identity $UserName
# Move the user
Get-ADUser $UserName | Move-ADObject -TargetPath "OU=Disabled - Retention,DC=intranet,DC=sw"
# Add Disabled Users group
Add-ADGroupMember "Disabled Users" -Members "$UserName"
# Set Disable Users as primary group
$Group = Get-ADGroup "Disabled Users" -Properties #("PrimaryGroupToken")
Get-ADUser "$UserName" | Set-ADUser -Replace #{PrimaryGroupID=$Group.PrimaryGroupToken}
# Remove all other groups
$User = Get-ADUser "$UserName" -Properties MemberOf
$Groups = $User.MemberOf |ForEach-Object { Get-ADGroup $_ }
$Groups | ForEach-Object { Remove-ADGroupMember -Identity $_ -Members $User -Confirm:$false }
# Output
Write-Host $LastName, $FirstName Disabled -ForegroundColor Red
Write-Output "$LastName, $FirstName Disabled" | Out-File $Export -Append
Break
}
}
Until ($Disable -eq "N")
}
}
Invoke-Item $Export
All of that works, what is scary is that if there are blank cells above a user then it returns all of the users in ad and asks if you want to disable all of them. In other words if the csv looks like this...
Surname GivenName
User Test
Everything works fine, but if it looks like this...
Surname GivenName
User Test
Pandemonium, well not really but it does ask if you want to initiate a resume generating event, which I don't so how can I build in some safety that would stop it from returning all of ad when there are blanks in the csv before users?
You can eliminate the blank lines by filtering out Null values on your import, which should resolve the problem.
$Users = Import-CSV $Import | Where-Object {$_.Surname}
Nowhere have I found anyone attempting to prompt for first and last names and then put that into a variable with a wildcard.
If I substitute real values with the asterisk, it works but attempting to do so with a variable returns nothing.
$LastName = Read-Host "Enter user's Last Name"
$FirstName = Read-Host "Enter users's First Name"
$GroupMembershipList = (Get-ADUser -Filter {(GivenName -like $FirstName*) -and (Surname -like $LastName*)}).SAMAccountName
Foreach ($Name in $GroupMembershipList) {
$GroupMemberShip = Get-ADPrincipalGroupMembership -Identity "$Name" | Sort Name |ForEach-Object {$_.name -replace ".*:"}
$FullName = Get-ADUser $Name -Properties * | Select -Property DisplayName
$UserPrincipalName = Get-ADUser $Name -Properties * | Select -Property UserPrincipalName
#Write-Output $PrincipalName
Write-Output $FullName
Write-Output $Name
Write-Output $GroupMembership
Write-Output " "
}
I think the issue is just that your braces are preventing your variables from expanding the way you expect them to.
I offer this since -Filter will work with properly formatted strings as well.
$GroupMembershipList = Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'" | Select-Object -ExpandProperty SamAccountName
and yes you can just get the property the same was you did before
$GroupMembershipList = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
I used the second suggestion and it worked. I am new to PS and also to programming in general.
I find PS confusing at times regarding the placement of parenthesis, brackets, etc. I generally have the logic but mess up on placing these delimiters.
You mentioned formatting my code. I am sorry I don't know what you mean by that.
Also, I would rather use Write-Host to allow for formatting but when I do, all of the data is on a single line and the user returned is specified as #{DisplayName=Doe, John}.
Can you address that or should this be posted to a new subject?
I worked on it more and figured the Write Host stuff. Also added a Do Loop
$ErrorActionPreference = "Stop"
$Continue = "Quit"
Do {
$LastName = Read-Host "Enter user's Last Name"
$FirstName = Read-Host "Enter users's First Name"
$GroupMembershipList = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
Foreach ($Name in $GroupMembershipList) {
$GroupMemberShip = Get-ADPrincipalGroupMembership -Identity "$Name" | Sort Name |ForEach-Object {$_.name -replace ".*:"}
Write-Host " "
Write-Host $FirstName, $LastName -ForegroundColor Yellow
Write-Host IMC UserName = $Name
Write-Host "*****************************" -ForegroundColor Red
Write-Host "Groups $Firstname $LastName is a member of:" -ForegroundColor Yellow
$GroupMembership
Write-Host " "
}
$Continue = Read-Host "Do you want to check another name? (Y/N)"
If($Continue -eq "Y"){
}
}
until ($Continue -eq "N")
$GivenName = read-host "What's the users first name (wildcard * ok)?"
$Surname = read-host "What's the users last name (wildcard * ok)?"
Get-ADUser -filter{(Surname -like $Surname -and GivenName -like $GivenName)} -properties GivenName, Surname, UserPrincipalName, mobile