I'd like to use a powershell script in Azure automation to schedule switching on/off resources.
I'd like to do this without creating an account as our domain enforces password resets. I know that the automation account creates a certificate - is it possible to authenticate with this instead, when using the resource manager (AKA not a "classic" account).
Yes, this is a valid approach, in fact if you create an Azure Automation account and use the defaults it will create that for you and you can use that transparently. Taken from example runbook:
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
dozen edits because my brain stopped working
Related
I am trying to make a code using PowerShell so that secrets are not hardcoded on my runbook so that it will not be exposed in the script. I created encrypted variables in my automation account. These variables are AppID, AppSecret and TenantID.
This is the part of the script to login automatically to Azure. I didn't use managed identity for some compatibility reasons with the script.
My script is running fine when secrets and IDs are hardcoded but when I created variables it is not working. Error message is "Run Connect-AzAccount". Below is my code. Need help on how to correct this. Thank you in advance.
$AzVariableApplicationID = 'AppID'
$AzVariableAppSecret = 'AppSecret'
$AzVariableTenantID = 'TenantID'
$AppID = Get-AzAutomationVariable -Name $AzVariableApplicationID
$AppSecret = Get-AzAutomationVariable -Name $AzVariableAppSecret
$TenantID = Get-AzAutomationVariable -Name $AzVariableTenantID
$SecureSecret = $AppSecret | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList $AppID, $SecureSecret
Connect-AzAccount -ServicePrincipal -Credential $Credential -Tenant $TenantID
As described in PsCustom Object - Hitchikers GUID(e) to Automation
, It is not possible to retrieve values for encrypted variables as they’re available within the runbook at runtime via the Get-AutomationVariable cmdlet
I found an alternative approach to "Connect Azure" by using "Certificate-based authentication" inside PowerShell runbook without hardcoding the values:
Created a new Service principal and provided the "Owner" role access to avoid any restrictions.
To authenticate via service principal, I create a new self-signed certificate with the command:
$cert=New-SelfSignedCertificate -Subject "CN=xxxxxCert" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature
Upload a certificate under Certifications & Secrets:
Click windows + R to open the run box and give certmgr.msc as shown here.
Export a certificate without private key.
Upload a certificate in the below path:
AzureAD -> App registrations -> Serviceprincipal
Now, I have exported the same certificate with key and uploaded inside my automation account to authenticate Service principal connection:
Added an "Azure Service Principal" connection inside automation accounts by providing "ApplicationID, TenantID, Certificate Thumbprint" of my Service principal as shown:
Inside PowerShell runbook, I ran the below script that works for me:
$connectionName = "serviceprincipalname"
try
{
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRMAccount
-ServicePrincipal `
-TenantID $servicePrincipalConnection.TenantID `
-ApplicationID $servicePrincipalConnection.applicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found. "
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Logged in to Azure:
Register an App in App registrations and create a service principal in AzureAD
Unable to assign role to user using New-AzureRmRoleAssignment command. When I run the above command its thronging an error as follows .
New-AzureRmRoleAssignment : Object reference not set to an instance of an object.
Can any one help to resole the issue.
To assign role to user successfully in the runbook, follow the steps below.
Note : The New-AzureRmRoleAssignment you used belongs to the old AzureRM, it was deprecated and will not be updated anymore. In my sample, I use the new Az command New-AzRoleAssignment, I also recommend you to use it.
1.Navigate to the subscription in the portal(you need to be Owner/User Access Administrator in the subscription) -> add the service principal of your automation RunAs account as an Owner/User Access Administrator(by default it will be added as Contributor when it was created, but Contributor have no permission to run New-AzRoleAssignment).
2.Navigate to the Azure Active Directory in the portal -> App registrations -> find the AD App of your RunAs Account and add the Directory.Read.All application permission in Azure Active Directory Graph(Not Microsoft Graph) like below, don't forget to click the Grant admin consent for xxx button at last(you need to be the admin role in your AAD tenant). The permission may take about 30 min to take effect.
3.Navigate to the automation account in the portal -> Modules -> make sure you have installed the Az.Accounts, Az.Resources modules, if not, go to Browse Gallery, search for the names, and install them.
4.Then in the runbook, use the script below, it works fine on my side. In my sample, I add the user as a Reader in the resource group joyRG, you can change it, it depends on your requirement.
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$user = Get-AzADUser -UserPrincipalName joyw2#xxxx.onmicrosoft.com
New-AzRoleAssignment -ObjectId $user.id -ResourceGroupName joyRG -RoleDefinitionName Reader
The following code works great via Azure Cloud Shell (completes, App Service deleted as expected).
Remove-AzWebApp -ResourceGroupName "ResourceGroup1" -Name "AppService1" -Force
It also completes without error within my Runbook workflow, but the App Service remains operational. This feels like a permissions problem, but I've tried adding the Owner role at the subscription level without success.
Any ideas/tips for how to make this work for the AzureRunAsConnection account?
This feels like a permissions problem, but I've tried adding the Owner role at the subscription level without success.
It is not a permission problem, when you create the automation account along with the RunAsAccount, it will add the service principal related to the RunAsAccount to the subscription as a Contributor role, which is enough to remove the web app.
If you are using the PowerShell Workflow Runbook, try the sample below, it works for me. (First, make sure you have installed the Az.Accounts, Az.Websites modules in the automation account -> Modules.)
workflow testrun3
{
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Remove-AzWebApp -ResourceGroupName "<group-name>" -Name "joywebapp1234" -Force
}
Check the result in the portal:
To create or update a Run As account, you must have specific privileges and permissions. An Application administrator in Azure Active Directory and an Owner in a subscription can complete all the tasks. Use Remove-AzAutomationConnection to remove an Automation connection.
For more details, you could refer to this article about Run As account permissions.
I am using Automation Account with execution of PowerShell Runbook for Pausing my Azure Datawarehouse database.
Setup is completed with creation of crendentials, certificate for Thumbprints.
When I executed the PS script and completed with error message
No Azure SQL Data Warehouse named ADWPOC exist on SQL Server At SuspendOrPauseAzureSQLDataWarehouse:72 char:72 + + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
I have provided the name of database and server details correctly while executing this script. I am not sure what is the problem here. Please advise.
I have imported the PS script from runbook gallery "Suspend Or Pause Azure SQL Data Warehouse". Please let me know if you want me to attach the script here?
Not sure, but the script looks too old, it still uses the AzureRm module which has been deprecated.
To pause the data warehouse in the runbook, I recommend you to use new Az module, sample here, to use that in runbook, just follow the steps as below.
1.Navigate to your automation account in the portal -> Modules, make sure you have imported the Az.Accounts and Az.Sql modules, if not, in the Modules -> Browse Gallery, search for the modules and import them.
2.After importing the modules successfully, navigate to the Runbooks -> create a PowerShell runbook(not the PowerShell Workflow), then use the script as below in the runbook.
Note: The <server-name> should be like testserver, not testserver.database.windows.net.
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$database = Get-AzSqlDatabase –ResourceGroupName "<resource-group-name>" –ServerName "<server-name>" –DatabaseName "<data-warehouse-name>"
if($database){
if($database.Status -eq 'Paused'){
Write-Output "The Data Warehouse was already paused."
}else{
$database | Suspend-AzSqlDatabase
Write-Output "The Data Warehouse has been paused."
}
}else{
Write-Output "The Data Warehouse does not exist."
}
Simply, I'm running Connect-AzureRmAccount using runbook automation in Azure, it gives me the error below:
Unable to find an entry point named 'GetPerAdapterInfo' in DLL
'iphlpapi.dll'.
I already imported the Azureprofile module and I can not figure out what is the issue.
If you want to connect to the Azure account with the PowerShell command Connect-AzureRmAccount in your Runbook, then it is really unnecessary. Just as I said in the comment, when you use the Runbook, you are already in an exact subscription of the tenant with an account. So just run your script without connecting the account.
If you really want to connect with the PowerShell, you can use the service principal like this:
Disable-AzureRmContextAutosave –Scope Process
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzureRmAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationID $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
But I really suggest you can just run the PowerShell script in your Runbook directly.
Update
When you create the Runbook, there will be a connection for you to run the PowerShell script. Or you can create the connection as your requirement. See Connection assets in Azure Automation. You could just use the default connection use the code like this:
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
I had the same problem, in my case I was trying to simply use the Azure Cmdlet Get-AzVm.
I previously used code similar to what Charles posted above, the problem is that doesn't work with the Az Cmdlets as you can't use both the AzureRM and the new Azure modules at the same time.
I replaced all of that with the following and now it works:
Disable-AzContextAutosave –Scope Process
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID `
-ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
$AzureContext = Select-AzSubscription -SubscriptionId $Conn.SubscriptionID
I found this in the following article: https://learn.microsoft.com/en-us/azure/automation/automation-first-runbook-textual