Azure ARM模式将资源进一步细化,比经典模式要更为灵活,但是带来的的问题是,资源整理和维护起来就要更为琐碎。举一个比较实际的例子,创建了一台虚拟机,会为虚拟机指定虚拟网络(对应子网会生成网络接口),存储账号,公网IP地址,NSG(网络安全组),可用性集,当然还可能有其他资源与其关联。如果删除这台虚拟机,默认虚拟机的所有磁盘会被保留,存储账号会保留,容器会保留,公网IP地址,网络接口会保留,NSG和可用性集也都还在订阅中。一方面是费用上,可能这些保留下来的资源不会再用了,而有些可能仍然会继续计费,另一方面管理上会很混乱,有一大堆“游离”的资源在订阅下,让人眼花缭乱,而且这些资源可能还会占用订阅的配额。
我们可以使用下面的脚本进行这些资源的清理工作,除此之外,脚本中还有对花销比较大的资源(DS虚拟机,高级存储,应用程序网关)的停止和删除逻辑,并且在脚本开始时,我们通过一些布尔变量进行整个脚本逻辑的控制(例如是否关停,是否删除),可以进行一个“test run”来看一下脚本的执行结果(利用脚本中的输出语句和前面的布尔变量控制),这样可以保证我们执行出我们想要的结果,避免关闭或删除掉我们希望保留的资源。同时脚本也定义了一些例外规则(有兴趣的同学可以仿照添加其他例外资源的逻辑)。
对整个脚本进行一些学习,也可以熟悉和掌握遍历订阅下的ARM常见资源的语句和方法。
脚本如下:
#True: Real run/ False: Test run
$doActions = $TRUE;
#True: Real rum/ False: Test run
$doCleanUnusedResources = $TRUE;
#True: Real rum/ False: Test run
$doShutdowns = $TRUE;
#switch for delete/shutdown expensive resources
$doDeleteAppGateway = $TRUE;
$doDeletePremiumStorageAccounts = $TRUE;
#Login Credentials
$e1=Get-AzureRmEnvironment -Name AzureChinaCloud
$Cred = New-Object System.Management.Automation.PSCredential(“XXXX@XXX.parter.onmschina.cn”, (ConvertTo-SecureString “XXXXX” -AsPlainText -Force));
#exceptions
$VMExceptions = @{
#<ResourceGroupName> = "<VM Name 1>;<VM Name 2>;<VM Name 3> ...";
#"Example 1"="VM1;VM2;VM3";
#"Example 2"="VM1;VM2"
};
$AppGWExceptions = @{
#<ResourceGroupName> = "<Application Gateway 1>;<Application Gateway 2>;<Application Gateway 3> ...";
#"Example 1"="ApplicationGateway1;ApplicationGateway2;ApplicationGateway3";
#"Example 2"="ApplicationGateway1;ApplicationGateway2"
};
#Login
$AzureRMCred = Get-Credential -Credential $Cred;
Login-AzureRmAccount -Environment $e1 -Credential $AzureRMCred;
#get all subscriptions
$subscriptions = Get-AzureRmSubscription;
#loop every subscriptions
foreach ($subscription in $subscriptions)
{
#skip disabled subscriptions
if ($subscription.State -eq "Disabled") { continue; }
Write-Host "========== Switched to subscription " + $subscription.SubscriptionName + " ==========";
Select-AzureRmSubscription -SubscriptionName $subscription.SubscriptionName;
#================================================ #Begin# shut down/remove expensive resources ================================================
#shutdown/delete Application Gateways
$applicationGateways = Get-AzureRmApplicationGateway;
foreach ($applicationGateway in $applicationGateways)
{
if ($doDeleteAppGateway)
{
Write-Host " [ApplicationGateway]Removing ApplicationGateway " + $applicationGateway.Name + "...";
if ($doActions)
{
Remove-AzureRmApplicationGateway -Name $applicationGateway.Name -ResourceGroupName $applicationGateway.ResourceGroupName -Force;
}
Write-Host " [ApplicationGateway]ApplicationGateway " + $applicationGateway.Name + " removed.";
} elseif ($doShutdowns)
{
Write-Host " [ApplicationGateway]Stopping ApplicationGateway " + $applicationGateway.Name + "...";
if ($doActions)
{
Stop-AzureRmApplicationGateway -ApplicationGateway $applicationGateway;
}
Write-Host " [ApplicationGateway]ApplicationGateway " + $applicationGateway.Name + " stopped.";
}
}
#stop ARM VMs
$DSVMs = @{};
$vms = Get-AzureRmVM;
foreach ($vm in $vms)
{
$except = $FALSE;
foreach ($resourceGroupName in $VMExceptions.Keys)
{
if ($vm.ResourceGroupName.ToLower().Equals($resourceGroupName.ToLower()))
{
$vmnames = $VMExceptions[$resourceGroupName].Split(";");
foreach ($vmname in $vmnames)
{
if($vmname.ToLower().Equals($vm.Name.ToLower()))
{
$except = $true;
break;
}
}
}
}
if ($vm.HardwareProfile.VmSize.Contains("DS"))
{
#add to DSVM dict to be deleted
if ($DSVMs.ContainsKey($vm.ResourceGroupName))
{
$DSVMs[$vm.ResourceGroupName] += ";";
$DSVMs[$vm.ResourceGroupName] += $vm.Name;
} else
{
$DSVMs.Add($vm.ResourceGroupName, $vm.Name);
}
}
if ($except)
{
Write-Host " [VirtualMachine]Virtual Machine" + $vm.Name + " skipped(In exception list)";
} else
{
$vmStatuses = (Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status).Statuses;
$status = "";
foreach ($code in $vmStatuses.Code)
{
if ($code.Contains("PowerState"))
{
$status = $code.Substring($code.LastIndexOf('/') + 1);
}
}
if (($status -eq "running") -or ($status -eq "stopped"))
{
Write-Host " [VirtualMachine]Stoping VirtualMachine " + $vm.Name + "...";
if ($doActions -and $doShutdowns)
{
Stop-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force;
}
Write-Host " [VirtualMachine]Virtual Machine " + $vm.Name + " stopped.";
} else
{
Write-Host " [VirtualMachine]Virtual Machine " + $vm.Name + " status is " + $status + ", skipped";
}
}
}
#remove ARM DS VMs
foreach ($resoruceGroupName in $DSVMs.Keys)
{
$vmNames = $DSVMs[$resoruceGroupName].Split(';');
foreach ($vmName in $vmNames)
{
Write-Host " [VirtualMachine]Removing DS VirtualMachine " + $vmName + "...";
if ($doActions)
{
Remove-AzureRmVM -ResourceGroupName $resoruceGroupName -Name $vmName -Force;
}
Write-Host " [VirtualMachine]DS VirtualMachine " + $vmName + " Removed.";
}
}
#remove Premium Storage Account
$storageAccounts = Get-AzureRmStorageAccount;
foreach ($storageAccount in $storageAccounts)
{
if($storageAccount.Sku.Tier -eq "Premium")
{
$storageName = $storageAccount.StorageAccountName;
$context = $storageAccount.Context;
$containers = Get-AzureStorageContainer -Context $context;
foreach ($container in $containers)
{
$blobs = Get-AzureStorageBlob -Container $container.Name -Context $context;
if ($blobs.Count -ne 0)
{
#Remove blobs
foreach ($blob in $blobs)
{
Write-Host " [Blob]Removing Blob " + $blob.Name + " in container " + $storageName + "\\" + $container.Name + "...";
if ($doActions -and $doDeletePremiumStorageAccounts)
{
Remove-AzureStorageBlob -Blob $blob.Name -Container $container.Name -Context $context -Force;
}
sleep(5);
$blobTest = Get-AzureStorageBlob -Blob $blob.Name -Container $container.Name -Context $context;
if ($blobTest -ne $NULL)
{
Write-Host " [Blob]Failed to remove Blob " + $blob.Name;
} else
{
Write-Host " [Blob]Blob " + $blob.Name + " Removed.";
}
}
}
#Remove container
Write-Host " [Container]Removing Container " + $container.Name + " under storage account " + $storageName + "...";
if ($doActions -and $doDeletePremiumStorageAccounts)
{
Remove-AzureStorageContainer -Name $container.Name -Context $context -Force;
}
sleep(5);
$containerTest = Get-AzureStorageContainer -Name $container.Name -Context $context;
if ($containerTest -ne $NULL)
{
Write-Host " [Container]Failed to remove Container " + $container.Name;
} else
{
Write-Host " [Container]Container " + $container.Name + " Removed.";
}
}
#Remove storage account
Write-Host " [PremiumStorageAccount]Removing Premium Storage Account " + $storageName;
if ($doActions -and $doDeletePremiumStorageAccounts)
{
Remove-AzureRmStorageAccount -ResourceGroupName $storageAccount.ResourceGroupName -Name $storageName -Force;
}
sleep(5);
$storageTest = Get-AzureRmStorageAccount -StorageAccountName $storageName -ResourceGroupName $storageAccount.ResourceGroupName;
if ($storageTest -ne $NULL)
{
Write-Host " [PremiumStorageAccount]Failed to remove Premium Storage Account " + $storageName;
} else
{
Write-Host " [PremiumStorageAccount]Premium Storage Account " + $storageName + " Removed.";
}
}
}
#================================================ #End# shut down/remove expensive resources ================================================
#================================================ #Begin# clean unused resources ================================================
#clear unused network interfaces
$nics = Get-AzureRmNetworkInterface;
foreach ($nic in $nics)
{
if ($nic.VirtualMachine -eq $NULL)
{
Write-Host " [NIC]Removing unused NIC " + $nic.Name + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureRmNetworkInterface -Name $nic.Name -ResourceGroupName $nic.ResourceGroupName -Force;
}
Write-Host " [NIC]NIC " + $nic.Name + " removed.";
} else
{
Write-Host " [NIC]NIC " + $nic.Name + " is in use, skipped";
}
}
#clear unused public IPAddresses
$ips = Get-AzureRmPublicIpAddress;
foreach ($ip in $ips)
{
if ($ip.IpConfiguration -eq $NULL)
{
Write-Host " [IP]Removing unused IPAddress " + $ip.Name + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureRmPublicIpAddress -Name $ip.Name -ResourceGroupName $ip.ResourceGroupName -Force;
}
Write-Host " [IP]IPAddress " + $ip.Name + " removed.";
} else
{
Write-Host " [IP]IPAddress " + $ip.Name + " is in use, skipped";
}
}
#clear unused NSGs
$nsgs = Get-AzureRmNetworkSecurityGroup;
foreach ($nsg in $nsgs)
{
if ($nsg.Subnets.Count -eq 0 -and $nsg.NetworkInterfaces.Count -eq 0)
{
Write-Host " [NSG]Removing unused NetworkSecurityGroup " + $nsg.Name + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureRmNetworkSecurityGroup -Name $nsg.Name -ResourceGroupName $nsg.ResourceGroupName -Force;
}
Write-Host " [NSG]NetworkSecurityGroup " + $nsg.Name + " removed.";
} else
{
Write-Host " [NSG]NetworkSecurityGroup " + $nsg.Name + " is in use, skipped";
}
}
$resourceGroups = Get-AzureRmResourceGroup;
foreach ($resourceGroup in $resourceGroups)
{
#clear unused AvailabilitySets
$avaSets = Get-AzureRmAvailabilitySet -ResourceGroupName $resourceGroup.ResourceGroupName;
foreach ($avaSet in $avaSets)
{
if ($avaSet.VirtualMachinesReferences.Count -eq 0)
{
Write-Host " [AvaSet]Removing unused AvailabilitySet " + $avaSet.Name + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureRmAvailabilitySet -ResourceGroupName $resourceGroup.ResourceGroupName -Name $avaSet.Name -Force;
}
Write-Host " [AvaSet]AvailabilitySet " + $avaSet.Name + " removed.";
} else
{
Write-Host " [AvaSet]AvailabilitySet " + $avaSet.Name + " is in use, skipped";
}
}
#shutdown Vmss
$vmsses = Get-AzureRmVmss -ResourceGroupName $resourceGroup.ResourceGroupName;
foreach ($vmssName in $vmsses.Name)
{
Write-Host " [Vmss]Stopping Vmss " + $vmssName + "...";
if ($doActions -and $doShutdowns)
{
Stop-AzureRmVmss -ResourceGroupName $resourceGroup.ResourceGroupName -VMScaleSetName $vmssName;
}
Write-Host " [Vmss]Vmss " + $vmssName + " stopped.";
}
}
#clear unused Disks
$storages = Get-AzureRmStorageAccount;
foreach ($storage in $storages)
{
$context = $storage.Context;
#get page blobs under container vhds
$blobs = Get-AzureStorageBlob -Context $context -Container "vhds" | where {$_.BlobType -eq "PageBlob"};
foreach ($blob in $blobs)
{
if ($blob.Name.EndsWith(".vhd") -and $blob.ICloudBlob.Properties.LeaseState -eq "Available" -and $blob.ICloudBlob.Properties.LeaseStatus -eq "Unlocked")
{
Write-Host " [VHD]Removing unused VHD " + $blob.Name + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureStorageBlob -Blob $blob.Name -Container vhds -Context $context -Force;
}
Write-Host " [VHD]VHD " + $blob.Name + " removed.";
} else
{
Write-Host " [VHD]VHD " + $blob.Name + " is in use, skipped";
}
}
}
#clear empty storages
foreach ($storage in $storages)
{
$context = $storage.Context;
#get containers
$containers = Get-AzureStorageContainer -Context $context;
#clear empty containers
foreach ($container in $containers)
{
$blobs = Get-AzureStorageBlob -Container $container.Name -Context $context;
if ($blobs.Count -eq 0)
{
Write-Host " [Container]Removing empty Container " + $container.Name + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureStorageContainer -Name $container.Name -Context $context -Force;
}
Write-Host " [Container]Container " + $container.Name + " removed.";
} else
{
Write-Host " [Container]Container " + $container.Name + " is not empty, skipped";
}
}
#get containers
$containers = Get-AzureStorageContainer -Context $context;
if ($containers.Count -eq 0)
{
Write-Host " [Storage]Removing empty Storage " + $storage.StorageAccountName + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureRmStorageAccount -ResourceGroupName $storage.ResourceGroupName -Name $storage.StorageAccountName -Force;
}
Write-Host " [Storage]Storage " + $storage.StorageAccountName + " removed.";
} else
{
Write-Host " [Storage]Storage " + $storage.StorageAccountName + " is not empty, skipped";
}
}
#clear empty resourcegroups
$resourceGroups = Get-AzureRmResourceGroup;
$resources = Get-AzureRmResource;
foreach ($resourceGroup in $resourceGroups)
{
$resourcesInGroup = $resources | where {$_.ResourceGroupName.Equals($resourceGroup.ResourceGroupName)}
if ($resourcesInGroup.Count -eq 0)
{
Write-Host " [ResourceGroup]Removing empty ResourceGroup " + $resourceGroup.ResourceGroupName + "...";
if ($doActions -and $doCleanUnusedResources)
{
Remove-AzureRmResourceGroup -Name $resourceGroup.ResourceGroupName -Force;
}
Write-Host " [ResourceGroup]ResourceGroup " + $resourceGroup.ResourceGroupName + " removed.";
} else
{
Write-Host " [ResourceGroup]ResourceGroup " + $resourceGroup.ResourceGroupName + " is not empty, skipped";
}
}
#================================================ #End# clean unused resources ================================================
}
Write-Host "Task finished...";