blog.icewolf.ch

Let's talk about IT!
posts - 2204, comments - 295, trackbacks - 0

My Links

Archives

Post Categories

icewolf

Friday, December 2, 2022

Create Azure AD App Registration with Microsoft.Graph PowerShell

Hi All,

In this Blog Post i explain you how to create an Azure AD App Registration with the Microsoft.Graph PowerShell.
You need to have the Azure Active Directory Role "Application Administrator" or "Application Developer".


By the way. All the Code is used here is also on my GitHub Repo

#Import Module
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Applications

###############################################################################
#Connect-MgGraph
#Connect to your Azure Active Directory with "Application Adminstrator" or "Global Administrator" Role
###############################################################################
Connect-MgGraph -Scopes "Application.Read.All","Application.ReadWrite.All","User.Read.All"
Get-MgContext



That's the User Approval when you sign in to Microsoft Graph with these Scopes


###############################################################################
#Create AAD Application
###############################################################################
$AppName =  "DemoApp"
$App = New-MgApplication -DisplayName $AppName
$APPObjectID = $App.Id

###############################################################################
#List Applications
###############################################################################
Get-MgApplication -ApplicationId $APPObjectID



List all the Details of an Application

Get-MgApplication | Where-Object {$_.DisplayName -eq "DemoApp"} | Format-List


There you have it - the Application has been created


###############################################################################
#Add additional Owner
#The User who created the Application is automatically the Owner
###############################################################################
$User = Get-MgUser -UserId "m.muster@icewolf.ch"
$ObjectId = $User.ID
$NewOwner = @{
    "@odata.id"= "https://graph.microsoft.com/v1.0/directoryObjects/{$ObjectId}"
    }
New-MgApplicationOwnerByRef -ApplicationId $APPObjectID -BodyParameter $NewOwner



The Owner has been addet to the Application


###############################################################################
#Add a ClientSecret
###############################################################################
$passwordCred = @{
    "displayName" = "DemoClientSecret"
    "endDateTime" = (Get-Date).AddMonths(+12)
}
$ClientSecret2 = Add-MgApplicationPassword -ApplicationId $APPObjectID -PasswordCredential $passwordCred
$ClientSecret2
$ClientSecret2.SecretText

#Show ClientSecrets
$App = Get-MgApplication -ApplicationId $APPObjectID
$App.PasswordCredentials



You have to patient in the Portal. It takes a Minute or so and needs a refresh of the whole Page to see the Client Secret.



###############################################################################
#Create a Self Signed Certificate
###############################################################################
#Create SelfSignedCertificate
$Subject = "DemoCert"
$NotAfter = (Get-Date).AddMonths(+24)
$Cert = New-SelfSignedCertificate -Subject $Subject -CertStoreLocation "Cert:\CurrentUser\My" -KeySpec Signature -NotAfter $Notafter -KeyExportPolicy Exportable
$ThumbPrint = $Cert.ThumbPrint

#View Certificates in the Current User Certificate Store
Get-ChildItem -Path cert:\CurrentUser\my\$ThumbPrint | Format-Table

#Export Certificate as Base64 (PEM Format)
$CurrentLocation = (Get-Location).path
$Base64 = [convert]::tobase64string((get-item cert:\currentuser\my\$ThumbPrint).RawData)
$Base64Block = $Base64 |
ForEach-Object {
    $line = $_

    for ($i = 0; $i -lt $Base64.Length; $i += 64)
    {
        $length = [Math]::Min(64, $line.Length - $i)
        $line.SubString($i, $length)
    }
}
$base64Block2 = $Base64Block | Out-String

$Value = "-----BEGIN CERTIFICATE-----`r`n"
$Value += "$Base64Block2"
$Value += "-----END CERTIFICATE-----"
$Value
Set-Content -Path "$CurrentLocation\$Subject-BASE64.cer" -Value $Value



You can see the Certification in the Certificate Store of the Current User (certmgr.msc)


There are diffrent way of loading the Certificate in the $Cert Variable

###############################################################################
#Add Certificate to AzureAD App
###############################################################################
#Loading Cert from *.cer (PEM) File
$Subject = "CN=DemoCert"
$CurrentLocation = (Get-Location).path
$CertPath = $CurrentLocation + "\" + $Subject + "-BASE64.cer"
$Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate($CertPath)

#Get Certificate with Thumbprint from UserCertStore
$ThumbPrint = "07EFF3918F47995EB53B91848F69B5C0E78622FD"
$Cert = Get-ChildItem -Path cert:\CurrentUser\my\$ThumbPrint

#Get Certificate with SubjectName from UserCertStore
$Subject = "CN=DemoCert"
$Cert = Get-ChildItem -Path cert:\CurrentUser\my\ | Where-Object {$_.Subject -eq "$Subject"}  
$Cert

# Create a keyCredential (Certificate) for App
$keyCreds = @{
    Type = "AsymmetricX509Cert";
    Usage = "Verify";
    key = $cert.RawData
}
 
try {
   Update-MgApplication -ApplicationId $APPObjectID  -KeyCredentials $keyCreds
} catch {
   Write-Error $Error[0]
}

#Show Certificate of Azure AD Application
$App = Get-MgApplication -ApplicationId $APPObjectID
$App.KeyCredentials



You have to patient in the Portal. It takes a Minute or so and needs a refresh of the whole Page to see the Certificate.



Another way would be to add the Permission in the Portal and then check the Manifest.

###############################################################################
#Add Permissions
###############################################################################
#Add Delegated Permission
#User.ReadBasic.All    Delegated    b340eb25-3456-403f-be2f-af7a0d370277
$params = @{
    RequiredResourceAccess = @(
        @{
            ResourceAppId = "00000003-0000-0000-c000-000000000000"
            ResourceAccess = @(
                @{
                    Id = "b340eb25-3456-403f-be2f-af7a0d370277"
                    Type = "Scope"
                }
            )
        }
    )
}
Update-MgApplication -ApplicationId $APPObjectID -BodyParameter $params



Delegated Permissions have been addet


This Code replaces the Permissions

###############################################################################
#Add Permissions
###############################################################################
#Add Application Permission
#User.ReadBasic.All    Application    97235f07-e226-4f63-ace3-39588e11d3a1
$params = @{
    RequiredResourceAccess = @(
        @{
            ResourceAppId = "00000003-0000-0000-c000-000000000000"
            ResourceAccess = @(
                @{
                    Id = "97235f07-e226-4f63-ace3-39588e11d3a1"
                    Type = "Role"
                }
            )
        }
    )
}
Update-MgApplication -ApplicationId $APPObjectID -BodyParameter $params



Now we have Application Permissions. Note that the Admin Consent is not yet granted.


###############################################################################
#Redirect URI
#If you need to add Redirect URI's.
###############################################################################
#Redirect URI
$App = Get-MgApplication -ApplicationId $APPObjectID -Property *
$AppId = $App.AppId
$RedirectURI = @()
$RedirectURI += "https://login.microsoftonline.com/common/oauth2/nativeclient"
$RedirectURI += "msal" + $AppId + "://auth"
$RedirectURI += "https://localhost:3000"

$params = @{
    RedirectUris = @($RedirectURI)
}
Update-MgApplication -ApplicationId $APPObjectID -IsFallbackPublicClient -PublicClient $params



The Redirect URI's have now been addet


###############################################################################
#Grant Admin Consent - Opens URL in Browser
###############################################################################
#https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={client-id}
$App = Get-MgApplication | Where-Object {$_.DisplayName -eq "DemoApp"}
$TenantID = $App.PublisherDomain
$AppID = $App.AppID
$URL = "https://login.microsoftonline.com/$TenantID/adminconsent?client_id=$AppID"
Start-Process $URL





Log in with a "Global Administrator" Role


Grant Admin Consent


As you can see the Application has now Granted Admin consent.



###############################################################################
#Remove the Application
###############################################################################
Remove-MgApplication -ApplicationId $APPObjectID






Regards
Andres Bohren


posted @ Friday, December 2, 2022 2:26 PM | Filed Under [ PowerShell Azure ]

Microsoft.Graph PowerShell Module 1.18.0 released

Hi All,

A few hours ago, Microsoft has released a new Version of the Microsoft.Graph PowerShell Module.
Apparently it covers the latest API version and Help as well as a minor fix.

Microsoft.Graph 1.18.0

1.18.0 Release Notes



Let's check the installed Version and what's available on the PowerShell Gallery

Get-InstalledModule Microsoft.Graph
Find-Module Microsoft.Graph


To install the newest Version of the PowerShell Modules and also uninstalling the old Versions, you can use my GitHub Script. It takes a while until all Modules are installed. Wait until "Cleanup finished" is shown.

#Run Script directly from GitHub
$ScriptFromGitHub = Invoke-WebRequest "https://raw.githubusercontent.com/BohrenAn/GitHub_PowerShellScripts/main/ExchangeOnline/GraphAPI/Cleanup-GraphModules.ps1"
Invoke-Expression $($ScriptFromGitHub.Content)


To list the Modules you can use the following Command

Get-Module Microsoft.Graph* -ListAvailable



Regards
Andres Bohren


posted @ Friday, December 2, 2022 7:47 AM | Filed Under [ PowerShell ]

Wednesday, November 30, 2022

Exchange Online Name Attribute change creates some inconsistencys

Hi All,

Back in April 2022 Microsoft has anounced in theyr Exchange Team Blog, that they will change the Name Attribute of the Objects to the ExternalDirectoryObjectId (EDOID).
After some Feedback from Customers and the Community they stopped the Rollout for Reflection as you can read on the Blog post of Tony Redmond.

Exchange Online Plans Changes to Make Mailbox Identification More Effective

Change in naming convention of user’s Name parameter

Some of the Comments indicate that the since 1. November the Rollout has started again - even the Banner of the Article says it's stopped until 23. January 2023.


I've created a new Mailenabled Security Group.
As you can see the new one has only the ExternalDirectoryObjectId (EDOID) as the Name unlike the Object that exists already a while.


I have added the new Mailenabled Security Group to the FullAccess for a Shared Mailbox in Exchange Admin Center


After you reopen the the Full Access Dialog in Exchange Admin Center you can only see the ExternalDirectoryObjectId (EDOID)


Let's view the Full Access Permission in ExchangeOnline PowerShell. You can see the diffrence in the two Groups

Get-MailboxPermission -Identity Sharedmbx@icewolf.ch | where {$_.User -ne "NT AUTHORITY\SELF"} | fl


Aldough you can resolve the Group with the ExternalDirectoryObjectId (EDOID)

Get-Recipient c5607117-7e0f-47de-b731-6fd923c5d892
Get-Recipient c5607117-7e0f-47de-b731-6fd923c5d892 | fl


Now let's try to add a User to Full Access in Exchange Admin Center


The Name Attribute of the Mailbox is also the ExternalDirectoryObjectId (EDOID)

Get-Mailbox -Identity c.kent |  Format-List Name, Alias, DisplayName, UserPrincipalName, *id*


Interesting that the Exchange Admin Center in the case of a user can resolve the Identity to UserPrincpalName


If you look at the Permissions the User Attribute is correct for the Mailbox

Get-MailboxPermission -Identity Sharedmbx@icewolf.ch | where {$_.User -ne "NT AUTHORITY\SELF"} | fl



Seems that there are still some inconcistencys all around that change. Hopefully that will be fixed until end of January.

Regards
Andres Bohren


posted @ Wednesday, November 30, 2022 1:48 PM | Filed Under [ Exchange ]

MSIdentityTools PowerShell Module v2.0.26 released

Hi All,

Just a few Hours ago, a new Version of MSIdentity Tools has been released.

MSIdentityTools 2.0.26


Uninstall the old version of the PowerShell Module and install the newest one

Get-InstalledModule MSIdentityTools
Find-Module MSIdentityTools


Uninstall-Module MSIdentityTools
Install-Module MSIdentityTools
Get-InstalledModule MSIdentityTools


To see what commands are available use the following command

Get-Command -Module MSIdentityTools



Regards
Andres Bohren


posted @ Wednesday, November 30, 2022 9:37 AM | Filed Under [ PowerShell ]

Tuesday, November 29, 2022

Microsoft Azure Active Directory Connect 2.1.20.0

Hi All,

A few weeks ago, Microsoft has released a new Version of Microsoft Azure Active Directory Connect.

Azure AD Connect: Version release history


Microsoft Azure Active Directory Connect 2.1.20.0











On the M365 Admin Center in the Health > Directory Sync Status you can find the new Version Number



Regards
Andres Bohren


posted @ Tuesday, November 29, 2022 8:21 PM | Filed Under [ Microsoft365 Azure ]

Monday, November 28, 2022

Create Microsoft Teams Holidays for Switzerland 2023

Hi All,

In Microsoft Teams the Holidays have always been a bit Tricky.
You can create Holidays direct in Teams Admin Center under Voice > Holidays or during the Creation or Modification of a Autoattendant.

The Problem is that you create the Holidays and these are mostly set up to a specific Year. Next year you have to redo the Holidays and go through all Autoattendants to see if they are still linked.

I'll show you how to create and update the Microsoft Teams Holidays for Switzerland and keep them up do date.
I had considered diffrent approaches:
  • Create Holidays for each Day that exists in Switzerland
  • Create Holidays for each Canton in Switzerland (26 Kantone)
  • Create National Holidays and Holidays per Canton or Individual Dates
In the end i have created all Holidays - because i think that's the most flexible Model.


#List of Holidays in Teams
Connect-MicrosoftTeams
$Shedule = Get-CsOnlineSchedule | Where-Object {$_.Type -eq "Fixed"}
$Shedule
$Shedule.FixedSchedule
$Shedule.FixedSchedule.DateTimeRanges



I used the following Source for Reference

Add the Holidays for Switzerland in 2023

#Neujahr 01.01.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-01-01T00:00:00" -End "2023-01-02T00:00:00"
New-CsOnlineSchedule -Name "Neujahr" -FixedSchedule -DateTimeRanges @($DateRange)

#Berchtoldstag 02.01.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-01-02T00:00:00" -End "2023-01-03T00:00:00"
New-CsOnlineSchedule -Name "Berchtoldstag" -FixedSchedule -DateTimeRanges @($DateRange)

#Heilige Drei Könige 06.01.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-01-06T00:00:00" -End "2023-01-07T00:00:00"
New-CsOnlineSchedule -Name "Heilige Drei Könige" -FixedSchedule -DateTimeRanges @($DateRange)

#St. Josef 19.03.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-03-19T00:00:00" -End "2023-03-20T00:00:00"
New-CsOnlineSchedule -Name "St. Josef" -FixedSchedule -DateTimeRanges @($DateRange)

#Karfreitag 07.04.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-04-07T00:00:00" -End "2023-04-08T00:00:00"
New-CsOnlineSchedule -Name "Karfreitag" -FixedSchedule -DateTimeRanges @($DateRange)

#Ostersonntag 09.04.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-04-09T00:00:00" -End "2023-04-10T00:00:00"
New-CsOnlineSchedule -Name "Ostersonntag" -FixedSchedule -DateTimeRanges @($DateRange)

#Sechseläuten 17.04.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-04-17T00:00:00" -End "2023-04-18T00:00:00"
New-CsOnlineSchedule -Name "Sechseläuten" -FixedSchedule -DateTimeRanges @($DateRange)

#Auffahrt 18.05.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-05-18T00:00:00" -End "2023-05-19T00:00:00"
New-CsOnlineSchedule -Name "Auffahrt" -FixedSchedule -DateTimeRanges @($DateRange)

#Pfingstmontag 29.05.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-05-29T00:00:00" -End "2023-05-30T00:00:00"
New-CsOnlineSchedule -Name "Pfingstmontag" -FixedSchedule -DateTimeRanges @($DateRange)

#Fronleichnam 08.06.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-06-08T00:00:00" -End "2023-06-09T00:00:00"
New-CsOnlineSchedule -Name "Fronleichnam" -FixedSchedule -DateTimeRanges @($DateRange)

#Peter und Paul 29.06.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-06-29T00:00:00" -End "2023-06-30T00:00:00"
New-CsOnlineSchedule -Name "Peter und Paul" -FixedSchedule -DateTimeRanges @($DateRange)

#Bundesfeier 01.08.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-08-01T00:00:00" -End "2023-08-02T00:00:00"
New-CsOnlineSchedule -Name "Bundesfeier" -FixedSchedule -DateTimeRanges @($DateRange)

#Mariä Himmelfahrt 15.08.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-08-15T00:00:00" -End "2023-08-16T00:00:00"
New-CsOnlineSchedule -Name "Mariä Himmelfahrt" -FixedSchedule -DateTimeRanges @($DateRange)

#Genfer Bettag 07.09.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-09-07T00:00:00" -End "2023-09-08T00:00:00"
New-CsOnlineSchedule -Name "Genfer Bettag" -FixedSchedule -DateTimeRanges @($DateRange)

#Knabenschiessen 11.09.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-09-11T00:00:00" -End "2023-09-12T00:00:00"
New-CsOnlineSchedule -Name "Knabenschiessen" -FixedSchedule -DateTimeRanges @($DateRange)

#Eidgenössischer Dank-, Buss- und Bettag 17.09.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-09-17T00:00:00" -End "2023-09-18T00:00:00"
New-CsOnlineSchedule -Name "Eidgenössischer Dank-, Buss- und Bettag" -FixedSchedule -DateTimeRanges @($DateRange)

#Mauritiustag 22.09.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-09-22T00:00:00" -End "2023-09-23T00:00:00"
New-CsOnlineSchedule -Name "Mauritiustag" -FixedSchedule -DateTimeRanges @($DateRange)

#St. Leodegar 02.10.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-10-02T00:00:00" -End "2023-10-03T00:00:00"
New-CsOnlineSchedule -Name "St. Leodegar" -FixedSchedule -DateTimeRanges @($DateRange)

#Allerheiligen 01.11.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-11-01T00:00:00" -End "2023-11-02T00:00:00"
New-CsOnlineSchedule -Name "Allerheiligen" -FixedSchedule -DateTimeRanges @($DateRange)

#Mariä Empfängnis 08.12.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-12-08T00:00:00" -End "2023-12-09T00:00:00"
New-CsOnlineSchedule -Name "Mariä Empfängnis" -FixedSchedule -DateTimeRanges @($DateRange)

#Weihnachten 25.12.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-12-25T00:00:00" -End "2023-12-26T00:00:00"
New-CsOnlineSchedule -Name "Weihnachten" -FixedSchedule -DateTimeRanges @($DateRange)

#Stephanstag 26.12.2023
$DateRange = New-CsOnlineDateTimeRange -Start "2023-12-26T00:00:00" -End "2023-12-27T00:00:00"
New-CsOnlineSchedule -Name "Stephanstag" -FixedSchedule -DateTimeRanges @($DateRange)




Now all the Holidays have been created.


#Show global Holidays
$Schedule = Get-CsOnlineSchedule | Where-Object {$_.Type -eq "Fixed"}
$Schedule | Select-Object Name,  @{label="Start";expression={$_.FixedSchedule.DateTimeRanges[0].Start}}, @{label="End";expression={$_.FixedSchedule.DateTimeRanges[0].End}} | Sort-Object Start




Now it's a little bit tricky. Because every canton in Switzerland (similar to US federal States) has it's own rules if these Holidays are free days or not.

In Teams Admin Center you add the Holidays like this: Select the Auto Attendant


Click on "Add"


Now you need to provide a Name for the Holiday. I simply use the same Name as the in the Holidays (Get-CsOnlineSchedule).
Then you can select from the Dropdown List and set Greeting and Call routing options.


Don't forget to Save at the End (Bottom of Window that is not part of the Screenshot)


Same in PowerShell

#Add Holiday to AutoAttendant
$AutoAttendantName = "AutoAttendantDemo01"
$HolidayName = "Berchtoldstag"
$HolidaySchedule = Get-CsOnlineSchedule | Where-Object {$_.Name -eq $HolidayName}
$HolidayScheduleName = $HolidaySchedule.Name
$GreetingPrompt = New-CsAutoAttendantPrompt -TextToSpeechPrompt "An Feiertagen sind wir nicht erreichbar"
$MenuOption = New-CsAutoAttendantMenuOption -Action DisconnectCall -DtmfResponse Automatic
$Menu = New-CsAutoAttendantMenu -Name $HolidayScheduleName -MenuOptions @($MenuOption)
$CallFlow = New-CsAutoAttendantCallFlow -Name $HolidayScheduleName -Menu $Menu -Greetings $GreetingPrompt
$CallHandlingAssociation = New-CsAutoAttendantCallHandlingAssociation -Type Holiday -ScheduleId $HolidaySchedule.Id -CallFlowId $CallFlow.Id
$AutoAttendant = Get-CsAutoAttendant -NameFilter $AutoAttendantName
$AutoAttendant.CallFlows += @($CallFlow)
$AutoAttendant.CallHandlingAssociations += @($CallHandlingAssociation)
Set-CsAutoAttendant -Instance $AutoAttendant



The Holiday has been addet to the Autoattendant.


By the way, this is the Code to remove a Holiday from an Auto Attendant

#Remove Holiday from AutoAttendant
$AutoAttendantName = "AutoAttendantDemo01"
$HolidayName = "Neujahr"
$AutoAttendant = Get-CsAutoAttendant -NameFilter $AutoAttendantName
$CallFlows = $AutoAttendant.CallFlows | Where-Object {$_.Name -ne $HolidayName}
$CallFlow = $AutoAttendant.CallFlows | Where-Object {$_.Name -eq $HolidayName}
$CallHandlingAssociations = $AutoAttendant.CallHandlingAssociations | Where-Object {$_.CallFlowId -ne $CallFlow.Id}
$AutoAttendant.CallFlows = @($CallFlows)
$AutoAttendant.CallHandlingAssociations = @($CallHandlingAssociations)
Set-CsAutoAttendant -Instance $AutoAttendant


Now let's see the Holidays for an Auto Attendant

#Show Holidays from Autoattendant
$AutoAttendantName = "AutoAttendantDemo01"
$AutoAttendant = Get-CsAutoAttendant -NameFilter $AutoAttendantName
$AutoAttendant.Schedule
$AutoAttendantHolidays = Get-CsAutoAttendantHolidays -Identity $AutoAttendant.Identity
$AutoAttendantHolidays
$AutoAttendantHolidays.DateTimeRanges



So next Year you simply need to update the Holidays. Here is an Example of how to do that for "Neujahr".

#Update Holiday 2024
$HolidayName = "Neujahr"
$DateRange = New-CsOnlineDateTimeRange -Start "2024-01-01T00:00:00" -End "2024-01-02T00:00:00"
$Neujahr = Get-CsOnlineSchedule | Where-Object {$_.Name -eq $HolidayName}
$Neujahr.FixedSchedule.DateTimeRanges = $DateRange
Set-CsOnlineSchedule -Instance $Neujahr



The Holiday has been updated


And the Associated Holiday in the Teams Auto Attendand also has the new Date.



Hope that help you to make your Teams Holidays more smart and easy to maintain.

Regards
Andres Bohren


posted @ Monday, November 28, 2022 4:43 PM | Filed Under [ PowerShell MicrosoftTeams ]

Saturday, November 26, 2022

PowerShell Module Microsoft.Online.SharePoint.PowerShell 16.0.23109.12000 released

Hi All,

Some hours ago, Microsoft has released a new Version of the Microsoft.Online.SharePoint.PowerShell Module to the PowerShell Gallery.

Microsoft.Online.SharePoint.PowerShell 16.0.23109.12000


Check what Module Version is installed and what's available from the PowerShell Gallery

Get-InstalledModule Microsoft.Online.SharePoint.PowerShell
Find-Module Microsoft.Online.SharePoint.PowerShell


Uninstall the old Module and install the new Version

Uninstall-Module Microsoft.Online.SharePoint.PowerShell
Install-Module Microsoft.Online.SharePoint.PowerShell
Get-InstalledModule Microsoft.Online.SharePoint.PowerShell



Regards
Andres Bohren


posted @ Saturday, November 26, 2022 8:24 AM | Filed Under [ PowerShell ]

Thursday, November 24, 2022

Azure AD User setting Tenant Creation

Hi All,

Since a few Days there is a new Setting in Azure AD User Settings "Tenant creation"

Per default this setting is set to "Yes". Means that a user with can create a new Azure AD Tenant.
"No" means that only users with "Global Administrator" or "Tenant Creator" Admin Role can create Azure AD Tenants.


I can't think much of a Szenario where this should be enabled. So setting this to "No" is a secure configuration.


You can have a look ath the Authorization Policy with the Graph Explorer

GET https://graph.microsoft.com/beta/policies/authorizationPolicy



You can view and change the Setting with PowerShell.

Connect-MgGraph -Scopes Policy.Read.All, Policy.ReadWrite.Authorization
Select-MgProfile -Name "beta"
Get-MgPolicyAuthorizationPolicy | fl
(Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions
(Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions.AdditionalProperties | fl



Allow Tenant creation for Users

#Users can create Tenants
$Param = @"
    {"allowedToCreateTenants": true}
"@
Update-MgPolicyAuthorizationPolicy -AuthorizationPolicyId "authorizationPolicy" -DefaultUserRolePermissions $Param


Disable Tenant creation for users

#Users can't create Tenants
$Param = @"
    {"allowedToCreateTenants": false}
"@
Update-MgPolicyAuthorizationPolicy -AuthorizationPolicyId "authorizationPolicy" -DefaultUserRolePermissions $Param




Regards
Andres Bohren


posted @ Thursday, November 24, 2022 2:07 PM |

Saturday, November 19, 2022

Deploy PowerShell 7 Script on Azure Automation

Hi All,

In this Blog Post i explain how to Create and Depoly a PowerShell 7 Runbook for Azure Automation with the AZ PowerShell Module.

#Connect to Azure
Connect-AzAccount

#Get Automation Account
Get-AzAutomationAccount


I have two Azure Automation Accounts. In this Example, we use the second one.


###############################################################################
# Create Runbook
###############################################################################
$accountName = "icewolfautomation"
$rgName = "RG_DEV"
$location = "West Europe"
$RunbookName = "DemoPS7"
$scriptContent = @'
    #Connect to Exchange with Managed Identity
    $tenant = "icewolfch.onmicrosoft.com"
    Connect-ExchangeOnline -ManagedIdentity -Organization $tenant

    #Get Accepted Domain
    Get-AcceptedDomain | Format-Table DomainName, DomainType

    #Disconnect Exchange Online
    Disconnect-ExchangeOnline -Confirm:$False
'@

Invoke-AzRestMethod -Method "PUT" -ResourceGroupName $rgName -ResourceProviderName "Microsoft.Automation" `
    -ResourceType "automationAccounts" -Name "${AccountName}/runbooks/${RunbookName}" -ApiVersion "2017-05-15-preview" `
    -Payload "{`"properties`":{`"runbookType`":`"PowerShell7`", `"logProgress`":false, `"logVerbose`":false, `"draft`":{}}, `"location`":`"${Location}`"}"

Invoke-AzRestMethod -Method "PUT" -ResourceGroupName $rgName -ResourceProviderName "Microsoft.Automation" `
    -ResourceType automationAccounts -Name "${AccountName}/runbooks/${RunbookName}/draft/content" -ApiVersion 2015-10-31 `
    -Payload "$scriptContent"



The Runbook is now visible in the Azure Portal


###############################################################################
# Publish Runbook
###############################################################################
Publish-AzAutomationRunbook -Name $RunbookName -AutomationAccountName $AccountName -ResourceGroupName $rgName



The Runbook is now published


It contains the code


I've already created Shedules for this Automation Account

###############################################################################
# Get Schedule
###############################################################################
$accountName = "icewolfautomation"
$rgName = "RG_DEV"
Get-AzAutomationSchedule -AutomationAccountName $AccountName -ResourceGroupName $rgName
Get-AzAutomationSchedule -AutomationAccountName $AccountName -ResourceGroupName $rgName -Name "Weekly"



Here are the Schedules in the Portal


###############################################################################
# Link Schedule with Runbook
###############################################################################
$accountName = "icewolfautomation"
$rgName = "RG_DEV"
$scheduleName = "Weekly"
Register-AzAutomationScheduledRunbook -AutomationAccountName $accountName `
-Name $RunbookName -ScheduleName $scheduleName -ResourceGroupName $rgName



Check in the Portal if the schedule is Linked


And finally test the Runbook



This Script is also available on my GitHub Repo

Regards
Andres Bohren


posted @ Saturday, November 19, 2022 11:55 AM | Filed Under [ PowerShell Azure ]

How to Manage PowerShell 5 and 7 Modules on Azure Automation

Hi All,

As you might already know, i am a big Fan of Azure Automation.

Yesterday there was a Release of "Microsoft.Graph PowerShell Module 1.17.0" and the Question of how to update the PowerShell Modules on Azure Automate arises once again.
Basically i've covered that already in a Blog Post earlyer this Year "Update Modules on Azure Automation with AZ PowerShell".

But i think i have improved the Script a little bit. And finally i explain how to Manage the PowerShell 7 Modules on Azure Automate.

#Connect to Azure
Connect-AzAccount

#Get Automation Account
Get-AzAutomationAccount



#Get Modules
$accountName = 'icewolfautomation'
$rgName = 'RG_DEV'
$ModuleName = "Microsoft.Graph"
$Modules = Get-AzAutomationModule -AutomationAccountName $accountName -ResourceGroupName $rgName | Where-Object {$_.Name -match "$ModuleName"}
$Modules



That's the same List as from the Azure Portal


#Remove Module
#For Microsoft.Graph it is important that Microsoft.Graph.Authentication is uninstalled last due to dependencys
Foreach ($Module in $Modules)
{
    If ($Module.Name -ne "Microsoft.Graph.Authentication")
    {
    $ModuleName = $Module.Name
    Write-Host "Remove ModuleName: $ModuleName"
    Remove-AzAutomationModule -AutomationAccountName $accountName -Name $ModuleName -ResourceGroupName $rgName -Confirm:$False -Force
    }
}
$ModuleName = "Microsoft.Graph.Authentication"
Write-Host "Remove ModuleName: $ModuleName"
Remove-AzAutomationModule -AutomationAccountName $accountName -Name $ModuleName -ResourceGroupName $rgName -Confirm:$False -Force


#Add Module
#For Microsoft.Graph it is important that Microsoft.Graph.Authentication is installed first due to dependencys
$ModuleName = "Microsoft.Graph.Authentication"
$moduleVersion = "1.17.0"
New-AzAutomationModule -AutomationAccountName $accountName -ResourceGroupName $rgName -Name $moduleName -ContentLinkUri "https://www.powershellgallery.com/api/v2/package/$moduleName/$moduleVersion"



The PowerShell 5 Modules have been removed.


#Add Module
#For Microsoft.Graph it is important that Microsoft.Graph.Authentication is installed first due to dependencys
$ModuleName = "Microsoft.Graph.Authentication"
$moduleVersion = "1.17.0"
New-AzAutomationModule -AutomationAccountName $accountName -ResourceGroupName $rgName -Name $moduleName -ContentLinkUri "https://www.powershellgallery.com/api/v2/package/$moduleName/$moduleVersion"

#Wait until Module is installed
Do {
    $Module = Get-AzAutomationModule -AutomationAccountName $accountName -ResourceGroupName $rgName | Where-Object {$_.Name -match "$ModuleName"}   
    Write-Host "State: $($Module.ProvisioningState) > Check again in 15 Seconds"
    Start-Sleep -Seconds 15
} until ($Module.ProvisioningState -eq "Succeeded")

#Install the Rest of the Modules
$Modules = @()
$Modules += "Microsoft.Graph.Users"
$Modules += "Microsoft.Graph.Users.Actions"
$Modules += "Microsoft.Graph.Groups"
$moduleVersion = "1.17.0"
Foreach ($ModuleName in $Modules)
{
    Write-Host "ModuleName: $ModuleName"
    New-AzAutomationModule -AutomationAccountName $accountName -ResourceGroupName $rgName -Name $moduleName -ContentLinkUri "https://www.powershellgallery.com/api/v2/package/$moduleName/$moduleVersion"
}



The Microsoft.Graph.Authentication will be installed and after the ProvisioningState is succeeded the Rest of the Modules can be installed and the dependencys will be fullfilled.


Voila - Upgrade was sucessful


In the Portal you are able to add PowerShell 7 Modules


As you can see, there is no Parameter to address PowerShell 7 Modules

New-AzAutomationModule


###############################################################################
# GET PS7 Module
###############################################################################
$subscriptionId = "42ecead4-eae9-4456-997c-1580c58b54ba"
$accountName = "icewolfautomation"
$rgName = "RG_DEV"
$ModuleName = "Microsoft.Graph.Authentication"
$Result = Invoke-AzRestMethod `
    -Method GET `
    -SubscriptionId $subscriptionId `
    -ResourceGroupName $rgName `
    -ResourceProviderName Microsoft.Automation `
    -ResourceType automationAccounts `
    -Name $accountName/powershell7Modules/$ModuleName `
    -ApiVersion 2019-06-01

($Result.Content | ConvertFrom-Json).Properties



###############################################################################
#Delete PS7 Module
###############################################################################
$subscriptionId = "42ecead4-eae9-4456-997c-1580c58b54ba"
$accountName = "icewolfautomation"
$rgName = "RG_DEV"
$Modules = @()
$Modules += "Microsoft.Graph.Authentication"
$Modules += "Microsoft.Graph.Users"
$Modules += "Microsoft.Graph.Users.Actions"
$Modules += "Microsoft.Graph.Groups"

#For Microsoft.Graph it is important that Microsoft.Graph.Authentication is uninstalled last due to dependencys
Foreach ($ModuleName in $Modules)
{
    If ($ModuleName -ne "Microsoft.Graph.Authentication")
    {
    Write-Host "Remove ModuleName: $ModuleName"
    Invoke-AzRestMethod `
        -Method DELETE `
        -SubscriptionId $subscriptionId `
        -ResourceGroupName $rgName `
        -ResourceProviderName Microsoft.Automation `
        -ResourceType automationAccounts `
        -Name $accountName/powershell7Modules/$ModuleName `
        -ApiVersion 2019-06-01
    }
}
$ModuleName = "Microsoft.Graph.Authentication"
Write-Host "Remove ModuleName: $ModuleName"
Invoke-AzRestMethod `
-Method DELETE `
-SubscriptionId $subscriptionId `
-ResourceGroupName $rgName `
-ResourceProviderName Microsoft.Automation `
-ResourceType automationAccounts `
-Name $accountName/powershell7Modules/$ModuleName `
-ApiVersion 2019-06-01



The PowerShell 7 Modules have been removed


###############################################################################
#Add PS7 Module
###############################################################################
$subscriptionId = "42ecead4-eae9-4456-997c-1580c58b54ba"
$accountName = "icewolfautomation"
$rgName = "RG_DEV"
$ModuleName = "Microsoft.Graph.Authentication"
$moduleVersion = "1.17.0"

#Install Microsoft.Graph.Authentication
$Payload = @"
    {"properties":
        {"contentLink":
            {"uri":"https://www.powershellgallery.com/api/v2/package/$ModuleName/$moduleVersion"}
        }
    }
"@

Write-Host "Install ModuleName: $ModuleName"

Invoke-AzRestMethod `
    -Method PUT `
    -SubscriptionId $subscriptionId `
    -ResourceGroupName $rgName `
    -ResourceProviderName Microsoft.Automation `
    -ResourceType automationAccounts `
    -Name $accountName/powershell7Modules/$ModuleName `
    -ApiVersion 2019-06-01 `
    -Payload $Payload

#Wait until Module is installed
Do {
    $Result = Invoke-AzRestMethod `
    -Method GET `
    -SubscriptionId $subscriptionId `
    -ResourceGroupName $rgName `
    -ResourceProviderName Microsoft.Automation `
    -ResourceType automationAccounts `
    -Name $accountName/powershell7Modules/$ModuleName `
    -ApiVersion 2019-06-01

    $ProvisioningState = (($Result.Content | ConvertFrom-Json).Properties).provisioningState

    $Module = Get-AzAutomationModule -AutomationAccountName $accountName -ResourceGroupName $rgName | Where-Object {$_.Name -match "$ModuleName"}   
    Write-Host "State: $ProvisioningState > Check again in 15 Seconds"
    Start-Sleep -Seconds 15
} until ($ProvisioningState -eq "Succeeded")




#Now install the Rest of the Modules
$Modules = @()
$Modules += "Microsoft.Graph.Users"
$Modules += "Microsoft.Graph.Users.Actions"
$Modules += "Microsoft.Graph.Groups"

Foreach ($ModuleName in $Modules)
{
$Payload = @"
    {"properties":
        {"contentLink":
            {"uri":"https://www.powershellgallery.com/api/v2/package/$ModuleName/$moduleVersion"}
        }
    }
"@

Write-Host "Install ModuleName: $ModuleName"

Invoke-AzRestMethod `
    -Method PUT `
    -SubscriptionId $subscriptionId `
    -ResourceGroupName $rgName `
    -ResourceProviderName Microsoft.Automation `
    -ResourceType automationAccounts `
    -Name $accountName/powershell7Modules/$ModuleName `
    -ApiVersion 2019-06-01 `
    -Payload $Payload
}


Here as well Microsoft.Graph.Authentication has to be sucessfully installed before the other Microsoft.Graph* Modules can be installed due to Module Dependencys.


And now all PowerShell 7 Modules on Azure Automate have been updated



By the Way. These PowerShell Commands are also available on my GitHub Repo

Regards
Andres Bohren


posted @ Saturday, November 19, 2022 10:43 AM | Filed Under [ PowerShell Azure ]

Powered by:
Powered By Subtext Powered By ASP.NET