Can't add device to Azure Active Directory because it has two Object IDs - azure

When I try to add the device looping through a txt file, it says its already a member. When I check the members in the group, nothing changes. From what I've researched, this is due to hybrid setup with on-prem and Azure AD, but I would like to add the devices to the Azure group.
$azgroup = "myGroup"
$machines = get-content ".\deviceList.txt"
write-host "Getting Object ID of group.." -ForegroundColor Green
$objid = (get-azureadgroup -Filter "DisplayName eq '$azgroup'" ).objectid
write-host "Getting group members (We dont want duplicates!).." -ForegroundColor Cyan
$members = Get-AzureADGroupMember -ObjectId $objid -all $true | select displayname
foreach ($machine in $machines) {
$refid = Get-AzureADDevice -Filter "DisplayName eq '$machine'"
$result = ""
$result = ($members -match $machine)
if($result -eq ""){
try{
Write-host "Adding " $refid.displayname -ForegroundColor Cyan
Add-AzureADGroupMember -ObjectId $objid -RefObjectId $refid.objectid[0]
}
catch{
write-host "An error occured for " $refid.displayname -ForegroundColor Red
}
}
else
{
write-host $machine " is already a member" -ForegroundColor Green
}
}
I tried treating the specific ObjectID as an array but neither worked to add to Azure AD group
Add-AzureADGroupMember -ObjectId $objid -RefObjectId $refid.objectid[0]
If the AzureAD module doesn't work within a hybrid infrastructure, is there any way to bulk add devices to a group in Azure AD?

Here is the working solution. Ok so due to each device having more than one reference IDs, I just treated like an array. This is the part of my code I had to change:
[String]$refid = (Get-AzureADDevice -Filter "DisplayName eq '$machine'")[0].ObjectId
I misplaced the my index ([0]) and placed it after the property, not before it. Then I made sure it outputed a string for good measure, although you can check this with the .gettype() method. Because the on-premise DC and Azure sync, you can use these Device reference IDs interchangeably. It also didnt help outputting a custom error at first, thats what I get for copy-pasting part of someone else's code...

Related

PowerShell to remove all AD attributes when matching the specific string?

I wanted to remove smtp:*#olddomain.com in all of my users, but somehow the cmdlet does not take the wild card to loop through the attributes.
Script:
$DefaultDomain = 'NewCompany.onmicrosoft.com'
$OldDomain = 'olddomain.com'
$DistributionGroups = Import-Csv -LiteralPath C:\Source-DL.csv
$DistributionGroups | ForEach-Object {
Write-Host "Set DL: $($_.DisplayName) into [$($_.Alias+"#"+$DefaultDomain)]" -ForegroundColor Yellow
Set-DistributionGroup -Identity $_.Alias -WindowsEmailAddress $($_.Alias+"#"+$DefaultDomain) -Emailaddresses #{remove="$($_.Alias)#$OldDomain"}
}
The environment is not on-premise AD hence I can only access the Azure AD or Exchange Online cmdlet.

How can I pass a specific item property to a variable in PowerShell?

I'm currently working on a script to manage Azure AD (as opposed to the console GUI) and am having issues at one particular part. I'm trying to do an 'add user to group' module, but with Add-AzureADGroupMember requiring the group ObjectId and not display name, it's not initially user-friendly.
Here's what I tried initially:
>> $UPN = "someuser#domain.com"
>> $Selected = "Group Display Name"
>> $Group = Get-AzureADGroup -Filter "DisplayName eq '$Selected'" -All $true | Select-Object -Property ObjectID
>> Add-AzureADGroupMember -ObjectID $Group -RefObjectID $UPN
The problem I have with this, is that $Group is returning '#{ObjectId=fba435cc-913c-46a0-9932-17c01733e143}' as opposed to '{fba435cc-913c-46a0-9932-17c01733e143}'
Is there a better way I can pass the group's ObjectID to a variable? I'd like for users to be able to select the display name and have the variable return the objectID.
To get just the value of a property, use ForEach-Object -MemberName instead of Select-Object -Property:
$Group = Get-AzureADGroup -Filter "DisplayName eq '$Selected'" -All $true | ForEach-Object -MemberName ObjectID

Azure Powershell Question for Virtual Machine

I am reviewing a script that is supposed to delete a vm along with all of the resources attributed to the vm
Write-Host -NoNewline -ForegroundColor Green "Please enter the VM name you would like to remove:"
$VMName = Read-Host
$vm = Get-AzVm -Name $VMName
if ($vm) {
$RGName=$vm.ResourceGroupName
Write-Host -ForegroundColor Cyan 'Resource Group Name is identified as-' $RGName
#boot diagnostics container auto generated in storage account. Auto delete this storageURI property
$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\.').groups[1].value
Write-Host -ForegroundColor Cyan 'Marking Disks for deletion...'
$tags = #{"VMName"=$VMName; "Delete Ready"="Yes"}
$osDiskName = $vm.StorageProfile.OSDisk.Name
$datadisks = $vm.StorageProfile.DataDisks
$ResourceID = (Get-Azdisk -Name $osDiskName).id
New-AzTag -ResourceId $ResourceID -Tag $tags | Out-Null
if ($vm.StorageProfile.DataDisks.Count -gt 0) {
foreach ($datadisks in $vm.StorageProfile.DataDisks){
$datadiskname=$datadisks.name
$ResourceID = (Get-Azdisk -Name $datadiskname).id
New-AzTag -ResourceId $ResourceID -Tag $tags | Out-Null
}
}
if ($vm.Name.Length -gt 9){
$i = 9
}
else
{
$i = $vm.Name.Length - 1
}
$azResourceParams = #{
'ResourceName' = $VMName
'ResourceType' = 'Microsoft.Compute/virtualMachines'
'ResourceGroupName' = $RGName
}
$vmResource = Get-AzResource #azResourceParams
$vmId = $vmResource.Properties.VmId
$diagContainerName = ('bootdiagnostics-{0}-{1}' -f $vm.Name.ToLower().Substring(0, $i), $vmId)
$diagSaRg = (Get-AzStorageAccount | where { $_.StorageAccountName -eq $diagSa }).ResourceGroupName
$saParams = #{
'ResourceGroupName' = $diagSaRg
'Name' = $diagSa
}
Write-Host -ForegroundColor Cyan 'Removing Boot Diagnostic disk..'
if ($diagSa){
Get-AzStorageAccount #saParams | Get-AzStorageContainer | where {$_.Name-eq $diagContainerName} | Remove-AzStorageContainer -Force
}
else {
Write-Host -ForegroundColor Green "No Boot Diagnostics Disk found attached to the VM!"
}
Write-Host -ForegroundColor Cyan 'Removing Virtual Machine-' $VMName 'in Resource Group-'$RGName '...'
$null = $vm | Remove-AzVM -Force
Write-Host -ForegroundColor Cyan 'Removing Network Interface Cards, Public IP Address(s) used by the VM...'
foreach($nicUri in $vm.NetworkProfile.NetworkInterfaces.Id) {
$nic = Get-AzNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $nicUri.Split('/')[-1]
Remove-AzNetworkInterface -Name $nic.Name -ResourceGroupName $vm.ResourceGroupName -Force
foreach($ipConfig in $nic.IpConfigurations) {
if($ipConfig.PublicIpAddress -ne $null){
Remove-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name $ipConfig.PublicIpAddress.Id.Split('/')[-1] -Force
}
}
}
Write-Host -ForegroundColor Cyan 'Removing OS disk and Data Disk(s) used by the VM..'
Get-AzResource -tag $tags | where{$_.resourcegroupname -eq $RGName}| Remove-AzResource -force | Out-Null
Write-Host -ForegroundColor Green 'Azure Virtual Machine-' $VMName 'and all the resources associated with the VM were removed sucessfully...'
}
else{
Write-Host -ForegroundColor Red "The VM name entered doesn't exist in your connected Azure Tenant! Kindly check the name entered and restart the script with correct VM name..."
}
I had a question: what does this block of code exactly do:
$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\.').groups[1].value
I know it matches the storage uri, but how? And why is this needed? I am not sure what the .groups[1].value is referring to either
$diagSa =
[regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri,
'^http[s]?://(.+?).').groups[1].value
I know it matches the storage uri, but how?
You are using the [regex] type accelerator & match method () in the above expression.
The Match() method is a way to instruct PowerShell to attempt to match a string inside of another string. The Match() method has two parameters; the string you'd like to match on and the regular expression you'd like to test against.
Whenever a match is found and a regex group is used; (), the [regex] type accelerator has a Captures property. This Captures property then has a property called Groups. This is a collection that contains lots of attributes of what was matched. The second element in that collection contains the actual value that was matched.
what the .groups[1].value is referring to either
groups[1].values returns the storage account name where the boot diagnostics container resides.
And why is this needed?
When creating an Azure VM, you always have the option of creating a boot diagnostics container. This is useful to troubleshooting VM boot issues but doesn’t get removed when a VM is deleted. Let’s remedy that.
To remove the boot diagnostics container, you first need to figure out the name of the storage account the container resides on. To find that storage account, you’ll have to do some parsing of the storageUri property that’s exists in the DiagnosticsProfile object on the VM.
for more information about [regex]::match().group[1].value expression refer the below blog :
https://mcpmag.com/articles/2015/09/30/regex-groups-with-powershell.aspx

Adding tags to azure VMs via CSV

trying to add tags to VMs via CSV data, right now I have the below code:
if ($context.Account -eq $null) {
# Login-AzureAccount
Connect-AzAccount
}
# Select Azure Subscription
$subscriptionId = (Get-AzSubscription | Out-GridView -Title "Select an Azure Subscription ..." -PassThru).SubscriptionId
#Select specified subscription ID
Select-AzSubscription -SubscriptionId $subscriptionId
$InputCSVFilePath = "test.csv"
$csvItems = Import-Csv $InputCSVFilePath
################
foreach ($item in $csvItems){
Clear-Variable r
#$r = Get-AzResource -ResourceGroupName $item.ResourceGroup -Name $item.VM -ErrorAction Continue
$r = Get-AzResource -Name $item.VM
################
if ($r -ne $null){
if ($r.Tags){
# Tag - Client DL
if ($r.Tags.ContainsKey("Client_DL")){
$r.Tags["Client_DL"] = $item.ClientDL
}else{
$r.Tags.Add("Client_DL", $item.ClientDL)
}
# Tag - Priority
if ($r.Tags.ContainsKey("Priority")){
$r.Tags["Priority"] = $item.Priority
}else{
$r.Tags.Add("Priority", $item.Priority)
}
}
}else{
Write-Host "No VM found named $($item.VMName)!"
}
}
I verified that my code does indeed go through the functions but for some reason the tags are not being set on my VM's. I ran the commands manually in powershell and I was able to set a tag by doing:
$r = Get-AzResource -Name TestVM
$r.Tags.Add("Client_DL", "TEST-DL")
Am I missing something? i'm running a Set-PSDebug -Trace 2 when running my code and it seems to check out just fine, but the tags aren't getting set/written.
So you're adding the tags in memory but you're not calling any of the Az cmdlets to set the tags back on the resource.
You can see in the example in the docs here they return the VM with Get-AzResource, append their new tag to the existing tags and then use Set-AzResource to write the newly added tag back.
Just be careful of that
When updating tags through PowerShell, tags are updated as a whole. If you are adding one tag to a resource that already has tags, you will need to include all the tags that you want to be placed on the resource
Alternatively you could use Update-AzTag which has an -Operation parameter and lets you choose whether you want to merge, replace or delete the existing tags.
https://learn.microsoft.com/en-us/powershell/module/az.resources/update-aztag?view=azps-6.0.0
Ultimately you'd need to set back your $r.Tags value to your resource as the last operation within your if statement.

Change List Field with Powershell in SharePoint Online

I'm attempting to change the field contents for multiple entries in a list. So far I've gotten to the point that I can edit the list, add columns really, but can't find anything on how to edit the field text. Here is what I have currently:
EDIT:
I've found a bunch of info for 2010 which isn't applicable but I've updated the code to almost get there. I'm getting 'null array' errors when I connect to the list now. I'm hopeful because I'm able to connect, but still can't get the field to change. I've updated my if statement as well to what is I believe a better format.
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user#email.com"
$Pass = "password"
$creds = New-Object System.Management.Automation.PSCredential($User, (ConvertTo-SecureString $Pass -AsPlainText -Force));
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
Connect-SPOService -Url https://site-admin.sharepoint.com -Credential $creds
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$WebUrl = 'https://site.sharepoint.com/'
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$List = $Context.Web.Lists.GetByTitle("VacationRequestForm")
#Edit existing list items
$items = $List.items
foreach($item in $items)
{
if($item["Export Flag"] -eq "New")
{
Write-Host "Changing export flags to Complete." -ForegroundColor Green
$item["Export Flag"] = "Complete"
$item.Update()
}
}
Write-Host "Your changes have now been made." -ForegroundColor Green
I am guessing you have trimmed the script since you are missing things like defining $context and such. You don't have any ExecuteQuery() calls.
MSDN doc on SP 2013 CSOM List Item tasks, which has C# examples of what you need and can be translated to PowerShell.
It generally looks like you have everything but if you could include your whole script I can try and run your script directly.
EDIT: with the updates here is the code that you need
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user#email.com"
$Pass = "password"
$WebUrl = "https://site.sharepoint.com/"
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, (ConvertTo-SecureString $Pass -AsPlainText -Force))
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$List = $Context.Web.Lists.GetByTitle("VacationRequestForm")
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100);
$Items = $List.GetItems($Query);
$Context.Load($Items);
$Context.ExecuteQuery();
#Edit existing list items
foreach($item in $Items)
{
if($item["Export_x0020_Flag"] -eq "New")
{
Write-Host "Changing export flags to Complete for Id=$($item.Id)." -ForegroundColor Green
$item["Export_x0020_Flag"] = "Complete"
$item.Update()
$Context.ExecuteQuery();
}
}
Write-Host "Your changes have now been made." -ForegroundColor Green
You had a space in your Export Flag name and SharePoint will not have that in the name of the field. By default it will replace that with a _x0020_ string. This value will be based on the first name of the field. So if you change this field name in the future, you will still refer to it as 'Export_x0020_Flag' in this script. I am doing the .ExecuteQuery() for each update but you could do this once at the end of the loop. There is also the limit of 100 records in the query. If you only want records with "New" you should change the CamlQuery to just pull those records back.

Resources