diff --git a/Connect MS Graph with Certificate-Automate Azure app registration/ConnectMSGraphCertificate.ps1 b/Connect MS Graph with Certificate-Automate Azure app registration/ConnectMSGraphCertificate.ps1 new file mode 100644 index 0000000..c389255 --- /dev/null +++ b/Connect MS Graph with Certificate-Automate Azure app registration/ConnectMSGraphCertificate.ps1 @@ -0,0 +1,444 @@ +<# +============================================================================================= +Name: Connect to MS Graph PowerShell using Certificate +Description: This script automates Azure app registration +For detailed Script execution: https://blog.admindroid.com/connect-to-microsoft-graph-powershell-using-certificate/ +============================================================================================ +#> +param ( + $TenantID =$null, + $ClientID = $null, + $CertificateThumbprint = $null +) +Function ConnectMgGraphModule +{ + $MsGraphModule = Get-Module Microsoft.Graph -ListAvailable + if($MsGraphModule -eq $null) + { + Write-host "Important: Microsoft graph module is unavailable. It is mandatory to have this module installed in the system to run the script successfully." + $confirm = Read-Host Are you sure you want to install Microsoft graph module? [Y] Yes [N] No + if($confirm -match "[yY]") + { + Write-host "Installing Microsoft graph module..." + Install-Module Microsoft.Graph -Scope CurrentUser + Write-host "Microsoft graph module is installed in this machine successfully" -ForegroundColor Magenta + } + else + { + Write-host "Exiting. `nNote: Microsoft graph module must be available in your system to run the script" -ForegroundColor Red + Exit + } + } + Connect-MgGraph -Scopes "Application.ReadWrite.All,Directory.ReadWrite.All" -ErrorAction SilentlyContinue -Errorvariable ConnectionError |Out-Null + if($ConnectionError -ne $null) + { + Write-Host "$ConnectionError" -Foregroundcolor Red + Exit + } + Write-Host "Microsoft Graph Powershell module is connected successfully" -ForegroundColor Green + $Script:TenantID = (Get-MgOrganization).Id +} +function RegisterApplication +{ + Write-Progress -Activity "Registering an application" + while(1) + { + $Script:AppName = Read-Host "`nEnter a name for the new App" + if($AppName -eq "") + { + Write-Host "You didn't enter any name. Please provide an app name to continue." -ForegroundColor Red + continue + } + break + } + $Script:RedirectURI = "https://login.microsoftonline.com/common/oauth2/nativeclient" + $params = @{ + DisplayName = $AppName + SignInAudience="AzureADMyOrg" + PublicClient=@{ + RedirectUris = "$RedirectURI" + } + RequiredResourceAccess = @( + @{ + ResourceAppId = "00000003-0000-0000-c000-000000000000" # Microsoft Graph Resource ID + ResourceAccess = @( + @{ + Id = "7ab1d382-f21e-4acd-a863-ba3e13f7da61" #Directory.Read.All -> Id + Type = "Role" #Role -> Application permission + } + ) + } + ) + } + try{ + $Script:App = New-MgApplication -BodyParameter $params + } + catch + { + Write-Host $_.Exception.Message -ForegroundColor Red + CloseConnection + } + Write-Host "`nApp created successfully" -ForegroundColor Green + $Script:APPObjectID = $App.Id + $Script:APPID = $App.AppId +} +function CertificateCreation +{ + Write-Progress -Activity "Creating certificate" + $Script:CertificateName = "$AppName-Keycertifcate" + $Script:path = "Cert:\CurrentUser\My\" + $Script:CertificatePath = Get-ChildItem -Path $path + $Script:Subject = "CN=$CertificateName" + try + { + $Script:Certificate = New-SelfSignedCertificate -Subject $Subject -CertStoreLocation "$path" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -HashAlgorithm SHA256 + } + catch + { + Write-Host $_.Exception.Message -ForegroundColor Red + CloseConnection + } + Write-Host "`nCertificate created successfully" -ForegroundColor Green +} +Function ImportCertificate +{ + Write-Progress -Activity "Importing certificate" + $UploadCertificate = Read-Host "Enter the certificate path(For example: C:\Users\Admin\user.cer)" + try + { + $Script:Certificate = Import-Certificate -FilePath "$UploadCertificate" -CertStoreLocation "Cert:\CurrentUser\My" + } + catch + { + Write-Host $_.Exception.Message -ForegroundColor Red + $ImportCertificateError = $True + ShowAppDetails + CloseConnection + } + Write-Host "`nCertificate imported successfully" -ForegroundColor Green +} +Function UpdateCertficateDetails +{ + $GetAppInfo= Get-MgApplication -ApplicationId $APPObjectID -Property KeyCredentials + $Thumbprint=$Certificate.Thumbprint + $CertificateName=$Certificate.Subject + if($GetAppInfo -ne $null) + { + $NewKeys+=$GetAppInfo.KeyCredentials + UploadCertificate + # Get new certificate key credentials after updating new certificate + Start-Sleep -Milliseconds 10000 # Takes time to update certificate to an application + while(1) + { + $GetAppInfo= Get-MgApplication -ApplicationId $APPObjectID -Property KeyCredentials + if($GetAppInfo.KeyCredentials -eq $null) + { + Write-Host "The certificate is not yet uploaded to an application. Waiting for 3 seconds..." -ForegroundColor Yellow + Start-Sleep -Seconds 3 + Continue + } + break + } + $NewKeys+=$GetAppInfo.KeyCredentials #new keycredential + Update-MgApplication -ApplicationId $APPObjectID -KeyCredentials $NewKeys + } + else + { + Write-Host "The application does not exist. Please try again with a different name." -ForegroundColor Green + } +} +function UploadCertificate +{ + Write-Progress -Activity "Uploading certificate" + $KeyCredential = @{ + Type = "AsymmetricX509Cert"; + Usage = "Verify"; + key = $Certificate.RawData + } + Update-MgApplication -ApplicationId $APPObjectID -KeyCredentials $KeyCredential -ErrorAction SilentlyContinue -ErrorVariable ApplicationError + if($ApplicationError -ne $null) + { + Write-Host "$ApplicationError" -ForegroundColor Red + CloseConnection + } + Write-Host "`nCertificate uploaded successfully" -ForegroundColor Green + $Script:Thumbprint = $Certificate.Thumbprint +} +function SecureCertificate +{ + Write-Progress -Activity "Exporting pfx certificate" + $Script:CertificateLocation = Get-Location + $Script:CertificateLocation = "$CertificateLocation\$CertificateName.pfx" + $GetPassword = Read-Host "`nPlease enter password to secure your certificate" + try + { + $script:ExportError="False" + $MyPwd = ConvertTo-SecureString -String "$GetPassword" -Force -AsPlainText + Export-PfxCertificate -Cert "Cert:\CurrentUser\My\$Thumbprint" -FilePath "$CertificateLocation" -Password $MyPwd |Out-Null + } + catch + { + $script:ExportError="True" + Write-Host $_.Exception.Message -ForegroundColor Red + return + } + Write-Host "`nPfx file exported successfully" -ForegroundColor Green +} +function GrantPermission +{ + Write-Progress -Activity "Granting admin consent..." + Start-Sleep -Seconds 20 + $Script:ClientID = $App.AppId + $URL = "https://login.microsoftonline.com/$TenantID/adminconsent" + $Url="$URL`?client_id=$ClientID" + Write-Host "`nMS Graph requires admin consent to access data. Please grant access to the application" -ForegroundColor Cyan + While(1) + { + Add-Type -AssemblyName System.Windows.Forms + $script:mainForm = New-Object System.Windows.Forms.Form -Property @{ + Width = 680 + Height = 640 + } + $script:webBrowser = New-Object System.Windows.Forms.WebBrowser -Property @{ + Width = 680 + Height = 640 + URL = $URL + } + $document={ + if($webBrowser.Url -eq "$RedirectURI`?admin_consent=True&tenant=$TenantID" -or $webBrowser.Url -match "error") + { + $mainForm.Close() + } + if($webBrowser.DocumentText.Contains("We received a bad request")) + { + $mainForm.Close() + } + } + $webBrowser.ScriptErrorsSuppressed = $true + $webBrowser.Add_DocumentCompleted($document) + $mainForm.Controls.Add($webBrowser) + $mainForm.Add_Shown({ $mainForm.Activate() ;$mainForm.Refresh()}) + [void] $mainForm.ShowDialog() + if($webBrowser.Url.AbsoluteUri -eq "$RedirectURI`?admin_consent=True&tenant=$TenantID") + { + Write-Host "`nAdmin consent granted successfully" -ForegroundColor Green + break + } + else + { + Write-Host "`nAdmin consent failed." -ForegroundColor Red + $Confirm = Read-Host "Do you want to retry admin consent? [Y] Yes [N] No" + if($confirm -match "[yY]") + { + Continue + } + else + { + Write-Host "You can grant admin consent manually in azure portal." -ForegroundColor Yellow + break + } + } + } +} +Function ShowAppDetails +{ + Write-Host "`nApp info:" -ForegroundColor Magenta + $GetAppInfo = Get-MgApplication|?{$_.AppId -eq "$APPID"} + $Owner = Get-MgApplicationOwner -ApplicationId $GetAppInfo.Id|Select-Object -ExpandProperty AdditionalProperties + $Script:CertificateList = $GetAppInfo.KeyCredentials + $AppInfo=[pscustomobject]@{'App Name' = $GetAppInfo.DisplayName + 'Application(Client) Id' = $GetAppInfo.AppId + 'Object Id' = $GetAppInfo.Id + 'Tenant Id' = $TenantID + 'CertificateThumbprint' = $Thumbprint + 'App Created Date Time' = $GetAppInfo.CreatedDateTime + 'App Owner' = (@($Owner.displayName)| Out-String).Trim() + } + if($ImportCertificateError -eq $True) + { + $AppInfo | select 'App Name','Application(Client) Id','Object Id','Tenant Id','App Created Date Time','App Owner'|fl + Write-Host "You can copy & save" -NoNewline + Write-Host " Client Id" -ForegroundColor Cyan -NoNewline + Write-Host " and try again to add certificate to your application." + Return + } + if($Action -ne 5) + { + $AppInfo | select 'App Name','Application(Client) Id','Object Id','Tenant Id','CertificateThumbprint','App Created Date Time','App Owner'|fl + Write-Host "You can copy and save" -NoNewline + Write-Host " Client Id, Tenant Id, Certificate ThumbPrint" -ForegroundColor Cyan -NoNewline + Write-Host " as they will be required to connect to MS Graph PowerShell using certificate-based authentication." + } + else + { + $AppInfo | select 'App Name','Application(Client) Id','Object Id','Tenant Id','App Created Date Time','App Owner'|fl + Write-Host "App certificates :" + $CertificateList | Format-Table -Property DisplayName, KeyId, StartdateTime, EndDateTime + + } +} +Function RevokeCertificate +{ + Write-Progress -Activity "Revoking certificate" + $NewKeys = @() + $APPID = Read-Host "Enter an application ID(Client ID) you want to revoke the certificate for that app" + $GetAppInfo = Get-MgApplication |?{$_.AppId -eq "$APPID"} + if($GetAppInfo -ne $null) + { + ShowAppDetails + $KeyId=Read-Host "`nEnter the certificate key ID to revoke that certificate" + if($GetAppInfo.KeyCredentials.KeyId -notcontains($KeyId)) + { + Write-Host "Certificate not found" -ForegroundColor Red + CloseConnection + } + foreach($List in $CertificateList) + { + if($List.KeyId -eq "$KeyId") + { + continue + } + $NewKeys+=$List + } + Update-MgApplication -ApplicationId $GetAppInfo.Id -KeyCredentials $NewKeys + Write-Host "`nCertificate revoked successfully" -ForegroundColor Green + } + else + { + Write-Host "The application does not exist." -ForegroundColor Red + CloseConnection + } +} +Function ConnectApplication +{ + Write-Progress -Activity "Connecting MS Graph" + try + { + if($ParameterPassed -eq "False") + { + $TenantID = Read-Host "`nPlease provide the tenant ID of the application" + $ClientID = Read-Host "Please provide the client ID of the application" + While($true){ + $CertificatePath = Read-Host "Please provide certificate path(.cer or .pfx)" + $TestPath = Test-Path -Path $CertificatePath -PathType Leaf + if($TestPath -eq $false) + { + Write-Host "The certificate file could not be found." -ForegroundColor Red + Continue + } + } + $CheckExtension = (Get-ChildItem "$CertificatePath").Extension + if($CheckExtension -eq ".pfx") + { + $Password = Read-Host "Please enter password to import certificate" + $MyPwd = ConvertTo-SecureString -String "$Password" -Force -AsPlainText + $LoadCertificate = Import-PfxCertificate -FilePath $CertificatePath -CertStoreLocation "Cert:\CurrentUser\My" -Password $MyPwd + } + else + { + $LoadCertificate = Import-Certificate -FilePath "$CertificatePath" -CertStoreLocation "Cert:\CurrentUser\My" + } + $CertificateThumbprint = $LoadCertificate.Thumbprint + } + } + catch + { + Write-Host $_.Exception.Message -ForegroundColor Red + Exit + } + Connect-MgGraph -TenantId $TenantID -ClientId $ClientID -CertificateThumbprint $CertificateThumbprint -ErrorAction SilentlyContinue -ErrorVariable ApplicationConnectionError + if($ApplicationConnectionError -ne $null) + { + Write-Host $ApplicationConnectionError -ForegroundColor Red + Exit + } + + Get-MgContext +} +function CloseConnection +{ + Disconnect-MgGraph|Out-Null + Exit +} +$ParameterPassed="False" +if($TenantID -ne $null -and $ClientID -ne $null -and $CertificateThumbprint -ne $null) +{ + $ParameterPassed="True" + ConnectApplication + Exit +} +Write-Host "`nWe can perform below operations." -ForegroundColor Cyan +Write-Host " 1. Register an app with new certificate" -ForegroundColor Yellow -NoNewline +Write-Host " (Creates application - >Adds new certificate -> Grants admin consent -> Exports certificate)" -ForegroundColor White +Write-Host " 2. Register an app with existing certificate" -ForegroundColor Yellow -NoNewline +Write-Host " (Creates application -> Adds existing certificate -> Grants admin consent)" -ForegroundColor White +Write-Host " 3. Add certificate to an existing application" -ForegroundColor Yellow +Write-Host " 4. Connect MgGraph" -ForegroundColor Yellow +Write-Host " 5. Revoke certificate" -ForegroundColor Yellow +$Action=Read-Host "`nPlease choose the action to continue" +switch($Action){ + 1 { + Write-Host "`nConnecting to MS Graph to create a application..." + ConnectMgGraphModule + RegisterApplication + CertificateCreation + UploadCertificate + SecureCertificate + GrantPermission + ShowAppDetails + if($ExportError -ne "True") + { + Write-Host "`nYour Pfx certificate is available in $CertificateLocation" -ForegroundColor Green + } + break + + } + 2 { + Write-Host "`nConnecting to MS Graph to create a application.." + ConnectMgGraphModule + RegisterApplication + ImportCertificate + UploadCertificate + GrantPermission + ShowAppDetails + break + } + 3 { + ConnectMgGraphModule + $APPID = Read-Host "Enter the application id(Client id) of the app:" + $AppInfo = Get-MgApplication |?{$_.AppId -eq "$APPID"} + if($AppInfo -eq $null) + { + Write-Host "Application not found." -ForegroundColor Red + CloseConnection + } + $AppName = $AppInfo.DisplayName + $APPObjectID =$AppInfo.Id + $confirm= Read-Host Are you sure you want to create new certificate? [Y] Yes [N] No. Select '"No"' to import existing certificate. + if($confirm -match "[yY]") + { + CertificateCreation + } + else + { + ImportCertificate + } + UpdateCertficateDetails + ShowAppDetails + break + } + 4 { + ConnectApplication + Exit + } + 5 { + ConnectMgGraphModule + RevokeCertificate + break + } + Default { + Write-Host "No Action Found" -ForegroundColor Red + Exit + } +} +CloseConnection \ No newline at end of file