Powershell command execution order problem - powershell

I'm new in learning Powershell and I ran into a problem that makes me go insane. I want to write a simple Powershell script, that can be used to get both the group memberships of certain ActiveDirectory users, and the users of certain ActiveDirectory groups, and in the end gives the option to write the result on the console, or save it as csv.
Everything works perfectly fine, except no matter what I do, I can't stop the window from closing right after it writes the results on the console. I know that I can run a PS1 from command line in a way that doesn't allow the window to close, but I'd like Powershell do it by itself.
I tried to use both "pause" and Read-Host after the query script, but the stop event always happens BEFORE the result gets out on the console, no matter what's the order between the two of them. I simply cannot understand why the order of the execution of the two commands is backwards. Could you give me some insight why Powershell does it?
$nameofgroup = Read-Host -Prompt "`nPlease enter the name of the group!`n"
Get-ADGroupMember -identity $nameofgroup | Get-ADObject -Properties description, samAccountName | select #{n='Name'; e='name'}, #{n='Description'; e='description'}, #{n='Username'; e='samAccountName'}
$temp = Read-Host "Press Enter to continue..."

So you need to explicitly tell powershell to output the string. I also added in some error handling for you, so you don't have to run the script every time. Like if the group was typed wrong or doesn't exist.
Do
{
$nameofgroup = Read-Host -Prompt "`nPlease enter the name of the group!`n"
try
{
Get-ADGroupMember -identity $nameofgroup | Get-ADObject -Properties description, samAccountName | select #{n='Name'; e='name'}, #{n='Description'; e='description'}, #{n='Username'; e='samAccountName'} | Out-String
$errorMessage = 'False'
Read-Host -Prompt 'Press Enter key to exit'
}
catch
{
Write-Host "Could not find group please try again"
$errorMessage = 'True'
}
}
while($errorMessage -eq 'True')

Related

Specifying a list of usernames to be deleted from AD via powershell

I was wondering if you could help me.
I was hoping you could assist me in creating a script where I would specify a list of usernames (could be either in .txt or csv file) to be deleted from AD in PowerShell.
I know there is command to do this but I have to change the username every time I run the command:
Remove-ADUser Username
Thanks for your assistance guys.
UPDATE 1
Can you stop changing the question (I would prefer help instead!)
I am looking into this myself and will attempt to answer the question (I am still learning so be patient!).
I have come up with a script:
$users=Get-Content -Path C:\Users\Me\Desktop\disableusers.txt
ForEach ($user in $users)
{
Remove-ADUser -identity $user
}
I know its not the most slickest of scripts but if it does the job I am happy.
I have also found something like this:
$Users = Import-Csv 'c:\temp\yourcsv.csv'
Foreach ($User in $Users)
{
Try
{
# Verify that users from your CSV exist in Active Directory
Get-ADUser $User -ErrorAction Stop | Out-Null
Remove-ADUser $User -Confirm:$False
}
Catch
{
  Write-Host "Username '$User' not found in Active Directory"
}
}
But the above script must take this into consideration:
Depending how your csv looks like you might need to change $User to $User.SamAccountName or whatever that column is named in your csv.
UPDATE 2
I tried to do the CSV method but I get error stating it can't find the usernames.
I tried with CSV only containing usernames and altering the script and also with the field header of SamAccountName, I know this will sound stupid but once I have a field header of SamAccountName does that mean all $Users and now $User.SamAccountName in the CSV script?

Powershell Get AD user group query

I am trying to create a script that will allow me to enter a user name and will then present me with all the groups that the user is a member of in AD. I have the following code which works when i run it in Powershell ISE but when i just run the script in Powershell it allows me to enter the username but closes as it has queried AD. It does not print the results out on the screen.
$username = Read-Host 'Please enter Username!'
get-aduser $username -Properties memberof | select -expand memberof
If you are pasting the code into an already open PowerShell terminal then yes, that is definitely weird.
If you are right clicking and "Running with PowerShell" then this is the expected behaviour because the script has finished. You'll need to tell the script to stay open after it has retrieved the information. The easiest way to do this is by telling the script to wait for your input using Read-Host
$username = Read-Host 'Please enter Username!'
get-aduser $username -Properties memberof | select -expand memberof
Read-Host 'Done!'
UPDATE
Using an if statement wouldn't be feasible since it only catches terminating errors and Get-ADUser doesn't return terminating errors you would need to use a try/catch block. I over engineered this solution use to show you how it could be done using different PowerShell features :)
#Function to search for the user
function searchUser{
Param([string]$userName)
try{
Get-ADUser -Identity $userName -Properties MemberOf | Select-Object -ExpandProperty MemberOf
}catch{
return $false
}
}
#Ask the user for input until a valid username is entered
do {
$userInput = Read-Host "Enter a username: "
}until ($Output = searchUser -userName $userInput)
#Output the value from the searchUser function
Write-Host $Output

Command to Unlock a locked domain user

I'v been using these to list locked users in my domain and prompt me for input samaccountname to unlock desired one:
I did it with 3 file.
first one is ps1 to list all of them
import-module activedirectory
search-adaccount -lockedout | select name, samaccountname, OU
second one is another ps1 file:
$user = Read-Host "Enter user account (SAMACCOUNTNAME) to unlock or press ENTER to refresh list"
Search-ADAccount -LockedOut | Where {$_.samaccountname -eq $user} | Unlock-ADAccount
and for executing above files, i use a .bat file:
:loop
powershell.exe -ExecutionPolicy Bypass -File c:\ps\lockedlist.ps1
powershell.exe -ExecutionPolicy Bypass -File c:\ps\unlock.ps1
cls
goto loop
and when i run it... it list all locked users and i can copy paste each samaacount name to unlock them
BUT the problem is,when I want to do it with ONE ps1 file it doesnt work. it just ask for samaccountname but it doesnt list it
import-module activedirectory
search-adaccount -lockedout | select name, samaccountname, OU
$user = Read-Host "Enter user account (SAMACCOUNTNAME) to unlock or press ENTER to refresh list"
Search-ADAccount -LockedOut | Where {$_.samaccountname -eq $user} | Unlock-ADAccount
i know .bat file will be pretty same...
thanks to anyone who reads and helps.
Powershell always tries to optimize the output it gives for you. So the order of the output might not be the same as you expect it from the commands you have in a script. If possible it will concatenate output to be more readable especially when it's the same type of objects. To break this you could use a format cmdlet like Format-Table par example.
Search-ADAccount -LockedOut |
Select-Object -Property Name, sAMAccountName, DistinguishedName |
Format-Table
$user = Read-Host -Prompt 'Enter user account (SAMACCOUNTNAME) to unlock or press ENTER to refresh list'
Search-ADAccount -LockedOut |
Where-Object -FilterScript {$_.samaccountname -eq $user} |
Unlock-ADAccount
At least, it worked in my environment.
And BTW: Since Powershell version 3 you don't need to explicitly import the modules anymore. They will be imported automaticaly. Better would be to use a #Requires statement like #Requires -Modules activedirectory on top of the script. That would even prevent the script to run if there's no active directory module installed

Log each Powershell process to text file through

Firstly, I'm by no means a PS expert, total newbie - admission done. I have scoured the internet for what I need in order to get the script to do what I want, but I've reached a point where I'm struggling and in need of help.
Basically, I've created a script using ISE that grabs the users in an AD OU, processes them by disabling the accounts, renaming them, stripping out the groups and moving them to another folder. In order to automate the deactivation process for users. But I now need to create a log file every time this runs, to show a) if it found any Users in the original OU (ToBeProcessed) and b) what processes were run and if they were successful. Here is the code.
$OUToBeProcessed = "OU=ToBeProcessed,OU=Users,OU=World,DC=local"
$OURetired = "OU=RetiredUsers,OU=Users,OU=World,DC=local"
$Users = Get-ADUser -SearchBase $OUToBeProcessed -Filter 'name -Like "*"' -Properties MemberOf
ForEach($User in $Users){
$SAN = $User.SamAccountName
#Disable user account
Disable-ADAccount -Identity $SAN
#Remove membership from groups for user
$User.Memberof | Remove-ADGroupMember -Member $User -Confirm:$False
$NewDN = "zzz_" + $User.Name
#Change display name
set-aduser $User -Displayname $newDN -ErrorAction SilentlyContinue
#Change distinguished name
Get-ADUser $SAN | Rename-ADObject -Newname $NewDN
Write-Host "$SAN may already exist."
#Move account to RetiredUsers
Get-Aduser $SAN | Move-ADObject -TargetPath $OURetired
}
I'm assuming I'll need to either use a Write-Output or Log-File cmdlet, though someone had also suggested Transcript, but I don't think that's what I need.
I've tried a number of ways to incorporate the Write-Output into the script, it runs without errors, but no text file is produced. But I'm placing it within the loop which may be the issue. I've placed it outside the loop but I think because it's not being passed anything it's creating the file with nothing in it. Would really appreciate some help as to where the Write-Output might need to go if that is the right cmdlet.
Personally I tend to add a Log function to my scripts. Something like this (where I output to the host and file):
Function Log {
Param (
[Parameter(Mandatory=$true)] [string] $String,
[Parameter(Mandatory=$true)] [string] $LogFilePath,
[Parameter(Mandatory=$false)][ValidateSet("ERROR","WARN","INFO","DEBUG")] [string] $Level = "INFO"
)
$LogString = ((Get-Date -Format "s") +" $Level $env:USERNAME $String")
Write-Host $LogString
Out-File -Append -FilePath $LogFilePath -InputObject $LogString
}
Then you could do logging:
Log "Something wrong!" "c:\mylog.log" "WARN"
Log "Updated stuff" "c:\mylog.log"
Or search the http://www.powershellgallery.com/ for logging modules.
Example (haven't tried this one myself):
https://www.powershellgallery.com/packages/PSLogging/2.5.2

Adding Users to Groups from another Domain with Powershell

I have been tasked with creating a PowerShell script that copies Active Directory Group Memberships from a specified Source User (as a template) to a specified Target User. These users can be in one of two domains: Domain_A and Domain_B. The groups are all located in Domain_B.
The issue that I'm running into is that when I specify that both of the users are in Domain_A, it attempts to look for the groups in Domain_A, when in reality the groups are all in Domain_B (this throws an error saying that it can't find the groups). There is a 2 way trust between the domains as they are all located in the same forest.
How can I make it so that it will still specify the domains that the users are located in, but it will also specify the domain that the groups are located in? Here is a copy of my source code for reference (edited to remove the server names):
$Source_Server = Read-Host "Please enter the Source Server: "
$Source_UPN = Read-Host "Please enter the Source UPN: "
$Target_Server = Read-Host "Please enter the Target Server: "
$Target_UPN = Read-Host "Please enter the Target UPN: "
Try {
Get-ADUser -Identity $Source_UPN -Properties memberof -Server$Source_Server |
Select-Object -ExpandProperty memberof |
# Find Properties of the memberships of the Source User
Add-ADGroupMember -Members $Target_UPN -Server $Target_Server |
Select-Object -ExpandProperty SamAccountName
# Copy the group memberships of the Source User to the Target User.
}
Catch {
$Error_Message = $_.Exception.Message
Write-Host $Error_Message
Write-Host -NoNewLine "Press any key to exit..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
# Exits the program
}
If (!$Error) {
"Group Copy Successful."
$Error_Message = "No errors occured."
# Shows that it ran error-free
Write-Host -NoNewLine "Press any key to exit..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
# Exits the program
}
If you're trying to add the user in Domain B to the group in Domain A, you need to fix the Server parameter here to go to the Source Server:
Add-ADGroupMember -Members $Target_UPN -Server $Target_Server