I need to empty my Azure account from all resources and there's too much to remove individually in the portal. Looking for a powershell script to do this. Thanks.
As resources in Azure are grouped into resource groups(RG), that would probably be the easiest way to go about this. Use these cmdlets to do this.
Get-AzureRmResourceGroup
Remove-AzureRmResourceGroup
Once you have retrieved all the RGs, you can pipe the results with the | character to the Remove cmdlet and iterate through them with a ForEach loop. Give it a go, it is the best way to learn, as opposed to simply asking for the solution on here.
Alternatively, if you don't want to use powershell, just delete your RGs from the portal. I assume you think it would take too long because you are looking at the individual resources and not their RGs, but if you really do have that many RGs, then scripting is best.
#It will delete all resources without asking any confirmation
Login-AzureRmAccount
$rgName = Get-AzureRmResourceGroup
Foreach($name in $rgName)
{
Write-Host $name.ResourceGroupName
Remove-AzureRmResourceGroup -Name $name.ResourceGroupName -Verbose -Force
}
A script like that could be really harmful... but also very useful.
I've created a little script and add little security on it to avoid nuking the wrong subscription.
The script asks you to login-in then list all the subscriptions that this account has access. Once you specify which one, it will list all the resource grouped by resource group. Then as a final warning, it will require one last validation before nuking everything.
# Login
Login-AzureRmAccount
# Get a list of all Azure subscript that the user can access
$allSubs = Get-AzureRmSubscription
$allSubs | Sort-Object SubscriptionName | Format-Table -Property SubscriptionName, SubscriptionId, State
$theSub = Read-Host "Enter the subscriptionId you want to clean"
Write-Host "You select the following subscription. (it will be display 15 sec.)" -ForegroundColor Cyan
Get-AzureRmSubscription -SubscriptionId $theSub | Select-AzureRmSubscription
#Get all the resources groups
$allRG = Get-AzureRmResourceGroup
foreach ( $g in $allRG){
Write-Host $g.ResourceGroupName -ForegroundColor Yellow
Write-Host "------------------------------------------------------`n" -ForegroundColor Yellow
$allResources = Find-AzureRmResource -ResourceGroupNameContains $g.ResourceGroupName
if($allResources){
$allResources | Format-Table -Property Name, ResourceName
}
else{
Write-Host "-- empty--`n"
}
Write-Host "`n`n------------------------------------------------------" -ForegroundColor Yellow
}
$lastValidation = Read-Host "Do you wich to delete ALL the resouces previously listed? (YES/ NO)"
if($lastValidation.ToLower().Equals("yes")){
foreach ( $g in $allRG){
Write-Host "Deleting " $g.ResourceGroupName
Remove-AzureRmResourceGroup -Name $g.ResourceGroupName -Force -WhatIf
}
}
else{
Write-Host "Aborded. Nothing was deleted." -ForegroundColor Cyan
}
The code is available on GitHub: AzurePowerTools
switch to the poweshell shell in Azure and run this command to wipe everything..
Get-AzureRmResourceGroup | Remove-AzureRmResourceGroup -verbose -Force
I know the ask was for Powershell, but if anyone is interested here is for Azure CLI
#!/bin/bash
# NOTE: Be careful as this code in intended to delete ALL Resources in a subscription. Use at your own risk.
# Set The correct Subscription
az account set -s "<Subscription_name / Id>"
# Get All resource groups and loop to delete them
for rg_name in `az group list -o tsv --query [*].name`; do
echo Deleting ${rg_name}
az group delete -n ${rg_name} --yes --no-wait
done
Updated for new Azure PowerShell module Az
# Login
Connect-AzAccount
# Get a list of all Azure subscript that the user can access
$allSubs = Get-azSubscription
$allSubs | Sort-Object SubscriptionName | Format-Table -Property SubscriptionName, SubscriptionId, State
$theSub = Read-Host "Enter the subscriptionId you want to clean"
Write-Host "You select the following subscription. (it will be display 15 sec.)" -ForegroundColor Cyan
Get-azSubscription -SubscriptionId $theSub | Select-azSubscription
#Get all the resources groups
$allRG = Get-azResourceGroup
foreach ( $g in $allRG){
Write-Host $g.ResourceGroupName -ForegroundColor Yellow
Write-Host "------------------------------------------------------`n" -ForegroundColor Yellow
$allResources = Get-azResource -ResourceGroupName $g.ResourceGroupName | FT
if($allResources){
$allResources | Format-Table -Property Name, ResourceName
}
else{
Write-Host "-- empty--`n"
}
Write-Host "`n`n------------------------------------------------------" -ForegroundColor Yellow
}
$lastValidation = Read-Host "Do you wich to delete ALL the resouces previously listed? (YES/ NO)"
if($lastValidation.ToLower().Equals("yes")){
foreach ( $g in $allRG){
Write-Host "Deleting " $g.ResourceGroupName
Get-AzResourceGroup -Name $g.ResourceGroupName | Remove-AzResourceGroup -Verbose -Force
}
}
else{
Write-Host "Aborded. Nothing was deleted." -ForegroundColor Cyan
}
To remove all resources from Azure Resource Group but to keep the group with its settings:
Get-AzResource -ResourceGroupName $ResourceGroupName | Remove-AzResource -Force
Below command can be used to delete all resources
Get-AzResource | Remove-AzResource -force
here is a one-line (please log in using az login)
az group list | ConvertFrom-Json | % {az group delete --name $_.name -y}
Simple pipeline with Az module.
Get-AzResourceGroup | Remove-AzResourceGroup -Force
Related
Please do not kill me as I am a newbie in Windows system administration ;) started few months ago and so I would kindly need a bit of help:
Basically , I would like to use values issued from a text file as variables:
($Clustername and $NewFSWPath) as described into the piece of PS code below:
$ClusterName = "GLA-CLU"
$NewFSWPath = "\\DC01\SQL-CLU"
#As quorum file share witness is a cluster core resource, the only way to remove an existing FSW in PS is to switch the cluster to node majority. It will remove the existing Cluster File Share Witness from the chosen cluster
Set-ClusterQuorum -Cluster $ClusterName -NodeMajority
#Set New Quorum File Share Witness for the cluster
#Add-ADGroupMember $FileShareSecurityGroup -Members "$ClusterName"
$t = $host.ui.RawUI.ForegroundColor
$host.ui.RawUI.ForegroundColor = "Yellow"
Write-Output "Setting A New Location for File Share Witness on cluster: '$($ClusterName)':"
Write-Host "`r"
$host.ui.RawUI.ForegroundColor = $t
Set-ClusterQuorum -Cluster $ClusterName -NodeAndFileShareMajority $NewFSWPath
Write-Host "`r"
$host.ui.RawUI.ForegroundColor = $t
$host.ui.RawUI.ForegroundColor = "Yellow"
Write-Output "Checking New File Share Witness Availablity:"
$host.ui.RawUI.ForegroundColor = $t
Get-clusterresource -cluster $ClusterName | where-object {$_.ResourceType -like "File Share Witness"} | get-clusterparameter
Much appreciated.
Thank you.
Assuming your TEXT_FILE.TXT contains only two lines:
Clustername = GLA-CLU
NewFSWPath = \\DC01\SQL-CLU
then
$Path = "C:\TEXT_FILE.TXT"
$Lines = [System.IO.File]::ReadLines($Path)
$Token = $Lines.Split('=').Trim()
$ClusterName = $Token[1]
$NewFSWPath = $Token[3]
Write-Host $ClusterName
write-host $NewFSWPath
output:
GLA-CLU
\\DC01\SQL-CLU
now you can use your variables $ClusterName, $NewFSWPath in your script as required.
Thanks, but I managed to sort it out using:
Get-Content 'fswsiteconf.txt' | Foreach-Object{
$var = $_.Split('=')
New-Variable -Name $var[0] -Value $var[1] }
It works for me now using the piece of code indicated above
What do you think as a solution?
Thanks for your help.
How to calculate size of all Azure Storage Tables from a Subscription using Powershell.
I tried to search online if there is any direct way of querying table sizes but looks like there isn't.
Can you someone please give me a working model of calculating a Azure Storage Table size.
Please.
FOREACH ($SubscriptionID in $Subscriptions) {
Write-Host -ForegroundColor Green "Working on $N. $SubscriptionID"
$StorageAccounts = Get-AzStorageAccount
FOREACH ($StorageAccount in $StorageAccounts) {
$StorageAccountName = $StorageAccount.StorageAccountName
Write-Host -ForegroundColor Yellow "Working on $StorageAccountName"
$AllTables = Get-AzStorageTable -Context $StorageAccount.Context
FOREACH ($TableName in $AllTables) {
$Name = $TableName.Name
Write-Host -ForegroundColor Green "Working on $StorageAccountName,$Name"
Get-AzStorageTable –Name $TableName.Name –Context $StorageAccount.Context
}
}
$N = $N+1
}
You can calculate the size of all Azure Storage Tables, but the minimum granularity could just be all the tables in a storage account, not a specific table.
Try the command as below, it works fine on my side.
$StorageAccounts = Get-AzStorageAccount
foreach($item in $StorageAccounts){
$id = $item.Id+"/tableServices/default"
$name = $item.StorageAccountName
$metric = Get-AzMetric -ResourceId $id -MetricName "TableCapacity" -WarningAction Ignore
$data = $metric.Data.Average/1024/1024
Write-Output "Tables in $name : $data MB"
}
Besides, looks you want to use the command in several subscriptions, if so, I think you need to run Set-AzContext to set the subscription before running the command above.
Set-AzContext -SubscriptionId "xxxx-xxxx-xxxx-xxxx"
Thought I would share this quick function I made for myself, feel free to adapt it and improve it according to your needs.
Sometimes you want to run commands as the logged on user of a remote computer.
As you know, some commands show output for the user who runs it and if you run the same command with Invoke-Command, it won't return the user's information, but yours). Get-Printer is an example amongst many others.
There is no easy, quick way of running commands as the logged on user natively without any third-party apps like PsExec or others so I made this quick function that uses VBS, PS1 and Scheduled Task to make it happen.
It runs completly silently for the user (thanks to the VBS) and the output is shown in your console. Please note it assumes the remote computer has a C:\TEMP.
Created in a Windows 10, powershell v 5.1.17763.503 environement.
I don't pretend it's final and perfect, it's the simplest way I found to do what is needed and I just wanted to share it with you guys as it can be very useful!
Check the comments for explanation of the code and feel free to use it as you wish. Please share your version as I'm curious to see people improve it. A good idea would be to make it support multiple computers, but as I said it's a quick function I did I don't have too much time to put into refining it.
That being said, I had no problems using it multiple times as is :)
*Output returned is in form of a string, if you want to have a proper object, add '| ConvertFrom-String' and play with it :)
PLEASE NOTE: The surefire way of grabbing the username of who is currently logged on is via QWINSTA (since Win32_ComputerSystem - Username is only reliable if a user is logged on LOCALLY, it won't be right if a user is using RDP/RemoteDesktop). So this is what I used to grab the username, however, please note that in our french environement the name of the username property in QWINSTA is "UTILISATEUR",so you have to change that to your needs (english or other language) for it to work. If I remember correctly, it's "USERNAME" in english.
On this line:
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
See code in the answer below.
function RunAsUser {
Param ($ComputerName,$Scriptblock)
#Check that computer is reachable
Write-host "Checking that $ComputerName is online..."
if (!(Test-Connection $ComputerName -Count 1 -Quiet)) {
Write-Host "$ComputerName is offline" -ForegroundColor Red
break
}
#Check that PsRemoting works (test Invoke-Command and if it doesn't work, do 'Enable-PsRemoting' via WMI method).
#*You might have the adjust this one to suit your environement.
#Where I work, WMI is always working, so when PsRemoting isn't, I enable it via WMI first.
Write-host "Checking that PsRemoting is enabled on $ComputerName"
if (!(invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)) {
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "powershell.exe -command Enable-PSRemoting -SkipNetworkProfileCheck -Force" | Out-Null
do {
Start-Sleep -Milliseconds 200
} until (invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)
}
#Check that a user is logged on the computer
Write-host "Checking that a user is logged on to $ComputerName..."
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
if (!($LoggedOnUser) ) {
Write-Host "No user is logged on to $ComputerName" -ForegroundColor Red
break
}
#Creates a VBS file that will run the scriptblock completly silently (prevents the user from seeing a flashing powershell window)
#"
Dim wshell, PowerShellResult
set wshell = CreateObject("WScript.Shell")
Const WindowStyle = 0
Const WaitOnReturn = True
For Each strArg In WScript.Arguments
arg = arg & " " & strArg
Next 'strArg
PowerShellResult = wshell.run ("PowerShell " & arg & "; exit $LASTEXITCODE", WindowStyle, WaitOnReturn)
WScript.Quit(PowerShellResult)
"# | out-file "\\$ComputerName\C$\TEMP\RAU.vbs" -Encoding ascii -force
#Creates a script file from the specified '-Scriptblock' parameter which will be ran as the logged on user by the scheduled task created below.
#Adds 'Start-Transcript and Stop-Transcript' for logging the output.
$Scriptblock = "Start-Transcript C:\TEMP\RAU.log -force" + $Scriptblock + "Stop-Transcript"
$Scriptblock | out-file "\\$ComputerName\C$\TEMP\RAU.ps1" -Encoding utf8 -force
#On the remote computer, create a scheduled task that runs the .ps1 script silently in the user's context (with the help of the vbs)
Write-host "Running task on $ComputerName..."
Invoke-Command -ComputerName $ComputerName -ArgumentList $LoggedOnUser -ScriptBlock {
param($loggedOnUser)
$SchTaskParameters = #{
TaskName = "RAU"
Description = "-"
Action = (New-ScheduledTaskAction -Execute "wscript.exe" -Argument "C:\temp\RAU.vbs C:\temp\RAU.ps1")
Settings = (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd)
RunLevel = "Highest"
User = $LoggedOnUser
Force = $true
}
#Register and Start the task
Register-ScheduledTask #SchTaskParameters | Out-Null
Start-ScheduledTask -TaskName "RAU"
#Wait until the task finishes before continuing
do {
Write-host "Waiting for task to finish..."
$ScheduledTaskState = Get-ScheduledTask -TaskName "RAU" | Select-Object -ExpandProperty state
start-sleep 1
} until ( $ScheduledTaskState -eq "Ready" )
#Delete the task
Unregister-ScheduledTask -TaskName "RAU" -Confirm:$false
}
Write-host "Task completed on $ComputerName"
#Grab the output of the script from the transcript and remove the header (first 19) and footer (last 5)
$RawOutput = Get-Content "\\$ComputerName\C$\temp\RAU.log" | Select-Object -Skip 19
$FinalOutput = $RawOutput[0..($RawOutput.length-5)]
#Shows output
return $FinalOutput
#Delete the output file and script files
Remove-Item "\\$ComputerName\C$\temp\RAU.log" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.vbs" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.ps1" -force
}
#____________________________________________________
#Example command
#Note: Sometimes Start-Transcript doesn't show the output for a certain command, so if you run into empty output, add: ' | out-host' or '| out-default' at the end of the command not showing output.
$Results = RunAsUser -ComputerName COMP123 -Scriptblock {
get-printer | Select-Object name,drivername,portname | Out-host
}
$Results
#If needed, you can turn the output (which is a string for the moment) to a proper powershell object with ' | ConvertFrom-String'
I'm tying to change a value on a tag, using an automation script. The users will have a startup script, which will change the shutdown tag key from true to false.
When I set the tags individually using the script below it sets the tag value to false. The current setting is true.
When I use the automation script it wipes all the tags, however If I specify the vm in the script the automaton account works and changes the key value from false to true.
I can't see what I'm missing. This is from a webhook and is running as a powershell script, not a workflow.
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[object]$WebhookData
)
Write-Output "------------------------------------------------"
Write-Output "`nConnecting to Azure Automation"
$Connection = Get-AutomationConnection -Name AzureRunAsConnection
Add-AzureRMAccount -ServicePrincipal -Tenant $Connection.TenantID `
-ApplicationId $Connection.ApplicationID -CertificateThumbprint $Connection.CertificateThumbprint
$RunbookVersion = "0.0.17"
$timeStartUTC = (Get-Date).ToUniversalTime()
Write-Output "Workflow started: Runbook Version is $RunbookVersion"
Write-Output "System time is: $(Get-Date)"
Write-Output "`nGetting tagged resources"
Write-Output "------------------------------------------------"
$ResourceGroupFilter = ""
$SupportedEnvironments = "DEV, Test, PREProd, Prod"
$isWebhookDataNull = $WebhookData -eq $null
Write-Output "Is webhook data null ? : $($isWebhookDataNull)"
# If runbook was called from Webhook, WebhookData will not be null.
If ($WebhookData -ne $null) {
# Collect properties of WebhookData
$WebhookName = $WebhookData.WebhookName
$WebhookHeaders = $WebhookData.RequestHeader
$WebhookBody = $WebhookData.RequestBody
$body = $WebhookBody | ConvertFrom-Json
$UserEmail = $body.user.email
Write-Output "Runbook started from webhook '$WebhookName' by '$($body.user.email)' for environment '$($body.environment)'"
Write-Output "Message body: " $WebhookBody
}
else {
Write-Error "Runbook mean to be started only from webhook."
}
If ($body.environment.ToUpper() -eq 'DEV') {
$ResourceGroupFilter = 'The-DEV-RG'
}
if ($ResourceGroupFilter -eq "") {
Exit 1
}
if($VMRG -eq ''){
Write-Output "No resource groups matched for selected environment. Webhook cant progress further, exiting.."
Write-Error "No resource groups matched for selected environment. Webhook cant progress further, exiting.."
Exit 1
}
$rgs = Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "*$rg*"}
foreach ($rg in $rgs)
{
$vms = Get-AzureRmVm -ResourceGroupName $rg.ResourceGroupName
$vms.ForEach({
$tags = $_.Tags
$tags['ShutdownSchedule_AllowStop'] = "$False";
Set-AzureRmResource -ResourceId $_.Id -Tag $tags -Force -Verbose
})
}
ForEach ($vm in $vms) {
Start-AzureRmVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Verbose
}
Thanks in advance :)
The root reason is your local Azure Power Shell is latest version, but in Azure automation account, it is not latest version. I test in my lab, older version does not support this.
You need upgrade Azure Power Shell version. More information about this please see this answer.
I'm trying to verify if ResourceGroup exist or not so i thought that following code should return true or false, but it doesn't output anything.
$RSGtest = Find-AzureRmResource | Format-List ResourceGroupName | get-unique
$RSGtest -Match "$myResourceGroupName"
Why am I not getting any output?
Update:
You should use the Get-AzResourceGroup cmdlet from the new cross-plattform AZ PowerShell Module now. :
Get-AzResourceGroup -Name $myResourceGroupName -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent)
{
# ResourceGroup doesn't exist
}
else
{
# ResourceGroup exist
}
Original Answer:
There is a Get-AzureRmResourceGroup cmdlet:
Get-AzureRmResourceGroup -Name $myResourceGroupName -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent)
{
# ResourceGroup doesn't exist
}
else
{
# ResourceGroup exist
}
try this
$ResourceGroupName = Read-Host "Resource group name"
Find-AzureRmResourceGroup | where {$_.name -EQ $ResourceGroupName}
I am a PS newbie and I was looking for a solution to this question.
Instead of searching directly on SO I tried to investigate on my own using PS help (to get more experience on PS) and I came up with a working solution.
Then I searched SO to see how I compared to experts answers.
I guess my solution is less elegant but more compact. I report it here so others can give their opinions:
if (!(Get-AzResourceGroup $rgname -ErrorAction SilentlyContinue))
{ "not found"}
else
{"found"}
Explanation of my logic: I analyzed the Get-AzResourceGroup output and saw it's either an array with found Resource groups elements or null if no group is found. I chose the not (!) form which is a bit longer but allows to skip the else condition. Most frequently we just need to create the resource group if it doesn't exist and do nothing if it exists already.
I was also looking for the same thing but there was a additional condition in my scenario.
So I figured it out like this. To get the scenario details follow
$rg="myrg"
$Subscriptions = Get-AzSubscription
$Rglist=#()
foreach ($Subscription in $Subscriptions){
$Rglist +=(Get-AzResourceGroup).ResourceGroupName
}
$rgfinal=$rg
$i=1
while($rgfinal -in $Rglist){
$rgfinal=$rg +"0" + $i++
}
Write-Output $rgfinal
Set-AzContext -Subscription "Subscription Name"
$createrg= New-AzResourceGroup -Name $rgfinal -Location "location"
Had a similar challenge, I solved it using the script below:
$blobs = Get-AzureStorageBlob -Container "dummycontainer" -Context $blobContext -ErrorAction SilentlyContinue
## Loop through all the blobs
foreach ($blob in $blobs) {
write-host -Foregroundcolor Yellow $blob.Name
if ($blob.Name -ne "dummyblobname" ) {
Write-Host "Blob Not Found"
}
else {
Write-Host "bLOB already exist"
}
}