I've been trying to run a script to create a lock on azure resource to prevent resources being deleted inadvertently.
I get an error message and I can't figure out why it's showing me this error message.
Script:
#Sign in to Azure account
Login-AzAccount
#Select the subscription you want to work on
Select-AzSubscription -Subscription "test.subscription"
#Get All Resources in a resource group
$Resources = Get-AzResource -ResourceGroupName dummy_rg | Format-Table
# Create lock "delete" on each Resource if it doesn't exist
foreach($Resource in $Resources) {
$ResourceName = $Resource.Name
$lck = Get-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType
if ($null -eq $lck)
{
Write-Host "$ResourceName has no lock"
New-AzResourceLock -resourceGroupName $rg -ResourceName $ResourceName -ResourceType $Resource.ResourceType -LockName "$ResourceName-lck" -LockLevel CanNotDelete -Force
Write-Host "$ResourceName has been locked"
}
else
{
Write-host "$ResourceName already locked"
}
}
Error message:
Gaurav request result:
#Start logging
Start-Transcript -Path "C:\Windows\Logs\Lock - $(((get-date).ToUniversalTime()).ToString("yyyy-MM-dd_hh-mm-ss")).log" -Force
#Connect to Azure account
Login-AzAccount
#Select Azure subscription
Set-AzContext -Subscription "subscription_id_numbers"
#Deny rule on Azure Data Factory and Azure Machine Learning
$Resources = Get-AzResource | Where-Object {$_.Name -NotLike '*adf*' -and $_.Name -NotLike '*aml*'}
# Create lock "delete" on each Resource if it doesn't exist
foreach($Resource in $Resources) {
$ResourceName = $Resource.Name
$lck = Get-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType
if ($lck -eq $null)
{
Write-Host "$ResourceName has no lock"
Set-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType -LockName "$ResourceName-lck" -LockLevel CanNotDelete -Force
Write-Host "$ResourceName has been locked"
}
else
{
Write-host "$ResourceName already locked"
}
}
#Stop Logging
Stop-Transcript
This will loop on every ressources except azure data factory in the tenant and create a "delete" type lock to make sure resources aren't deleted inadvertently.
Read comments in each section to understand the code.
Related
I have runbook in Azure that i want to use in different RG,
My code
$vms = Get-AzVM -ResourceGroupName RG-TEST
foreach($vm in $vms)
{
$statuscheck = Get-AzVM -ResourceGroupName RG-TEST -Name $vm.Name -Status
if($statuscheck.Statuses.DisplayStatus[1] -eq "VM running")
{
Write-Output "Stopping virtual machine...$($vm.Name)"
Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force
}
else
{
Write-output "Virtual machine $($vm.Name) is already in stopped state"
}
}
How can I update the code that the script will get the name of the RG where it's located,
So that the RG is not hard coded
Dont know how to do it
Do something like this
$rgs = $(Get-AzVM)
# Get Distinct RG Names
$rgs = $rgs | Select-Object -Property ResourceGroupName | Sort-Object -Unique
foreach($rg in $rgs){
$vms = Get-AzVM -ResourceGroupName $rg.ResourceGroupName
foreach($vm in $vms)
{
$statuscheck = Get-AzVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name -Status
if($statuscheck.Statuses.DisplayStatus[1] -eq "VM running")
{
Write-Output "Stopping virtual machine...$($vm.Name)"
Stop-AzVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name -Force
}
else
{
Write-output "Virtual machine $($vm.Name) is already in stopped state"
}
}
}
I want to get the list of azure servers having auto-shutdown disabled on them, I have the below script but the issue with the script is that it gets the list of RG's under the Subscription GUID but repeats the output after every loop.
Import-AzureRmContext -Path "$PSScriptRoot\AzureProfile.json"
Select-AzureRmSubscription -SubscriptionId {subscriptionId}
[array]$ResourceGroupArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId
foreach ($resourceGroup in $ResourceGroupArray){
$targetResourceId = (Get-AzureRmVM -ResourceGroupName $resourcegroup.ResourceGroupName -Name $resourceGroup.Name).Id
$shutdownInformation = (Get-AzureRmResource -ResourceGroupName $resourcegroup.ResourceGroupName -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
Write-Host "ID: " $targetResourceId
$shutdownInformation
The output for each VM is displayed in the following format,
What I want is simple, I want the VM name and its status of Auto-shutdown to be displayed on the screen so that its easy for me to find out which all VM have auto-shutdown currently disabled on them.
Any help related to this would be helpful.
You just need to get the microsoft.devtestlab/schedules resource ID using:
/subscriptions/{subscriptionId}/resourceGroups/{rgName}/providers/microsoft.devtestlab/schedules/shutdown-computevm-{vmName}
Then iterate over all your VMs using Get-AzVM, Get the microsoft.devtestlab/schedules resource using Get-AzResource, then output VM name and status into a table using Format-Table.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzVM) {
try {
$shutdownResource = Get-AzResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
To set the context to the correct subscription, we can use Set-AzContext.
The above however is using the latest Az modules. You can do the same using the equivalent AzureRm modules.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzureRmContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzureRmVM) {
try {
$shutdownResource = Get-AzureRmResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
Although I do recommend moving to the Az module since support for AzureRm is ending December 2020. You can read the documentation for more information about this.
The above code should give you an output similar to the following
VMName ShutdownStatus
------ --------------
vm1 Enabled
vm2 Disabled
Update
The Call operator & is used here to run the for loop as a script block. You can read more about this in about_Script_Blocks.
Try something like this to get the auto-shutdown status of all VMs. Instead of trying to get the schedules inside the loop, get all the ones in the subscription and match them based on the VM's full resource Id.
[array]$VMArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId, Id
$ShutdownInformation = (Get-AzureRmResource -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
foreach($vm in $VMArray) {
$ShutdownStatus = "Not Configured"
$Schedule = $ShutdownInformation | Where-Object { $_.targetResourceId -eq $vm.Id } | Select -First 1
if($Schedule -ne $null) {
$ShutdownStatus = $Schedule.status
}
Write-Host $vm.VmId $ShutdownStatus
}
I'm using below script to create a storage account, Key Vault and ADF. I would also like to enable diagnostic logging on both Storage account and Key Vault. Script runs fine and creates the resources however it does not enable the diagnostic logs for KV and Storage account. Would appreciate if you can help.
$subscription="Azure subscription 1"
$rgName = "Test"
$location = "eastus"
$storageaccountName = "tempaccountlogs"
$adfName = "tempdpadf"
$department = "Testtemp"
$kvname = "kvnamAkbt"
$sa = New-AzStorageAccount -ResourceGroupName $rgName -AccountName $storageaccountName -Location $location -SkuName Standard_LRS -Kind BlobStorage -AccessTier Hot -Tag #{department=$department}
$DataFactory = Set-AzDataFactoryV2 -Name $adfName -ResourceGroupName $rgName -Location $location -Tag #{chargecode=$chargeCode;department=$department;environment=$environment;project=$project}
$kv = New-AzKeyVault -VaultName $kvname -ResourceGroupName $rgName -Location $location
set-AzDiagnosticSetting -ResourceId $kv.ResourceId -StorageAccountId $sa.Id -Enabled $true -Categories AuditEvent
set-AzDiagnosticSetting -ResourceId $kv.ResourceId -StorageAccountId $sa.Id -RetentionEnabled $true -RetentionInDays 90
The problem with your script is that it gives error:
A parameter cannot be found that matches parameter name 'Categories'.
You are using "Categories" parameter instead of "Category". If you check this documentation correct parameter is -Category, use this as shown below:
set-AzDiagnosticSetting -ResourceId $kv.ResourceId -StorageAccountId $sa.Id -Enabled $true -Category AuditEvent
set-AzDiagnosticSetting -ResourceId $kv.ResourceId -StorageAccountId $sa.Id -RetentionEnabled $true -RetentionInDays 90
To enable logging for storage account, Please look at this documentation.
$diagname = "storage logs"
$ErrorActionPreference = "SilentlyContinue"
Import-Module -Name Az
Import-Csv "$home\azuresubscription.csv" |`
ForEach-Object{
#CentralLogAnalytics
$workspaceid = "your central logging resource id - exact object"
Select-AzSubscription -Subscription $_.Name
$storageAccounts = Get-AzStorageAccount | Select-Object Id
foreach ($stor in $storageAccounts)
{
Set-AzDiagnosticSetting -Name $diagname -ResourceId $stor.Id -WorkspaceId $workspaceid -Enabled $true
$blobid = -join($stor.id,"/blobServices/default")
$fileid = -join($stor.id, "/fileServices/default")
$queueid = -join($stor.id, "/queueServices/default")
$tableid = -join($stor.id, "/tableServices/default")
$resourcetypeid = #($blobid, $fileid, $queueid, $tableid)
foreach ($item in $resourcetypeid)
{
Set-AzDiagnosticSetting -Name $diagname -ResourceId $item -WorkspaceId $workspaceid -Enabled $true
}
}
}
Prerequisite:
The script expects a list of azure subscription in a CSV file. Putting in CSV is best to easy test in NonProd subscriptions. An object of the subscriptions can also be provided here.
Functionality:
This will enable the metrics for blob, queue, file, and table and at the parent level as well.
You should include -WorkspaceId parameter in the cmd. See reference here.
My example which runs successfully:
set-AzDiagnosticSetting -ResourceId $kv.ResourceId -StorageAccountId $sa.Id -Enabled $true -Category AuditEvent -WorkspaceId {resource id of the Log Analytics workspace}
For how to create a Log Analytics workspace, please refer to Create workspace.
Update:
For how to enable diagnostic logs for ADF, please refer to this sample:
$ws = Get-AzOperationalInsightsWorkspace -Name "testLAW" -ResourceGroupName "test"
$DataFactory = Set-AzDataFactoryV2 -ResourceGroupName "test" -Name "testADF" -Location "WestUS"
set-AzDiagnosticSetting -ResourceId $DataFactory.DataFactoryId -Enabled $true -WorkspaceId $ws.ResourceId
I'm trying to set a Tag on all virtual machines in my subscription but I keep getting errors when running the Runbook.
The error is the following:
Get-AzureRmVM : Cannot process command because of one or more missing mandatory parameters: ResourceGroupName. At line:30
Here is my Runbook:
$azureConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
#Authenticate
try {
Clear-Variable -Name params -Force -ErrorAction Ignore
$params = #{
ServicePrincipal = $true
Tenant = $azureConnection.TenantID
ApplicationId = $azureConnection.ApplicationID
CertificateThumbprint = $azureConnection.CertificateThumbprint
}
$null = Add-AzureRmAccount #params
}
catch {
$errorMessage = $_
Throw "Unable to authenticate with error: $errorMessage"
}
# Discovery of all Azure VM's in the current subscription.
$azurevms = Get-AzureRmVM | Select-Object -ExpandProperty Name
Write-Host "Discovering Azure VM's in the following subscription $SubscriptionID Please hold...."
Write-Host "The following VM's have been discovered in subscription $SubscriptionID"
$azurevms
foreach ($azurevm in $azurevms) {
Write-Host "Checking for tag $vmtagname on $azurevm"
$tagRGname = Get-AzureRmVM -Name $azurevm | Select-Object -ExpandProperty ResourceGroupName
$tags = (Get-AzureRmResource -ResourceGroupName $tagRGname -Name $azurevm).Tags
If ($tags.UpdateWindow){
Write-Host "$azurevm already has the tag $vmtagname."
}
else
{
Write-Host "Creating Tag $vmtagname and Value $tagvalue for $azurevm"
$tags.Add($vmtagname,$tagvalue)
Set-AzureRmResource -ResourceGroupName $tagRGname -ResourceName $azurevm -ResourceType Microsoft.Compute/virtualMachines -Tag $tags -Force `
}
}
Write-Host "All tagging is done"
I tried importing the right modules but this doesn't seem to affect the outcome.
Running the same commands in Cloud Shell does work correctly.
I can reproduce your issue, the error was caused by this part Get-AzureRmVM -Name $azurevm, when running this command, the -ResourceGroupName is needed.
You need to use the Az command Get-AzVM -Name $azurevm, it will work.
Running the same commands in Cloud Shell does work correctly.
In Cloud shell, azure essentially uses the new Az module to run your command, you can understand it runs the Enable-AzureRmAlias before the command, you could check that via debug mode.
Get-AzureRmVM -Name joyWindowsVM -debug
To solve your issue completely, I recommend you to use the new Az module, because the AzureRM module was deprecated and will not be updated.
Please follow the steps below.
1.Navigate to your automation account in the portal -> Modules, check if you have imported the modules Az.Accounts, Az.Compute, Az.Resources, if not, go to Browse Gallery -> search and import them.
2.After import successfully, change your script to the one like below, then it should work fine.
$azureConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
#Authenticate
try {
Clear-Variable -Name params -Force -ErrorAction Ignore
$params = #{
ServicePrincipal = $true
Tenant = $azureConnection.TenantID
ApplicationId = $azureConnection.ApplicationID
CertificateThumbprint = $azureConnection.CertificateThumbprint
}
$null = Connect-AzAccount #params
}
catch {
$errorMessage = $_
Throw "Unable to authenticate with error: $errorMessage"
}
# Discovery of all Azure VM's in the current subscription.
$azurevms = Get-AzVM | Select-Object -ExpandProperty Name
Write-Host "Discovering Azure VM's in the following subscription $SubscriptionID Please hold...."
Write-Host "The following VM's have been discovered in subscription $SubscriptionID"
$azurevms
foreach ($azurevm in $azurevms) {
Write-Host "Checking for tag $vmtagname on $azurevm"
$tagRGname = Get-AzVM -Name $azurevm | Select-Object -ExpandProperty ResourceGroupName
$tags = (Get-AzResource -ResourceGroupName $tagRGname -Name $azurevm).Tags
If ($tags.UpdateWindow){
Write-Host "$azurevm already has the tag $vmtagname."
}
else
{
Write-Host "Creating Tag $vmtagname and Value $tagvalue for $azurevm"
$tags.Add($vmtagname,$tagvalue)
Set-AzResource -ResourceGroupName $tagRGname -ResourceName $azurevm -ResourceType Microsoft.Compute/virtualMachines -Tag $tags -Force `
}
}
Write-Host "All tagging is done"
We have multiple VM's in our azure environment with multiple resourcegroups. Some of the resourcegroups have multiple VM's. We are now using an URL triggers webhook that will start or stop VM's. This is working, but when a resourcegroup contains multiple VM's all the VM's will start or all the VM's will stop instead of the one you want to start/stop.
Tried multiple scripts but it's isn't working or give me errors.
param(
[Parameter(Mandatory=$false)]
[object]
$WebHookData
)
write output "Data WebHook $WebHookData"
#retrieve ResourceGroup
$ResourceGroupName = $WebHookData.RequestBody
write output "Data ResourceGroup $ResourceGroupName"
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzureRmAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
$VMs = Get-AzureRmVM -ResourceGroupName $ResourceGroupName
if(!$VMs)
{
Write-Output -InputObject 'No VMs were found in the specified Resource Group.'
}
else
{
ForEach ($VM in $VMs)
{
$StartVM = Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VM.Name -Force #-ErrorAction SilentlyContinue
}
}
$message = ConvertTo-Json -Compress -InputObject ([ordered]#{
headers = #{'content-type' = 'text/plain'}
body = ''
statusCode = 200
})
You could try below script for Start/Stop Virtual machine.
Start VM
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$VMs = Get-AzureRmResource|Where-Object {$_.Tags.Keys -eq "owner" -and $_.Tags.Values -eq "daneum"}
foreach ($VM in $VMs) {
if ($VM.ResourceType -eq "Microsoft.Compute/virtualMachines") {
Start-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Verbose
}
}
Stop VM
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$VMs = Get-AzureRmResource|Where-Object {$_.Tags.Keys -eq "owner" -and $_.Tags.Values -eq "daneum"}
foreach ($VM in $VMs) {
if ($VM.ResourceType -eq "Microsoft.Compute/virtualMachines") {
Stop-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Force -Verbose
}
}
For webhook integration procedure you could take a look here