How to loop through list of objects in terraform? - azure

I am trying to dynamically fetch list of VMs from azure using external data source and display VM individually.
Below is powershell script
$rgroup = [Console]::In.ReadLine()
$json = ConvertFrom-Json $rgroup
$name = $json.rg
$vm=Get-AzVM -ResourceGroupName $name | select name | convertTo-json
Write-Output "$vm"
Main.tf
variable "resourcegroup" {}
data "external" "test" {
program = ["Powershell.exe", "./vm.ps1"]
query = {
rg = "${var.resourcegroup}"
}}
output "value" {
value = "${data.external.test.result}"}
However, I am getting an error " command "Powershell.exe" produced invalid JSON: json: cannot unmarshal number into Go value of type map[string]string"
Can someone tel me how to loop through list of VMs and display it individually ?
-------------Edited------------
Powershell Script
$rgroup = [Console]::In.ReadLine()
$json = ConvertFrom-Json $rgroup
$name = $json.rg
$vms=(Get-AzVM -ResourceGroupName $name ).name
foreach ($vm in $vms){
$vmname= $vm |convertTo-json
Write-Output "{""Name"" : $vmname}"}
Main.tf
output "value" {
value = "${data.external.powershell_test.result.Name}"}
Powershell output

For your issue, as victor said, Terraform data "external" can only handle flat maps of a JSON module.
With your update, when you output them in the loop, they are not JSON module, just multiple JSON modules, so it also does not match the input of the Terraform data "external".
You can create a JSON module and add the VM names to it. Change your PowerShell script like this:
$rgroup = [Console]::In.ReadLine()
$json = ConvertFrom-Json $rgroup
$name = $json.rg
$vmlist=(Get-AzVM -ResourceGroupName $name).Name
$vmNames=#{}
for($i=0; $i -lt $vmlist.Length; $i++) {
$vmNames["Name$i"] = $vmlist[$i]
}
$vmNames | ConvertTo-Json

data "external" can only handle flat maps, a JSON doc with nested objects will make it fail. You might want to pre-process your Powershell output.

Related

Need to check if 7 specific tags exist on a list of azure VMs

Hello I need to check for if a list of azure VMs have 7 specific tags using PowerShell, the tag values don't need to be checked. If any of the 7 tags are missing then the script will need to write error and print what tags were missing. I can get the tags from
$vmDetails = Get-AzVM -Name $sourceVMName -ResourceGroupName $sourceResourceGroupName
$vmTags = $vmDetails.Tags
Then I can run a loop
foreach ($keyval in $vmtags.keys)
but I am unsure how to do the comparison without a bunch of if statements. I'm sure an array is needed but can't remember what may be best. thanks a bunch.
Assuming the Tags property is a hashtable as you have shown on your code, the code (pseudo code as I don't have a way of testing this) could look like this:
# Get the base Tags needed to compare
$vmDetails = Get-AzVM -Name $sourceVMName -ResourceGroupName $sourceResourceGroupName
# Assuming the Tags property is a Hashtable
$vmTags = $vmDetails.Tags.Keys
# Get the count of Tags
$i = $vmTags.Count
# Get all existing VMs on a Resource Group
$allVMs = Get-AzVM -ResourceGroupName $sourceResourceGroupName
foreach($vm in $allVMs)
{
# Store the Tags of this VM
$thisVMtags = $vm.Tags.Keys
# If the count of Tags of this VMs is not the same as the count of Base Tags
if($thisVMtags.Count -ne $i)
{
# Get the missing Tags of this VM
$missingTags = $vmTags.where({
$_ -notin $thisVMtags
}) -join ', '
# Write a warning with details of this VM Name and the missing Tags
Write-Warning "{0} is missing the following Tags: {1}" -f $vm.Name, $missingTags
}
}

Recursively list all resource tags within Azure Resource Groups

We have a large number of Azure Subscriptions which currently run into the hundreds.
I'm looking to generate a report (ideally using Azure Powershell or Azure CLI) to recursively extract a list of all tags assigned to every single resource within every resource group, for between 40-50 of the subscriptions.
Currently, I can list all tags assigned at Resource Group level, but I simply can't find a way to list the tags assigned to the individual resources within each Resource Group. The list of subscriptions and resource groups on which I'd like to extract this report, are saved in a CSV file which includes two columns displaying the Subscription name and Resource Group respectively.
Any tips on how to achieve the above would be fantastic and most appreciated.
Not detailed code but the idea here.
1.You should write a loop, in the loop, change the subscription each time by using this cmdlet:
Set-AzContext -Subscription $subscription_name.
2.Then get all the resource group in the specified subscription by using this cmdlet:
$resource_groups = Get-AzResourceGroup
3.Then write a nested loop(loop for each resource group), in this nested loop, use this cmdlet to get all azure resources within a resource group:
foreach($rg in $resource_groups){
$azure_resources = Get-AzResource -ResourceGroupName $rg.ResourceGroupName
}
4.Write another nested loop in step 3, this loop is used to go though all the azure resources within the specified resource group. Then use the code below to fetch tags for each azure resource within the resource group:
foreach($r in $azure_resources){
#the following code can get all the tags for one resource
$r.tags
}
Based on Ivan Yang's logic. I have built the PowerShell Script;
#---------DECLARE VARIABLES------------------------------------#
$bnsSubscription = Get-AzSubscription
$day = Get-Date -Format " ddMMMyyyy"
$tagPath = "C:\mytempfolder\"+"$day-Tag-Details.csv"
$tagFolderPath = "C:\mytempfolder\"
#---------DECLARE VARIABLES------------------------------------#
function Get-ResourceTag {
foreach ($subs in $bnsSubscription) {
Select-AzSubscription -SubscriptionName $subs.Name | Out-Null
Write-Host 'The selected Subscription is' ($subs).Name
New-Item -ItemType file -Path "$tagFolderPath\$($subs.Name).csv" -Force
$resource_groups = Get-AzResourceGroup
$resource_groups_details = Get-AzResourceGroup | Sort-Location ResourceGroupName | Format-Table -GroupBy Location ResourceGroupName,ProvisioningState,Tags
Write-Host 'The selected Resource Group is' ($resource_groups).Name 'and the tag information as follows'
#$resource_groups_details
$resource_groups | Select-Object ResourceGroupName,Tags | Export-CSV -Path "$tagFolderPath\$($subs.Name).csv" -Append
$OutputFile = #()
foreach($rg in $resource_groups){
$azure_resources = Get-AzResource -ResourceGroupName $rg.ResourceGroupName
$TestTags = $Resource.Tags.GetEnumerator()
foreach($r in $azure_resources){
Write-Host 'The selected resource is' ($r).Name 'and the information as follows'
$RGHT = New-Object "System.Collections.Generic.List[System.Object]"
$RGHT.Add("RGName",$r.ResourceGroupName)
$RGHT.Add("ResourceName",$r.name)
$RGHT.Add("Location",$r.Location)
$RGHT.Add("Id",$r.ResourceId)
$RGHT.Add("ResourceType",$r.ResourceType)
$RGHT.Add("ResourceTags",$r.Tags)
$OutputFile += New-Object psobject -Property $RGHT
$OutputFile | Export-Csv -Path "C:\mytempfolder\test22.csv" -append -NoClobber -NoTypeInformation -Encoding UTF8 -Force
}
}
}
}
#---------CALL FUNCTION------------------------------------#
Get-ResourceTag

Powershell question about parsing the tag values in Get-AzVm

I'm attempting to load individual tag key and value records per VM using the Get-AzVm cmdlet. The values are stored like:
"Tags : {"Purpose":"SQL Server","Test":"Value"}"
I want to load them like:
VMID, VMName, Key, Value
No amount of searching or testing with ForEach, ForEach-Object or loading in to a hash is working as the results are always null, but what is loaded in to a variable is not. I would be very grateful for any suggestions.
$vm_list = Get-AzVM -Name #######
foreach ($name in $vm_list)
{
$_ = $vm_list.tags.GetEnumerator() |
ForEach-Object{
$k = $_.key
$v = $_.value
Write-Host $tagkeys.VMID, $tagkeys.Name, $k, $v
}
}
There is more to the script, but this is what I have working now. Using enumerator, I would have expected to need to reference the objects as {0} and {1}.

How do i get a list of Vm in a recourse group

Im trying to get all Vms in a resource group then send every element to a function
$a = Get-AzureRmVM -ResourceGroupName Test2 | ft Name
foreach($output in $a) {Stop-AzRmVM -ResourceGroupName "Test2" -Name $output}
Im getting this error message
Start-AzureRmVM : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Name'. Specified
method is not supported.
Anish K is correct about the Name parameter expecting a String, not an array of objects.
However, you should also remove the | ft Name because that is only for outputting stuff to console.
I'd use a ForEach-Object here like this (untested):
Get-AzureRmVM -ResourceGroupName 'Test2' | ForEach-Object {
$_ | Stop-AzRmVM
}
As per the error, you are passing an object[] instead of string. Your function Stop-AzRmVm expects string for Name parameter.
Changes your script like below:
$a = Get-AzureRmVM -ResourceGroupName Test2 | ft Name
foreach($output in $a) {Stop-AzRmVM -ResourceGroupName "Test2" -Name $output.Name}

Custom Objects to CSV PowerShell

#Function to get the computerlist: Name,OS,IPv4, IPv6,DiskInfo
function Get-ComputerListnDiskInfo{
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)] [string[]]$ComputerName
)
BEGIN {
Import-Module ActiveDirectory -Cmdlet Get-ADComputer -ErrorAction SilentlyContinue
}
PROCESS {
try{
$computerinfo = Get-ADComputer -Filter * -Properties OperatingSystem
#Information about Name,Ipv4,IPv6,Device,VolumeName,Free,Busy,Size,Pfree,Pbusy for ALL COMPUTERS container
$AllComputerInfo = #()
foreach ($comp in $computerinfo){
#Testing if computers is ON LINE
$TestCon = Tester $comp.name
$test = $TestCon.BooleanV
if($test) {
#write-output "$Test"
$PhysicalDisks = Get-WMIObject -computername $comp.name -query "SELECT * from win32_logicaldisk where DriveType = 3" | Select Deviceid,VolumeName,FreeSpace,Size
$Target = #()
#Create the Object foreach disk and append in the Target Variable
$GetOPNHealthStatus = Get-PhysicalDisk | select FriendlyName,OperationalStatus,HealthStatus
Write-Output "$PhysicalDisk.count"
#write-output $GetOPNHealthStatus.OperationalStatus
$i=0
foreach ($disk in $physicalDisks){
#Get all Items: size,free,busy,pfree and pbusy disk space info (can add a number at the end to set decimals)
$Size=FormatNSetSizeFreeSpace $disk.Size
$Free=FormatNSetSizeFreeSpace $disk.FreeSpace
$Busy=FormatNSetBusySpace $disk.Size $disk.FreeSpace
$Pfree=PercentFreeBusy $Free $size
$PBusy=PercentFreeBusy $Busy $size
#Create a new Object using all the info
$result =New-Object PSObject -Property #{
Device=$disk.DeviceID
VolumeName=$disk.VolumeName
Size=$Size
Free=$Free
Busy=$Busy
Pfree = $PFree
PBusy = $PBusy
OPStatus = $GetOPNHealthStatus.OperationalStatus[$i]
HStatus = $GetOPNHealthStatus.HealthStatus[$i]
}
$i++
#add this info to the target array
$Target+= $result
}
#Add all info into new object
$allIComnDiskInfo=New-Object PSObject -Property #{
Name = $comp.Name
OS = $comp.OperatingSystem
IPV4 = $TestCon.IPv4
IPV6 = $TestCon.IPv6
disksInfo = $Target
}
#and Fill any just add this info to the $Allcomputer info (just online computer's)
$AllComputerInfo+= $allIComnDiskInfo
}
}
return $AllComputerInfo
}
Catch{
Write-Warning $_.Exception.Message
}
}
}
$test = Get-ComputerListnDiskInfo
running $test
$test = Get-ComputerListnDiskInfo
$test
disksInfo : {#{PBusy=8,148; VolumeName=; Busy=10,306; Pfree=91,853; Free=116,178; Device=C:; Size=126,483; OPStatus=O; HStatus=H}}
Name : DC2012
OS : Windows Server 2012 R2 Standard
IPV4 : 192.168.1.251
IPV6 : fe80::cd63:76bf:3d2b:340f%12
And running
$test | Export-Csv here.csv
I got this:
#TYPE System.String
"Length"
"6"
Why is happening this?
Why I don't get all this info?
And how should I search the info contained in the "diskInfo" variable
I tried to pass this $test variable to another function to format it and It seem not to work:
Thank you in advance for the answers
To start out with, you aren't just outputting a custom object, or an array of custom objects. But that's not the first problem I see. The first problem I see is that you have this big function that has a parameter, and then you do this:
$test = Get-ComputerListnDiskInfo
So you call that function with no arguments, so it has no computer to run it against. Some of the parts of the function will probably default to the local computer, but will they all? I don't know, maybe.
So what does $test actually contain? An array. Of what? Well, the first thing that the function outputs is a string:
Write-Output "$PhysicalDisk.count"
So the first item in your array is a string. Then you build a bunch of custom objects and arrays, and what not, and you Return those. Great, the next item in your $test array is a custom object. But $test is not an array of custom objects, or a single custom object, it is an array with a variety of things within it.
That is why Export-CSV will not work.
Basically the issue is this one:
I have an system.object[] in the output while using CSV.
object or similar output when using export-csv

Resources