I created multiple script to identify who started or stopped a Vm using the activity log but unable to get the results - the script just executes without an output
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-audit
Get-AzureRmLog -StartTime 2018-10-01T10:30 -EndTime 2018-10-12T11:30
-ResourceId /subscriptions/S1sub/resourceGroups/SamRG/providers/microsoft.compute/test
-DetailedOutput -Maxrecord 100 -InformationAction stop
Get-AzureRmLog -ResourceGroup samitrg -StartTime 2018-10-01T10:30
-EndTime 2018-10-12T11:30 | Select-Object level,eventtimestamp,caller,ID,resourcegroupname,Authorization,scope |
Export-Csv -Path c:\abc.csv
Get-AzureRmLog -ResourceGroup samitrg -StartTime 2018-10-01T10:30
-EndTime 2018-10-12T11:30 | Where-Object OperationName -EQ Microsoft.compute/virtualmachines/deallocate/action
Try the command below, add the extra parameters you need, like -StartTime,-EndTime,etc, it will work fine.
Start a VM:
$start = Get-AzureRmLog -ResourceId "<ResourceId>" | Where-Object { $_.Authorization.Action -eq "Microsoft.Compute/virtualMachines/start/action"}
$start | Select-Object level,eventtimestamp,caller,ID,resourcegroupname,Authorization,scope
Stop a VM:
$stop = Get-AzureRmLog -ResourceId "<ResourceId>" | Where-Object { $_.Authorization.Action -eq "Microsoft.Compute/virtualMachines/deallocate/action"}
$stop | Select-Object level,eventtimestamp,caller,ID,resourcegroupname,Authorization,scope
I found the solution
START
Get-AzureRmLog -ResourceID /subscriptions/<SUBID>/resourceGroups/<ResourceGroup>/providers/Microsoft.Compute/virtualMachines/<VMName> -StartTime 2018-10-16T21:30 -EndTime 2018-10-16T21:50 -MaxRecord 20 | Where-Object { $_.Authorization.Action -eq "Microsoft.Compute/virtualMachines/start/action"} | Select-Object level,eventtimestamp,caller,ID,resourcegroupname,Authorization | Format-table -wrap -AutoSize -Property level,eventtimestamp,caller,resourcegroupname,ID -groupby Authorization
STOP
Get-AzureRmLog -ResourceID /subscriptions/<SUBID>/resourceGroups/<ResourceGroup>/providers/Microsoft.Compute/virtualMachines/<VMName> -StartTime 2018-10-16T21:30 -EndTime 2018-10-16T21:45 -MaxRecord 20 | Where-Object { $_.Authorization.Action -eq "Microsoft.Compute/virtualMachines/deallocate/action"} | Select-Object level,eventtimestamp,caller,ID,resourcegroupname,Authorization | Format-table -wrap -AutoSize -Property level,eventtimestamp,caller,resourcegroupname,ID -groupby Authorization
Hope this helps everyone :)
Related
Azure: Extend Psh command with two columns resource type & name
I am trying to write a Azure Psh command with two columns resource type & name and query the RBAC assignments for a user.
I have these two tables, is there a way to merge the following two tables?
Following is my current progress with the command:
Get-AzRoleAssignment -SignInName A12345#abc.com | Select-Object -Property RoleDefinitionName, {Get-AzResource -ResourceId $_.RoleAssignmentID | Select-Object -Property Name,ResourceType} | Format-Table;
Get-AzRoleAssignment -SignInName A12345#abc.com | Select-Object -Property RoleDefinitionName, {Get-AzResource -ResourceId $_.Scope | Select-Object -Property Name, ResourceType} | Format-Table
You can use the below command to directly get the two information in one line :
Get-AzRoleAssignment -SignInName ansuman#xyz.com | Select-Object -Property RoleDefinitionName, {Get-AzResource -ResourceId $_.RoleAssignmentID | Select-Object -Property Name,ResourceType} , {Get-AzResource -ResourceId $_.Scope | Select-Object -Property Name, ResourceType} | Format-Table
Update:
To prettify the Headers you can use this :
Get-AzRoleAssignment -SignInName ans#xyz.com | Select-Object -Property RoleDefinitionName, #{N='RoleDetails';E={Get-AzResource -ResourceId $_.RoleAssignmentID | Select-Object -Property Name,ResourceType}} , #{L='ScopeDetails';E={Get-AzResource -ResourceId $_.Scope | Select-Object -Property Name, ResourceType}}
Output:
Trying to retrieve the value of Authorization.action from Get-AzActivityLog | select-Object but I am having difficulty filtering my results down to what I need.
When running the below, I get results but when I pipe to Select-Object to only return the specified values, I get values for all except Autorization.action. Fairly new so not sure how to accomplish this and not finding documentation that clarifies to me online. Obviously Authorization.action is not correct but I can't seem to find a solution.
Get-AzActivityLog -ResourceId $sa.Id `
-StartTime ((Get-Date).AddDays($timeframe)) `
-Status Succeeded `
| where {$_.Authorization.action -like "Microsoft.Storage/storageAccounts/regenerateKey/action"} `
| Select-Object Authorization.action, EventTimestamp, ResourceGroupName, ResourceId
Output
Thanks for any insight in to this.
You could do it in Multiple ways :
Get-AzActivityLog -ResourceId $sa.Id `
-StartTime ((Get-Date).AddDays($timeframe)) `
-Status Succeeded `
| where {$_.Authorization.action -like "Microsoft.Storage/storageAccounts/regenerateKey/action"} `
| Select-Object {$_.Authorization.action}, EventTimestamp, ResourceGroupName, ResourceId
Or
Like Mathias Mentioned :
Get-AzActivityLog -ResourceId $sa.Id `
-StartTime ((Get-Date).AddDays($timeframe)) `
-Status Succeeded `
| where {$_.Authorization.action -like "Microsoft.Storage/storageAccounts/regenerateKey/action"} `
| Select-Object #{Name='AuthorizationAction';Expression={$_.Authorization.action}}, EventTimestamp, ResourceGroupName, ResourceId
The Reason Being Select-Object chooses the immediate property of the object. However, in your case the Authorization.Action is one level down being a complex property. So you will have to evaluate the expression.
Also you could use the -ExpandProperty parameter to expand a complex property.
Select-Object Authorization -ExpandProperty Authorization | Select-Object Action
I want to list all the VMs that generate costs in a specific timeframe or billing period.
I managed to create this script to get me the desired output:
$file="C:\temp\GeneratedCost-short.csv"
(az consumption usage list `
--start-date "2020-07-01" --end-date "2020-07-31" | ConvertFrom-Json)`
| Where-Object {$_.product -Match "Virtual Machines"}`
| Sort-Object -Property instanceName -Descending | Select-Object instanceName, subscriptionName`
| Get-Unique -AsString | ConvertTo-Csv -NoTypeInformation | Set-Content $file
But this will give me the output only for the current subscription.
How can I run on all the subscriptions that I have on the azure tenant?
I tried using the below version but it doesn't seem to work:
$file="C:\temp\GeneratedCost-short.csv"
$VMs = #()
$Subscriptions = Get-AzSubscription
foreach ($sub in $Subscriptions) {
Get-AzSubscription -SubscriptionName $sub.Name | az account set -s $sub.Name
$VMs += (az consumption usage list --start-date "2020-07-01" --end-date "2020-07-03" | ConvertFrom-Json)
}
#
$VMs | Where-Object {$_.product -Match "Virtual Machines"}`
| Sort-Object -Property instanceName -Descending | Select-Object instanceName, subscriptionName`
| Get-Unique -AsString | ConvertTo-Csv -NoTypeInformation | Set-Content $file
Any suggestions?
Mixing the Azure PowerShell module and Azure CLI could be causing issues with your code if the accounts haven't been retrieved between the two. Verify that az cli has the proper subscriptions
az account list -o table
If you don't see the accounts be sure to re-run az login.
Here's your code with the azure cli only
$file="C:\temp\GeneratedCost-short.csv"
$VMs = #()
az account list -o json | ConvertFrom-Json |
ForEach-Object {
Write-Host "Getting usage for account: " $_.Name
az account set -s $_.Name
$VMs += (az consumption usage list --start-date "2020-07-01" --end-date "2020-07-03" | ConvertFrom-Json)
}
$VMs | Where-Object {$_.product -Match "Virtual Machines"} |
Sort-Object -Property instanceName -Descending |
Select-Object instanceName, subscriptionName |
Get-Unique -AsString | ConvertTo-Csv -NoTypeInformation |
Set-Content $file
never do += on an array, worst pattern ever.
[System.Collections.Generic.List[PSObject]]$VMs = #()
$subs = Get-AzSubscription # | Where-Object {$_.State -eq 'Enabled'}
foreach ($s in $subs) {
Set-AzContext -SubscriptionObject $s | Out-Null
$vm = # your search here ...
$VMs.Add($vm)
}
I've got a list of virtua machines in Azure which I'm trying to convert to managed disks.
I have a list of vm's, I read from the list and export to csv capturing resourcegroupname and vm name, however I seem to get vms from the whole subscription.
Also when I attempt to import the csv, when I run $comps it returns the correct information in the csv, however I can't seem to pass them through to the next lines.
CSV format is
ResouceGroupName Name
RG-01 vm-01
RG-01 vm-02
RG-01 vm-03
RG-01 vm-04
The code I'm trying is
Login-AzureRmAccount
$sub = Get-AzureRmSubscription | ogv -PassThru
Select-AzureSubscription -SubscriptionId $sub
$virtualmachines = Get-Content C:\temp\vm.txt | % {
Get-Azurermvm | select ResourceGroupName,Name | export-csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Append
}
$comps = Import-Csv c:\temp\Vm.csv |
foreach ($Comp in $comps)
{
Stop-AzureRmVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Force
ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $_.ResourceGroupName -VMName $_.Name
}
Thanks in advance..
For your issue, you export the virtual machines in a csv file and use it in the foreach code. So, it's unneccesary to use command:
$virtualmachines = Get-Content C:\temp\vm.txt | % {
Get-Azurermvm | select ResourceGroupName,Name | export-csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Append
}
And your VMs all in a resourcegroup, you can get them with ResourceGroupName directly.
For the pipeline in foreach, it's unneccesary. You can use the following code that I make a little change with your code and it works well.
Login-AzureRmAccount
$sub = Get-AzureRmSubscription | ogv -PassThru
Select-AzureRmSubscription -Subscription $sub
Get-Azurermvm –ResourceGroupName RG-01 | select ResourceGroupName,Name | export-csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Append
$comps = Import-Csv c:\temp\Vm.csv
foreach ($Comp in $comps)
{
Stop-AzureRmVM -ResourceGroupName $Comp.ResourceGroupName -Name $Comp.Name -Force
ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $Comp.ResourceGroupName -VMName $Comp.Name
}
This is the screenshot of my result.
I've used a hash table to calculate some values for my VMWare inventory script, but now when I output the data, it records it as a key/value pair. I'd like to dump just the value. When I simply take what I'm handed that works fine, but when I get picky PS starts to stonewall me. :-)
Here is the relevant part of the script.
foreach ($machine in $vmList) {
$vmname = $machine.Name
$properties = #{
'Name'=Get-VM $vmname | Select -ExpandProperty Name
'RAM'=Get-VM $vmname | Select -ExpandProperty MemoryGB
'CpuCount'=Get-VM $vmname | Select -ExpandProperty NumCpu
'UsedDiskGB'=Get-VM $vmname | Select-Object #{n="UsedDiskGB"; e={[math]::Round( $_.UsedSpaceGB, 3 )}}
'TotalDiskGB'=Get-VM $vmname | Select-Object #{n="TotalDiskGB"; e={[math]::Round((Get-HardDisk -vm $_ | Measure-Object -Sum CapacityGB).Sum)}}
'Networks'=Get-VM $vmname | Select-Object #{n="Networks"; e={(Get-NetworkAdapter -VM $_ |Sort-Object NetworkName |Select -Unique -Expand NetworkName) -join '; '}}
'OS'=(Get-VM -Name $vmname | Get-View).summary.config.guestFullName
}
$object=New-Object -TypeName PSObject -Prop $properties
Export-Csv -Path $WorkDir\vms.csv -Append -Encoding UTF8 -InputObject $Object
Write-Output $Object
}
How do I get UsedDiskGB, Networks and TotalDiskGB to display just the value instead of something like '#{TotalDiskGB=80}'? Ram, OS, CpuCount and Name work exactly as desired already.
Also, suggestions on doing this in a faster way are welcome. I'm sure all these calls can be done better. I had it done in a single line, but then they asked for OS to be added and that changed everything.
Easy, but bad way:
In the expression pipe to |Select -ExpandProperty <property name> to get just the value. Such as:
'TotalDiskGB'=Get-VM $vmname | Select-Object #{n="TotalDiskGB"; e={[math]::Round((Get-HardDisk -vm $_ | Measure-Object -Sum CapacityGB).Sum)}}|select -expand totaldiskgb
The better way:
Structure your properties better to start with. Try this:
'TotalDiskGB'= [math]::Round((Get-HardDisk -vm (Get-VM $vmname) | Measure-Object -Sum CapacityGB).Sum)
The reason you're having issues is because you are creating a PSCustomObject with your Select, and Totaldiskgb is a property of that object. You don't want to make an object, you just want the value of that property.
Edit: Thank you to #briantist for pointing out that Get-VM $vmname should be called once, and stored as an object to be used later, rather than called for each time it is needed for a member of $Properties. For example:
foreach ($machine in $vmList) {
$vmname = $machine.Name
$vmobject = Get-VM $vmname
$properties = #{
'Name'=$vmobject | Select -ExpandProperty Name
'RAM'=$vmobject | Select -ExpandProperty MemoryGB
'CpuCount'=$vmobject | Select -ExpandProperty NumCpu
'UsedDiskGB'=[math]::Round( $vmobject.UsedSpaceGB, 3 )
'TotalDiskGB'=[math]::Round((Get-HardDisk -vm $vmobject | Measure-Object -Sum CapacityGB).Sum)
'Networks'=(Get-NetworkAdapter -VM $vmobject |Sort-Object NetworkName |Select -Unique -Expand NetworkName) -join '; '
'OS'=($vmobject | Get-View).summary.config.guestFullName
}
$object=New-Object -TypeName PSObject -Prop $properties
Export-Csv -Path $WorkDir\vms.csv -Append -Encoding UTF8 -InputObject $Object
Write-Output $Object
}