Bulk Azure AD Update - powershell

I have written a script to update the users' contact information in Azure AD. The CSV I'm using is an export from our local AD. I found some examples as a starting place and this is what I have hacked out ...
Start-Transcript "transcript.log"
# Connect to AzureAD
Connect-AzureAD
# Get CSV content
$CSVrecords = Import-Csv userexport.csv -Delimiter ","
# Create arrays for skipped and failed users
$SkippedUsers = #()
$FailedUsers = #()
# Loop trough CSV records
foreach ($CSVrecord in $CSVrecords) {
$upn = $CSVrecord.samaccountname + "#daytonrogers.com"
$user = Get-AzureADUser -Filter "userPrincipalName eq '$upn'"
if ($user) {
$command = "Set-AzureADUser -ObjectID $($user.objectid) "
if ($CSVrecord.title) {$command = "$command -jobtitle '$($CSVrecord.title)'"}
if ($CSVrecord.department) {$command = "$command -department '$($CSVrecord.department)'"}
if ($CSVrecord.office) {$command = "$command -PhysicalDeliveryOfficeName '$($CSVrecord.office)'"}
if ($CSVrecord.officephone) {$command = "$command -TelephoneNumber '$($CSVrecord.officephone)'"}
if ($CSVrecord.fax) {$command = "$command -FacsimileTelephoneNumber '$($CSVrecord.fax)'"}
if ($CSVrecord.mobilephone) {$command = "$command -Mobile '$($CSVrecord.mobilephone)'"}
if ($CSVrecord.streetaddress) {$command = "$command -streetaddress '$($CSVrecord.streetaddress)'"}
if ($CSVrecord.city) {$command = "$command -city '$($CSVrecord.city)'"}
if ($CSVrecord.state) {$command = "$command -state '$($CSVrecord.state)'"}
if ($CSVrecord.postalcode) {$command = "$command -postalcode '$($CSVrecord.postalcode)'"}
Write-Information $command
try{
$command
} catch {
$FailedUsers += $upn
Write-Warning "$upn user found, but FAILED to update."
}
}
else {
Write-Warning "$upn not found, skipped"
$SkippedUsers += $upn
}
}
Stop-Transcript
It runs and builds the command just fine. However, none of the users get updated. If I copy / past the command from the transcript.log file, it works. It just does not work if I run the script from the PowerShell command line.
What am I missing here?

Creating command strings and then executing them is going to lead to bad practices I think. You will have to resort to Invoke-Expression. That is something we want to avoid. I would build a hash table with your parameters and use splatting. From that, you can build your command string to send to the information stream. See below for an example.
if ($user) {
$command = "Set-AzureADUser"
$params = #{}
$params.ObjectID = $user.objectid
if ($CSVrecord.title) {$params.jobtitle = $CSVrecord.title}
if ($CSVrecord.department) {$params.department = $CSVrecord.department}
if ($CSVrecord.office) {$params.PhysicalDeliveryOfficeName = $CSVrecord.office}
if ($CSVrecord.officephone) {$params.TelephoneNumber = $CSVrecord.officephone}
if ($CSVrecord.fax) {$params.FacsimileTelephoneNumber = $CSVrecord.fax}
if ($CSVrecord.mobilephone) {$params.Mobile = $CSVrecord.mobilephone}
if ($CSVrecord.streetaddress) {$params.streetaddress = $CSVrecord.streetaddress}
if ($CSVrecord.city) {$params.city = $CSVrecord.city}
if ($CSVrecord.state) {$params.state = $CSVrecord.state}
if ($CSVrecord.postalcode) {$params.postalcode = $CSVrecord.postalcode}
Write-Information "$command $($params.GetEnumerator() |% {"-{0} '{1}'" -f $_.Key,$_.Value})"
& $command #params
}

Related

Send confirmation message if command ran with Invoke-Expression completes successfully

I'm writing a PowerShell script to add / remove people from a distribution group. I want to send a message if the action was successful and another if it failed. This is part of the script:
foreach ($x in Get-Content $pathfile\inputfile.txt) {
$USER = $x.Split(',')[0]
$ACTION = $x.Split(',')[1]
$COMMAND = (Write-Output "$ACTION-DistributionGroupMember -Identity 'Group Name' -Member $USER")
if ($ACTION -ieq "remove") {
$COMMAND = $COMMAND + ' -Confirm:$false'
Invoke-Expression $COMMAND
}
else {
Invoke-Expression $COMMAND
}
}
inputfile.txt, for the sake of information is:
jdoe#example.com,Add
jsmith#example.com,Remove
I've tried using $? and $lasExitCode but neither of those worked as expected as they only consider the output of "Invoke-Expression" and that is always successful.
What I am expecting is:
foreach ($x in Get-Content $pathfile\inputfile.txt) {
$USER = $x.Split(',')[0]
$ACTION = $x.Split(',')[1]
$COMMAND = (Write-Output "$ACTION-DistributionGroupMember -Identity 'Group Name' -Member $USER")
if ($ACTION -ieq "remove") {
$COMMAND = $COMMAND + ' -Confirm:$false'
Invoke-Expression $COMMAND
#if $COMMAND successful: Write-Output "$ACTION on $USER succeeded."
#if $COMMAND unsuccessful: Write-Output "$ACTION on $USER failed."
}
else {
Invoke-Expression $COMMAND
#if $COMMAND successful: Write-Output "$ACTION on $USER succeeded."
#if $COMMAND unsuccessful: Write-Output "$ACTION on $USER failed."
}
}
$? won't work because even if the command fails, Invoke-Expression was invoked successfully.
Use the & call operator to invoke the call directly instead, and $? will work. For the conditional parameter argument, use splatting!
foreach ($x in Get-Content $pathfile\inputfile.txt) {
$user,$action,$null = $x.Split(',')
# construct command name
$command = "$ACTION-DistributionGroupMember"
# organize the parameter arguments in a hashtable for splatting later
$paramArgs = #{
Identity = 'Group Name'
Member = $USER
}
# conditionally add the `-Confirm` parameter
if ($ACTION -ieq "remove") {
$paramArgs['Confirm'] = $false
}
# invoke the command with the call operator
& $command #paramArgs
if($?){
# command invocation suceeded
}
else {
# command invocation failed
}
}

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 to remove Disabled account in Windows PowerShell Script

I have PowerShell script which access the AD users and insert into the SharePoint list.
Now the problem is some of the accounts are disabled or not active. I am using the following PowerShell script in the windows task scheduler which do the job in an interval. Can anyone Help me to figure out What I suppose to do in this script to filter only active accounts?
#if not already added
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
$site = new-object Microsoft.SharePoint.SPSite("https://portal.company.gov.sa/");
$ServiceContext = [Microsoft.SharePoint.SPServiceContext]::GetContext($site);
#Get UserProfileManager from the My Site Host Site context
$ProfileManager = new-object Microsoft.Office.Server.UserProfiles.UserProfileManager($ServiceContext)
$AllProfiles = $ProfileManager.GetEnumerator()
# Open SharePoint List
$spWeb = Get-SPWeb "https://my.gac.gov.sa/"
$spData = $spWeb.GetList("Lists/EmployeesDirectory/")
$spDepartments = $spWeb.GetList("Lists/Departments/")
$total=0;
$withErros=0;
foreach($profile in $AllProfiles)
{
try
{
$DisplayName = $profile.DisplayName
$WorkEmail = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::WorkEmail]
$AccountName = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::AccountName]
$Department = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::Department]
$Position = $profile.JobTitle
$LastName = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::LastName]
$FirstName = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::FirstName]
$FullName= "$FirstName $LastName"
$PreferredName = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::PreferredName]
$WorkPhone =$profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::WorkPhone]
$Manager = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::Manager]
$JobTitleArabic=$profile["JobTitleArabic"];
if($Department -ine '' -and $Manager -ine ''){
$total++;
$departmnetItem = $spDepartments.Items | Where {$_["FF_TitleEn"] -eq $Department}
# Add properties to this list item
$user=$spWeb.EnsureUser($AccountName);
write-host $DisplayName "|" $AccountName "|" $Department "|" $Position "|" $PreferredName "|" $WorkPhone "|" $Manager ;
if($user.ID -gt 0)
{
#Query to filter List Items which contains user account
$SPQuery = new-object Microsoft.SharePoint.SPQuery
$Query = "<Where><Eq><FieldRef Name='FF_Emlpoyee' LookupId='TRUE'/><Value Type='User'>$($user.ID)</Value></Eq></Where>"
$SPQuery.Query=$Query
#Filter List Items by Query
$ListItems = $spData.GetItems($SPQuery)
if($ListItems.Count -gt 0)
{
$newItem=$ListItems[0];
}
else
{
#Create a new item
$newItem = $spData.Items.Add()
}
$newItem["FF_Emlpoyee"] = $user.ID;
# $newItem["FF_UserID"] = $user.ID;
$newItem["Title"] = $PreferredName
if($WorkPhone -ine '')
{
$newItem["FF_ExtensionNumber"] = $WorkPhone
}
try
{
if($Manager -ine $null)
{
$userManager=$spWeb.EnsureUser($Manager);
$newItem["FF_Manager"] = $userManager.ID
}
}
catch
{
write-host -ForegroundColor Red "Manager Not Found fro : " $user
}
$newItem["FF_Position"] = $Position
IF($JobTitleArabic -ine '')
{
$newItem["FF_PositionAr"] = $JobTitleArabic
}
$newItem["FF_FullNameAr"] = $FullName
$newItem["FF_Department"] = $departmnetItem.ID
$newItem.Update()
Write-Host "---------------------------------";
}
$user=$null
}
}
catch
{
write-host -ForegroundColor Red $_.Exception
$withErros+=1
}
}
Write-Host "Total: " $total;
Write-Host "withErros: " $withErros

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
}}
}
}

I want to display a popup message of date contains in text file

I am having a script file to compare the my system login username and samaccountname. If the system login username and samaccountname is matched then my output is display popup message of my system login username. But the below script is working fine if the data is in excel file format. Due to some of user not having the ms office. Those used are doing browser based work. So i need to read the text file if the samaccountname matches contains in text file i want display the samaccountname and date.
Sample text file screenshot
$FilePath = 'd:\Alluserreport.xlsx'
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $false
$wb = $xl.Workbooks.Open($filepath)
# get data from columns 2 and 3
$sheet = $wb.Worksheets['Alluserreport']
$rowMax = $sheet.UsedRange.Rows.Count
$data = for ($row = 2; $row -le $rowMax; $row++) {
[PsCustomObject] #{
SamAccountName = $sheet.Cells.Item($row, 2).Value2
LastLogonDate = [datetime]::FromOADate($sheet.Cells.Item($row, 3).Value2) # convert to DateTime object
}
}
# cleanup
$wb.close()
$xl.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# filter for a specific username in the data
$user = $data | Where-Object { $_.SamAccountName -eq $env:USERNAME }
if ($user) {
$msgBody = "User: {0}`r`nLastLogon: {1}" -f $user.SamAccountName, $user.LastLogonDate
$msgTitle = "Test"
$msgButton = 'OK'
$msgImage = 'Asterisk'
$Result = [System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)
}
else {
Write-Host "Not found"
}
Thanks for accepting the previous question.
Working with CSV files is even a lot easier than getting data from Excel.
Using your example:
# import the data from the file
$data = Import-Csv -Path 'd:\Alluserreport.csv'
# filter for a specific username in the data
$user = $data | Where-Object { $_.SamAccountName -eq $env:USERNAME }
if ($user) {
$msgBody = "User: {0}`r`nLastLogon: {1}" -f $user.SamAccountName, $user.'Expiration Date'
$msgTitle = "Test"
$msgButton = 'OK'
$msgImage = 'Asterisk'
$Result = [System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)
}
else {
Write-Host "Not found"
}