diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/PSCONFEU22_masterslide.pptx" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/PSCONFEU22_masterslide.pptx" new file mode 100644 index 0000000..27ea088 Binary files /dev/null and "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/PSCONFEU22_masterslide.pptx" differ diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/PowerShell, ExchO and Graph - the 3 musketeers.pptx" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/PowerShell, ExchO and Graph - the 3 musketeers.pptx" new file mode 100644 index 0000000..8ad560f Binary files /dev/null and "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/PowerShell, ExchO and Graph - the 3 musketeers.pptx" differ diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/01_Create-AppRegistrationAndEnterpriseApp.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/01_Create-AppRegistrationAndEnterpriseApp.ps1" new file mode 100644 index 0000000..2afdec3 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/01_Create-AppRegistrationAndEnterpriseApp.ps1" @@ -0,0 +1,13 @@ +Connect-AzureAD #Module AzureAD required! +# https://docs.microsoft.com/en-us/powershell/microsoftgraph/azuread-msoline-cmdlet-map +$myAppRegistration = 'PSConfEU-Exchange' +$appHomepageURL = 'https://localhost:12345' +$appReplyURL = 'https://localhost:12345/signin-oidc' +$myCoolApp = New-AzureADApplication -DisplayName $myAppRegistration -AvailableToOtherTenants $false -Homepage $appHomePageUrl -ReplyUrls @($appReplyUrl) +# New-MgApplication +# now create the Service Principal from that app +$myEnterpriseApp = New-AzureADServicePrincipal -AppId $myCoolApp.AppID -Tags @(“WindowsAzureActiveDirectoryIntegratedApp”,”PSConfEU”) +# New-MgServicePrincipal + +# now be happy with Conditional Access +# afterwards grant Graph permissions \ No newline at end of file diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/02_CreateAppSecret.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/02_CreateAppSecret.ps1" new file mode 100644 index 0000000..30e5b06 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/02_CreateAppSecret.ps1" @@ -0,0 +1,3 @@ +Connect-AzureAD #Module AzureAD required! +$myAppRegistrationID = "" +$newSecret = New-AzureADApplicationPasswordCredential -ObjectId $myAppRegistrationID -CustomKeyIdentifier "PowerShellGenerated" -StartDate (get-date) -endDate (get-date).AddDays(720) diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/03_CreateSelfSignedCertificate.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/03_CreateSelfSignedCertificate.ps1" new file mode 100644 index 0000000..8101bff --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/03_CreateSelfSignedCertificate.ps1" @@ -0,0 +1,20 @@ +$myAppRegistrationID = "" +New-SelfSignedCertificate -Subject "CN=PSConfEUCertificate" -KeySpec Signature -CertStoreLocation "cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256 -NotAfter (Get-Date).AddYears(10) +$thumbprint = (Get-ChildItem "cert:\CurrentUser\My" | Where-Object {$_.Subject -eq "CN=PSConfEUCertificate"}).Thumbprint +if ($tmppath -eq $false) {New-Item C:\cert -ItemType Directory} + +#PFX +$certPW = "myUncrackableSecret123!" +$certPW = ConvertTo-SecureString -String $certPW -Force -AsPlainText +Export-PfxCertificate -cert "cert:\CurrentUser\my\$thumbprint" -FilePath C:\cert\PSConfEUCertificate.pfx -Password $certPW +$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("C:\cert\PSConfEUCertificate.pfx", $certPW) +$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData()) +New-AzureADApplicationKeyCredential -ObjectId $myAppRegistrationID -CustomKeyIdentifier "PSConfEU" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue +# New-MgApplicationKey + +#CER +Get-ChildItem "Cert:\CurrentUser\My\$thumbprint" | Export-Certificate -FilePath "C:\cert\PSConfEUCertificate.cer" +$CERcert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("C:\cert\PSConfEUCertificate.cer") +$keyValue = [System.Convert]::ToBase64String($CERcert.GetRawCertData()) +New-AzureADApplicationKeyCredential -ObjectId $myAppRegistrationID -CustomKeyIdentifier "PSConfEU" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue +# New-MgApplicationKey diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/04_ScopingExchangeOnline.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/04_ScopingExchangeOnline.ps1" new file mode 100644 index 0000000..f0f66ef --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/04_ScopingExchangeOnline.ps1" @@ -0,0 +1,2 @@ +$myAppRegistrationID = "" #AppID, not ObjectID! +New-ApplicationAccessPolicy -AppId $myAppRegistrationID -PolicyScopeGroupId "TargetedUsers@contoso.com" -AccessRight RestrictAccess -Description "Restrict this app to members of this security or distribution group" diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/999_odata.nextlink.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/999_odata.nextlink.ps1" new file mode 100644 index 0000000..6e2344e --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/999_odata.nextlink.ps1" @@ -0,0 +1,8 @@ +$found = $false +while (-not $found) +{ + $user = $allUsers.Value | Where-Object {$_.proxyaddresses -ilike ("*" + $owner.Email + "*")} + if($user){$found = $true;break} + $uri = $allUsers.'@odata.nextLink' + $allUsers = Invoke-RestMethod -Method Get -Uri $uri -ContentType 'application/json' -Headers $script:APIHeader +} \ No newline at end of file diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_ExchangeOnlineSampleScript-Native.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_ExchangeOnlineSampleScript-Native.ps1" new file mode 100644 index 0000000..49364b0 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_ExchangeOnlineSampleScript-Native.ps1" @@ -0,0 +1,117 @@ +#======================================================================== +# Created on: 16.06.2022 19:02 +# Created by: Andreas Hähnel +# Organization: Black Magic Cloud +# Function name: 99_ExchangeOnlineSampleScript_Native.ps1 +# Script Version: 0.1 +#======================================================================== +# RequiredPermissions: +# Delegated (work or school account) Not supported. +# Delegated (personal Microsoft account) Not supported. +# Application Mail.ReadWrite +# +# Grant admin consent for the tenant +# +#======================================================================== +# Description: +# this script reads the contents from the inbox of a specified mailbox +# and exports the content as XML +# +#======================================================================== +# Useful links: +# +# +#======================================================================== +# +# Changelog: +# Version 0.1 16.06.2022 +# - initial creation +# +#======================================================================== +# +# EXAMPLE (replace variables with actual values): +# +#======================================================================== +# TODO: +# - add logging +#======================================================================== + +#======================================================================== +# Global Variables +#======================================================================== +#region global variables +$TargetMailboxes = @("UPN OF YOUR MAILBOX") + +New-Variable -Name appID -Value "" -Option ReadOnly +New-Variable -Name tenantID -Value "" -Option ReadOnly +New-Variable -Name clientSecret -Value "" -Option ReadOnly + +#endregion + +#======================================================================== +# Functions +#======================================================================== +#region functions +function Get-GraphAuthorizationToken { + param + ( + [string]$ResourceURL = 'https://graph.microsoft.com', + [string][parameter(Mandatory)] $TenantID, + [string][Parameter(Mandatory)] $ClientKey, + [string][Parameter(Mandatory)] $AppID + ) + + $Authority = "https://login.windows.net/$TenantID/oauth2/token" + [Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null + $EncodedKey = [System.Web.HttpUtility]::UrlEncode($ClientKey) + $body = "grant_type=client_credentials&client_id=$AppID&client_secret=$EncodedKey&resource=$ResourceUrl" + # Request a Token from the graph api + $result = Invoke-RestMethod -Method Post -Uri $Authority ` + -ContentType 'application/x-www-form-urlencoded' -Body $body + $script:APIHeader = @{ 'Authorization' = "Bearer $($result.access_token)" } +} +#======================================================================== + +function Normalize-String { + param( + [Parameter(Mandatory = $true)][string]$str + ) + + $str = $str.ToLower() + $str = $str.Replace(" ", "") + $str = $str.Replace("ä", "ae") + $str = $str.Replace("ö", "oe") + $str = $str.Replace("ü", "ue") + $str = $str.Replace("ß", "ss") + $str = $str.Replace("?","") + + Write-Output $str +} +#======================================================================== +#endregion + +#======================================================================== +# Scriptstart +#======================================================================== +Get-GraphAuthorizationToken -AppID $appID -TenantID $tenantID -ClientKey $clientSecret + +foreach($mailbox in $TargetMailboxes) +{ + $uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/Inbox" + #in v1.0 you need to use the well-known name, in beta there is a parameter wellKnownName + $EmailFolderInbox = Invoke-RestMethod -Uri $uri -Method Get -Headers $script:APIHeader + + #list all emails in the inbox + $uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/$($EmailFolderInbox.id)/messages" + $allMails = Invoke-RestMethod -Uri $uri -Method Get -Headers $script:APIHeader + + #export all emails to 1 comprehensive XML + $allMails | Export-Clixml -Path "C:\dev\allmails.xml" + #each email to a single XML and delete it + foreach($mail in $allMails.value) #if you need to spend some hours of debugging, forget ".value" :) + { + $mail | Export-Clixml -Path "C:\dev\$(Normalize-String $mail.Subject).xml" -Force + $uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/$($EmailFolderInbox.id)/messages/$($mail.id)" + Invoke-RestMethod -Uri $uri -Method DELETE -Headers $script:APIHeader + } +} \ No newline at end of file diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_ExchangeOnlineSampleScript_GraphSDK.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_ExchangeOnlineSampleScript_GraphSDK.ps1" new file mode 100644 index 0000000..7e0e67a --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_ExchangeOnlineSampleScript_GraphSDK.ps1" @@ -0,0 +1,61 @@ +#======================================================================== +# Created on: 16.06.2022 19:02 +# Created by: Andreas Hähnel +# Organization: Black Magic Cloud +# Function name: 99_ExchangeOnlineSampleScript_GraphSDK.ps1 +# Script Version: 0.1 +#======================================================================== +# RequiredPermissions: +# Delegated (work or school account) Not supported. +# Delegated (personal Microsoft account) Not supported. +# Application Mail.ReadWrite +# +# Grant admin consent for the tenant +# +#======================================================================== +# Description: +# this script reads the contents from the inbox of a specified mailbox +# and exports the content as XML +# +#======================================================================== +# Useful links: +# +# +#======================================================================== +# +# Changelog: +# Version 0.1 16.06.2022 +# - initial creation +# +#======================================================================== +# +# EXAMPLE (replace variables with actual values): +# +#======================================================================== +# TODO: +# - add logging +#======================================================================== + +Import-Module Microsoft.Graph.Mail +Import-Module Microsoft.Graph.Authentication + +New-Variable -Name appID -Value "" -Option ReadOnly +New-Variable -Name tenantID -Value "" -Option ReadOnly + +# Graph SDK only supports certificate based auth for unattended scripts, no secret (currently): +# https://docs.microsoft.com/en-us/powershell/microsoftgraph/app-only?view=graph-powershell-1.0&tabs=powershell + + +Connect-MgGraph -Scopes Mail.Read.Shared,User.Read.All -ClientId $appID -TenantId $tenantID - +$user = Get-MgUser -Search '"DisplayName:Spiderman"' -ConsistencyLevel eventual +#$inbox = Get-MgUserMailFolder -UserId $user.Id | Where-Object {$_.DisplayName -eq "Inbox"} + +$allMails = Get-MgUserMessage -UserId $user.Id +$allMails | Export-Clixml -Path "C:\dev\allmails.xml" +foreach($mail in $allMails.Value) +{ + $mail | Export-Clixml -Path "C:\dev\$($mail.Subject).xml" + #here you can use the UPN + #Remove-MgUserMessage -UserId $user.Id -MessageId $mail.id +} + diff --git "a/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_WebRequestVSRestMethod.ps1" "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_WebRequestVSRestMethod.ps1" new file mode 100644 index 0000000..23138ab --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - PowerShell, Exchange Online and MS Graph - the 3 musketeers/ps1/99_WebRequestVSRestMethod.ps1" @@ -0,0 +1,34 @@ +$mailbox = "" + +New-Variable -Name appID -Value "" -Option ReadOnly +New-Variable -Name tenantID -Value "" -Option ReadOnly +New-Variable -Name clientSecret -Value "" -Option ReadOnly + +function Get-GraphAuthorizationToken { + param + ( + [string]$ResourceURL = 'https://graph.microsoft.com', + [string][parameter(Mandatory)] $TenantID, + [string][Parameter(Mandatory)] $ClientKey, + [string][Parameter(Mandatory)] $AppID + ) + + $Authority = "https://login.windows.net/$TenantID/oauth2/token" + [Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null + $EncodedKey = [System.Web.HttpUtility]::UrlEncode($ClientKey) + $body = "grant_type=client_credentials&client_id=$AppID&client_secret=$EncodedKey&resource=$ResourceUrl" + # Request a Token from the graph api + $result = Invoke-RestMethod -Method Post -Uri $Authority ` + -ContentType 'application/x-www-form-urlencoded' -Body $body + $script:APIHeader = @{ 'Authorization' = "Bearer $($result.access_token)" } +} + +Get-GraphAuthorizationToken -TenantID $tenantID -AppID $appID -ClientKey $clientSecret + +$uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/Inbox" + +$EmailFolderInboxIRM = Invoke-RestMethod -Uri $uri -Method Get -Headers $script:APIHeader +$EmailFolderInboxIWR = Invoke-WebRequest -Uri $uri -Method Get -Headers $script:APIHeader + +#get the body: +$EmailFolderInboxIWR.Content | Convertfrom-Json \ No newline at end of file diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/Building a secure script vith Graph API.pptx" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/Building a secure script vith Graph API.pptx" new file mode 100644 index 0000000..48b9bd9 Binary files /dev/null and "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/Building a secure script vith Graph API.pptx" differ diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/PSCONFEU22_masterslide.pptx" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/PSCONFEU22_masterslide.pptx" new file mode 100644 index 0000000..27ea088 Binary files /dev/null and "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/PSCONFEU22_masterslide.pptx" differ diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/01_Create-AppRegistrationAndEnterpriseApp.ps1" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/01_Create-AppRegistrationAndEnterpriseApp.ps1" new file mode 100644 index 0000000..59ec228 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/01_Create-AppRegistrationAndEnterpriseApp.ps1" @@ -0,0 +1,13 @@ +Connect-AzureAD #Module AzureAD required! +# https://docs.microsoft.com/en-us/powershell/microsoftgraph/azuread-msoline-cmdlet-map +$myAppRegistration = 'PSConfEU22' +$appHomepageURL = 'https://localhost:12345' +$appReplyURL = 'https://localhost:12345/signin-oidc' +$myCoolApp = New-AzureADApplication -DisplayName $myAppRegistration -AvailableToOtherTenants $false -Homepage $appHomePageUrl -ReplyUrls @($appReplyUrl) +# New-MgApplication +# now create the Service Principal from that app +$myEnterpriseApp = New-AzureADServicePrincipal -AppId $myCoolApp.AppID -Tags @(“WindowsAzureActiveDirectoryIntegratedApp”,”PSConfEU”) +# New-MgServicePrincipal + +# now be happy with Conditional Access +# afterwards grant Graph permissions \ No newline at end of file diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/02_CreateAppSecret.ps1" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/02_CreateAppSecret.ps1" new file mode 100644 index 0000000..ad538d9 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/02_CreateAppSecret.ps1" @@ -0,0 +1,4 @@ +Connect-AzureAD #Module AzureAD required! +$myAppRegistrationID = "" +$newSecret = New-AzureADApplicationPasswordCredential -ObjectId $myAppRegistrationID -CustomKeyIdentifier "PowerShellGenerated" -StartDate (get-date) -endDate (get-date).AddDays(720) +# Add-MgApplicationPassword \ No newline at end of file diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/03_CreateSelfSignedCertificate.ps1" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/03_CreateSelfSignedCertificate.ps1" new file mode 100644 index 0000000..8f24e3a --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/03_CreateSelfSignedCertificate.ps1" @@ -0,0 +1,20 @@ +$myAppRegistrationID = "" +New-SelfSignedCertificate -Subject "CN=PSConfEUCertificate" -KeySpec Signature -CertStoreLocation "cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256 -NotAfter (Get-Date).AddYears(10) +$thumbprint = (Get-ChildItem "cert:\CurrentUser\My" | Where-Object {$_.Subject -eq "CN=PSConfEUCertificate"}).Thumbprint +if ($tmppath -eq $false) {New-Item C:\cert -ItemType Directory} + +#PFX +$certPW = "myUncrackableSecret123!" +$certPW = ConvertTo-SecureString -String $certPW -Force -AsPlainText +Export-PfxCertificate -cert "cert:\CurrentUser\my\$thumbprint" -FilePath C:\cert\PSConfEUCertificate.pfx -Password $certPW +$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("C:\cert\PSConfEUCertificate.pfx", $certPW) +$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData()) +New-AzureADApplicationKeyCredential -ObjectId $myAppRegistrationID -CustomKeyIdentifier "PSConfEU" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue +# New-MgApplicationKey + +#CER +Get-ChildItem "Cert:\CurrentUser\My\$thumbprint" | Export-Certificate -FilePath "C:\cert\PSConfEUCertificate.cer" +$CERcert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("C:\cert\PSConfEUCertificate.cer") +$keyValue = [System.Convert]::ToBase64String($CERcert.GetRawCertData()) +New-AzureADApplicationKeyCredential -ObjectId $myAppRegistrationID -CustomKeyIdentifier "PSConfEU" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue +# New-MgApplicationKey diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/04_ScopingExchangeOnline.ps1" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/04_ScopingExchangeOnline.ps1" new file mode 100644 index 0000000..bbbe04c --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/04_ScopingExchangeOnline.ps1" @@ -0,0 +1,2 @@ +$myAppRegistrationID = "" #AppID, not ObjectID! +New-ApplicationAccessPolicy -AppId $myAppRegistrationID -PolicyScopeGroupId "TargetedUsers@contoso.com" -AccessRight RestrictAccess -Description "Restrict this app to members of this security or distribution group" diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/05_ScopingSharePointOnline.ps1" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/05_ScopingSharePointOnline.ps1" new file mode 100644 index 0000000..11232c2 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/05_ScopingSharePointOnline.ps1" @@ -0,0 +1,55 @@ +$SiteCollectionRelativePath = ".sharepoint.com:/sites/PSConfEU22" +$tenantID = "" +#Worker App +$appID = "" +#Admin App +$secretAdminApp = "" +$appIDAdminApp = "" + + +function Get-GraphAuthorizationToken { + param + ( + [string]$ResourceURL = 'https://graph.microsoft.com', + [string][parameter(Mandatory)]$TenantID, + [string][Parameter(Mandatory)]$ClientKey, + [string][Parameter(Mandatory)]$AppID + ) + + $Authority = "https://login.windows.net/$TenantID/oauth2/token" + + [Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null + $EncodedKey = [System.Web.HttpUtility]::UrlEncode($ClientKey) + + $body = "grant_type=client_credentials&client_id=$AppID&client_secret=$EncodedKey&resource=$ResourceUrl" + + # Request a Token from the graph api + $result = Invoke-RestMethod -Method Post -Uri $Authority -ContentType 'application/x-www-form-urlencoded' -Body $body + + $script:APIHeader = @{ 'Authorization' = "Bearer $($result.access_token)" } +} + +Get-GraphAuthorizationToken -TenantID $tenantID -AppID $appIDAdminApp -ClientKey $secretAdminApp + +$uri = "https://graph.microsoft.com/v1.0/sites/$SiteCollectionRelativePath" +$GraphResultSiteCollection = Invoke-RestMethod -Method Get -Uri $uri -Headers $script:APIHeader +$siteID = $GraphResultSiteCollection.id.Split(",")[1] + +$body = @" +{ + "roles": ["write"], + "grantedToIdentities": [ + { + "application": { + "id": "$appID", + "displayName": "PSConfEU22" + } + } + ] +} +"@ + +$uri = "https://graph.microsoft.com/v1.0/sites/$siteID/permissions" + +# and store the permissions for the app: +Invoke-RestMethod -Method Post -uri $uri -Headers $script:APIHeader -Body $body -ContentType "application/json; charset=utf-8" diff --git "a/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/99_UseCaseExampleScript.ps1" "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/99_UseCaseExampleScript.ps1" new file mode 100644 index 0000000..0635080 --- /dev/null +++ "b/Andreas H\303\244hnel/From the field - building a secure script with Graph API/ps1/99_UseCaseExampleScript.ps1" @@ -0,0 +1,106 @@ +#======================================================================== +# Created on: 17.06.2022 11:39 +# Created by: Andreas Hähnel +# Organization: Black Magic Cloud +# Function name: 99_UseCaseSampleScript.ps1 +# Script Version: 0.1 +#======================================================================== +# RequiredPermissions: +# Delegated (work or school account) Not supported. +# Delegated (personal Microsoft account) Not supported. +# Application Sites.ReadWrite.All +# User.ReadAll +# Grant admin consent for the tenant +# +#======================================================================== +# Description: +# this script reads the AAD users and stores the data in SPO +# +#======================================================================== +# Useful links: +# +# +#======================================================================== +# +# Changelog: +# Version 0.1 17.06.2022 +# - initial creation +# +#======================================================================== +# +# EXAMPLE (replace variables with actual values): +# +#======================================================================== +# TODO: +# +#======================================================================== + +#======================================================================== +# Global Variables +#======================================================================== +#region global variables + +New-Variable -Name appID -Value "" -Option ReadOnly +New-Variable -Name tenantID -Value "" -Option ReadOnly +New-Variable -Name clientSecret -Value "" -Option ReadOnly +New-Variable -Name SharePointListURI -Value "https://graph.microsoft.com/v1.0/sites//lists//items" -Option ReadOnly +# find the IDs easy by using Graph Explorer + +#endregion + +#======================================================================== +# Functions +#======================================================================== +#region functions +function Get-GraphAuthorizationToken { + param + ( + [string]$ResourceURL = 'https://graph.microsoft.com', + [string][parameter(Mandatory)]$TenantID, + [string][Parameter(Mandatory)]$ClientKey, + [string][Parameter(Mandatory)]$AppID + ) + + $Authority = "https://login.windows.net/$TenantID/oauth2/token" + + [Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null + $EncodedKey = [System.Web.HttpUtility]::UrlEncode($ClientKey) + + $body = "grant_type=client_credentials&client_id=$AppID&client_secret=$EncodedKey&resource=$ResourceUrl" + + # Request a Token from the graph api + $result = Invoke-RestMethod -Method Post -Uri $Authority -ContentType 'application/x-www-form-urlencoded' -Body $body + + $script:APIHeader = @{ 'Authorization' = "Bearer $($result.access_token)" } +} +#======================================================================== + +#endregion + +#======================================================================== +# Scriptstart +#======================================================================== +Get-GraphAuthorizationToken -AppID $appID -TenantID $tenantID -ClientKey $clientSecret + +$uri = "https://graph.microsoft.com/v1.0/users/" +$allUsers = Invoke-RestMethod -Method Get -Uri $uri -Headers $script:APIHeader + +foreach($user in $allusers.value) +{ + #generate the bogy for the SPO request + # be careful with special characters: e.g. ß -> _x00df_ + $body = @{ + fields = @{ + "Title" = $user.surname + "Firstname" = $user.givenName + "UserPrincipalName" = $user.userPrincipalName + "preferredLanguage" = $user.preferredLanguage + } + } | ConvertTo-Json -Depth 4 + + Invoke-RestMethod -Uri $SharePointListURI -Method Post -Headers $script:APIHeader -ContentType "application/json; charset=utf-8" -Body $body + +} + + +