I'm writing a script to disable users for our security team but I'm a bit hung up on distribution lists(DL). I have it correctly cycle through every DL but when it gets to one on one of our association's domains, I get an error that the server is not willing to process the request. I've seen a workaround using ADSI and the LDAP filter but that didn't work for me at all. I also found that this issue used to be caused by a weak password/strong password policy but the password policy is the same across all domains so I don't think that's the case.
EDIT- Here is the code I use for the DL portion of the script:
$user = Get-QADUser -Identity "$domain\$account"
$dList = Get-QADMemberof $user
Write-Output "The following distribution lists were removed from $domain\$account: `n" | Out-File -filepath $output
foreach($dL in $dList){
if ($dL.DN -match "OU=Distribution Lists"){
out-file -filepath $output -inputobject $dL -Append
remove-QADGroupMember $dL.DN -member $user
}
}
Related
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
I am writing a powershell script to be deployed by SCCM via a package. The aim of this is to remove an account with a specific name then write to a file stating if the account exists or not. The code is below:
$Computer = hostname
foreach ($C in $Computer) {
if (Test-Connection $C -Quiet) {
Write-Verbose "$C > Online"
$Users = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True" -ComputerName $C
if ($Users.Name -contains 'test') {
Add-Content \\SERVERNAME\SHARENAME.$\$computer-found_$(get-date -Format yyyymmdd_hhmmtt).txt "User 'test' found, Disable 'test' found"
net user test /active:no }
else {
Add-Content \\SERVERNAME\SHARENAME.$\$computer-notfound_$(get-date -Format yyyymmdd_hhmmtt).txt "User 'test' not found"
}
}
else {
Write-Verbose "$C > Offline"
}
}
I have also tried replace Write-Verbose with Write-Host and Add-Content with Out-File but the problem I having is that no content / file is created when I use the full network path or share e.g. \\SERVERNAME\SHARENAME.$ the path identified has all the correct permissions and is being ran locally using the System account.
I wanted to see if the issue occured when writing the file locatlly consequently this does not happen when written to C:\Temp\
Does anyone have any ideas on to solve this.
I don't think that local system account has access to a network resource. I'm not sure if you have ever configured it or not. And what the command you used to run the command
Here I post a working way of doing this using Configuration Manager deployment after testing in my lab.
Basically I created a package with source files
and created a task sequence with single "Run Command Line" step.
The reason I use a task sequence is because I want to use an account to access the txt file on the network, which I can configure within a task sequence. I don't think Local System Account have such permission.
The script (DeactivateTest.ps1) I use as below just like what you provided and changed a little on the logic:
$Computer = hostname
foreach ($C in $Computer) {
if (Test-Connection $C -Quiet) {
Write-host "$C > Online"
$Users = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True" -ComputerName $C
$result=0
Foreach($user in $Users){
if ($User.Name -like '*test*') {
$username = $user.Name
"`n$(get-date -Format yyyymmdd_hhmmtt) User $username found ON $C, Disable 'test'" | Add-Content \\cas\resource\Result.txt
net user $username /active:no
$result+=1
}}
if($result =0){
"`n$(get-date -Format yyyymmdd_hhmmtt) User 'test' not found ON $C" | Add-Content \\cas\resource\Result.txt}
}
else {
"`n$C is Offline" | Add-Content \\cas\resource\Result.txt
}
}
The script query local account and disable accounts which have words "Test" in the name. If you don't like this logic, you can change :).
\\cas\resource\Result.txt is a txt file on the network share. Clients will write result to this txt file.
The command in the task sequence is (it's a x64 machine):
PowerShell.exe -ExecutionPolicy Bypass -File ".\DeactiveTest.ps1"
The output is like:
I may get downvoted for this as my answer isn't technically directly answering your question, it is, however, intended to try and point you in what may be a more logical direction. All apologies if I offend anyone, but here it is:
Why not just disable the user using Group Policy? If you really want to know where the user is/isn't disabled then you could just use hardware inventory for that, but GP really is the best way to enforce this kind of setting.
I want to remove all of the permissions on an MSMQ queue before we set the new permissions, this will be deployed via Octopus.
This is so that we can be sure that no legacy permissions can exist and be sure that the permissions will be the same.
$QueueName = "MyQueue"
$QueuePermissions = Get-MsmqQueue -Name $QueueName | Get-MsmqQueueACL
$QueueUsers = $QueuePermissions.AccountName | Get-Unique
foreach ($User in $QueueUsers)
if ($User -like 'MyDomain*'){
#Something like
$QueueName | Set-MsmqQueueACL -UserName $User -Remove
}
Unfortunately I need to create a CSV list of permissions for Set-MsmqQueueACL to be removed.
How can I get this?
I'm fairly new to PowerShell so anyhelp would be appreciated.
Thanks!
First of all, delete queues and recreate is the more reliable approach.
I assume you have a reason that requires you to not delete them. Here is an approach I think suit you best.
Using MessageQueue.ResetPermissions Method from System.Messing.MessageQueue
Code example for powershell:
$QueueName = ".\private$\MyQueue"
Add-Type -AssemblyName System.Messaging
$Q = [System.Messaging.MessageQueue]($QueueName)
$Q.ResetPermissions()
Note: This method put queue permission back to default where only creator has full access to the queue. My powershell is using an automation account that created these queues thus it would take away fine from this point. However, in my past experience if all the queue permissions are messed, and you don't have an account that have full control of the queue, you might end up have to remove the physical queue file from storage and restart MSMQ service to clean it up. Thus I'd urge you to maintain consistence of the permission so your later operations on the queue can be performed without problem.
I have created a solution that appears to work, as mentioned above I am no PowerShell expert but it may help someone else in the future:
$Queue= "MyQueueName"
#remove old permissions
$QueuePermissions = Get-MsmqQueue -Name $Queue | Get-MsmqQueueACL
$QueueUsers = $QueuePermissions.AccountName | Get-Unique
foreach ($User in $QueueUsers)
{
Write-Output "Permissions found for user: $User"
$tst = $QueuePermissions | where {$_.AccountName -eq $User}
$tst = $tst | Select -ExpandProperty Right
foreach ($Permission in $tst)
{
Write-Output "Removing permissions: $Permission"
$thisQueue | Set-MsmqQueueAcl -UserName $User -Remove $Permission | Out-Null
}
}
The company I am working for would like a splash screen that I did to pop up when ever a user changes password (90 day rule at present), this is mainly due to a external requirement.
One of the snags I have is that the system has no email to show me that a user is expiring, I am looking at a couple of things
A log output of expired accounts and locked accounts, ignoring accounts not logged on disabled accounts system etc.
On the 90 day policy a splash screen pops up with the t$c with an accept or decline window (they see this when they first turn the PC and pops up just before the logon box on basically saying by accepting you agree to have read blah and blah)
I do not know how to get either this to run as one script or have two separate scripts,
Any input greatly appreciated
Import-Module ActiveDirectory # Required for PowerShell 2.0 only
$a = (Get-Date).Date.AddDays(-89)
# The following line will build the variable based upon the noted criteria
$b = Get-ADUser `
-Property Name, SamAccountName, PasswordLastSet, CannotChangePassword, PasswordNeverExpires `
-Filter { (PasswordLastSet -lt $a) -and (PasswordNeverExpires -eq $false) } |
Where-Object { $_.CannotChangePassword -eq $false }
# The following line will display/export the data logging the accounts to be changed
# please note the Out-File path and change to suit your needs.
$b | Format-Table Name, PasswordLastSet, CannotChangePassword, PasswordNeverExpires -AutoSize |
Out-File -FilePath "C:\passwordchanges.txt"
# The following line will actually flag the accounts to require a password change
# (after -WhatIf is removed)
$b.SamAccountName | ForEach-Object {
Set-ADUser -Identity $_ -ChangePasswordAtLogon $true -WhatIf
}
Getting an ambiguous identity error. I can search successfully to return the group that a user account is a member of, but when I try to search for the groups that a computer account is a member of there is the ambiguous identity error. I tried to use a -type or -identity switch, but either I did not have the syntax correct or it was just not applicable.
Where my targeted computer account is called SNA00760856, I have been working on using...
Get-QADGroup -Containsindirectmember SNA00760856
Any massaging that I can do to the command to get the groups that the computer SNA00760856 is a member of? Dropping in a user account in place of the computer account works like a charm.
I have also tried to qualify the computer name with the domain info.
Ie SNA00760856.mydivision.mydomain.com or mydivision\SNA00760856
Also tried to collect the membership of the computer using which I know is wrong after a closer reading of the switch info....
Get-QADobject -IndirectMemberOf SNA00760856
Results in ambiguous identity as well.
You can get the group memberships of a computer in AD through the ActiveDirectory module with Get-ADPrincipalGroupMembership. You'll need to search via the computers DistinguishedName, which can be achieved by leveraging Get-ADComputer:
Get-ADPrincipalGroupMembership (Get-ADComputer SNA00760856).DistinguishedName
That'll return all of the group objects SNA00760856 is a member of.
If you want to clean up the output, use this
Get-ADPrincipalGroupMembership (Get-ADComputer ComputerName) | select-object name
If you export to a list use
Get-AdPrincipalGroupMembership ( Get-ADComputer XXXXXXX ) | Out-File C:\XXX\XXX
I used something to pull down the AD Computer information and the Computer membership into one Text file.
This is using $Env:computerName to get the name of computer script is run on. If you want to select a different computer, change out the variable $HostName = to a computer name of your choice. Example $HostName = "Janes-Laptop01" .
The computer you run this script on must have the Active Directory module installed for this to work.
Import-module -Name ActiveDirectory
$HostName = $Env:computerName
$path = "c:\temp\Computer_AD_Membership_Info_$($HostName)_$(get-date -f yyyyMMdd-hhmm).txt"
Echo "`r`n ******* Computer OU Information. ******* `r`n" | Out-File -FilePath $path -Encoding utf8 -Force ;
Get-AdComputer -Identity $($HostName) -Properties * | Out-File -FilePath $path -Encoding utf8 -Append -Force ;
Echo "`r`n ******* AD Groups Computer Member of. ******* `r`n" | Out-File -FilePath $path -Encoding utf8 -Append -Force ;
Get-ADPrincipalGroupMembership (Get-ADComputer $($HostName)).DistinguishedName | Out-File -FilePath $path -Encoding utf8 -Append -Force ;