I want to retrieve the creator of a virtual machine under Azure using azure rm powershell cmdlt or an api whitxh could return this type of information.
I used the "Get-AzureRmVM" command and the "GET https://management.azure.com/subscriptions/subscriptionId/resourceGroups/resourceGroupName/providers/Microsoft.Compute/virtualMachines/vmName?api-version=2018-06-01" api but both of them don't return information about the creator of the VM
You can use the Get-AzLog command to look for the caller value in the Azure Activity logs.
Examples can be found here:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-audit#powershell
You can also set up alerts in Azure Monitoring that can send you an email or text message everytime a VM is created.
https://learn.microsoft.com/en-us/azure/azure-monitor/platform/alerts-overview
Example
# Requires the AZ module be installed on your machine. You can get this by running Install-Module 'AZ'
Connect-AzAccount # after calling this a browser window opens, allowing you to log into Azure through the UI under the relevant credentials; on successful login the token for this session is returned to your PowerShell session
# Sets your scope to the subscription you're interested in
Set-AzContext -Subscription 'myAzSubscription'
# Fetches (successful) events in the past 2 weeks
# Filters for those related to VM write events (which includes creating VMs, though sadly we can't just VM creations)
# groups by resource id (i.e. VM).
# Note: The Get-AzLog function can return a maximum of 100,000 events (and this count is based on the filters provided as parameters; filters applied to the results of the cmdlet won't impact this limit), so if things have been particularly busy some of the log may be truncated. If that's a common issue for you, try narrowing the event's time window or restricting queries to specific resource groups.
$events = Get-AzLog -StartTime ((Get-Date).AddDays(-14)) -ResourceProvider 'Microsoft.Compute' -Status 'Succeeded' -MaxRecord 100000 |
Where-Object {$_.Authorization.Action -eq 'Microsoft.Compute/virtualMachines/write'} |
Group-Object -Property #{E={$_.Authorization.Scope}}
# For each VM get the first event with a human caller (i.e. ignore system generated events) and return that caller's name. Filter out events that didn't have a human caller as irrelevant
$events |
Select-Object Name, #{N='InitiatedBy'; E = {
$_.Group |
Sort-Object SubmissionTimestamp |
Select-Object -ExpandProperty 'caller' |
Where-Object{$_ -like '*#*'} |
Select-Object -First 1
} } |
Where-Object InitiatedBy |
Format-Table -AutoSize
This information is not exposed in Azure API (unfortunately). Your only option is to take a look at activity logs of the resource and find the very first write operation to the resource, unfortunately resources do not expose creation time either, so you cannot be sure you will find proper creator, because activity logs only go back 90 days.
Related
I want to receive a notification when there is an Azure database running that matches a defined name pattern. What script can I use to check for existence of a database by name pattern?
For example when are debugging live issues we will often use the Copy feature from Azure to back up our production database onto a dev server. The databases are always named with a *_copy suffix. Occasionally we forget to delete these databases when we are finished with them, so they continue to be billed.
We would like a daily notification if there are any running *_copy databases running.
The script below will give you a list of databases with "copy" at the end of the name. Put it inside a Runbook to send you a daily report of the databases.
$ListServers = Get-AzSqlServer | Select-Object ResourceGroupName, ServerName
Foreach ($Server in $ListServers){
Get-AzSqlDatabase -ResourceGroupName $Server.ResourceGroupName -ServerName $Server.ServerName `
| Where-Object {$_.DatabaseName -like "*copy"} `
| Select-Object ResourceId
}
$definition = Get-AzPolicyDefinition | Where-Object {$_.Properties.DisplayName -eq "Allowed virtual machine SKUs"}
New-AzPolicyAssignment -Name 'Test' -DisplayName 'Test' -Scope $ResourceGroup.ResourceID -PolicyDefinition $definition
Running this command will ask for 'listOfAllowedSKUs' for which SKUs i want to allow to be created in the specified resource group. I can find a list of them by going into the azure portal, finding policy and clicking assign policy, then selecting "Allowed virtual machine skus" and then going into parameters and looking at the names.
I can type in those names manually one by one when i get asked for it after running the command, but instead of opening the azure portal every time, i want to be able to list the available SKUs in powershell instead. I can't find anything online about getting a list of available SKUs in the console.
Is is possible to get a list of available SKUs to create?
Hello and welcome to Stack Overflow!
If you want to get the SKUs corresponding to a specific Location, Publisher and Offer, you may use the Get-AzVMImageSku cmdlet to get the VMImage SKUs by providing the Location, PublisherName and Offer as input parameters, and then construct the AllowedSkus object. For example:
$sku = Get-AzVMImageSku -Location "Central US" -PublisherName "Fabrikam" -Offer "LinuxServer"
$AllowedSkus = #{'listOfAllowedSKUs'=($sku.Skus)}
Else, to mimic the list of available SKUs as appearing in the portal, you may use the Get-AzVMSize cmdlet to get the available virtual machine sizes as follows:
$allsizes = Get-AzLocation | Get-AzVmSize | Select-Object -ExpandProperty Name | Sort-Object | Get-Unique
$AllowedSkus = #{'listOfAllowedSKUs'=($allsizes)}
This can finally be passed to the New-AzPolicyAssignment cmdlet using the -PolicyParameterObject option:
New-AzPolicyAssignment -Name '<policy assignment name>' -DisplayName '<display name>' -Scope $ResourceGroup.ResourceID -PolicyDefinition $definition -PolicyParameterObject $AllowedSkus
Other examples here. Hope this helps.
According to my test, if you want to know the available virtual machine SKUs in the subscription, you can use the following PowerShell command
Get-AzComputeResourceSku | where{$_.ResourceType.Equals('virtualMachines')}| fl
Its outputs contain parameter Restrictions. The parameter will tell us which SKU cannot be used.
For example
Giving one type of restriction : Zone Type for size Standard_A0 which means that under a particular subscription, Standard_A0 is not available to be created in West Europe region if placed in Availability Zones
Giving no Restrictions at the end, which means that VM Size : Standard_F8s can be created under this particular subscription in this region : West Europe without any restrcitions ( i.e : it can be created with Availaibility Zone and without Availaibility zone as well )
Giving two types of restrictions : Zone Type and Location Type, which means that VM Size of Standard_DS2_V2_Promo cannot be created in this particular subscription in this region : WestEurope at all.
I have prepared Azure PowerShell script for catching RBAC changes information from Azure Activity Logs. When I am testing this script on my test subscription, script works fine. Problem is when I used connect-azurermaccount -subscription command and switched to the prod subscription. In the Azure activity log blade I saw that there were some logs related to RBAC changes, log names like "Create role assignment". I was testing with commands like below:
Get-AzureRmLog -StartTime (Get-Date).AddDays(-10) |
Where-Object {$_.Authorization.Action -like
"Microsoft.Authorization/roleAssignments/*"}
and
Get-AzureRmLog -StartTime 2019-09-01T10:30 | Where-Object {$_.Authorization.Action -like "*Microsoft.Authorization/*"}
I didnt see any output in the console. When I logged to the Azure portal and opened Activity log I was able to see logs related to RBAC changes, log names --> "Delete role assignment", "Create role assignment". I was testing mentioned commands with string "Microsoft.Compute":
Get-AzureRmLog -StartTime (Get-Date).AddDays(-10) |
Where-Object {$_.Authorization.Action -like
""*Microsoft.Compute/*""}
and
Get-AzureRmLog -StartTime 2019-09-01T10:30 | Where-Object {$_.Authorization.Action -like "*Microsoft.Compute/*"}`
I could see the logs information in the output. I am not sure what is wrong and what should I correct. Why can't I use this filter in my prod subscription --> "Microsoft.Authorization/", I would like to highlight that on my test subscription script worked perfectly fine.
If you want to get the logs related to RBAC changes, you can use the following the script to get it.
Connect-AzureRmAccount
Get-AzureRmLog -ResourceProvider Microsoft.Authorization -StartTime (Get-Date).AddMonths(-1)
For more details, please refer to
https://learn.microsoft.com/en-us/powershell/module/azurerm.insights/get-azurermlog?view=azurermps-6.13.0
Update
If you want to use Azure rest api to get the logs related to RBAC changes, you need to use the rest api as below:
Method : GET
URL:https://management.azure.com/subscriptions/<subscription id>/providers/microsoft.insights/eventtypes/management/values
Params:
api-version = 2017-03-01-preview
$filter = eventTimestamp ge 'your strat time' and resourceTypes eq 'microsoft.authorization/roleassignments'
Header:
Authorization : Bearer access_token
For example:
According to my test, if the numbers of your log are too big, the results will be paged. If you want to get the other pages' results, we need to send request to the nextlink which is a parameter in the result.
Is there a possible way to get the VM creation date ?
I've tried the following by now
AzureActivity
| where TimeGenerated > ago(90d)
| where ResourceProvider == "Microsoft.Compute" and OperationName == "Create or Update Virtual Machine"
| project Resource ,Datum = format_datetime(EventSubmissionTimestamp, 'MM') ,Caller
| distinct Datum , Resource , Caller
| order by Datum
This kusto query will read the logs from the VM's connected to it. and get all the Create or update virtual machine operations from a vm and its caller ID.
But this is create and update So it gives me double values every time an VM is being updated.
I tried also in PowerShell
$GetVM = Get-AzureRMVM
Foreach ($vms in $GetVM)
{
$vm = get-azurermvm -name $vms.Name -ResourceGroupName $vms.ResourceGroupName
$log = Get-AzureRmLog -ResourceId $vm.Id -StartTime (Get-Date).AddDays(-90) -WarningAction silentlyContinue
Write-Output "- Found VM creation at $($log.EventTimestamp) for VM $($log.Id.split("/")[8]) in Resource Group $($log.ResourceGroupName) found in Azure logs"
}
But Can't seem to find the creation date inside the log files either. Does anyone have a clue if it is possible to find the creation date of a Virtual Machine inside a scripting language , Kusto , Powershell , ...
The easiest way that worked for me to get the Azure VM creation date was to look at the creation date of the OS Disk
Browse to your VM on Azure Portal
On Left Hand side, click on the blade "Disks"
Under OS Disk section, click on your OS Disk.
In the Overview blade of your OS Disk, you can see Time Created field.
Note: All my Azure VMs were created with the OS Disk and were never changed.
Hope it helps. Cheers.
There is no direct way to find out the creation date if it's later than 90 days. But here is a nice workaround solution: https://savilltech.com/2018/02/13/checking-the-creation-time-of-an-azure-iaas-vm/
You can use azure cli
use below command
az vm list
This will list json data with fields and you can filter
date = vm['timeCreated']
//"timeCreated": "2022-06-24T14:13:00.326985+00:00",
The portal does show Created for a cloud service in the Dashboard of a Cloud Service, but that is not shown for a specific VM (which you can see with Azure PowerShell with Get-AzureService <cloud service name> | select DateCreated).
When you do a Quick Create of a VM, that will always create a new cloud service, so the time created would be the same for VM and cloud service. But since you can add multiple VMs to a cloud service, you can't always rely on that.
On the VM's Dashboard in the portal, at the bottom if you look at the VHD column, the VHD name includes the date the disk was created as part of the name, though this is only true for VMs created from an image. If the VM was created from a disk, the name could be anything. You can get that OS disk name in Azure PowerShell with Get-AzureVM <cloud service name> <VM name> | Get-AzureOSDisk | select medialink.
Operation Logs under Management Services in the portal lets you search the last 30 days for operations, so if the VM was created in the last month, you can find evidence of the operation there (for example CreateHostedService and CreateDeployment operations).
For Windows VMs created from an image, the timestamp on WaSetup.log and WaSetup.xml in C:\Windows\panther\ reflect when the VM was provisioned.
Hope it helps.
If you check Deployments in the respective resource group, you will see Last Modified date for each of the deployment in that RG.
I found another way to get it working for me by tweaking your ActivityLog query instead of Powershell. Using the HTTPRequest property seemed to give me what I needed.
AzureActivity
| where TimeGenerated > ago(7d)
| where ResourceProvider contains "Microsoft.Compute" and OperationName == "Create or Update Virtual Machine"
| where HTTPRequest contains "PUT"
| project VMName = Resource, Created_On = format_datetime(EventSubmissionTimestamp,'dd-MM-yyyy-HHtt'), User = Caller
| distinct Created_On, VMName, User
| order by Created_On
In my case, I was trying to get the VMs deleted in the last 7 days. For some reason the time wasn't displaying properly for the query below, hence I had to convert it to my timezone.
AzureActivity
| where TimeGenerated > ago(7d)
| where ResourceProvider == "Microsoft.Compute" and OperationName == "Delete Virtual Machine"
| where HTTPRequest contains "DELETE"
| extend MyTimeZone = EventSubmissionTimestamp + 8h
| project VM_Name = Resource, Deleted_On = format_datetime(MyTimeZone, 'dd-MM-yyyy-HHtt'), User = Caller
| distinct Deleted_On , VM_Name , User
| order by Deleted_On
I have the following PS script that runs fine locally:
Get-AzureVM | Where-Object { $_.Name -eq "my-server-selector" } | select name | ForEach-Object {
Write-Output $_.Name
Start-AzureVM $_.Name $_.Name
}
In the context of my local PS console, I add my subscription info and the code executes without a problem; all VMs are printed to the output and the servers are started up.
When I move it to the cloud I need to do a few other things, namely, bring the subscription in scope. I do that by creating the credential asset in the portal, adding the account to my script via said credentials, then selecting the correct subscription in the script. I also wrap it in a workflow (there are aspects I intent to parametrize at a later date).
The final code is as follows:
workflow StartServer
{
$credential = GetAutomationPSCredential -Name "credential-asset-name"
Add-AzureAccount -Credential $credential
Select-AzureSubscription -SubscriptionName "subscription-name"
Write-Output "Starting the server."
Get-AzureVM | Where-Object { $_.Name -Contains "my-server-selector" } | select name | ForEach-Object {
Write-Output $_.Name
Start-AzureVM $_.Name $_.Name
}
Write-Output "Execution Complete."
}
If I remove the Start-AzureVM command, the workflow runs as expected. I get a listing of all the matching VMs printed out. If I attempt to put the command back in, I get the following error:
Parameter set cannot be resolved using the specified named parameters.
So, things I think I know:
the credentials are working as I'm getting the correct list of VMs
the subscription is being correctly set, as it's dumped to the output
the inner part of the script works on a local powershell console without any changes
Can anyone provide any ideas as to what needs to be done differently in an Azure Automation workflow to get this to work?
The fix was to be more explicit in the naming of parameters, both in the filter for the Where-Object as well as in the call to Start-AzureVM. I'm not sure why this would make a difference; as I said, the call to write the names of the servers worked without the explicit parameter name, but low and behold, here it works with it set.
The final code of the inner block is as follows:
Get-AzureVM | Where-Object -FilterScript { $_.Name -Contains "my-server-selector" } | select name | ForEach-Object {
Write-Output $_.Name
Start-AzureVM -ServiceName $_.Name -Name $_.Name
}
Thanks to #DexterPOSH on Twitter for the direction on -FilterScript.
Please take a look at http://azure.microsoft.com/blog/2014/11/25/introducing-the-azure-automation-script-converter/ which talks about this exact issue. When authoring Powershell in the ISE to move into Azure Automation, make sure you are testing / writing as Powershell Workflow in the ISE, since Powershell workflow has some differences vs Powershell script.
Or, if you need to take PS script and use it in Azure Automation, make sure you import the script, not copy paste it in. Azure Automation will then convert the PS script to PS Workflow for you. The link above has more details on this.