Powershell QADUser Password Expiry - powershell

Hi I have the below script which emails users who's passwords are due to expire in $daysleftonpwd, but not sure how to add in an "only if user has password set to expire" meaning I don't want to email users who's password is set to next expire.
Get-QADGroupMember -Identity TEAM_GROUP | % {
$name = $_.Name
$email = $_.Email
$daysleftonpwd = ((Get-QADUser -SizeLimit 0 -SearchRoot $OU -Identity $_.SamAccountName | select PasswordExpires).PasswordExpires - $date | select Days).Days
if (((Get-QADUser -Identity $_.SamAccountName | select PasswordExpires).PasswordExpires - $date).Days -lt $threshold){
Write-Host "$Name would be emailed using $email because password is less than $threshold"
$y = $y + "<br>$name</br>"
mailuser
}
Any ideas?

One of the fields that Get-QADUser returns is PasswordNeverExpires:
PS C:\> ( Get-QADUser regularuser ).PasswordNeverExpires
False
PS C:\> ( Get-QADUser specialuser ).PasswordNeverExpires
True
Should be easy enough to use that in your scripts to test. There's other ways to check it directly (you have to look at both UserAccountControl -- https://msdn.microsoft.com/en-us/library/ms680832%28v=vs.85%29.aspx AND msDS-User-Account-Control-Computed -- https://msdn.microsoft.com/en-us/library/ms677840%28v=vs.85%29.aspx), but that's a bit uglier...

Related

How come my condition determining if a user is in a group always returns as false?

I'm writing a script that requires detecting if the executing user account is a domain admin. I do this by getting the current user and checking if they are in the Domain Admins security group.
#Get current user
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name | Out-String
$CurrentUser = $CurrentUser -replace 'DOMAIN\\'
#Get list of Domain Admins members
$DomainAdmins = Get-ADGroupMember -Identity "Domain Admins" -Recursive | Select -ExpandProperty SamAccountName | Out-String
#Relevant condition
If ($DomainAdmins -like ($CurrentUser)) {
Write-Output "You're a domain admin." #example
}
Else {
Write-Output "You're not a domain admin."
}
Without fail, this script always runs the Else code when run from our domain controller using a domain administrator account.
I have also tried using -contains and .contains() with the exact same results. I've verified that the $CurrentUser value represents the current user accurately and that $DomainAdmins lists out the expected list of users.
I can also do this:
if ($DomainAdmins -contains ("USERNAME")) {Write-host "true"}
Where USERNAME is the current user typed out directly (case-correct or not) and it correctly returns true when that user is a member of the group.
Try with this:
$userSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
$DomainAdmins = Get-ADGroupMember -Identity "Domain Admins" -Recursive
if($DomainAdmins.SID.Contains($userSID))
{
Write-Output "You're a domain admin."
}
...
# OR
if($userSID -in $DomainAdmins.SID)
{
Write-Output "You're a domain admin."
}
...
# OR
if($DomainAdmins.SID -contains $userSID)
{
Write-Output "You're a domain admin."
}
The Out-String on Get-ADGroupMember is converting your array into a string which is why you can't use it as comparison:
PS /> #(
'one'
'two'
'three'
) -contains 'one'
True
PS /> (#(
'one'
'two'
'three'
) | Out-String) -contains 'one'
False
An alternative, instead of using Get-ADGroupMember:
$userSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
$domainAdminsDN = (Get-ADGroup -Identity "Domain Admins").DistinguishedName
$recursiveMembers = Get-ADUser -LDAPFilter "(memberOf:1.2.840.113556.1.4.1941:=$domainAdminsDN)"
if($recursiveMembers.SID.Contains($userSID))
{
Write-Output "You're a domain admin."
}
...
...
My preferred way to do this is by checking the MemberOf property of the user. It works a little better to keep them as AD objects when you have multiple domains or other oddities:
# check if DA
$DAdn = (Get-ADGroup 'Domain Admins').distinguishedname
If ( Get-ADUser -LDAPFilter "(&(SamAccountName=$Env:USERNAME)(MemberOf:1.2.840.113556.1.4.1941:=$DAdn))" ) {
Write-Output "You're a domain admin." #example
}
Your $DomainAdmins variable is a single string with the members instead of a list object. Using ... | Select -ExpandProperty SamAccountName is enough to get your list without Out-String.
-contains Looks for exact matches in collections, not for substrings.
You have to either remove Out-String from $DomainAdmins, to make it a list and make sure that the name matches entirely, or use .Contains(...) to look for a substring inside the $DomainAdmins string

Searching for User in Powershell. Allow Choice for Duplicate User

I wrote a PowerShell script that searches for a user based on given input and then removes said user from all groups (except for Domain Users). However, while you can't have a user with the same name in an OU group, you can have a user with the same name in a different OU group in the organization. Would it be possible to search for a user (John Smith), and allow one to select which user to remove from all groups if a duplicate user is returned? Here is my script so far. It works, but this is the functionality I would like to add.
#Requires -Module ActiveDirectory
Import-Module ActiveDirectory
function Disable-ADUser{
$msg = "Do you want to remove a user from all Security groups? [Y/N]"
do {
$response = Read-Host -Prompt $msg
if ($response -eq "y") { # Beginning of if statment
#Asks user via a text prompt to ender the firstname and lastname of the end user to remove
$firstName = Read-Host "Please provide the First name of the User"
$lastName = Read-Host "Please provide the Last name of the User"
#The user's samaccoutname is found by searching exactly for the user's first name and lastname given in the above prompts
$samName = Get-ADUser -Filter "GivenName -eq '$firstName' -and Surname -eq '$lastName'"| Select-Object -ExpandProperty "SamAccountName"
#All of the user's groups are queried based on their sam name
$listGroups = Get-ADUser -Identity $samName -Properties MemberOf | Select-Object -ExpandProperty MemberOf
#All of the user's groups are placed in an array
[System.Collections.ArrayList]$groupsArray = #($listGroups)
#Every group in the groupsArray is cycled through
foreach ($group in $groupsArray) {
#A text output is displayed before the user is removed from each group listed in the above array
#Once all groups have been cycled through, the for loop stops looping
Write-Host "Removing $samName " -f green -NoNewline
Write-Host "from $group" -f red
$OutputLine="Removing $samName from $group"
Out-File -FilePath remove_user_groups.log -InputObject $OutputLine -Append
Remove-ADGroupMember -Identity $group -Members $samName
}
} # End of if statement
} until ($response -eq "n")
}
Disable-ADUser
I use Out-GridView. It allows me to select user(s) with mouse, or to select no one. See -OutputMode parameter.
<# Example part #>
$data = #'
[
{displayName: "Don Pedro Fizikello", employeeNumber: "Emp001", phone: "+888888888" },
{displayName: "Don Pedro Gonzalez", employeeNumber: "Emp002", phone: "+77777777777" },
{displayName: "Natalia Marisa Oreiro", employeeNumber: "Emp456", phone: "+987654321" },
{displayName: "Juan Carlos Rodrigez", employeeNumber: "Emp123", phone: "+1234567890"}
]
'# | ConvertFrom-Json
$userList = #($data | Where-Object { $_.displayName -like 'Don*' })
#Real-world case from Active Directory: $userList = #( Get-ADUser -Filter "(displayName -like 'Don*')" -Properties #('displayName', 'phone') )
<# /Example part #>
$user = $null
if ($userList.Count -eq 1) {
$user = $userList[0] # // The only entry
} elseif ($userList.Count -gt 1) {
$user = $userList | Out-GridView -OutputMode Single -Title 'Select User you want co tall to or press cancel'
}
if ($null -eq $user) {
# // There is no users found or selected by human
Write-Host "Nothing to do" -f Yellow
} else {
# // Work with User
Write-Host "Call $($user.displayName) : $($user.phone)" -f Green
}
The negative option is that Out-GridView can not hide parameters that it will display. There are some workarounds depending on task. Example: I show only DisplayName and some ID in Out-GridView (no phone property), but I use returned ID to take full user (with phone) from cache I've created before.
This allows me not to break the original object ( if it's from Get-ADUser, it contains tons of human-useless data like SID, GUID, ObjectClass, ObjectCategory, etc. )
<# Example part #>
Same as previous
<# /Example part #>
$user = $null
$userCacheOriginal = #{}
$userCacheCut = #{}
for ($i = 0; $i -lt $userList.Count; $i++)
{
# !! Here I assign some entryUniqueId to two collections -
# - userCacheOriginal - Original user object with Phone field ( and others )
# - userCacheCut - Transformed objects that contains only ID and info I want to show in Out-GridView
$entryUniqueId = "Idx$($i)"
$userCacheOriginal[$entryUniqueId] = $userList[$i]
$userCacheCut[$entryUniqueId] = [PSCustomObject]#{ID = $entryUniqueId; displayName = $userList[$i].DisplayName;}
}
if ($userList.Count -eq 1) {
$user = $userList[0] # // The only entry
} elseif ($userList.Count -gt 1) {
$userChoice = $userCacheCut.Values | <# Set order of columns this way#> Select #('ID', 'DisplayName') | Out-GridView -OutputMode Single -Title 'Select User or press cancel'
if (($null -ne $userChoice.ID) -and ($userCacheOriginal.ContainsKey($userChoice.ID))) # Check if returned value contains ID,
{ # And select original user object from userCacheOriginal
$user = $userCacheOriginal[$userChoice.ID]
}
}
if ($null -eq $user) {
# // There is no users found or selected by human
Write-Host "Nothing to do" -f Yellow
} else {
# // Work with User
Write-Host "Call $($user.displayName) : $($user.phone)" -f Green
}
If you want to keep it console based, you can add a while loop that requires further input from the user.
#The user's samaccoutname is found by searching exactly for the user's first name and lastname given in the above prompts
$samName = Get-ADUser -Filter "GivenName -eq '$firstName' -and Surname -eq '$lastName'"|
Select-Object -ExpandProperty "SamAccountName"
if ($samname.count -gt 1) {
$newsamname = $null
while ($newsamname -notin $samname) {
$newsamname = Read-Host "Multiple names were found:`n$($samname -join ""`n"")`nPlease type the SamAccountName of the target user"
}
$samname = $newsamname
}
The idea is if multiple user objects are found, then $samname will initially be a collection of count greater than one. Here the executor will be required to enter a valid SamAccountName value from the presented list. Otherwise, the loop will go on forever until the program is manually halted. You could build in a counter to automatically exit the program after a certain number of retries or exit when no value is entered. You could implement a menu system where a number can be entered, which corresponds to the index of the list.

Will Office 365 (Admin center or Powershell) tell me if a user's password is expired?

I feel like this question has to have been asked before, but I've spent way too much time searching for it here and elsewhere.
I'm looking for something to tell me that a user's password has expired. When I search for this, I get a ton of sites telling me how to set a user's password to never expire or how to set the password policy. I just want to be able to look up a user in the Admin Center or using PowerShell to see if the password is expired.
I user this cmdlet as a workaround for the moment, but it would be so much easier if I could have it tell me "Password Expired: Yes" or something like that.
Get-MsolUser -SearchString (Read-Host `n Whose info?) | select DisplayName, LastPasswordChangeTimeStamp, #{Name=”PasswordAge (in days.time)”;Expression={(Get-Date)-$_.LastPasswordChangeTimeStamp}}, PasswordNeverExpires | fl
Thanks!
04-Aug-16 Edit based on Junaid's suggested answer below:
I've changed the script to allow for searching, for vertical spacing, and for the accounts where PasswordNeverExpires = TRUE. I hope it's helpful.
$valid = Get-MsolPasswordPolicy -DomainName domain.com | select ValidityPeriod -ExpandProperty ValidityPeriod
Get-MsolUser -SearchString (Read-Host `n Whose info?) | Select DisplayName, LastPasswordChangeTimeStamp, PasswordNeverExpires | foreach{
$user = $_.DisplayName
$exp = $_.LastPasswordChangeTimeStamp.addDays($valid)
If ($_.PasswordNeverExpires -eq $TRUE){
$exp = "Never"
}
Write-Output "$user's Password Expiration: $exp"
}
Write-Output `n
You can achieve it like this. First get the domain's password policy and save the ValidityPeriod to a variable. Then get all users and their last password change time stamp, add the validity period to it and there you have it, the date when the password will expire.
$valid = Get-MsolPasswordPolicy -DomainName yourdomain.com | select ValidityPeriod -ExpandProperty ValidityPeriod
Now we have the validity period in $valid variable.
Get-MsolUser -All | Select UserPrincipalName, LastPasswordChangeTimeStamp | foreach{
$user = $_.UserPrincipalName
$exp = $_.LastPasswordChangeTimeStamp.addDays($valid)
Write-Output "$user's password expires on $exp"
}
I ran this in a powershell session with Msol service connected. So i hope it helps you.

Writing a mailbox property to a Variable or text box

I am writing a basic GUI that makes it easier for staff to find current mailbox/calendar rights. Essentially they type the name of the mail box and the user who's permissions they wish to check, and it writes what the permissions are
I have tried two ways and both ran into problems. The first:
$Property = get-mailboxpermission -Identity $Mailbox -User $User | Format-List AccessRights if($Property -eq "AccessRights : {FullAccess}")
$PermissionText.AppendText(($Property))
Results with the output:
"Microsoft.PowerShell.Commands.Internal.Format.FormatStartData....."
(I have also get the same when simply inputting the get-mailbox command to the append text)
I have also tried instead to convert the access rights property to a variable, then writing that to the text box using if conditions as below code, but that doesn't play nice either
Method:
$Property = get-mailboxpermission -Identity $Mailbox -User $User | format-list AccessRights
if($Property -eq "AccessRights : {FullAccess}")
{$PermissionText.AppendText("Full Access")}
if($Property -eq "AccessRights : {ReadAccess}")
{$PermissionText.AppendText("Read Only")}
Output: Nothing whatsoever
in short, I need a way of either outputting just the permissions to the text box, or, making the variable equal something useable
Try this:
$Property = Get-MailboxPermission -Identity $Mailbox -User $User | ? {$_.AccessRights -eq "FullAccess"}
if($Property)
{
$PermissionText.AppendText($Property.User.ToString())
}
Thankyou #Avshalom i figured it from your idea:
$Property = Get-MailboxPermission -Identity $Mailbox -User $User | ? {$_.AccessRights}
$PermissionText.AppendText($Permission.AccessRights)

Determining if a given user is in a given global group

I’m trying to search through Active Directory using the AD module in PowerShell. I’m trying to determine whether a given user is in a given global group. The issue is that I’m using -match meaning if there is a username that contains another within it, such as 'smith_pl' containing 'smith_p'. The user 'smith_p' will be shown to be in the group.
So my question is: Is there a better way of getting a $True or $False return depending if a user is in a giving global group using the AD module?
If not
Is there a way of getting the output from $ListOfmembers into an array so I can use -eq instead of -match?
Part of Script:
$ListOfmembers = dsquery group domainroot -name $globalgroup |
dsget group -members |
dsget user -samid -L
$checkMember = $False
#Search if the user is in output the list
If($ListOfmembers -match $Logonname){
$checkMember = $True
}
ListOfmembers Output:
samid: user05_t
samid: user23_s
samid: Admin
samid: user45_s
dsget succeeded
Any help would be appreciated, Cheers.
$member = Get-ADGroupMember group1 -Recursive | where {$_.samaccountname -eq 'user1'}
if($member) {'user 1 is a member of group1'}
You can do it like this:
[reflection.assembly]::LoadWithPartialName("System.DirectoryServices.AccountManagement")
$username = "samaccountname"
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($ct, $username)
$g = $user.GetGroups()
( $g | select -expa name ) -contains 'groupname'
You should checkout QAD: http://www.quest.com/powershell/activeroles-server.aspx
$user get-qaduser samAccountName
$user.memberof