Showing posts with label Azure. Show all posts
Showing posts with label Azure. Show all posts

Tuesday, June 11, 2024

Connect to Azure (Connect-AzAccount / Connect-PnPOnline) using certificate from Azure Automation or KeyVault

Situation: You want to connect to Azure using a certificate file (typically a PFX file) in a PowerShell script, especially in an unattended scenario (e.g. Azure Automation) or a multi-tenant environment.

Problem: Connect-AzAccount (and Connect-PnPOnline and other cmdlets) don't yet (as of 2026-06-29) allow the use of x509 certificate objects, only a CertificatePath that you must specify to a local store OR a CertificateThumbprint that indicates that you installed the certificate on the local computer. AND you don't want to use a managed identity for an entire Automation Account or similar.

Resolution: You can use PowerShell commands to perform the following steps to make it work -

  1. Get the Certificate file and a credential of some sort (usually a service principal involved in the process anyway)
  2. Export as password-encoded certificate PFX file to a temp folder on the local machine (this works on Automation workers as well)
  3. Connect to AzAccounts using the temp path and the password.
You can view my commands below as they aren't a full script and thus not in my github. My scenario is to use Azure Automation's Certificates and its Credentials section to store a service principal account password securely, the Cert securely, and leverage the Credential password to secure the file, disconnect from the automatic Automation Az connection, and connect with the certificate. This is all done within a Runbook. If you needed to do this from a KeyVault, then you would need to obtain the Certificate from the Vault and include the private key in the particular x509 object you retrieve:

$Credential = Get-AutomationPSCredential -Name "MyServicePrincipal"
$Tenant = "YOURTENANTGUIDGOESHERE"
$ApplicationId = "YOURAPPLICATIONIDGOESHERE"

#Prep azure connection by getting cert, exporting to local temp file securely, then using for Az connection
$Cert = Get-AutomationCertificate -Name 'MyAppCertificate'
$CertTempPath = "$env:TEMP\temp.pfx" #You can name it dynamically if you like

try {
    $PfxCert = $Cert.Export(3,$($Credential.GetNetworkCredential().Password))
} catch {
    $Msg = "Error exporting cert - $_"
    Write-Error -Message $Msg
    Disconnect-AzAccount *> $null
    throw $Msg
}
if (Test-Path $CertTempPath) {
    Remove-Item -Path $CertTempPath
}
try {
Set-Content -Value $PfxCert -Path $CertTempPath -Encoding Byte #<-- PS 5.1
    #Set-Content -Value $pfxCert -Path $certTempPath -AsByteStream #<-- PS 6+
} catch {
    $Msg = "Error setting content - $_"
    Write-Error -Message $Msg
    Disconnect-AzAccount *> $null
    throw $Msg
}
try {
    $CertArgs = @{
        CertificatePath = $certTempPath
        CertificatePassword = $Credential.Password
        Tenant = $Tenant
        ApplicationId = $ApplicationId
    }
} catch {
    Write-Error -Message "Unable to get Automation Cert info - $($_.exception.message)";
    Disconnect-AzAccount *> $null
    throw
}
try {
    Disconnect-AzAccount *> Out-Null
    Write-Output -InputObject "Disconnected from Az. Connecting using $($Credential.UserName)..."
    $context = Connect-AzAccount @CertArgs -ErrorAction Stop
    Write-Output -InputObject "Done"
} catch {
    Disconnect-AzAccount *> Out-Null
    throw "Unable to connect to AzAccount using supplied Credential"
} #DO STUFF HERE LIKE GET-AZADUSER OR SOMETHING Disconnect-AzAccount *> Out-Null #Always close out your sessions properly Remove-Item -Path $CertTempPath #Remove the PFX file so it is unobtainable

Thursday, April 11, 2019

Getting around the 50k/250k limit for Azure / O365 Groups in Azure AD Sync

Problem: A giant group in your on-premises Active Directory does not sync through Azure Active Directory Sync

Source: Azure / O365 has a limit in the Azure / Entra AD Connect Sync (AAD Sync) such that it ignores groups that are over 50k/250k (depends on your version and which portion of Azure is processing groups as to their maximum size) - I even found groups really close to this limit acted weird

Resolution: Script a solution that will take your on-prem group and create mirror groups with a maximum number of users in each so that all the miniature groups will sync and auto-add/remove users from the mirror groups, and you can use these groups in Azure.

Update 2019-06-17 - I have moved this script to a github repository to make updates easier. DO NOT WORRY - it is not some crazy-looking developer page...just a list of scripts from this site. Here is the url to my repository: https://github.com/hornerit/powershell/blob/master/ActiveDirectory-SplitAndSyncGroups-Public.ps1

Azure CloudShell - Store Scripts Centrally for your Team

Problem: Cannot find or run scripts from Azure Cloud Shell that are centrally managed

Source: Azure Cloud Shell uses a secure linux vm with Powershell Core running on it and that shell has no access to any local resources (aka your file server) and you really can't connect to a git repo made by one of those fancy developers in your area - though you can clone one every time you open your cloud shell if that helps and may be good for their source control...I'm a sysadmin, I don't really get the git mantra except for backups. Also, many of your IT workers may attempt to access secure resources on insecure devices (aka their random personal tablet since you called them on a saturday and they don't want to VPN in using a laptop).

Resolution:

Assuming you have an AD group or Azure/O365 group that has your team members in it like we did:

  1. Log into portal.azure.com with permissions to create stuff in your subscription
  2. Create a Resource Group for your team in the same location as your subscription
  3. Grant Reader permissions for the team to the Resource Group (use the IAM menu option to grant this)
  4. Create a storage account with the cheapest settings possible (see below)
    1. Set the Resource Group to the one you created for your team in step 2
    2. Give it a nice, short, simple name for the Storage Account Name
    3. Set the location to the same location as your resource group (NOTE: I had problems with East US 2; if your subscription is in East US 2, choose US EAST for this)
    4. Set Performance to Standard
    5. Leave Account kind for StorageV2 (general purpose v2)
    6. Set Replication to Locally Redundant Storage (LRS) if possible, it's the cheapest
    7. Set Access Tier to Cool
    8. Use the Review and Create button and create the resource...this will take a minute
  5. Once the storage account is created, navigate to the Storage Account, and grant "Reader and Data Access" for your team
    • If you receive errors about an unauthorized header, close your browser and re-login to Azure portal
  6. Inside the storage account, click Files and create a file share, call it something like "share", don't set a quota - every new user that accesses CloudShell and creates a profile will commit 5gb to this share so there's really no point in trying to limit unless you are scared of the hackers
  7. Click the "share" share so that it opens and click "Upload" and upload scripts and other resources here for your team
To access these resources, you need to have your each member on your team open a new Cloud Shell and, hopefully, they've never used this before. If they have, you will need to have them use a command to mount this new storage instead of their original storage (clouddrive mount -s SUBSCRIPTIONGUID -g "YOURRESOURCEGROUPNAME" -n "YOURSTORAGEACCOUNTNAME" -f "YOURSHARENAME")...beware, they may want to backup their stuff before they switch storage like that:

  1. Click the Cloud Shell button immediately to the right of the search bar in Azure Portal
  2. Click PowerShell as the language (you can change this later if you like)
  3. Click Advanced Settings on the right
  4. Make sure the settings all match what you have made (you may have to manually type the Share name)
  5. Click Connect/Yes/whatever allows it to go
Now that it is connected (you can verify if you use the Get-Clouddrive command and it gives you useful information), you can access those shared resources by typing this:
cd $HOME/clouddrive
Now your PowerShell window is located in the main directory of the share...you can use dir to list the contents and even use tab completion to load your script name and it'll work. One downside: you cannot access local resources (e.g. local Active Directory or modules) when the script is accessed within cloud shell (you can actually map it as a network drive). The best way to handle this situation is to create a Hybrid Runbook Worker so that you can create Runbooks (aka scripts) and use the scripts stored in your shared location to call the runbooks and specify that they run on the Hybrid Runbook Worker.