Automating a boring task - powershell

The second half of my script does not function the way I want it to. I believe I am using the incorrect cmdlet. I am trying to add a group from active directory to the local administrator account on a laptop/pc. And after this add a domain user to the power user group.
I want to pull from AD the group name, which I thought this cmdlet would do so. Any ideas?
I only ran the second half but receive errors. I have tried other cmdlets but I think this one is the most accurate.
#change computer name of the device + condition
$answer = Read-Host -Prompt 'Do you want to change the computer name?'
# First condition - 1) name comupter 2) take user creds 3) Rename computer using stored cred 4) write host if yes is the answer
if ($answer -match "yes"){
$computername = Read-Host -Prompt "What will be the name of the computer?"
#This part of the script will contain your credentials to change the computername and priveledges
$cred = Get-Credential -Message "This will be used to changed the computername. Do not worry!"
#$cred = Read-Host -Prompt "Enter your network username" - Uneeded string
Rename-Computer -NewName "$computername" -LocalCredential $cred -DomainCredential $cred
Write-Host "Computername has been changed to $computername successfully!"
}
#Second condition - If answer is no move on to second portion of the script to set privledges
elseif($answer -match "no"){
Write-Host "Moving to the next part of the script"
}
#Third condition - If answer is anything else - loop to the beginning of the script to accept the right answer
else{
write-host "Please answer with yes or no"
}
#Second half of script
#Adding AD group to local adminitrator
$localuser= Read-Host "Enter username of the PowerUser."
Add-LocalGroupMember -Group "Administrator" -Member "memeber"
Add-LocalGroupMember -Group "Power Users" -Member $localuser + "tamu.jaguar.edu"

Related

password change for delegated users

I'm having some problems running a powershell script when not on the domain controller.
The idea is that a delegated user such as a principal can change the passwords for students.
On the server I have added the membership into the powershell script allowing users to remote connect.
I have tested the code line by line on an end users account and computer.
However, when I run the script the import-module active directory doesn't work.
The error I get on the screen shows that it doesn't know what get-ADUser is followed by still being connected to the remote powershell connection on the domain controller.
Enter-PSSession -ComputerName DomainController
Import-Module ActiveDirectory
Write - Host "********************************************************** `r`nDomainController - Studnet Password Configurator `r`n********************************************************** `r`n `r`nThis program will assist when a student requires a password change. `r`nPlease ensure that you verify the student prior to implementing the change. `r`n"
do
{
$TargetUser = Read-Host -Prompt 'Enter a student user ID name'
if (Get-ADUser -Filter {SamAccountName -eq $TargetUser})
{
"Process user $TargetUser"
Get-ADUser -Identity $TargetUser
$passwordchange = Read-Host -Prompt 'Would you like to change the user password? [y|n]'
if ($passwordchange -eq 'y')
{
$newPassword = Read-Host -Prompt 'Please type new password'
Set-ADAccountPassword $TargetUser -Reset -NewPassword (ConvertTo-SecureString -Force -AsPlainText '$newPassword')
Write - Host "$TargetUser` password has now been changed to: $newPassword"
}
}
else
{
Write - Host "$TargetUser` does not exist, please try again."
}
$answer = Read-Host -Prompt 'Would you like to see another user? [y|n]'
}
until ($answer -eq 'n')
Exit-PSSession

Find a user by their real name in Active Directory

This script is for reseting passwords on AD users if they lost it and need to make a new one. But let's say we dont know the username only their real name, so we want to search for the username and insert it to $Username.
function Reset_Password_Account () {
$Username = Read-Host "Enter your username"
Write-Host "Changing Password for account" $Username
$Newpassword = Read-Host "Enter Temporary Password" -AsSecureString
Write-Host "Running Script..."
Set-ADAccountPassword $Username -NewPassword $Newpassword
Write-Host "Temporary password set"
Set-ADUser $Username -ChangePasswordAtLogon $True
Write-Host "You can now change password on login"
# Stop powershell from exiting after script is run
Read-Host "Press enter to exit"
}
$Readhost = Read-Host "To run script: Enter y
To decline script: Enter n and exit PowerShell
Press Enter to accept your input. ( y / n )"
switch ($ReadHost) {
Y {Reset_Password_Account}
N {exit}
I would recommend using Ambiguous Name Resolution, it searches a range if AD Attributes (list in link) and finds any matches.
The example query below would return both Jimmy Smith and Jim Smith-Williams
Get-ADUser -LDAPFilter "(anr=Jim Smith)"
It will search for all objects where any of the naming attributes start with the string "jim smith*", plus all objects where (givenName=jim*) and (sn=smith*), plus objects where (givenName=smith*) and (sn=jim*).

Create local user as part of Administrator group on Windows 10

Setup:
We are all in domain environment. Active Directory is Windows Server 2012 R2
Client Workstations are mix of Windows 10 versions (1703 and 1709)
Need to create user "Servis" on all workstation and place it to local Administrator group. I will input a text file with the host names.
This is the script im trying to make it work, but no success.
The user is created, but user is not added to local admin group.
This is the error i get :
Error creating Service23 on WinNT://WS-TEST: The following exception occurred while retrieving member "add": "The network path was not found.
$computers = Get-Content -path C:\Scripts\CreateLocalUser\New\Computers.txt
$username = "Servis"
$password = "P4$$w0rd!##"
Foreach ($computer in $computers) {
$users = $null
$computer = [ADSI]"WinNT://$computername"
Try {
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username already exists" -ForegroundColor Green
}
Else {
$user_obj = $computer.Create("user", "$username")
$user_obj.SetPassword($password)
$user_obj.SetInfo()
$user_obj.Put("description", "$username")
$user_obj.SetInfo()
$user_obj.psbase.invokeset("AccountDisabled", "False")
$user_obj.SetInfo()
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username has been created on $($computer.name)"
$group = [ADSI]("WinNT://" + $computername + "/administrators,group")
$group.add("WinNT://" + $computername + "/" + $username + ",user")
}
Else {
Write-Host "$username has not been created on $($computer.name)"
}
}
}
Catch {
Write-Host "Error creating $username on $($computer.path): $($Error[0].Exception.Message)"
}
}
Once you've defined your credential correctly with a password in a SecureString format creating a local admin is a 2 step process:
Create a user
Add that user to the Local Administrators group
These few lines are the powershell code needed:
$username = "Servis"
$password = ConvertTo-SecureString -AsPlainText "P4$$w0rd!##" -Force
New-LocalUser "$username" -Password $password -FullName "$username" -Description "Local admin $username"
Add-LocalGroupMember -Group "Administrators" -Member "$username"
If you want make you script more robust you should consider to create some Pester tests and add these checks to your script:
Validate if your file exists
Validate the content of the file (if is an IP or a FQDN with a regex)
Test if the host is reachable (e.g. Test-Connection -computername $computer -count 1 -quiet) before connecting
Using invoke-command with computername and argumentlist (username, password)
Check if the user was created successfully and is a member of the administrator group if not throwing an error
Write a log file to keep trace of all the tasks completed (by who, when on what host and so on).
I wrote a blog post on www.scriptinglibrary.com on few better ways of completing this task if you're interested.

Trying to script profile deletion for remote workstations

I work in a large company and that is global and I would like to be able to run a script that will allow me to clean up old profile remotely. I found this script but it doesn't seem to do anything. Does anyone have thought to why. I am a novice in powershell so any help would be appreciated. Thanks in advance!
function Remove-ProfileWD {
<#
.SYNOPSIS
Interactive menu that allows a user to connect to a local or remote computer and remove a local profile.
.DESCRIPTION
Presents an interactive menu for user to first make a connection to a remote or local machine. After making connection to the machine,
the user is presented with all of the local profiles and then is asked to make a selection of which profile to delete. This is only valid
on Windows Vista OS and above for clients and Windows 2008 and above for server OS.
.EXAMPLE
Remove-ProfileWF
Description
-----------
Presents a text based menu for the user to interactively remove a local profile on local or remote machine.
#>
#Prompt for a computer to connect to
(
[Parameter(Mandatory=$true)]
$Computer = Read-Host "Please enter a computer name"
)
#Test network connection before making connection
If ($computer -ne $Env:Computername) {
If (!(Test-Connection -comp $computer -count 1 -quiet)) {
Write-Warning "$computer is not accessible, please try a different computer or verify it is powered on."
Break
}
}
Do {
#Gather all of the user profiles on computer
Try {
[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" -ea stop
}
Catch {
Write-Warning "$($error[0]) "
Break
}
#Cache the number of users
$num_users = $users.count
Write-Host -ForegroundColor Green "User profiles on $($computer):"
Write-Host -ForegroundColor Green "User profile Last Use ate"
#Begin iterating through all of the accounts to display
For ($i=0;$i -lt $num_users; $i++) {
Write-Host -ForegroundColor Green "$($i): $(($users[$i].localpath).replace('C:\Users\','')) $(get-item \\$computer\C`$\users\$(($users[$i].localpath).replace('C:\Users\',''))| Foreach {$_.LastWriteTime}) "
}
Write-Host -ForegroundColor Green "q: Quit"
#Prompt for user to select a profile to remove from computer
Do {
$account = Read-Host "Select a number to delete local profile or 'q' to quit"
#Find out if user selected to quit, otherwise answer is an integer
If ($account -NotLike "q*") {
$account = $account -as [int]
}
}
#Ensure that the selection is a number and within the valid range
Until (($account -lt $num_users -AND $account -match "\d") -OR $account -Like "q*")
If ($account -Like "q*") {
Break
}
Write-Host -ForegroundColor Yellow "Deleting profile: $(($users[$account].localpath).replace('C:\Users\',''))"
#Remove the local profile
($users[$account]).Delete()
Write-Host -ForegroundColor Green "Profile: $(($users[$account].localpath).replace('C:\Users\','')) has been deleted"
#Configure yes choice
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Remove another profile."
#Configure no choice
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No","Quit profile removal"
#Determine Values for Choice
$choice = [System.Management.Automation.Host.ChoiceDescription[]] #($yes,$no)
#Determine Default Selection
[int]$default = 0
#Present choice option to user
$userchoice = $host.ui.PromptforChoice("","Remove Another Profile?",$choice,$default)
}
#If user selects No, then quit the script
Until ($userchoice -eq 1)
}

Using Read-host with Input validation and TRAP

I'm just a typical admin trying to make a simple script for some IT assistants in remote offices, to make domain joins easier while minimizing potential errors. The script's end game is to run the one-liner command Add-Computer -DomainName $DomainToJoin -OUPath $LocDN -NewName $WS_NewName -Restart.
But the whole script is supposed to include input validation for the computer's new name as well as for the target OU for the two-letter code for the remote office.
Googling for code snippets for days, esp. from sites like yours, was very helpful. But the problem I have now is I couldn't find the right codes to combine Read-Host , input length validation, and TRAP to work together without losing the value for my variables.
Pardon my coding as obviously I'm no real PS scripter, and I know the wrong portions of it are very basic. I would want to spend more time if I had the luxury, but I would really so much appreciate it if you could point me in the right direction.
Thank you so much in advance.
Please see my code below:
# START: Display name and purpose of invoked script
$path = $MyInvocation.MyCommand.Definition
Clear-Host
Write-Host $path
Write-Host " "
Write-Host "This script will allow you to do the following in a single-step process:"
Write-Host "(1) RENAME this computer"
Write-Host "(2) JOIN it to MYDOMAIN"
Write-Host "(3) MOVE it to a target OU"
Write-Host "(4) REBOOT"
Write-Host " "
Pause
# Function: PAUSE
Function Pause ($Message = "Press any key to continue . . . ") {
if ((Test-Path variable:psISE) -and $psISE) {
$Shell = New-Object -ComObject "WScript.Shell"
$Button = $Shell.Popup("Click OK to continue.", 0, "Script Paused", 0)
}
else {
Write-Host -NoNewline $Message
[void][System.Console]::ReadKey($true)
Write-Host
}
Write-Host " "
}
# Function: Define the parameters
Function Define-Parameters {
# Specify new computer name, with validation and TRAP
$WS_NewName = $null
while ($null -eq $WS_NewName) {
[ValidateLength(8,15)]$WS_NewName = [string](Read-Host -Prompt "NEW NAME of computer (8-15 chars.)" )
TRAP {"" ;continue}
}
Write-Host " "
# Domain to join.
$DomainToJoin = 'mydomain.net'
# Specify the target OU, with validation and trap
$baseOU='OU=Offices OU,DC=mydomain,DC=net'
$OU2 = $null
while ($null -eq $OU2) {
[ValidateLength(2,2)]$OU2 = [string](Read-Host -Prompt 'Target OU (TWO-LETTER code for your office)' )
TRAP {"" ;continue}
}
Write-Host " "
$LocDN = "OU=$OU2,$baseOU"
}
# Function: Summary and confirmation screen for defined parameters.
Function Confirm-Parameters {
Write-Host "==========================================================================="
Write-Host "Please confirm that you are joining this computer to
$DomainToJoin (MYDOMAIN)"
Write-Host "with the following parameters:"
Write-Host ""
Write-Host ""
Write-Host "Computer's NEW NAME: $WS_NewName"
# Write-Host "Domain to Join: $DomainToJoin"
Write-Host "TARGET mission OU: $OU2"
}
# Call Define-Parameters Function
Define-Parameters
# Call Confirm-Parameters Function
Confirm-Parameters
<#
Some more code here
#>
# FINAL COMMAND if all else works: Join the computer to the domain, rename it, and restart it.
# Add-Computer -DomainName $DomainToJoin -OUPath $LocDN -NewName $WS_NewName -Restart
In your code, you have a lot of things defined very strangely. Your functions create a new scope and the variables you're trying to define therein will disappear after calling them unless you change the variable scope (in this case, to $script: or $global:). Also, to use functions, you need to define them first (your Pause doesn't actually do anything)
Here's something you can do with your Define-Parameters function (I suggest looking at Get-Verb)
# Domain to join.
$DomainToJoin = 'mydomain.net'
# Function: Define the parameters
Function Get-Parameters {
do {
$global:WS_NewName = Read-Host -Prompt 'NEW NAME of computer (8-15 chars)'
} until ($WS_NewName.Length -gt 7 -and $WS_NewName.Length -lt 16)
''
do {
$global:OU2 = Read-Host -Prompt 'Target OU (TWO-LETTER code for your office)'
} until ($OU2 -match '^[a-z]{2}$')
''
$OU2 = "OU=$global:OU2,OU=Offices OU,DC=mydomain,DC=net"
}
I'd strongly recommend moving away from the ISE to do your testing and test in an actual powershell console.
Perhaps Try/Catch block instead of trap?
Try {
[ValidatePattern('^\w{8,15}$')]$compname=read-host 'enter comp name' -ErrorAction Stop
[ValidatePattern('^\w{2}$')]$OU=read-host 'enter OU name' -ErrorAction Stop
}
Catch {
$ErrorMessage = $_.Exception.Message
$ErrorLineNumber = $_.InvocationInfo.ScriptLineNumber
$ErrorCommandName = $_.InvocationInfo.InvocationName
Write-Error -Message "The error message was: <$ErrorMessage>, script line: <$ErrorLineNumber>, command name: <$ErrorCommandName>"
exit 255
}