resource cleanup which are only tagged to specific tag - azure

I am using the below AZ script to delete the tag for a resource. But I want only specific tag needs to be deleted not all the tags that are associated with resource. Example
There is tag name "Business unit" value 101, below are the resource name which are inside this tag:
hrm01vm, hrmvnet, hrmappservice
The above resource are also associated with other tags as well like "Department" & "supportedby"
az tag delete --resourceid --yes -y
This deletes the entire tags which are associated with the resource. I want only "Businessunit" tags to be deleted. Any command that I need to include?
Parameters in PS.

After reproducing from my end, I could able to achieve this using Remove("<Key>"). Below is the complete script that worked for me.
$a = Get-AzResource -ResourceGroupName <RESOURCE_GROUP> -Name <FUNCTION_APP>
$a.Tags.Remove("<YOUR_REQUIRED_TAG>")
$a | Set-AzResource -Force
RESULTS:
After execution

Related

Powershell - Using a variable inside a variable

I am trying to leverage Powershell with Azure CLI commands to create variables in an Azure DevOps variable group.
This is typically done using this command:
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value "valueforthevariable"
Since this command is run in a powershell task in my AzureDevOps pipeline, the value comes from a previous step in the pipeline
In short lets assume that the name of the variable (coming from the previous step) is vmStorageAccountName then the following command works perfectly:
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value $(StepsOutputs.vmStorageAccountName)
StepsOutputs being the name of the previouspipeline step.
However since I am getting multiple outputs from the previous step I don't want to manually modify the value name multiple times.
So I have a list of 3 outputs, for example:
$outputs = 'vmstorageAccountname', 'VnetName', 'Rgname'
I tried the following classic loop:
foreach ($output in $outputs) {
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value "$("StepsOutputs.$output")"
But when doing that it takes StepsOutputs.vmstorageAccountname string (or any of the other outputs) as the value for the variable to be created in the variable group. When what I was expecting was to get the vmstorageaccountname itself as we do when not using the loop.
So I guess there is something wrong in the way I am filling the value argument in the command, using a variable inside a variable. I have trying many ways of writing the value arugment but none of them worked. Again if I am not using a loop and the $output variable, this works fine.
To summarize, what I would like is to first have StepsOutputs.$output translated to something like StepOutputs.vmstorageaccountname and then the value should be filled using $(StepOutputs.vmstorageaccountname)
I hope that is clear.
Thank you for your help.
Glad that #user2154222 for solved the issue. Thank you #mclayton for your suggestions that helped to fix the issue. Posting this on behalf of your discussion so that it will be beneficial for other community members.
Using single quotes fix your issue
# with single quotes
# without using additional string while passing value
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value '$($StepsOutputs.vmStorageAccountName)'
Adding some more information to fix the issue:
If you are adding some additional string in your pipeline --value, you have to keep (double quotes) "". or just pass the variable value.
# without quotes
# without using additional string while passing value
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value $($StepsOutputs.vmStorageAccountName)
#using Double Quotes
# using additional string as TESTAPP-$($StepsOutputs.vmStorageAccountName)
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value "TESTAPP-$($StepsOutputs.vmStorageAccountName)"

how do you select just one property from an array of "results" from the Azure command 'az group list in powershell'?

I am trying to select just one property from an array of "result" (objects?) which come back from the Azure command az group list in powershell?
I know this sounds trivial, but here's where it gets strange, and I hope there is a simple explanation.
If I run the Azure command az group list -o table (after I have succesfully logged in using az login) I get the following typical response
PS src> az group list -o table
Name Location Status
---------------- ---------- ---------
group0 westeurope Succeeded
group1 westeurope Succeeded
group2 uksouth Succeeded
group3 westeurope Succeeded
group4 westeurope Succeeded
group5 westeurope Succeeded
group6 westeurope Succeeded
group7 uksouth Succeeded
group8 westeurope Succeeded
group9 westeurope Succeeded
however, if I try to select just the Name property by doing
az group list | select -p name
Then i get about 2 screens full of empty lines, with nothing displayed. So the question is, what's wrong with the command above? And how should I fix it?
I tried the following experiments to dig into the exact types of objects being returned and get some results that I don't understand. I'm hoping this will make sense to someone with more Azure and powershell experience.
Here's the steps to reproduce the problem very easily, assuming you have an azure account.
start powershell, e.g. on mac terminal, type pwsh
log in to azure az login
type az group list -o table
observe that the list comes back and is formatted correctly.
type az group list | select -p name
observe a few screens full of blank lines. no text.
scratch your head and wonder whats just happened? (grin)
THE PLOT THICKENS
az group list on it's own returns a few screens full of this
[
... lots of these ...
{
"id": "/subscriptions/this-is-super-wierd-i-cant-select-name-prop/resourceGroups/spikes",
"location": "westeurope",
"managedBy": null,
"name": "spikes",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {},
"type": null
}
]
however, (az group list).getType() returns
PS src> (az group list).getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
and lastly, hopefully the last 2 pieces of the puzzle
PS src> (az group list)[0].getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
so the return types from az group list appear to be an array of objects or maybe it's an array of object[], my powershell is scratchy here. So to double check, I query for the first 10 elements of that array by doing...(az group list)[0..10] and that returns bizarely 10 strings!. Ok, I know it's supposed to be 10 strings, only because it's a computer and if that's what it is, then, that's what it really is. I just dont understand why.
[
{
"id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/somegroup",
"location": "westeurope",
"managedBy": null,
"name": "admin",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {},
"type": null
So all of this, to cut a long story short, is I'm wanting to know, how do you select just one property from the result of an azure query? In my case, I simply want to display the names of all my resource groups.
This az group list | select -p name should work, but does not, and I'd like to know how to do it properly, and in the process find out why it didn't work, and we can all learn something about Azure and powershell in the process, and life can be great!
Love you all,
Alan
Let's work through this. When we specify -o table e.g.:
az group list -o table
We say to Azure PowerShell CLI take the JSON content you get, and format it into a nice table for us. Typically, we don't want to work with RAW JSON, and we don't want to work with formatted tables either. Working with string arrays in PowerShell are also not a nice thing to use. In PowerShell, we want to work with "nice" easy objects. So, let's look at the other ways to get our information. Let's take your example and simply save it to a variable that we can look at:
$GroupList = az group list
Then if we look as the type:
PS C:\> $GroupList.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Indeed, we have an array of objects. They must be an array of our groups... right?... well no. It's not what you think. If we look at the size of the array and return the first few elements of the array we will see what's going on:
PS C:\> $GroupList.Count
125
PS C:\Temp> $GroupList[0..2]
[
{
"id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/somegroup",
Well, that's not what we wanted. The array is far to large... and looking at the content reveals that what we actually have is an array of each line of the JSON text. This means that running:
az group list | select -p name
or:
$GroupList | select -p name
Is saying, loop through the array, and only output the "Name" property. Since the "Name" property does not exist on a string of text, it simply outputs a blank line. Since there are a few hundred lines of text, we get a few hundred lines of blanks.
So why does PowerShell take the input and break it into an array of strings separated by new lines? Isn't this kinda hard to use? Isn't this not a "great" way to handle a JSON formatted text? Why don't we just get one giant string? Isn't that easier to handle and parse? What's the one reason for this oddness?
Well with PowerShell, the need to support pipelines drives decisions on how we output objects:
"The primary purpose ... is to provide a way to ensure that the result of a pipeline execution is always an indexable collection."
Quote
This is why we get an array of objects outputted (See: #mklement0 answer here for more in depth discussion) to support pipeline operations. And if we look at how text files are read and written to, we can highlight exactly why we end up with this specific cough Programmer cough convenience cough... I mean weirdness.
To set things up, we can pipe the output directly to a text file:
az group list | Out-File -FilePath List.json
Woah, wait a second, why did that just work? (In situations like this, I like to say that PowerShell does Magic!), Don't we have to mess with looping through arrays, appending strings terminated with newlines to get one giant contiguous block of text that ends with an EOF, and exactly matches our desired text file?
A simplified reason behind what really happens? Well, out of programmer convenience, Out-File takes the array of strings, iterates through it, and does a simple File.WriteLine() for each string (not bad for a 3 line for loop!). Hence, we just generated a nice JSON formatted text file complete with newlines without breaking a sweat. Reading it back in:
PS C:\> $ListFromFile = Get-Content .\List.json
PS C:\> $ListFromFile.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS C:\> $ListFromFile.Count
125
Does the reverse. It takes the file, does a File.ReadLine(), appends the strings to an array, and returns it. That's why we end up with an object array that contains strings.
Now, what do we really want? Well we know from the start, we don't want to work with one giant string, and we especially don't want to work with strings in an object array, what we want to work with is a nice native PSCustomObject that we can access. That's what PowerShell works best with, that's what we work best with. So, we simply have to convert our (big air quotes) "text input", which we know is formatted as JSON, and convert it into an object:
$List = $GroupList | ConvertFrom-Json
And looking at the count and properties:
PS C:\> $List.Count
10
PS C:\> $List.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS C:\> $List[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
We see the count now matches how many groups we have, and the types are no longer an array of strings, but actual objects. So... Now, we can start sorting and selecting:
PS C:\> $List | select -Property Name
Name
----
group0
group1
group2
group3
group4
group5
group6
group7
group8
group9
And we get the output that we really wanted.
wow, so much text for something as simple as:
az group list --query '[].name' -o tsv

PowerShell: update O365 AD bulk attributes through csv file

We are trying to bulk update our Azure Active Directory. We have a excel csv list of UserPrincipalNames that we will update the Title, Department, and Office attributes
# Get List of Clinical CMs
$PATH = "C:\Users\cs\Documents\IT Stuff\Project\Azure AD Update\AD-Update-ClinicalCMs-Test.csv"
$CMs = Import-csv $PATH
# Pass CMs into Function
ForEach ($UPN in $CMs) {
# Do AD Update Task Here
Set-Msoluser -UserPrincipalName $UPN -Title "Case Manager" -Department "Clinical" -Office "Virtual"
}
The CSV:
User.1#domain.com
User.2#domain.com
User.3#domain.com
The Set-MsolUser command will work on its own, but it is not working as intended in this For loop. Any help or insight is greatly appreciated
As Jim Xu commented, here my comment as answer.
The input file you show us is not a CSV file, instead, it is a list of UPN values all on a separate line.
To read these values as string array, the easiest thing to is to use Get-Content:
$PATH = "C:\Users\cs\Documents\IT Stuff\Project\Azure AD Update\AD-Update-ClinicalCMs-Test.csv"
$CMs = Get-Content -Path $PATH
Of course, although massive overkill, it can be done using the Import-Csv cmdlet:
$CMs = (Import-Csv -Path $PATH -Header upn).upn

Call Set-AzureRmAppServicePlan cmdlet with arbitrary parameters

I want to call Set-AzureRmAppServicePlan with arbitrary parameters, the list of parameters is defined in runtime and is not set statically.
In other languages like Perl I would use Hash for this, but I get stuck here in Powershell even though I know that Powershell supports HashTables.
Following example does not work
$params = #{}
$params.add('-WorkerSize', 'Small');
$params.add('-NumberofWorkers', '2');
Set-AzureRmAppServicePlan -ResourceGroupName 'RG1' -Name 'AppServicePlna1' $params
I get Set-AzureRmAppServicePlan : Long running operation failed with status 'BadRequest'. error from Azure.
PowerShell does support what you are trying to do. It is known as splatting.
In your case, you have a minor typo. All you need to do is change the $ to an # in this line:
Set-AzureRmAppServicePlan -ResourceGroupName 'RG1' -Name 'AppServicePlna1' $params
So the working version looks like this:
Set-AzureRmAppServicePlan -ResourceGroupName 'RG1' -Name 'AppServicePlna1' #params
The issue is not with PowerShell per say.
Last time I checked you cannot pass 'Parameter key' for an Azure Module command.

I am trying to read the output values from ARM template in post deployment script file. Can you give me the syntax to read those values?

I am trying to read the output values from ARM template in post deployment script file. Can you give me the syntax to read those values?
You could retrieve the out value from a linked template by using reference function.
retrieve the property value with syntax like: "[reference('<name-of-deployment>').outputs.<property-name>.value]"
Note: You cannot use the reference function in the outputs section of a nested template. To return the values for a deployed resource in a nested template, convert your nested template to a linked template.
If Powershell command is possible, we could get the following command
$deploy = New-AzureRmResourceGroupDeployment -Name $deployment -ResourceGroupName $resourceGroupName -TemplateFile $deployJsonFilePath -TemplateParameterFile $deployJsonParameterFilePath
$outPuts = $deploy.Outputs

Resources