Deleting Multiple Local Users - powershell

This is my first post in the community even though I was reading it for many years. The truth is that I just started scripting so I am very new to it. So I am trying to make a script that searches for a few specific local users and deletes them if it finds them.
Clear-Host
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
$USERNAME = "test1"
$ObjLocalUser = $null
try {
Write-Verbose "Searching for $($USERNAME) in LocalUser DataBase"
$ObjLocalUser = Get-LocalUser $USERNAME
Write-Verbose "User $($USERNAME) was found"
}
catch [Microsoft.PowerShell.Commands.UserNotFoundException] {
"User $($USERNAME) not was found" | Write-Warning
}
catch {
"An unspecifed error occured" | Write-Error
Exit # Stop Powershell!
}
if ($ObjLocalUser) {
Write-Verbose "Deleting User $($USERNAME)" #(Example)
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$op = Get-LocalUser | Where-Object {$_.Name -eq $USERNAME}
if ($op)
{
Remove-LocalUser ($op) | Out-Null
}
}
This is what I have up to now. It seems to work good with one username but when I try to add more than one usernames in the variable it doesn't work. Can you please help?

So I found the solution to my question and it was pretty simple. That's the final code.
Clear-Host
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
$USERNAMES = #("test1","test2","test3","test14","testpass")
foreach ($username in $USERNAMES) {
$ObjLocalUser = $null
try {
Write-Verbose "Searching for $($username) in LocalUser DataBase"
$ObjLocalUser = Get-LocalUser $username
Write-Verbose "User $($username) was found"
}
catch [Microsoft.PowerShell.Commands.UserNotFoundException] {
"User $($username) was not found" | Write-Warning
}
catch {
"An unspecifed error occured" | Write-Error
Exit # Stop Powershell!
}
if ($ObjLocalUser) {
Write-Verbose "Deleting User $($username)" #(Example)
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$op = Get-LocalUser | Where-Object {$_.Name -eq $username}
if ($op)
{
Remove-LocalUser ($op) | Out-Null
}
}
}

Related

My powershell script can't delete multiple users from csv file but can delete 1 user

This is the script which deletes user but only if 1 entry in there in csv file. however when I entered multiples entries in csv, the script takes values of all the rows as a single entry. How do I repair it? Thanks in advance!
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinue
$CSVPath = "D:\Temp\userss.csv"
$CSVFile = Import-CSV $CSVPath
$web = Get-SPWeb -Identity https://................./
$DocLibsName = "Bilder der websitesammlung"
$folder = $web.Folders[$DocLibsName].SubFolders
foreach($Files in $CSVFile)
{
Write-Host "Retreiving user..." -ForegroundColor Blue
$user = $CSVFile.users
$items = $folder.Files | where {$_.Title -eq $user}
If($items.Title -contains $user)
{
$items.Delete()
Write-Host $user "deleted" -ForegroundColor DarkGreen
}
Else {
Write-Host $user"not found" -ForegroundColor DarkRed
}
}
Write-Host "Finished" -ForegroundColor Green
Please try to change the code "$user = $CSVFile.users" to "$user = $Files.users".Hope it can help you.
Try using this PowerShell code:
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinue
$CSVPath = "D:\Temp\userss.csv"
$CSVFile = Import-CSV $CSVPath
$web = Get-SPWeb -Identity https://................./
$DocLibsName = "Bilder der websitesammlung"
$folder = $web.Folders[$DocLibsName].SubFolders
foreach($Files in $CSVFile)
{
foreach($loopItem in $Files.users) {
Write-Host "Retreiving user..." -ForegroundColor Blue
$user = $loopItem
$items = $folder.Files | where {$_.Title -eq $user}
If($items.Title -contains $user)
{
$items.Delete()
Write-Host $user "deleted" -ForegroundColor DarkGreen
}
Else {
Write-Host $user"not found" -ForegroundColor DarkRed
}
}
}
Write-Host "Finished" -ForegroundColor Green

Deleting admin local group member script doesnt work

I created the below script to delete the Specified Members from Administrators Group but it crashes when it can't find the member. Specificaly it shows my code and in the end adds
: An unspecifed error occured
At line:21 char:5
"An unspecifed error occured" | Write-Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException"
Clear-Host
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
#User to search for
$MEMBERS = #("Test1","Test5","Test2","Test76","Test3")
foreach ($MEMBER in $MEMBERS) {
#Declare LocalUser Object
$ObjLocalGroupMember = $null
try {
Write-Verbose "Searching for $($MEMBER) in LocalGroup DataBase"
$ObjLocalGroupMember = Get-LocalGroupMember -Group "Administrators" -Member $MEMBER
Write-Verbose "User $($MEMBER) was found"
}
catch [Microsoft.PowerShell.Commands.MemberNotFoundException] {
"User $($MEMBER) was not found" | Write-Error
}
catch {
"An unspecifed error occured" | Write-Error
Exit
}
if ($ObjLocalGroupMember) {
Write-Verbose "Deleting User $($MEMBER)"
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$op = Get-LocalGroupMember -Group "Administrators"| Where-Object {$_.Name -eq $MEMBER}
if ($op)
{
Remove-LocalGroupMember ($op) | Out-Null
}
}
}
I am still very new in this so the solution could be very simple but your help will be very much apreciated.
The main issue is your use of Write-Error in combination with $ErrorActionPreference = 'Stop', since the preference is Stop, the non-terminating error generated by Write-Error will be treated as a terminating error, hence the script stops at first occurrence of an error.
The other main issue is your use of exit instead of continue in your catch block, but also to explain why it's reaching that catch statement, you're trying to catch the error type Microsoft.PowerShell.Commands.MemberNotFoundException however, when Get-LocalGroupMember can't find a member, the exception type is Microsoft.PowerShell.Commands.PrincipalNotFoundException:
try {
Get-LocalGroupMember -Group Administrators -Member doesnotexist
}
catch {
$_.Exception.GetType().FullName
}
# Results in: `Microsoft.PowerShell.Commands.PrincipalNotFoundException`
As for your code, you could simplify it a bit, there are some not needed redundancies:
Clear-Host
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
#User to search for
$members = "Test1", "Test5", "Test2", "Test76", "Test3"
foreach($member in $members) {
try {
Write-Verbose "Searching for $member in LocalGroup DataBase"
$ObjLocalGroupMember = Get-LocalGroupMember -Group Administrators -Member $member
Write-Verbose "User $member was found"
Write-Verbose "Deleting User $member"
Remove-LocalGroupMember $ObjLocalGroupMember
}
catch [Microsoft.PowerShell.Commands.PrincipalNotFoundException] {
Write-Warning "User $member was not found"
continue # Go to next user
}
catch {
# Adding `$_` so at least you know what happened
Write-Warning "An unspecifed error occured: $_"
continue
}
# Unclear what is this doing here, never being used and
# should also be outside the loop in any case:
# $password = ConvertTo-SecureString -String "password" -AsPlainText -Force
}

Testing and reporting Invoke-command execution

I have the following PowerShell script that creates a session with Windows server administrator account.I want to report in case of failure of Invoke-command the error and save it in a file
Below is the code that I wrote but if i tamper for example .json file(set a wrong username),execution fails and error_report.txt is not created
#Param(
$user = "lamda"
#)
$user_domain = (Get-WmiObject Win32_ComputerSystem).Domain
$user_computer = (Get-WmiObject Win32_ComputerSystem).Name
$file = "error_report.txt"
If ((Test-Path "creds.json") -eq $True)
{
$jsonfile = Get-ChildItem creds.json
if ($jsonfile.Length -eq 0)
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:The file 'creds.json' is empty"
break
}
else
{
$creds= (Get-Content creds.json | Out-String | ConvertFrom-Json)
$admin = $creds.username
$passwd = $creds.password
if (($admin) -and ($passwd))
{
$Password = ConvertTo-SecureString -String $passwd -AsPlainText -Force
$credential = [pscredential]::new($admin,$Password)
$command = Invoke-Command -ComputerName Server.$user_domain -FilePath
C:\SECnology\Data\Utilities\Updating.ps1 -ArgumentList
$user,$admin,$user_computer -Credential $credential
If ($command -eq $false)
{
$file = "error_report.txt"
Set-Content -Path $file -Value "Error:Session between user and server
could not be created,please check your Credentials"
}
break
}
elseif (([string]::IsNullOrEmpty($admin)) -or ([string
]::IsNullOrEmpty($passwd)))
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:One object of 'creds.json' seems
to be empty.Please check your file "
}
}
break
}
else
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:The file 'creds.json' does not exist"
}
I think the issue is the way you are defining the condition on your if statement.
You use -eq $false however if you connections fails it does not set the vale of command to $false it will leave command as a null as it return no value (it errorred).
What you can try is either use the null operator (!) in your if statement so:
If (!$command){Do stuff}
Or you can give you invoke command an error variable and check if that has a value when run.
$command = Invoke-Command -ComputerName Server.$user_domain -FilePath
C:\SECnology\Data\Utilities\Updating.ps1 -ArgumentList
$user,$admin,$user_computer -Credential $credential -ErrorVariable TheError
If ($TheError)
{Do stuff}

Logging actual error when script fails

I have a script here that reads a list of computers and changes the administrator password. When the script is ran, it'll have a log file that says whether the task succeeded or fail. But I also want to log the actual error to the log when it fails. How do I accomplish this?
[cmdletbinding()]
param (
[parameter(mandatory = $true)]
$InputFile,
$OutputDirectory
)
if(!$outputdirectory) {
$outputdirectory = (Get-Item $InputFile).directoryname
}
$failedcomputers = Join-Path $outputdirectory "output.txt"
$stream = [System.IO.StreamWriter] $failedcomputers
$stream.writeline("ComputerName `t IsOnline `t PasswordChangeStatus")
$stream.writeline("____________ `t ________ `t ____________________")
$password = Read-Host "Enter the password" -AsSecureString
$confirmpassword = Read-Host "Confirm the password" -AsSecureString
$pwd1_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
$pwd2_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($confirmpassword))
if($pwd1_text -ne $pwd2_text) {
Write-Error "Entered passwords are not same. Script is exiting"
exit
}
if(!(Test-Path $InputFile)) {
Write-Error "File ($InputFile) not found. Script is exiting"
exit
}
$Computers = Get-Content -Path $InputFile
foreach ($Computer in $Computers) {
$Computer = $Computer.toupper()
$Isonline = "OFFLINE"
$Status = "SUCCESS"
Write-Verbose "Working on $Computer"
if((Test-Connection -ComputerName $Computer -count 1 -ErrorAction 0)) {
$Isonline = "ONLINE"
Write-Verbose "`t$Computer is Online"
} else { Write-Verbose "`t$Computer is OFFLINE" }
try {
$account = [ADSI]("WinNT://$Computer/username,user")
$account.psbase.invoke("setpassword",$pwd1_text)
Write-Verbose "`tPassword Change completed successfully"
}
catch {
$status = "FAILED"
Write-Verbose "`tFailed to Change the administrator password. Error: $_"
}
$obj = New-Object -TypeName PSObject -Property #{
ComputerName = $Computer
IsOnline = $Isonline
PasswordChangeStatus = $Status
}
$obj | Select ComputerName, IsOnline, PasswordChangeStatus
if($Status -eq "FAILED" -or $Isonline -eq "OFFLINE") {
$stream.writeline("$Computer `t $isonline `t $status")
}
}
$stream.close()
Write-Host "`n`nFailed computers list is saved to $failedcomputers"
Change this:
catch {
$status = "FAILED"
Write-Verbose "`tFailed to Change the administrator password. Error: $_"
}
to this:
catch {
$status = "FAILED"
Write-Verbose "`tFailed to Change the administrator password. Error: $_"
$errmsg = $_.Exception.Message
}
to preserve the error message(s). And change this:
if($Status -eq "FAILED" -or $Isonline -eq "OFFLINE") {
$stream.writeline("$Computer `t $isonline `t $status")
}
to this:
if($Status -eq "FAILED" -or $Isonline -eq "OFFLINE") {
$stream.writeline("$Computer `t $isonline `t $status `t $errmsg")
}
to include the error message in the log.
If you want to unroll inner exceptions as well you can use this:
$e = $_.Exception
$errmsg = $e.Message
while ($e.InnerException) {
$e = $e.InnerException
$errmsg = "`n" + $e.Message
}
instead of just
$errmsg = $_.Exception.Message

Powershell 2.0 - Memory Leaking

So here's the scope of what I'm trying to do:
Get remote computer information for Windows computers in multiple sites and write the information found to the .Description property of each computer object in Active Directory. If the script can't connect to the remote machine, log that information into a text file and don't make any changes to the computer object that can't be connected to.
In order to time how long the script is taking to run, I have a second script that measures the execution time.
I have this setup as a scheduled task to run the second script (which calls the first) that is executed via a batch file on a Windows 7 Pro virtual machine.
My problem is I believe the script may be running into memory problems based on the information I see in my log. Any help on possible diagnosing the root cause would be appreciated to the extreme. Without further adieu, here's my code for both scripts as well as a sample of the strange log output.
Main Script (script 1):
set-location \\myscriptcomputer\c$\somefolder\PSScripts
enter code here`function Measure-Latest {
BEGIN { $latestlogon = $null }
PROCESS {
if (($_ -ne $null) -and (($latestlogon -eq $null) -or ($_ -gt $latestlogon))) {
$latestlogon = $_
}
}
END { $latestlogon }
}
Function CreateLog {
#Create a log file
$global:path = "C:\Somefolder\PSScripts\WriteComputerDescriptions"
$global:LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
$global:LogName = 'CompDescriptions'
$global:LogFile = 'C:\Somefolder\PSScripts\WriteComputerDescriptions\'+$LogName+$LogTime+'.txt'
Write-Host "Creating log file" -foregroundcolor yellow
if([IO.Directory]::Exists($global:path))
{
#Do Nothing
}
else
{
New-Item -ItemType directory -Path C:\Somefolder\PSScripts\WriteComputerDescriptions
}
cd C:\Somefolder\PSScripts\WriteComputerDescriptions
echo "WriteComputerDescriptions Script Log" >> $global:logfile
}
Function WriteDescription {
Write-Host "Gathering Computer information..." -foregroundcolor yellow
$UserWorkstations = get-qadcomputer -sizelimit 0 -includeallproperties -searchroot my.domain.com/MyUserWorkstations
$IPv4Regex = "^(\d{1,3}\.){3}\d{1,3}$"
foreach ($computerobject in $UserWorkstations) {
$computerIP = $NULL
$computerIP2 = $NULL
$computerIP3 = $NULL
$computerserial = $NULL
$computerserial2 = $NULL
$findlastuser = $NULL
$findlastuser2 = $NULL
$lastlogontime = $NULL
$findlastuserFname = $NULL
$findlastuserFname2 = $NULL
$findlastuserLname = $NULL
$findlastuserLname2 = $NULL
$fullname = $NULL
$userlogon = $NULL
$computerName = $computerobject.name
$oldcomputerdescription = $computerobject.description
Write-Host " "
Write-Host "Testing connection to $computerName ..."
$testConnection = test-connection -computername $computerName -count 2 -quiet
Write-Host "Connection is $testconnection"
if ($testConnection -eq $True) {
$Connect = $testConnection
#get IP address(es)
try {
$computerIP = get-wmiobject -class win32_networkadapterconfiguration -filter IPEnabled=TRUE -computername $computerName
$computerIP2 = $computerIP.ipaddress[0]
$computerIP3 = $computerIP.ipaddress[1]
Write-Host = $computerIP2
if ($computerIP3 -match $IPv4Regex){
Write-Host = $computerIP3
}
}
catch [system.exception]{
$connect = $False
Write-Host "Could not connect to $computerName. No IP collected."
}
#get computer serial
try {
$computerSerial = gwmi win32_bios -computername $computerName | select serialnumber
$computerserial2 = $computerSerial.serialnumber.tostring()
}
catch [system.exception]{
Write-Host "Could not get serial for $computerName."
$computerSerial = "Unavailable"
$computerSerial2 = "Unavailable"
}
#get username of currently logged in user
try {
$findlastUser = gwmi win32_computersystem -computer $computerName | select username
$findlastuser2 = ($findlastUser.username).replace("mydomain\","")
}
catch [system.exception]{
Write-Host "Could not get username of logged in user on $computerName"
$findlastUser = "Unavailable"
$findlastUser2 = "Unavailable"
}
#get last logon time of user
try {
if($findlastuser2 -ne $NULL -and $findlastuser2 -notlike "Unavailable") {
#ignore domain controllers in a datacenter due to connectivity stuff
$lastlogontime = get-qadcomputer -computerrole domaincontroller | where { $_.name -notmatch "-COLO"} | foreach {(get-qaduser -service $_.name -samaccountname $findlastuser2).LastLogon } | Measure-Latest
}
}
catch {
if ($lastlogontime -eq $NULL -and $findlastuser2 -eq $NULL){
Write-Host "Could not find a last logon time"
Write-Host "No username available to query"
$lastlogontime = "Unavailable"
}
if ($lastlogontime -eq $NULL -and $findlastuser2 -ne $NULL){
Write-Host "Could not find a last logon time for user $findlastuser"
$lastlogontime = "Unavailable"
}
}
#search AD for the user identified, select first name
try {
$findlastuserFname = get-qaduser $findlastuser2 | select firstname
$findlastuserFname2 = $findlastuserFname.firstname.tostring()
}
catch [system.exception]{
if ($findlastuserFname2 -eq $NULL) {
Write-Host "No first name for user found"
}
}
#search AD for the user identified, select last name
try {
$findlastuserLname = get-qaduser $findlastuser2 | select lastname
$findlastuserLname2 = $findlastuserLname.lastname
}
catch [system.exception] {
if ($findlastuserLname2 -eq $NULL) {
Write-Host "No last name for user found"
}
}
#join the first and last names together if both properties are available
if ($findlastuserFname2 -ne $NULL -and $findlastuserLname2 -ne $NULL){
$fullname = "$findlastuserFname2" + " $findlastuserLname2"
}
elseif ($findlastuserFname2 -eq $NULL -and $findlastuserLname -ne $NULL){
$fullname = $findlastuserLname2
}
elseif ($findlastuserFname2 -ne $NULL -and $findlastuserLname -eq $NULL){
$fullname = $findlastuserFname2
}
else {
$fullname = "Unavailable"
}
#Set the description data format
#With only 1 IPv4 Address
if ($computerIP3 -notmatch $IPv4Regex -or $computerIP3 -eq $NULL){
$newcomputerdescription = "$fullname | $computerIP2 | $computerSerial2 | $lastlogontime"
}
#With 2 IPv4 Addresses
if ($computerIP3 -match $IPv4Regex) {
$newcomputerdescription = "$fullname | $computerIP2, $computerIP3 | $computerSerial2 | $lastlogontime"
}
#If the description data is the same, leave it as it is
if ($newcomputerdescription -eq $oldcomputerdescription){
Write-Host " "
Write-Host "Information for $computerName has not" -foregroundcolor yellow
Write-Host "changed. No edits were made on this object." -foregroundcolor yellow
}
if ($newcomputerdescription -ne $oldcomputerdescription -and $Connect -eq $TRUE) {
set-qadcomputer -identity $computerName -Description $newcomputerdescription
Write-Host " "
Write-Host "Computer description updated for object $computerName" -foregroundcolor yellow
Write-Host "New host information:"
Write-Host "$newcomputerdescription"
}
}
else {
Write-Host "Could not connect to computer $computerName"
Write-Host "No changes made to description for $computerName"
$noconnecterror = "Could not connect to computer $computerName"
$noconnecterror | Out-File $global:logfile -Append -Force
}
}
Write-Host "Processing complete!"
}
CreateLog -erroraction silentlycontinue
WriteDescription -erroraction silentlycontinue
start-sleep -s 3
##END OF SCRIPT
Second Script:
set-location \\myscriptcomputer\c$\somefolder\PSScripts
Add-PSSnapin Quest.ActiveRoles.ADManagement -erroraction SilentlyContinue
$timeoutput = Measure-Command {\\myscriptcomputer\c$\Somefolder\PSScripts\WriteComputerDescriptions.ps1}
cd \\myscriptcomputer\c$\Somefolder\PSScripts\WriteComputerDescriptions
$scriptlog = get-childitem | sort creationtime | select -last 1
$logname = $scriptlog.name
Add-Content c:\somefolder\PSScripts\WriteComputerDescriptions\$logname "`nExecution Time: $timeoutput"
Write-Host "Script complete!"
Start-sleep -s 3
exit
In the results in my environments Active Directory, this works effectively for several hundred objects, but here's a sample of what I see in my log file:
Could not connect to computer computer391
Could not connect to computer computer392
Could not connect to computer computer393
Could not connect to computer computer394
䔊數畣楴湯吠浩㩥ㄠ㨱㘰㈺⸱㜵㤵㐰ഷ
The very last line with the garbled text is what made me think there's a memory-related issue perhaps. If I run my scripts against a container/OU with a much smaller amount of computers, the last line in my log is a time, which is what I would normally expect.
If any seasoned Powershell pros could offer some advice here, I'd really appreciate the help.
Thanks!
I don't know why my comments are not getting added. Anyways, let me just post it here.
In order to track the free memory, you just look at its the performance counter.
Here is the powershell command:
Get-Counter -Counter "\Memory\Available MBytes"