Few questions regarding Powershell ForEach MFA script - powershell

I'm working on a script to implement MFA deployment through Powershell. I'm connecting to an office365 and running the Get-MsolUser command to grab a list of users from AD (I believe). I'm putting it into an array which I'm then running through a ForEach loop. I'm not sure if this is even functional yet, but I'm trying to figure out how to exclude certain users from this loop as I don't want to activate MFA for domain admins.
Connect-MsolService
$array = #(Get-MsolUser | Select UserPrincipalName)
ForEach ($users in $array)
{
$st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty = "*"
$st.State = "Enabled"
$sta = #($st)
Set-MsolUser -UserPrincipalName $users -StrongAuthenticationRequirements $sta
}
So I guess the 3 questions I have are:
How can I exclude users with names matching a certain string such as "Admin, Administrator" in the Array?
Is there anyway to take user input and apply it to the username/password fields for Connect-MsolService?
3)Is this code even functional as it stands or am I totally off the mark?

As commented, there are some enhancements to be made in your code.
Try:
Starting with your question 2)
Connect-MsolService has a -Credential parameter and the easiest way to obtain that is by using the Get-Credential cmdlet:
# ask for credentials to make the connection
$cred = Get-Credential -Message 'Please enter your credentials to connect to Azure Active Directory'
Connect-MsolService -Credential $cred
Next, you want to define a list of users to exclude from being affected.
$excludeTheseUsers = 'admin', 'user1', 'user2' # etc.
# for using the regex `-notmatch` operator later, you need to combine the entries with the regex OR sign ('|'),
# but you need to make sure to escape special characters some names may contain
$excludes = ($excludeTheseUsers | ForEach-Object { [regex]::Escape($_) }) -join '|'
# create the StrongAuthenticationRequirement object just once, to use on all users
$st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty = "*"
$st.State = "Enabled"
$sta = #($st)
# get an array of UserPrincipalNames
$array = (Get-MsolUser | Where-Object { $_.DisplayName -notmatch $excludes }).UserPrincipalName
foreach ($user in $array) {
Set-MsolUser -UserPrincipalName $user -StrongAuthenticationRequirements $sta
}

Related

Powershell - Check if user with this SID Exist and remove his UPD

Hello dear community.
We got MS RDS Terminal Server and we would like to remove User Profile Disks for deleted and (maybe) disabled users.
I would like one script with following tasks:
Get all UPDs from path
Check UPD Owner
Check if the owner exist in AD and if is enabled
Remove UPD if owner not exist in ad or if is enabled
$updtest = Get-ChildItem -Path C:\updtest -Force
foreach($UPD in $updtest) {
##Get User Name
$UPD = $UPD.ToString()
$UPD = $UPD.Trim("UVHD-")
$UPD = $UPD.Trim(".vhdx")
$objSID = New-Object System.Security.Principal.SecurityIdentifier `
($UPD)
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
$userTest = $objUser.Value
$userTest = $userTest.Trim("Domain\")
$AdUser = [bool] (Get-ADUser -Filter {SamAccountName -eq $userTest })
if ($AdUser -eq $false) {Write-Host "User $userTest exist"}
else {Write-Host "User $AdUser exist"}
In step no. 3 is getting harder, because some users are not right trimmed (first letter missing). $UPD and $userTest have to be trimmed because Get-ADUser don't accept "DOMAIN" and New-Object System.Security.Principal.SecurityIdentifier don't accept ".vhdx" and "UVHD-"
Is there any another possibility to do easier this tasks?
It is possible to check if SID exists in AD without any conversion?
Thank you in advance!

Powershell - Update-MgUserLicenseDetail : Filtered searches against this resource are not supported

So with the notice that came out today stating that Microsoft will be discontinuing support for the MSOnline module and replacing it with the Microsoft.graph module, I figured I would get a head start on fixing my scripts. I have a script that I use for creating new users and assigning a O365 license. The code I replaced it with looks right, but I get an error when trying to run the script.
$User = get-mguser -filter "mail eq '$email'"
#update-mguser -UserId $user -UsageLocation CA
$licensetype = Read-host -Prompt 'Press 1 for EOP1, 2 for Business Basic, and 3 for Business Standard'
# hash table with string keys 1,2,3
# Expected usage: $emails['1'] for first email address
$License = #{ '1' = 'Z8x8mo80bEqMyf-7sJWmsrAFlEuId2hFrdGZYU5hO2k'
'2' = 'Z8x8mo80bEqMyf-7sJWmshhRVTtq2hhEiU998eIJaHA'
'3' = 'Z8x8mo80bEqMyf-7sJWmssjsRfKvdY5Pth8n2BFN5fM' }
# Only want to add licenses when user enters 1,2, or 3
if ($licensetype -in 1,2,3) {
#$LicensedUser = Get-AzureADUser -ObjectId $email[$licensetype]
$User = get-mguser -filter "mail eq '$email'"
#$Licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
#$Licenses.AddLicenses = $LicensedUser.AssignedLicenses
#Set-AzureADUserLicense -ObjectId $User.Id -AssignedLicenses $Licenses
Update-MgUserLicenseDetail -UserID $user.ID -LicenseDetails $License[$licensetype] }
Error:
Update-MgUserLicenseDetail : Filtered searches against this resource are not supported.

Powershell: Create local administrators remotely

I'm looking at creating a local administrator on a handful of machines (>30). I don't really want to use GPO if I can get away with it. LAPS is a little overkill for what I need.
I found a nice script online but it only creates the user and doesn't add them to the administrators group. Can anyone see the error?
#Define variables
$computers = Get-Content C:\Computers.txt
#$computers = Import-CSV C:\Computers.txt | select Computer
$username = "Admin"
$password = "Password99"
$fullname = "Admin"
$local_security_group = "Administrators"
$description = "Description"
Foreach ($computer in $computers) {
$users = $null
$comp = [ADSI]"WinNT://$computer"
#Check if username exists
Try {
$users = $comp.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username already exists on $computer"
} else {
#Create the account
$user = $comp.Create("User", "$username")
$user.SetPassword("$password")
$user.Put("Description", "$description")
$user.Put("Fullname", "$fullname")
$user.SetInfo()
#Set password to never expire
#And set user cannot change password
$ADS_UF_DONT_EXPIRE_PASSWD = 0x10000
$ADS_UF_PASSWD_CANT_CHANGE = 0x40
$user.userflags = $ADS_UF_DONT_EXPIRE_PASSWD + $ADS_UF_PASSWD_CANT_CHANGE
$user.SetInfo()
#Add the account to the local admins group
$group = ([ADSI]"WinNT://$computer/$local_security_group,group")
$username = [ADSI]"WinNT://$Computer/$username,user"
#Validate whether user account has been created or not
$users = $comp.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username has been created on $computer"
} else {
Write-Host "$username has not been created on $computer"
}
}
}
Catch {
Write-Host "Error creating $username on $($computer.path): $($Error[0].Exception.Message)"
}
}
In your code you are not actually adding the user to the group.
Here you are actually retrieving a group object, but you are not doing anything with it.
#Add the account to the local admins group
$group = ([ADSI]"WinNT://$computer/$local_security_group,group")
$username = [ADSI]"WinNT://$Computer/$username,user"
First you must remove the assignment to $username. Then you must invoke a method on the $group object to add the user:
#Add the account to the local admins group
$group = ([ADSI]"WinNT://$computer/$local_security_group,group")
$computerHostName = (Get-WmiObject -ComputerName $computer Win32_ComputerSystem).Name
$group.Add([ADSI]"WinNT://$computerHostName/$username,user")
There is a catch here. Notice I use Get-WmiObject to get the hostname from the computer. When using the Add() method, the computer name must be the unqualified hostname. For example server-01, and NOT server-01.domain.lan
If you want to retrieve the ADSI object for the user later, I recommend assigning it to a different variable name, like this:
$adsiUser = [ADSI]"WinNT://$Computer/$username,user"

PowerShell Function to check group member not working

I found this function I'd like to use in a script I'm writing, but it keeps coming back $false when I can see an account is in a group and I can't figure out why?
function Check-IsGroupMember{
Param($user,$grp)
$strFilter = "(&(objectClass=Group)(name=" + $grp +"))"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
$colResults = $objSearcher.FindOne()
$objItem = $colResults.Properties
([string]$objItem.member).contains($user)
}
Usage:
Check-IsGroupMember "name of user" "DomainAdmins"
$objItem.member contains the DistinguishedName value of each principal who is a member of the group.
Even though the proper name of a person might be John Doe, the common name of the user account object may still be Doe, John, John G. Doe or anything else. This means that Contains() check (which is just a simple substring search) is not guaranteed to work as you expect.
The only real way to check is to either run another search for the user to find his/her DistinguishedName.
Personally, I would go for the AD PowerShell module from RSAT, rather than using a DirectorySearcher:
function Test-GroupMembership
{
Param(
[string]$UserName,
[string]$GroupName
)
$User = Get-ADUser -Identity $UserName
$Group = Get-ADGroup -Identity $GroupName -Properties member
$Group.member -contains $User.DistinguishedName
}
If size limit is your problem, you can use the DirectoryServer to retrieve a ranged result of the member attribute:
function Test-GroupMembership
{
[CmdletBinding()]
Param(
[string]$UserName,
[string]$GroupName
)
# Fetch User
$User = Get-ADUser -Identity $UserName
# return on failure
if(-not $User){
Write-Error -Message ('User "{0}" not found' -f $GroupName)
return $false
}
# Use DirectorySearcher to retrieve ranged member attribute
$GroupSearcher = '' -as [adsisearcher]
$GroupSearcher.Filter = '(&(objectClass=group)(name={0}))' -f $GroupName
$GroupSearcher.SearchScope = 'Subtree'
$GroupSearcher.SearchRoot = '' -as [adsi]
# AD reponds with at least 1500 values per multi-value attribute since Windows Server 2003
$Start = 1
$Range = 1500
$GroupMembers = #()
$HasMoreMembers = $false
# Keep retrieving member values until we've got them all
do{
# Use range operator to "page" values
# Ref: https://msdn.microsoft.com/en-us/library/aa367017(v=vs.85).aspx
$RangedMember = 'member;range={0}-{1}' -f $Start,$($Start + $Range - 1)
$GroupSearcher.PropertiesToLoad.Add($RangedMember) | Out-Null
# Retrieve group
$Group = $GroupSearcher.FindOne()
# return on failure
if(-not $Group) {
Write-Error -Message ('Group "{0}" not found' -f $GroupName)
return $false
}
# If we've reached the end of the member list,
# AD will return a property where the upper range
# value is *, so it might not be the same property
# name we specified in PropertiesToLoad
$ReturnedMember = #($Group.Properties.PropertyNames) -like 'member;*'
# Add all members to the $GroupMembers variable
foreach($member in $Group.Properties."$ReturnedMember") {
# Test if user is in the member list
if($member -eq $User.DistinguishedName){
return $true
}
}
# If we've reached the end, exit the loop
if($ReturnedMember -eq $RangedPropertyName){
$HasMoreMembers = $true
}
} while ($HasMoreMembers)
# User wasn't found
return $false
}
To provide a bit of consistency in user experience, please use Approved Verbs for command names in PowerShell (eg. Test-* instead of Check-*)
[adsisearcher] is a type accelerator for the DirectorySearcher class

Add proxyAddresses to Active Directory users when created in PowerShell

I am trying to add users in Active Directory. Those users need to have proxyAddresses. My problem is that those proxyAddresses are multiples and stored in an array.
I try :
$proxyAddresses = #("address1#test.com", "address2#test.com", "address3#test.com")
$userInstance = new-object Microsoft.ActiveDirectory.Management.ADUser
$userInstance.ProxyAddresses = $proxyAddresses
New-ADUser test -Instance $userInstance
And I get this error :
Invalid type 'System.Management.Automation.PSObject'. Parameter name: proxyAddresses
I would like to add this proxyAddresses array to the attribute proxyAddresses of my AD user but it don't seem to be possible.
Any idea how this could be done?
Anything wrong with using Set-ADUser?
$username = '...'
$proxyAddresses = 'address1#example.com', 'address2#example.com', 'address3#example.com'
New-ADUser -Name $username
Set-ADUser -Identity $username -Add #{
'proxyAddresses' = $proxyAddresses | % { "smtp:$_" }
}
I just had this same issue and I was pretty sure I was passing in a string array (that's how it was declared).
Problem was just before I sent my string array into AD I was passing it to "Sort-Object -Unique" - which unbeknownst to me was changing either the type or something that made the cmdlet unhappy.
Just FYI...Sort-Object can burn you in these circumstances.
So, in my testing of this. I made Get-ProxyAddresses at https://gist.github.com/PsychoData/dd475c27f7db5ce982cd6160c74ee1d0
function Get-ProxyAddresses
{
Param(
[Parameter(Mandatory=$true)]
[string[]]$username,
[string[]]$domains = 'domain.com'
)
#Strip off any leading # signs people may have provided. We'll add these later
$domains = $domains.Replace('#','')
$ProxyAddresses = New-Object System.Collections.ArrayList
foreach ($uname in $username) {
foreach ($domain in $domains ) {
if ($ProxyAddresses.Count -lt 1) {
$ProxyAddresses.Add( "SMTP:$uname#$domain" ) | Out-Null
} else {
$ProxyAddresses.Add( "smtp:$uname#$domain" ) | Out-Null
}
}
}
return $ProxyAddresses
}
It just returns as a collection. Pretty kludgy, but works for what I need. It also assumes the first username and first domain are the "primary"
I combined that with #ansgar's answer and tried just -OtherAttributes on New-Aduser
$proxyAddresses = Get-ProxyAddress -username 'john.smith', 'james.smith' -domains 'domain.com','domain.net'
New-ADUser -Name $username
-OtherAttributes #{
'proxyAddresses'= $proxyAddresses
}
Works perfectly and added the proxyAddresses for me right at creation, without having to have a separate set action afterwards.
If you are Going to do separate actions, I would recommend to use -Server, like below, so that you don't run into talking to two different DCs by accident (and you also know that the New-ADUser is finished and already there, you don't have to wait for replication)
#I like making it all in one command, above, but this should work fine too.
$ADServer = (Get-ADDomainController).name
New-ADUser -Server $ADServer -name $Username
Set-ADUSer -Server $ADServer -Identity $username -Add #{
'proxyAddresses' = $proxyAddresses | % { "smtp:$_" }
}