Powershell - Azure licence based on ad group - powershell

I have been developing AzureAD licence script based on AD Group. So, Find users with a direct assigned, find them in AD, evaluate what group they should be a member of, add them to licensing group. I have hashtable with multiple values $SKUToGroupRev. I can not match hashtable with multiple values with if($ADGroup = $SKUToGroupRev[$SKU.SkuId]) .
From what I want to do :
if there are 18181a46-0d4e-45cd-891e-60aabd171b4e and 0c266dff-15dd-4b49-8397-2bb16070ed52 inside SKUs variable for below command then I will add AD group related to the inside hashtable such as O365_E1_Users
OR
if there are 6fd2c87f-b296-42f0-b197-1e91e994b900 and 0c266dff-15dd-4b49-8397-2bb16070ed52 inside SKUs variable for below command then I will add AD group related to the inside hashtable such as O365_E3_Users
e.g:
# Get licensed SKUs for the user
$aaduser = get-azureaduser -objectID $user.UserPrincipalName
$SKUs = $aaduser | Select UserPrincipalName,ImmutableID -ExpandProperty AssignedLicenses
e.g output:
UserPrincipalName ImmutableId DisabledPlans SKUId
----------------- ----------- ------------- -------------
User01#contoso.com x+MVG6EKEUWHi3r6zjgzCA== {041fe683-03e4-45b6-b1af-c0cdc516da4f... 6fd2c87f-b296-42f0-b197-1e91e994b900
User01#contoso.com x+MVG6EKEUWHi3r6zjgzCA== {} 0c266dff-15dd-4b49-8397-2bb16070ed52
Here is my script :
$CSVfile = "C:\temp\LicenseToGroupUsers.csv"
# Import the CSV file
try {
$users = import-csv $CSVfile
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
Break
}
write-warning "About to add the following users to license groups for complete SKU:"
foreach ($user in $users){
write-host $user.UserPrincipalName
}
Read-Host -Prompt "Press Enter to continue or CTRL+C to quit"
$e3 = -split "0c266dff-15dd-4b49-8397-2bb16070ed52 6fd2c87f-b296-42f0-b197-1e91e994b900"
$e1 = -split "18181a46-0d4e-45cd-891e-60aabd171b4e 0c266dff-15dd-4b49-8397-2bb16070ed52"
$TEAMS_EXPLORATORY = -split "710779e8-3d4a-4c88-adb9-386c958d1fdf 0c266dff-15dd-4b49-8397-2bb16070ed52"
#$FLOW_FREE_E3 = -split "f30db892-07e9-47e9-837c-80727f46fd3d 6fd2c87f-b296-42f0-b197-1e91e994b900 0c266dff-15dd-4b49-8397-2bb16070ed52"
foreach ($user in $users){
$groupsToAdd = #()
$groupsToRemove = #()
write-host "Processing" $user.UserPrincipalName
# Get licensed SKUs for the user
$aaduser = get-azureaduser -objectID $user.UserPrincipalName
#$SKUs = $aaduser | Select UserPrincipalName,ImmutableID -ExpandProperty AssignedLicenses
#Get the AD ObjectGuid for the group add (cannot use UPN)
$ImmutableID = "" #Null these out otherwise gets reused from previous
#Have to match using the guid
$ImmutableID = $aaduser.ImmutableID
if ($ImmutableID) {$objectGUID = ([GUID][System.Convert]::FromBase64String($ImmutableID)).Guid}
else {
write-warning "Error getting ImmutableID for $UPN, user is likely cloud only, skipping"
Break
}
# test 1
$licenses = $aaduser.AssignedLicenses.SkuId
$is_e1 = !($e1 | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_e1 -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to E1Group" -ForegroundColor Green
Write-Host "Test 1: $is_e1"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}
$is_e3 = !($e3 | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_e3 -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to E3Group" -ForegroundColor Green
Write-Host "Test 3: $is_e3"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}
$is_TEAMS_EXPLORATORY = !($TEAMS_EXPLORATORY | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_TEAMS_EXPLORATORY -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to (TEAMS_EXPLORATORY)E1Group" -ForegroundColor Green
Write-Host "Test 1: $is_TEAMS_EXPLORATORY"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}
<# $is_FLOW_FREE_E3 = !($FLOW_FREE_E3 | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_FLOW_FREE_E3 -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to (FLOWFREE)E3Group" -ForegroundColor Green
Write-Host "Test 1: $is_FLOW_FREE_E3"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}#>
}

To test agains a combination of SkuID's, using a lookup hashtable as in your first approach is not the easiest way I think. Your current approach looks much better to me, only I would not put the ID's in array variables, but test them literally against the ID's as they are found in the users AssignedLicenses.
Something like this:
$CSVfile = "C:\temp\LicenseToGroupUsers.csv"
# Import the CSV file
$users = Import-Csv -Path $CSVfile
Write-Warning "About to add the following users to license groups for complete SKU:"
$users.UserPrincipalName -join [environment]::NewLine
Write-Host
$answer = Read-Host -Prompt "Press Enter to continue or Q to quit"
if ($answer[0] -eq 'Q') { Clear-Host; exit }
foreach ($user in $users) {
Write-Host "Processing" $user.UserPrincipalName
$ImmutableID = $null # Null these out
$ADGroup = $null
# Get licensed SKUs for the user
$aaduser = Get-AzureADUser -objectID $user.UserPrincipalName
# Get the AD ObjectGuid for the group add (cannot use UPN)
# Have to match using the guid
$ImmutableID = $aaduser.ImmutableID
if (![string]::IsNullOrWhiteSpace($ImmutableID)) {
$objectGUID = ([GUID][System.Convert]::FromBase64String($ImmutableID)).Guid}
else {
Write-Warning "Error getting ImmutableID for $($user.UserPrincipalName), user is likely cloud only, skipping"
continue # skip this one and proceed with the next user
}
$licenses = #($aaduser.AssignedLicenses.SkuId) # force it to be an array
##########################################################################################
# Apparently, SkuId '0c266dff-15dd-4b49-8397-2bb16070ed52' is needed for all combinations,
# so we could already rule out users that do not have that ID in their $licenses..
# if that is indeed the case, you can simplify al other tests by not having to check
# for this ID every time..
# for now, this is an assumption, so commented out.
# if (!($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52')) {
# Write-Warning "Could not determine a group for user $($user.UserPrincipalName)"
# continue # skip this one and proceed with the next user
# }
##########################################################################################
# test E1: 'Microsoft 365 Audio Conferencing' and 'OFFICE 365 E1'
if ($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52' -and
$licenses -contains '18181a46-0d4e-45cd-891e-60aabd171b4e') {
# Add this user to group 'O365_E1_Users'
$ADGroup = 'O365_E1_Users'
}
# test E3: 'Microsoft 365 Audio Conferencing' and 'OFFICE 365 E3'
elseif ($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52' -and
$licenses -contains '6fd2c87f-b296-42f0-b197-1e91e994b900') {
if ($licenses -contains 'f30db892-07e9-47e9-837c-80727f46fd3d') { # also 'MICROSOFT FLOW FREE' ?
# Add this user to group 'FLOW_FREE_E3'
$ADGroup = 'FLOW_FREE_E3'
}
else {
# Add this user to group 'O365_E3_Users'
$ADGroup = 'O365_E3_Users'
}
}
# test 'Microsoft 365 Audio Conferencing' and 'MICROSOFT TEAMS EXPLORATORY'
elseif ($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52' -and
$licenses -contains '710779e8-3d4a-4c88-adb9-386c958d1fdf') {
# Add this user to group 'TEAMS_EXPLORATORY'
$ADGroup = 'TEAMS_EXPLORATORY'
}
# finished the conditions, now see if we can add the user to one of the groups
if (![string]::IsNullOrWhiteSpace($ADGroup)) {
try {
Write-Host "Adding $($user.UserPrincipalName) to $ADGroup" -ForegroundColor Green
# Add-ADGroupMember -Identity $ADGroup -Members $objectGUID
}
catch {
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
}
}
else {
Write-Warning "Could not determine a group for user $($user.UserPrincipalName)"
}
}

Related

Remove 'True' and replace with object in a ForLoop in Powershell

I have a small script that loops through a .csv file and applies a policy based on their location. It works fine except that when it runs its prints out "True" for every Line. How do you remove the word True and replace it with the username or something else or even nothing?
Connect-MicrosoftTeams
$userList = Import-Csv -Path "C:\Users\locationbasedpolicy1.csv"
Write-host "Logging to Microsoft Tenant to Execute Policies....." -ForegroundColor Cyan
Write-Host "There are $($userList.Count) Users in the List" -ForegroundColor Magenta
$TotalItems=$userList.Count
$CurrentItem = 1
# List Policies for Different Locations
$policyMappings = #{
USA = #{
VRP = 'VRP-USA-International';
CPP = 'CPP-USA-All-Users';
ECRP = 'ECRP-USA-All-Users';
ECP = 'ECP-USA-All-Users';
CHP = 'CHP-Global-MOH';
CIPD = 'CIDP-Global-User-Policy'
}
UK = #{
VRP = 'VRP-UK-National';
CPP = 'CPP-UK-All-Users';
ECRP = 'ECRP-UK-All-Users';
ECP = 'ECP-UK-All-Users';
CHP = 'CHP-Standard-MOH';
CIDP = 'CIDP-Block-Number'
}
}
# Loop Through the csv and identify Users Information
foreach ($Users in $userList){
Try {
$upn = $Users.UserPrincipalName
#$phone = $Users.TelephoneNumber
$Location = $Users.Location
# Search for Users Location
$policyMappings.ContainsKey($Location)
$policy = $policyMappings[$Location]
# Apply Policies to User based on their Location
Grant-CsOnlineVoiceRoutingPolicy -Identity $upn -PolicyName $policy.VRP
Grant-CSTeamsCallParkPolicy -Identity $upn -PolicyName $policy.CPP
Grant-CSTeamsEmergencyCallRoutingPolicy -Identity $upn -PolicyName $policy.ECRP
Grant-CsTeamsCallHoldPolicy -Identity $upn -PolicyName $policy.CHP
Grant-CSTeamsEmergencyCallingPolicy -Identity $upn -policyname $policy.ECP
Grant-CsCallingLineIdentity -Identity $upn -PolicyName $policy.CIDP
$PercentCompleted = [int](($CurrentItem / $TotalItems) * 100)
Write-progress -Activity "Processing User $CurrentItem of $TotalItems : $upn" -Status
"Total percent completed is: $PercentCompleted%:" -PercentComplete $PercentCompleted
$CurrentItem++
Start-Sleep -Milliseconds 3000
} Catch { Write-Host "Failed to assign policies to : $($upn)" -ForegroundColor Yellow }
}
Adding following changes and it worked.
$null = $($policyMappings.ContainsKey($Location))

How i get this powershell dynamic script working?

Hello everyone i need this script to work and i'm stuck with a error.
I need to have a dynamic script with user choice and linking the mailbox we enter in first step to the HR choice.
In the csv part we have a group distribution list
Error says that i can not do the add-distributiongroupmember and i don't know why
can someone help me on this one ?
(I just do the 0 part choice because i need this one to work before doing the other choice)
code below
Connect-ExchangeOnline
$User = Read-Host "Enter Name of the mailbox to add"
Try {
$Mbx = Get-Mailbox -Identity $User -ErrorAction Stop | Select -ExpandProperty PrimarySmtpAddress}
Catch {
Write-Host "No mailbox can be found called" $User; break }
$Services = [System.Management.Automation.Host.ChoiceDescription]::new('&Services')
$Services.HelpMessage = 'Get running services'
$HR = New-Object System.Management.Automation.Host.ChoiceDescription '&HR', 'Get running HRDL'
$Legal = New-Object System.Management.Automation.Host.ChoiceDescription '&Legal', 'Get running LegalDL'
$Quit = New-Object System.Management.Automation.Host.ChoiceDescription '&Quit', 'Quit menu'
$options = [System.Management.Automation.Host.ChoiceDescription[]]($HR, $Legal, $Quit)
$Result = $host.UI.PromptForChoice('Task menu', 'Select a Department', $options , 0 )
$DLs = Import-Csv -Path "C:\Users\GregorySemedo\Desktop\Script\DL\DL-HR.csv"
switch($Result)
{
0 { ForEach ($DL in $DLs) {
Try {
Add-DistributionGroupMember -Identity $DL."HR" -Member $Mbx -ErrorAction Continue }
Catch {
Write-Host "Couldn't add" $Mbx "to DL" (Get-DistributionGroup -Identity $DL."HR").DisplayName }
If($?)
{
Write-Host $User Succesfully added -ForegroundColor Green
}
Else
{
Write-Host $User - Error occurred -ForegroundColor Red
}}
}
}

Powershell Error: Exception Calling "Approve" with "2" argument(s): Value cannot be null

I'm writing a powershell script to automate WSUS. One of the functions approves non-superseded updates to a sandbox testing computer group in order to download/install them on the console. However, all updates it finds return this same error. Here is the code for my definitions and the approval function:
[String]$updateServer1 = hostname
[Boolean]$useSecureConnection = $False
[Int32]$portNumber = 8530
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($updateServer1,$useSecureConnection,$portNumber)
$updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$u = $updateServer.GetUpdates($updatescope)
$install = [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install
$group = $updateServer.GetComputerTargetGroups | where-object {$_.Name -eq "Update Testing"}
function Approve-Nonsuperseded {
Write-host "Creating new Computer Group to approve updates for installation..." -foregroundcolor green
try {
$updateserver.CreateComputerTargetGroup("Update Testing")
}
catch {
Write-host "Update Group already exists. Moving on..." -ForegroundColor Green
}
$count = 0
Write-host "Approving new updates for installation..." -foregroundcolor green
foreach ($u2 in $u )
{
if ($u2.IsDeclined -ne 'True' -and $u2.IsSuperseded -ne 'True' -and $u2.CreationDate -ge $PatchDay)
{
write-host Approving Update : $u2.Title
$u2.Approve($install,$group)
$count = $count + 1
}
}
write-host Total Approved Updates: $count
}
It returns all the correct updates that are meant to be approved, but always gives me that same error on the $u2.Approve($install,$group) line. I'd appreciate any insight. Thanks!
$u2 should be a string and not an variable. Try using $u2.Approve("Install",$group)
The [Microsoft.UpdateServices.Administration.UpdateApprovalAction] namespace only provides the options ;)

Delete local administrator account with delete() method ADSI with Powershell

I am writing a powershell script to manage our local administrator accounts using a csv file.
#variable to store the data in data.csv
$userobjects = Import-CSV C:-data.csv
function main-list{
Write-Host "--------------------------------------"
Write-Host "Windows Powershell Account Manager"
Write-Host "--------------------------------------"
Write-Host "1 - Change Name"
Write-Host "2 - Disabled Account"
Write-Host "3 - Delete User"
Write-Host "4 - Exit"
[int]$action = Read-Host "Enter the menu number from above"
if ($action -eq 1){change-name}
if ($action -eq 2){disable-account}
if ($action -eq 3){delete-user}
if ($action -eq 4){cls; break}
}
function change-name
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
# Rename
if (($user.Account -ne $user.Rename) -and ($user.Rename -ne '' ))
{
#Write-Host "old name :"$FileHostname"/"$FileAccount "-> new name :"$FileHostname"/"$FileNewname
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://$connection")
if ($accName.path -eq "WinNT://"+$connection+"")
{
$accName.psbase.Rename($FileNewname)
Write-Host "Account(s) renamed"
$user.Account = $user.Rename
}
else
{
Write-Host "Account name :"$connection "can't be found on the host"
}
$user.Account = $user.Rename
$userobjects | export-csv C:-data.csv -notype
}
}
Write-Host "--------------------------------------"
main-list
}
function disable-account
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
if ($user.Disable -eq 'yes')
{
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://"+$connection+"")
if ($accName.UserFlags -eq '515')
{
Write-Host "Account :"$connection "is already disabled"
}
else
{
$accName.description = "Account disabled"
$accName.UserFlags = 2
$accName.setinfo()
Write-Host "Account(s) disabled"$connection
}
}
}
Write-Host "--------------------------------------"
main-list
}
function delete-user
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
#Delete
if ($user.Delete -eq 'yes')
{
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://"+$connection+"")
$accName.delete("user",$accName.name)
#Write-Host $connection deleted
}
else
{
Write-Host "Account name :"$connection "can't be found on the host"
}
}
}
}
$userobjects | export-csv C:-\data.csv -notype
main-list
I don't really know why I have this message when I am trying to use the delete function : "Unknown name", it is like it doesn't find the local account to delete it but I am not sure. However, It works perfectly when I want to rename or disable accounts.
My data file looks like that
http://www.noelshack.com/2016-05-1454622367-capture.png
I will post the real message when I will be back to work tomorow.
Thank you for your help.
Quick skim... wouldn't this need to be used instead? I think your $accName.name would be using the machine name.
$accName.delete("user",$user.account)
You delete() the user from the computer, so your [adsi] object should bind to the computer and call Delete() on that instead:
# Just the machine name, nothing more:
$Machine = [ADSI]"WinNT://$FileHostname"
# Now delete the user account from the machine
$Machine.Delete('user',$FileAccount)

Powershell - Generating username for Active Directory

I'm trying to create a script that creates a unique user I Active Directory.
Before the script can create a user it needs to make sure the username is available by asking two different domains if the generated username exists. The problem is I don't how generate a new username or rerun part of the script if necessary. Lets say that if the generated username exists in one of the domains I wan't to generate a new username and try again with the new one. This is what I have so far.
Import-Module ActiveDirectory
$firstname = "Test"
$lastname = "Tester"
$SecondaryDomain = "server1.domain1.net"
$PrimaryDomain = "server2.domain2.net"
$ErrorActionPreference = "SilentlyContinue"
$Generate = [Char[]]"$firstname$lastname"
$Generatedusername = ($Generate | Get-random -Count 3) -join ""
Write-host $Generatedusername
if (Get-ADUser -Filter {SamAccountName -eq $Generatedusername} -Server $PrimaryDomain)
{
#If the variable equals 1 the user exists
$PrimaryDomainOK = "1"
}
else
{
$PrimaryDomainOK = "0"
}
if (Get-ADUser -Filter {SamAccountName -eq $Generatedusername} -Server $SecondaryDomain)
{
#If the variable equals 1 the user exists
$SecondaryDomainOK = "1"
}
else
{
$SecondaryDomainOK = "0"
}
Write-host "Primary Domain $PrimaryDomainOK"
Write-host "Secondary Domain $SecondaryDomainOK"
If ($PrimaryDomainOK -and $SecondaryDomainOK -eq 0)
{
Write-host "Creating Account"
}
Else
{
Write-host "Can't create account"
}
Add a while statement embracing your generation/verification which checks for the status of $PrimaryDomainOK and $SecondaryDomainOK.
...
$Generate = [Char[]]"$firstname$lastname"
while(($PrimaryDomainOK -ne 0) -and ($SecondaryDomainOK -ne 0)) {
$Generatedusername = ($Generate | Get-random -Count 3) -join ""
Write-host $Generatedusername
...
...
...
If ($PrimaryDomainOK -and $SecondaryDomainOK -eq 0)
{
Write-host "Creating Account"
}
Else
{
Write-host "Can't create account"
}
}
Remember the closing brace.