Deleting admin local group member script doesnt work - powershell

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
}

Related

Deleting Multiple Local Users

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
}
}
}

Argument Passed into ScriptBlock Doesn't Work on Last Iteration

I'm using the following script to run through all of the servers in a specified Active Directory OU and log out the specified user. This runs perfectly well for the first 35 servers but always errors out on the very last server it iterates through. The error is:
Program 'quser.exe' failed to run: Object reference not set to an instance of an object. At line:6 char:24
+ $result = (quser $userAccount)
+ ~~~~~~~~~~~~~~~~~~.
At \\path\to\script.ps1:79 char:5
+ invoke-command -ComputerName $server -ScriptBlock $scriptBlock -A ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Program 'quser....~~~~~~~~~~~~~~.:String) [], RuntimeException
+ FullyQualifiedErrorId : Program 'quser.exe' failed to run: Object reference not set to an instance of an object.At line:6 char:24
+ $result = (quser $userAccount)
+ ~~~~~~~~~~~~~~~~~~.
My reading of the error is that it thinks $userAccount has no value. Is that correct and, if so, can anyone point at what I'm missing? Thank you in advance!
Write-Host " "
Write-Host "This script will log out all active sessions for the specified user. Proceed with caution." -ForegroundColor Black -BackgroundColor Yellow
Write-Host " "
$servers = [System.Collections.ArrayList]::new()
foreach ($server in (Get-ADComputer -SearchBase "OU=FictionalDepartment,DC=Company,DC=net" -Filter "OperatingSystem -like 'Windows Server*'" -Properties Name | select -ExpandProperty name))
{
$servers.add($server) | Out-Null
}
$servers.Sort()
$userAccount = Read-Host "Enter account to log out"
Write-Host " "
foreach ($server in $servers)
{
$scriptBlock = {
param($userAccount)
$ErrorActionPreference = 'Stop'
try
{
$result = (quser $userAccount)
$session = ((quser $userAccount)[1] -split "\s+")[2]
logoff $session
Write-Host " The user was logged into session #$session. They have been LOGGED OFF." -ForegroundColor Yellow
}
catch
{
if ($_.Exception.Message -match 'No user exists')
{
Write-Host " User is not logged in." -ForegroundColor Green
}
else
{
throw $_.Exception.Message
}
}
}
Write-Host "$server"
Invoke-Command -ComputerName $server -ScriptBlock $scriptBlock -ArgumentList $userAccount
$session = $null
}
Based on feedback, I modified the script so that it no longer uses Invoke-Command, but parses the active sessions by running quser <user> /SERVER:<server> as follows:
Write-Host "Will log specified user out of all servers..." -ForegroundColor Black -BackgroundColor Yellow
Write-Host " "
$servers = [System.Collections.ArrayList]::new()
foreach ($server in (Get-ADComputer -SearchBase "OU=Fictional,DC=Company,DC=net" -Filter "OperatingSystem -like 'Windows Server*'" -Properties Name | select -ExpandProperty name))
{
$servers.add($server) | Out-Null
}
$servers.Sort()
$userAccount = Read-Host "Enter account to scan for"
Write-Host ""
foreach ($server in $servers)
{
Write-Host "$server"
$ErrorActionPreference = 'Stop'
try
{
$session = ((quser $userAccount /SERVER:$server)[1] -split "\s+")[3]
logoff /SERVER:$server $session
Write-Host " The user was logged into session #$session. They have been LOGGED OFF." -ForegroundColor Yellow
}
catch
{
if ($_.Exception.Message -match 'No user exists')
{
Write-Host " User is not logged in." -ForegroundColor Green
}
}
}

Remove Disabled users in a CVS file from all Office 365 Groups that appear on the admin portal

I am Trying to Remove all users who are in a csv file from all the groups they are showing up under in the Office 365 admin portal, The code bellow doesn't seem to delete all the groups and still has some left under their name. Is there something I am missing?
Write-Host "Fetching the CSV..."
$file = "X:\1Onboarding.TerminationCSV\DisabledUsers.csv"
Write-Host "Importing from $file..."
$csv = Import-Csv $file
if ($csv -eq $null)
{ Write-Host "No CSV file found. exiting script in 3 seconds"
#Start-Sleep -Seconds 3
Exit }
#Credentials
$password = ConvertTo-SecureString “*Hidden*” -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential (“*hidden*”, $password)
#Connect to AzureAD
Connect-AzureAD -Credential $Cred
#Get all Azure AD Unified Groups
$AADGroups = Get-AzureADMSGroup -All:$true
foreach ($member in $csv) #loop through csv for users--------------------
{
$username= $member.username
Write-Output "username is $username"
#Get the Azure AD User
$AADUser = Get-ADUser -filter {sAMAccountName -eq $username}
$groupCount = 0
ForEach ($Group in $AADGroups)
{
$GroupMembers = (Get-AzureADGroupMember -ObjectId $Group.id).UserPrincipalName
If ($GroupMembers -contains $UserUPN)
{
Write-Output "$username is in $($Group.DisplayName)"
#Remove user from Group
try { Remove-AzureADGroupMember -ObjectId $Group.Id -MemberId $AADUser.ObjectId }
catch { "$($Group.DisplayName) is not an azure group" }
try {Remove-DistributionGroupMember -Identity $Group.Id -Member $AADUser.ObjectId -BypassSecurityGroupManagerCheck -Confirm:$false }
catch { "$($Group.DisplayName) is not a distribution group" }
$groupCount +=1
}
}
Write-Output "$AADUser is in $groupCount groups"
}
See, this should be more efficient than bringing all existing Azure AD Groups.
First, search for the user provided in the CSV on Azure AD
If the user exist, get it's membership. Else, write a warning
Loop over the AADuser's membership removing it from all of them
$ErrorActionPreference = 'Stop'
#Connect to AzureAD
Connect-AzureAD -Credential $Cred
foreach ($member in $csv) #loop through csv for users
{
$AADUser = Get-AzureADUser -SearchString $member.userName
if($AADUser)
{
$membership = Get-AzureADUserMembership -ObjectId $AADUser.ObjectID
foreach($group in $membership)
{
try
{
Remove-AzureADGroupMember -ObjectId $group.ObjectID -MemberId $AADUser.ObjectID
Write-Output "Successfully removed {0} from {1}" -f $AADUser.userPrincipalName,$group.displayName
}
catch
{
Write-Warning "Failed to remove {0} from {1} with the following error:`n$_" -f $AADUser.userPrincipalName,$group.DisplayName
}
}
}
else
{
Write-Warning "{0} could not be found on Azure AD" -f $member.userName
}
}

Suppress Powershell Errors while adding to $Error Variable

I have a block of code executing that has been set up with a simple If/Else block to catch errors. I would normally use Try/Catch but the Exchange 2010 PS environment I'm working in doesn't allow me to use most of the Try/Catch features (and I can't update it or change it in any way because it's the customer's system and they're unwilling).
The issue is that while the code will function as expected when the Add-DistributionGroupMember cmdlet is set with -ErrorAction "Stop", it will output the error to the host each time, which annoys the customer (and me) because it's effectively just red noise since all the possible errors are being handled via a detailed output file.
If I set the cmdlet to -ErrorAction "SilentlyContinue" the error text is suppressed, but the Error is not added to the $Error[0] spot as I expected. The same is true of -ErrorAction "Ignore". The code requires that the Error be added to the $Error variable each time there is an error.
Here is the code:
$ListMembershipsIn | % {
$Alias = $_.Alias
$Member = $_.Member
Add-DistributionGroupMember -Identity $Alias -Member $Member -Confirm:$false -ErrorAction Stop
if($Error[0] -match "The recipient"){
Write-Host -ForegroundColor Yellow "Already a member"
Add-Content -Path $OutputPath -Value "$($Alias),$($Member),Group already contains Member"
}
elseif($Error[0] -match "couldn't be found"){
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Group does not exist or cannot be found,$($Alias),N/A"
}
elseif($Error[0] -match "couldn't find"){
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Member does not exist or cannot be found,$($Alias),$($Member)"
}
elseif($Error[0] -match "There are Multiple"){
Add-Content -Path $OuputPath -Value "Member name matches too many recipient - Add Member Manually,$($Alias),$($Member)"
}
else{
Add-Content -Path $OutputPath -Value "Member Successfully Added to Group,$($Alias),$($Member)"
Write-Host -ForegroundColor Green "Throw Flag here"
}
}
You have two options for recourse, you can utilize the -ErrorVariable common parameter, or a Try/Catch block to interact with the specific error.
ErrorVariable
When interacting with ErrorVariable, you can prepend the name with a + to append additional errors to it just like the $Error automatic variable, e.g.: -ErrorVariable '+MyError'
$ListMembershipsIn | ForEach-Object {
$Alias = $_.Alias
$Member = $_.Member
Add-DistributionGroupMember -Identity $Alias -Member $Member -ErrorVariable 'MyError'
## No error = good, continue the next iteration of the loop
If (-not $MyError)
{
Add-Content -Path $OutputPath -Value "Member Successfully Added to Group,$Alias,$Member"
Write-Host -ForegroundColor Green "Throw Flag here"
Continue
}
Switch -Regex ($MyError.Exception.Message)
{
'The recipient'
{
Write-Host -ForegroundColor Yellow "Already a member"
Add-Content -Path $OutputPath -Value "$Alias,$Member,Group already contains Member"
}
"couldn't be found"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Group does not exist or cannot be found,$Alias,N/A"
}
"couldn't find"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Member does not exist or cannot be found,$Alias,$Member"
}
'There are Multiple'
{
Add-Content -Path $OuputPath -Value "Member name matches too many recipient - Add Member Manually,$Alias,$Member"
}
}
}
Try/Catch
$ListMembershipsIn | ForEach-Object {
$Alias = $_.Alias
$Member = $_.Member
Try
{
Add-DistributionGroupMember -Identity $Alias -Member $Member -ErrorAction 'Stop'
## No error thrown = successful processing
Add-Content -Path $OutputPath -Value "Member Successfully Added to Group,$Alias,$Member"
Write-Host -ForegroundColor Green "Throw Flag here"
}
Catch
{
Switch -Regex ($_.Exception.Message)
{
'The recipient'
{
Write-Host -ForegroundColor Yellow "Already a member"
Add-Content -Path $OutputPath -Value "$Alias,$Member,Group already contains Member"
}
"couldn't be found"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Group does not exist or cannot be found,$Alias,N/A"
}
"couldn't find"
{
Write-Host -ForegroundColor Yellow "not found"
Add-Content -Path $OutputPath -Value "Member does not exist or cannot be found,$Alias,$Member"
}
'There are Multiple'
{
Add-Content -Path $OuputPath -Value "Member name matches too many recipient - Add Member Manually,$Alias,$Member"
}
}
}
}
It appears that Add-DistributionGroupMember command doesn't fill ErrorVariable when specified.
I found no way to avoid the unwanted output, so I handled the error with Tristan's trick rather than by exception handling (which is absolutely fine, but not fitting my own dev):
$Error.clear()
Add-DistributionGroupMember -Identity $mySite.MailingList -Member $emailAddress
if ($Error.count -eq 0) {
$script:logger["ldissue"] += "<li>Liste de diffusion $($mySite.MailingList) : La ressource <b>$($ADRecord.Name)</b> ($($ADRecord.SamAccountName) - $($BoondRecord.flags)) a été ajoutée à la liste</li>"
} else {
$script:logger["ldissue"] += "<li>Liste de diffusion $($mySite.MailingList) : La ressource <b>$($ADRecord.Name)</b> ($($ADRecord.SamAccountName) - $($BoondRecord.flags)) n'a pas pu être ajoutée à la liste (<i>$($Error[0])</i>)</li>"
}
Use the "-ErrorAction Continue" this won't suppress the error but it will ensure the script continues and it places the error in the $Error variable.
You can also use the $Error.clear() command to remove any stored errors in the session.

Check if OU exists not working properly

Wrote this small script to test if an OU exists, if exists write to console and terminate. If not exists create OU and do some other stuff. Though can't seem to understand why i cant get it working.
For some reason the output will always tell me that the OU exists, and I am pretty sure it does not. Am I doing something terribly wrong?
This is the code:
param (
[parameter(mandatory=$true)] [string] $servername
)
Import-Module ActiveDirectory
Function CheckOU {
$script:OUpath = "OU=$servername,OU=Rechtengroepen,OU=danny,dc=Doenoe,DC=com"
$Status = $false
$GetOU = Get-ADOrganizationalUnit -Identity $OUpath -ErrorAction SilentlyContinue
if ($GetOU -eq $null) {
$status = $false
Write-Host -ForegroundColor Green "$OUpath does not exist."
} else {
$Status = $true
Write-Host -ForegroundColor Red "$OUpath exists!"
}
return $Status
}
$OUStatus = CheckOU
if ($OUStatus -eq $true) {
Write-Host "$OUpath exists. Function working."
} else {
Write-Host "$OUpath does not exsist, do something."
}
Output:
Get-ADOrganizationalUnit : Directory object not found
At C:\Scripts\CreateOUgroups\createadgroups_test02.ps1:10 char:14
+ $GetOU = Get-ADOrganizationalUnit -Identity $OUpath -ErrorAction SilentlyCon ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (OU=notexistsing...c=Doenoe,DC=com:ADOrganizationalUnit) [Get-ADOrganizationalUnit], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADOrganizationalUnit
OU=notexistsingOU,OU=Rechtengroepen,OU=danny,dc=Doenoe,DC=com exists!
OU=notexistsingOU,OU=Rechtengroepen,OU=danny,dc=Doenoe,DC=com exists. Function working.
Using the cmdlet with the -Identity parameter causes a terminating error if the object with the given identity doesn't exist. Use -Filter to avoid this issue:
Get-ADOrganizationalUnit -Filter "distinguishedName -eq '$OUPath'"