Unable to remove the Active sync devices leaf object from AD user - powershell

I am trying to delete a user account from AD, but it fails as the user object contains some leaf objects (Exchange active sync devices).
Tried using the Exchange powershell cmdlet:
Remove-ActiveSyncDevice
but the "ExchangeActiveSyncDevices" leaf object does not get removed from the user object.
After entering the command Remove-ActiveSyncDevice
Is there a way to completely remove the ExchangeActiveSyncDevices from the user object in AD through exchange powershell?

Untested by me, but by reading the documentation, this should work:
# parameter Mailbox can use any of these user properties:
# Name
# Alias
# Distinguished name (DN)
# Canonical DN
# <domain name>\<account name>
# Email address
# GUID
# LegacyExchangeDN
# SamAccountName
# User ID or user principal name (UPN)
# get the list of devices for your user and loop through, removing them one-by-one
Get-ActiveSyncDevice -Mailbox "the.user#yourcompany.com" | ForEach-Object {
$_ | Remove-ActiveSyncDevice -WhatIf
}
Exchange 2013 or later
Get-MobileDevice -Mailbox "the.user#yourcompany.com" | ForEach-Object {
$_ | Remove-MobileDevice -WhatIf
}
When satisfied with what info is shown in the console, remove the -WhatIf switch to actually have the code remove the devices.

I've had the same problem - you need to use Get-ADObject to find the empty nodes, and then pipe to Remove-ADObject to remove them. Sorry I don't have a script to share as I used Excel and some powershell commands to:
see if the node exists
check it's empty
remove the node
This is just to confirm that Remove-MobileDevice doesn't delete the empty offending node that affected my ADMT migration.

Related

Bult attribute edit in local AD

I'm trying to find a PowerShell script that updates the title attrubute in AD for a large number of users. I was hoping to find a script that imports the changes from a csv file and updates the atribute only for the users in the list. I found the below script but apparently it is working only for Azure AD, and I need it for the local AD. Perhaps someone more switche on than me can help me amend the below script.
#Import Active Directory module
Import-Module ActiveDirectory
#Import CSV File to set variable for the user’s logon name + update data + delimiter
$Users = Import-CSV -Delimiter ";" -Path "c:\psscripts\users.csv"
#Using your code to filter AD Sam Accounts listed CSVData is listed with the information you wish to update
Foreach($user in $users){
#Using your code to filter AD Sam Accounts Based on column samaccountname in the csv file
Get-ADUser -Filter "SamAccountName -eq '$($user.samaccountname)'" | Set-ADUSer `
-title $($User.Title)`
}
That code is fine, beyond some variable consistency and lack of checks, and does target local AD, though use of that deliminator would likely be unusual if you're just using a standard csv file. If you have the data in an excel document with the column headers of "SamAccountName" (typically email addresses) and "Title", and then save the file as a csv, the below amended code should work for you. Added logic to test for blank Title, as you can't assign a blank value to an attribute.
#Import Active Directory module
Import-Module ActiveDirectory
#Import CSV File with AD SAM account and Title data from users.csv in the C:\psscripts directory of your computer
$Users = Import-CSV -Path "c:\psscripts\users.csv" | Where {$_}
#Filter AD Sam Accounts listed in CSV and update title for listed accounts
Foreach($user in $Users){
#Check for value of $user.Title in case of null value
If ($user.Title){
#Filter AD Sam Accounts Based on column SamAccountName in the csv file and update the account Title field
Get-ADUser -Filter "SamAccountName -eq '$($user.SamAccountName)'" | Set-ADUSer -Title $($user.Title)
}
else {
#Filter AD Sam Accounts Based on column SamAccountName in the csv file and clear the account Title field
Get-ADUser -Filter "SamAccountName -eq '$($user.SamAccountName)'" | Set-ADUSer -clear -Title
}
}
I'd recommend testing it on a test user account or two before going whole hog on your actual list. Goes without saying that you need to be logged into a PS session as a domain account with adequate privileges to make the changes to the accounts when running the script. VS Studio Code is a good environment to work in, and you can launch the program as the elevated account (shift + right-click program icon, choose run as a different user) within your normal account environment, to sandbox the privileges to just what you're working on in VS Studio Code.
If you are trying to work in Azure AD, you'd need to add these lines and approve your account access request within Azure, depending on your tenant setup, to actually run the script successfully. Depending on the tenant configuration, this may be required in a hybrid AD/Azure AD environment regardless of your intent to apply to local AD.
Connect-MgGraph -Scopes "User.ReadWrite.All", "Directory.ReadWrite.All"
Select-MgProfile -Name "beta"
Best regards, no warranties given or implied, please accept as answer if this works for you.

Correct way to access the USERPROFILE dir of a specific user in a script?

I'm writing a script to perform some file operations in the USERPROFILE folder of each (local) user on a Windows machine.
I have found various examples that use $env:USERPROFILE to identify the profile directory of the current logged-in user. I have also seen examples that assume all user profiles are saved in C:\Users\ and iterate/filter over that folder.
However, profile folders can be moved on Windows. My aim is to find (robustly) the profile directory of a specific user, given either that user's username (string) or a LocalUser object.
I can get an array of User objects based on active accounts with-
$users = Get-LocalUser | Where-Object Enabled -eq true
But the properties of those LocalUser objects are limited, and the UserProfile path is not among them. I believe this information is stored in the registry. I've through the PowerShell docs multiple times, but I haven't yet found the correct incantation that will give me the path of a user profile for a given user, which I can use in a loop to iterate across all users and their profile folders.
You can retrieve the root (parent) directory of all user profile directories from the registry as follows:
$profilesRootDir =
Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' ProfilesDirectory
To get a specific user's profile directory, say jdoe, you can then use:
# See more robust alternative below.
Join-Path $profilesRootDir jdoe
However, the ultimate source of truth is the ProfileImagePath value in the subkeys of the above registry key path, named for each user's SID (security identifier), which Get-LocalUser does provide (the output objects have a .SID property).
Thus, it is better to use:
Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$((Get-LocalUser jdoe).SID)" ProfileImagePath
To reliably get the profile directories of all enabled local users, use the following:
Get-LocalUser |
Where-Object Enabled |
ForEach-Object {
# Note the use of ...\ProfileList\$($_.SID) and value name ProfileImagePath
Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$($_.SID)" ProfileImagePath
}
Perhaps something along this line:
$users = Get-LocalUser | Where-Object Enabled -eq true
$profilesRootDir = #(
Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' ProfilesDirectory)
ForEach ($User in $Users) {
$UserPath = Join-Path -Path "$profilesRootDir" -ChildPath "$User"
"User : $User`n" +
"User-Path: $UserPath"
}
Output:
User : Bruce
User-Path: C:\Users\Bruce
You can use the wmi class win32_userprofile, but it only has sid, not username:
get-wmiobject win32_userprofile | select sid,localpath
sid localpath
--- ---------
S-1-5-21-3961843708-1234567890-2901110831-1002 C:\Users\user

Create a second variable from the first variablbe

I'm trying to run a command again some mailboxes, after obtaining the mailbox names from a Retention Compliance Policy.
I can export the GUID to a CSV and then call the CSV, but I'm trying to limit my use of CSV's
The Below works with a CSV file
$Accounts = Import-Csv 'C:\Temp\MailboxInfoGUID.csv'
ForEach($Account in $Accounts)
{
$Guid = $null
$Guid = #()
$Guid = $Account.ArchiveGuid
Start-ManagedFolderAssistant -Identity $Guid -FullCrawl}
$Users = Get-RetentionCompliancePolicy $LabelPolicyName -
DistributionDetail | Select - ExpandProperty ExchangeLocation | Select -
ExpandProperty Name
I'd like to run the command without using a CSV file, but to get the mailbox identity I need to look in the Compliance Policy
How can I use the mailbox names obtained from the policy to then run a crawl on the mailbox
If I understood you correct, you would like the following:
Get the mailboxes from Get-RetentionCompliancePolicy.
Iterate through each of those mailboxes grabbing the GUID property.
Using Get-Mailbox.
Pass the newly obtained GUID to Start-ManagedFolderAssistant.
Given that's what you're after, the following should work:
(Get-RetentionCompliancePolicy $LabelPolicyName -DistributionDetail).ExchangeLocation.Name |
ForEach-Object -Process {
Start-ManagedFolderAssistant -Identity (Get-Mailbox -Identity $_).ArchiveGuid -FullCrawl
}
Due keep in mind that I don't have the ExchangePowerShell module installed so I am going off just logic; you may have to adjust the properties.

How can I get a value out of powershell system array object

I have a following piped command that should print a GPO name and the group that is associated with it, repeating this untill all GPOs and groups have been printed. The output isn't right though. The name comes out correctly but the group says Microsoft.GroupPolicy.GPTrustee instead of the groups name.
How should I access it to get the value?
Here is my piped command:
Get-GPO -All | ForEach-Object {$gpo = $_.DisplayName; Write-Output $_;} | Get-GPPermission -All |
Where-Object {$_.Permission -eq "GpoApply"} |
Select-Object #{Name="GpoName"; Expression={$gpo}},#{Name="Group"; Expression={$_.trustee}}
EDIT: The problem was solved, but I'll still copy the output of "Microsoft.GroupPolicy" -object here to clarify why I thought I'd be able to access it with $_.trustee variable.
It looked like this so $_.trustee.name didn't even cross my mind.
Trustee : Domain Computers
TrusteeType : Group
Permission : GpoApply
Inherited : False

PowerShell command to query Exchange online autoreply configurations

We sync our local AD to Office 365.
I have been asked to get the out-of-office reply for users who are:
Disabled
Still have an Exchange mailbox.
I have some of the command but cannot figure out how to make it work:
$disabled = Get-ADUser -SearchBase "ou=Employees,ou=accounts,dc=domain,dc=local" -Filter { UserAccountControl -eq 514 } -Properties mail | Select-Object mail
foreach ($mail in $disabled) {
Get-MailboxAutoreplyConfiguration -Identity $mail
}
I believe this can be achieved without the call to AD via Get-ADUser cmdlet to get the list of disabled accounts. You can check the result of Get-Mailbox for the property ExchangeUserAccountControl. If the value is AccountDisabled then the account should be disabled in AD.
So that means you can do this :
Get-Mailbox -ResultSize Unlimited |
Where {
$_.recipienttype -eq "UserMailbox" -and ` # make sure we only get user mailboxes
$_.recipienttypedetails -eq "UserMailbox" -and ` # make sure we only get licenced mailboxes only, no shared mailboxes, no room mailboxes, etc
$_.exchangeuseraccountcontrol -like "*accountdisabled*" # make sure we only get disabled user accounts
} |
Get-MailboxAutoreplyConfiguration | # we can pipe user mailbox object directly into this cmdlet (no need to go into a foreach loop)
Format-List identity,autoreplystate,internalmessage,externalmessage # you can remove this and replace with Select then send to Csv or wherever you need
That last line with Format-List is just for viewing (and should be changed if you want to send data to a file, for example), this data can have large output depending if a user has internal or external messages set or not.
Please note that the above will return list of all Active Mailboxes in your Office365 tenant that :
have an Office365 UserMailbox (should be licensed mailbox)
is Disabled in Active Directory (AD account has Enabled : $False)
You can tell if the AutoReply messages are Active by looking at the autoreplystate value. It will either be Enabled or Disabled. So you can even add another Where clause to filter down to only those mailboxes that have autoreplystate : Enabled to only view mailboxes that have active auto replies set (based on your description, this was not clear if it was required or not).