Unable to get current cost of subscription using Azure Runbook - azure

I am trying to get the subscription current cost using azure runbook but a 'Bad Request' error is displayed. The same script is working fine on my local machine.
FYI: I updated the Az.Accounts and Az.Billing modules in the Runbook gallery.
Powershell:
Write-Host "Get the subscription current billing period"
$currentBillingPeriod = Get-AzBillingPeriod -MaxCount 1
$startDate = $currentBillingPeriod.BillingPeriodStartDate.ToString("dd-MM-yyyy")
Write-Host "currentBillingPeriod startDate : " $startDate
$endDate = $currentBillingPeriod.BillingPeriodEndDate.ToString("dd-MM-yyyy")
Write-Host "currentBillingPeriod endDate : " $endDate
Write-Host "Get the subscription current cost"
$currentCost = Get-AzConsumptionUsageDetail -StartDate $startDate -EndDate $endDate | Measure-Object -Property PretaxCost -Sum
Write-Host "Current Cost of Subscription : " $currentCost.Sum
Output on local powershell:
Get the subscription current billing period
currentBillingPeriod startDate : 11-08-2021
currentBillingPeriod endDate : 10-09-2021
Get the subscription current cost
Current Cost of Subscription : 497.729683916108
Output when run on Azure Runbook:
Get-AzConsumptionUsageDetail : Operation returned an invalid status code 'BadRequest' At line:44 char:16 + ... rrentCost = Get-AzConsumptionUsageDetail -StartDate $startDate -EndDa ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Get-AzConsumptionUsageDetail], ErrorResponseException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Consumption.Cmdlets.UsageDetails.GetAzureRmConsumptionUsageDetail
Debug Output:
Body:
{
"error": {
"code": "400",
"message": "Invalid time range, start: 2021-11-08 end: 2021-10-09 (Request ID: dc5f1cc4-4361-4378-adfd-0b9065ecbce3)"
}
}
Get-AzConsumptionUsageDetail : A command that prompts the user failed because the host program or the command type does not support user interaction. The host was attempting to request confirmation with the following message: A command that prompts the user failed because the host program or the command type does not support user interaction. The host was attempting to request confirmation with the following message: Operation returned an invalid status code 'BadRequest' At line:44 char:16 + ... rrentCost = Get-AzConsumptionUsageDetail -StartDate $startDate -EndDa ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotImplemented: (:) [Get-AzConsumptionUsageDetail], HostException + FullyQualifiedErrorId : HostFunctionNotImplemented,Microsoft.Azure.Commands.Consumption.Cmdlets.UsageDetails.GetAzureRmConsumptionUsageDetail

Finally able to resolve this issue. Actually, i am passing date format in ("dd-MM-yyyy") for 'BillingPeriodStartDate' and 'BillingPeriodEndDate'.
The date format should be ("yyyy-MM-dd")
$startDate = $currentBillingPeriod.BillingPeriodStartDate.ToString("yyyy-MM-dd")
$endDate = $currentBillingPeriod.BillingPeriodEndDate.ToString("yyyy-MM-dd")
I don't know why it is correctly working with ("dd-MM-yyyy") format in my local machine. After using ("yyyy-MM-dd") format, It is working on both local and Azure runbook.
Debug logs really help me to find out the exact problem.

Related

Powershell to Stop Azure backups

So i'm running into a Bad Request error using the Stop-AzRecoveryServicesBackupJob powershell command. The documentation isn't helpfull as it only requires -JobID $Job.InstanceId as a parameter. BUT, InstanceId doesn't exist. JobID does, but returns the bad request error.
My code: The bad request is on Stop-AzRecoveryServicesBackupJob -JobID $BackupJob.JobId
#get RSV
$myVault = Get-AzRecoveryServicesVault -ResourceGroupName $myResourceGroup -Name $vaultName
#Disable soft delete on RSV
$myVault.ID | Set-AzRecoveryServicesVaultProperty -SoftDeleteFeatureState Disable | Out-Null
$BackupJob = $myVault.ID | Get-AzRecoveryServicesBackupJob -Operation Backup
Stop-AzRecoveryServicesBackupJob -JobID $BackupJob.JobId
Error msg:
Stop-AzRecoveryServicesBackupJob : Cannot cancel the job. Only in progress jobs can be cancelled. Please attempt cancellation only on an in progress job.
At C:\Users\azureuser\Documents\WindowsPowerShell\temp.ps1:20 char:1
Stop-AzRecoveryServicesBackupJob -Job $BackupJob
+ CategoryInfo : InvalidOperation: (:) [Stop-AzRecoveryServicesBackupJob], CloudException
+ FullyQualifiedErrorId : BMSUserErrorJobNotInProgressToCancel,Microsoft.Azure.Commands.RecoveryServices.Backup.Cmdlets.StopAzureRmRecoveryServicesBackupJo
b
So following up on the "In Progress Job" Stop-AzRecoveryServicesBackupJob will only stop the job while it is in progress. If you want to stop the backup of jobs that aren't currently in progress you need to use Disable-AzRecoveryServicesBackupProtection. No exactly self explanitory.
correct code :
$Cont = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVM -Status Registered
$PI = Get-AzRecoveryServicesBackupItem -Container $Cont[0] -WorkloadType AzureVM
Disable-AzRecoveryServicesBackupProtection -Item $PI[0]
This will change the status to disabled. (Even though the choice manually is "Stop Backup") 🤷‍♂️

Handling connection errors when connecting to Azure using Connect-AzAccount

I've written a runbook Powershell script. However I am having issues catching any errors I receive using the Connect-AzAccount command. It seems that wrapping the Connect-AzAccount in a try catch does not work. The script continues. How can I handle the errors returned using this command?
try
{
The catch is never executed even when there is an error
Connect-AzAccount -Identity;
}
catch
{
write-output "Error connecting to Azure";
write-output $_.Exception.message;
$response = .\SendEmail.ps1 -To "xxx#xxx.com" -From "xxx#xxx" -Subject "xxxx" -Message "xxxxx";
}
The error message below is rendered to the console automatically
Unable to acquire token for tenant 'organizations'
Connect-AzAccount : ManagedIdentityCredential authentication unavailable. The requested identity has not been assigned
to this resource.
Status: 400 (Bad Request)
Content:
{"error":"invalid_request","error_description":"Identity not found"}
Headers:
Content-Length: xx
Content-Type: xxxxx
Date: xxxxx
Server: xxxx/xxxxxxxxxx
At line:71 char:5
+ Connect-AzAccount -Identity;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Connect-AzAccount], CredentialUnavailableException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand
As far as I know in order for the catch to be executed, you should include -ErrorAction Stop.
So your code should read:
Connect-AzAccount -Identity -ErrorAction Stop
You could also set:
$ErrorActionPreference = "Stop" at the top of your cmdlet.

Failed when running powershell code in azure automation

I set an azure policy adding two tags, which are CreatedTime and Type.
The value of CreatedTime is utcNow(), which default format is 'yyyy-MM-ddTHH:mm:ss.fffffffZ'.
My goal is to delete all resources whose Type is private and created time is longer than 2 days by running powershell code in azure automation.
I have done it in power shell locally, but when I run the code in automation, it failed. I will post the code and the error page below.
Anybody can tell me what's wrong with my code? Or I miss something?
This is my code in Azure Automation:
$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
}
}
$AllRes = (get-AzureRMResource).ResourceId
$TimeOutDays=2
foreach ($Res in $AllRes){
$Resource = Get-AzureRMResource -ResourceId $Res
$Tags=$Resource.Tags
$TypeInTags=$Tags['Type']
$CreatedTimeInTags=$Tags['CreatedTime']
try{
$CreatedTime=[Datetime]::ParseExact($CreatedTimeInTags, 'MM/dd/yyyy HH:mm:ss', $null)
}
catch{
$CreatedTime=[Datetime]::ParseExact($CreatedTimeInTags, 'yyyy-MM-ddTHH:mm:ss.fffffffZ', $null)
}
finally
{
$CreatedTime
}
$daypan=((get-date)-$CreatedTime).Days
if($TypeInTags -eq 'private')
{
if($daypan -gt $TimeOutDays)
{
$daypan
Remove-AzureRMResource -ResourceId $Res -Force
}
}
}
This is the error page:
Suspended
The runbook job was attempted 3 times, but it failed each time. Common reasons that runbook jobs fail can be found here: https://learn.microsoft.com/en-us/azure/automation/automation-troubleshooting-automation-errors
A piece of error message:
Get-AzureRMResource : ResourceNotFound : The Resource
'microsoft.alertsmanagement/smartDetectorAlertRules/Failure+Anomalies+-+arrowbottest2-config' under resource group
'arrowbot2' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix
At line:28 char:17
+ $Resource = Get-AzureRMResource -ResourceId $Res
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzureRmResource], ErrorResponseMessageException
+ FullyQualifiedErrorId :
ResourceNotFound,Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.GetAzureResourceCmdlet
Exception calling "ParseExact" with "3" argument(s): "String was not recognized as a valid DateTime."
At line:34 char:5
+ $CreatedTime=[Datetime]::ParseExact($Tags['CreatedTime'], 'yyyy-M ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
Cannot find an overload for "op_Subtraction" and the argument count: "2".
At line:35 char:5
+ $daypan=((get-date)-$CreatedTime).Days
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Cannot find an overload for "op_Subtraction" and the argument count: "2".
At line:35 char:5
+ $daypan=((get-date)-$CreatedTime).Days
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Exception calling "ParseExact" with "3" argument(s): "String was not recognized as a valid DateTime."
At line:34 char:5
+ $CreatedTime=[Datetime]::ParseExact($Tags['CreatedTime'], 'yyyy-M ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
For the type of $Tags['CreatedTime'], I did this for a test: $Tags['CreatedTime'].GetType().FullName.
Since you say The value of CreatedTime is utcNow(), then that value is already a DateTime object and you should not treat it as string. (you think it is a string, because when you write it out to console, it will show its ToString() representation)
Simply do
$CreatedTime=$Tags['CreatedTime']
You can test this with a write-host $Tags['CreatedTime'].GetType().FullName
There are two things wrong.
1.Didn't specify the resource I need.
Detailes:
That's the reason for the error message: Can not index to a null array. I traverse the entire resource in my subscription, but the
resources created before I set the policy do not have a Tag named
"CreatedTime" or "Type", so when I run $Tags=$Resource.Tags, it
said Can not index to a null array.
My solution:
Do $AllRes = (get-AzResource -TagName "CreatedTime").ResourceId other than $AllRes = (get-AzureRMResource).ResourceId.
I found that AzureRM module don't
recognize -TagName as a variable, so I import the Az module and
change every AzureRM module to Az module.
2.Confused with utcNow().
Details:
As I said, with utcNow() function I get a DateTime object with default
format 'yyyy-MM-ddTHH:mm:ss.fffffffZ', after testing a lot,
I found some special resources like application insight' tag value is
not formated with 'yyyy-MM-ddTHH:mm:ss.fffffffZ', and when I call
it, it comes to a string.
My solution:
So when I use it comparing to get-date, I
need to do two things:
(1)Change the string to DateTime object;
(2)Use try-catch to meet two kinds of formats.

getting "Bad Request" error in powershell while transferring the nsg flow log to the storage account in different subscription in azure

I am getting "Bad Request" error while transferring the nsg flow log to the storage account in different subscription. My script is working fine while using the storage account of same subscription.
$workspaceResourceId = "/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxx/resourcegroups/rg-log-mgmt-prd-westeurope-01/providers/microsoft.operationalinsights/workspaces/nbsapucscoms"
$workspaceGUID = "xxxxxxxxxxxxxxxxxx"
$workspaceLocation = "westeurope"
$n = Get-AzureRmNetworkSecurityGroup -ResourceGroupName rg-8kmiles-dfi-westeurope-01 -Name apitst-nsg
$NwName = 'NetworkWatcher_' + $n.Location
$NW = Get-AzureRmNetworkWatcher -ResourceGroupName NetworkWatcherRg -Name $NwName
#enter the storage account details.
$storageAccount="/subscriptions/xxxxxxxxxxxxxxx/resourceGroups/rg-log-mgmt-prd-westeurope-01/providers/Microsoft.Storage/storageAccounts/nvsswelogmgmt001"
$flowLogStatus=Get-AzureRmNetworkWatcherFlowLogStatus -NetworkWatcher $NW -TargetResourceId $n.Id
if($false -eq $flowLogStatus.Enabled){
#Configure Version 2 FLow Logs with Traffic Analytics Configured
Set-AzureRmNetworkWatcherConfigFlowLog -NetworkWatcher $NW -TargetResourceId $n.Id `
-StorageAccountId $storageAccount -EnableFlowLog $true -EnableTrafficAnalytics `
-WorkspaceResourceId $workspaceResourceId -WorkspaceGUID $workspaceGUID `
-WorkspaceLocation $workspaceLocation -EnableRetention $true -RetentionInDays 365
#Query Flow Log Status
$flowLogStatus=Get-AzureRmNetworkWatcherFlowLogStatus -NetworkWatcher $NW -TargetResourceId $n.Id
write-verbose "$($n.Name) Nsg Flow Log Enabled : $($flowLogStatus.Enabled)" -verbose
}
The error which i am getting is this
Set-AzureRmNetworkWatcherConfigFlowLog : Operation returned an invalid status
code 'BadRequest'
At C:\Users\singhniu\Desktop\Pipeline\TestNsgFlowLog.ps1:22 char:5
+ Set-AzureRmNetworkWatcherConfigFlowLog -NetworkWatcher $NW -Targe ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzureRmNetworkWatcherConfig
FlowLog], ErrorResponseException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Network.SetAzureNetwork
WatcherConfigFlowLogCommand
after debugging i came to know that i was using V1 storage account which does not support retention. for retention policy to be applied we need to upgrade it to V2.
bellow is the output after debugging.
Body:
{
"error": {
"code": "UnsupportedStorageAccountVersionWithRetention",
"message": "Storage /subscriptions/xxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/rg-lo
g-mgmt-prd-westeurope-01/providers/Microsoft.Storage/storageAccounts/nvss is a V1 st
orage account and with retention policy. Only V2 storage account are supported with retention po
licy. Read more -> aka.ms/LogsHelp",
"details": []
}
}

Is there someone can tell me how to fix the Error "The remote server returned an error: (409) Conflict."

I use Automation Runbook to create the Azure Files' snapshot. And I get one error
Exception calling "Snapshot" with "0" argument(s): "The remote server returned an error: (409) Conflict." At line:3 char:1 + $snapshot = $share.Snapshot() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : StorageException,
but it was not consistent.
I use the runbook to create the Azure Files snapshots. At first, it can work well, but recently there have some errors of "The remote server returned an error: (409) Conflict."
I use the code as below to create the snapshots everyday.
$context = New-AzureStorageContext -StorageAccountName "storage" -StorageAccountKey "********"
$share = Get-AzureStorageShare -Context $context -Name "test"
$snapshot = $share.Snapshot()
I want to fix the error.
Exception calling "Snapshot" with "0" argument(s): "The remote server returned an error: (409) Conflict." At line:3 char:1 + $snapshot = $share.Snapshot() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : StorageException
As per discussed with Arthur, we try to use try-catch as a workaround since we didnot figure out the root cause.
when the create snapshot operation fails, then we can retry more times(like 3 times). The sample code like below:
$RetryIntervalInSeconds = 10
$NumberOfRetryAttempts = 2
$CmdOk = $False
do{
try{ *the code I using now $CmdOk = $True}
catch{ * the error I met $NumberOfRetryAttempts-- Start-Sleep -Seconds $RetryIntervalInSeconds }
}
while (-not $CmdOk -and $NumberOfRetryAttempts -ge 0)

Resources