Skip to content

Lab 1.3: Cloud Service Provider Tools

VMs Needed

  • Windows
  • Ubuntu

Lab Video

CSP Tools

Objectives

  • Configure CLI and PowerShell tools on Windows to connect to cloud service providers (CSPs).
  • Configure Ubuntu tools to connect to CSPs.
  • Test connectivity with queries in each CLI/PowerShell module.
  • Use JMESPath and jq to manage returned data.

Lab Preparation

Launch a PowerShell Core terminal on the Windows VM by clicking the Windows Terminal icon in the taskbar.

Part 1: Explore AWS CLI and PowerShell Commands

Environment Check

Before proceeding, ensure that you are working in Windows Terminal in PowerShell Core.

Background: In this section, you will practice using CLI and PowerShell commands to gather information from AWS and to manipulate the output format to suit your needs. The CLI has numerous options to customize the data being returned and the format in which it is displayed.

Instructions: Start by retrieving your own account information in text table format.

aws sts get-caller-identity --output table
Sample Results
PS > aws sts get-caller-identity --output table
-------------------------------------------------------------
|                     GetCallerIdentity                     |
+---------+-------------------------------------------------+
|  Account|  ############                                   |
|  Arn    |  arn:aws:iam::###############################   |
|  UserId |  #####################                          |

Note that the CLI returns property names and values in color (obviously not visible in our monochrome screen captures). You can disable color output using the --color off flag

aws sts get-caller-identity --output table --color off

The CLI offers output for many commands as plain text. Rerun the command with text output using this command:

aws sts get-caller-identity --output text
Sample Results
PS > aws sts get-caller-identity --output text
############    arn:aws:iam::###############################    #####################

We will often try to get data in a machine-readable format like CSV, XML, or JSON. Most cloud service providers support JSON output from their APIs and CLI tools. Run the command again, specifying JSON output:

aws sts get-caller-identity --output json
Sample Results
PS > aws sts get-caller-identity --output json
{
    "UserId": "#####################",
    "Account": "############",
    "Arn": "arn:aws:iam::###############################"
}

The default output format is something that you configured when you logged in to AWS using the aws configure command earlier. AWS stores your credentials and configuration options for the CLI in two different files. The config file contains your region and data output settings. You can view the config file with this command. Note that your default output format is json if you correctly followed the login instructions in Lab 1.1.

Get-Content C:\Users\Student\.aws\config
Sample Results
PS > Get-Content C:\Users\Student\.aws\config
[default]
region = us-east-2
output = json

The AWS CLI allows you to use the JMESPath language to perform server-side filtering of results. This can greatly speed up requests for specific records in a large data set. To query the AWS IAM service for a user list, but return only the first record, you can use this command, which includes a JMESPath query:

aws iam list-users --query 'Users[0]'
Sample Results
PS > aws iam list-users --query 'Users[0]'
{
    "Path": "/",
    "UserName": "AMartinez-####",
    "UserId": "#####################",
    "Arn": "arn:aws:iam::############:user/AMartinez-####",
    "CreateDate": "2023-02-05T22:36:47+00:00"
}

JMESPath also allows you to query for only the properties you specify. To view only the username for each user, use this command:

aws iam list-users --query 'Users[*].UserName'
Sample Results
PS > aws iam list-users --query 'Users[*].UserName'
[
    "AMartinez-####",
    "BSmith-####",
    "GLee-####",
    "instructor-####",
    "JAllen-####",
    "KJones-####",
    "student-####",
    "WAlexander-####"
]

If the results don't fit onto your console, you can press spacebar to move to the next page of results until you have viewed them all. You will configure the paging option later in the lab.

aws iam list-users --query 'Users[*].{username:UserName,created:CreateDate}'
Sample Results
PS > aws iam list-users --query 'Users[*].{username:UserName,created:CreateDate}'
[
    {
        "username": "AMartinez-####",
        "created": "2023-02-05T22:36:47+00:00"
    },
    {
        "username": "BSmith-####",
        "created": "2023-02-05T22:36:47+00:00"
    },
...
[Results Truncated]

Working with AWS Profiles

The profile you created when you logged in created a second text file with the access key and secret key that are associated with your AWS IAM account. You can view the cached credentials with this command:

Get-Content C:\Users\Student\.aws\credentials
Sample Results
PS > Get-Content C:\Users\Student\.aws\credentials
[default]
aws_access_key_id = ####################
aws_secret_access_key = ########################################

The AWS CLI allows you to have multiple profiles that use different credentials and/or different regions and output formats. To create a second profile, named demo, use the following command. Populate with the same Access Key ID and Secret Access Key as before (provided by your instructor), but use us-west-1 as the region and table as the output format:

aws configure --profile demo
us-west-1
table
Sample Results
PS > aws configure --profile demo
AWS Access Key ID [None]: ####################
AWS Secret Access Key [None]: ########################################
Default region name [None]: us-west-1
Default output format [None]: table

Now, if you list your configured AWS profiles, you will see both the default and the demo profiles listed.

aws configure list-profiles
Sample Results
PS > aws configure list-profiles
default
demo

Your config file will now contain entries for both profiles. Note the different region and output format settings for each.

Get-Content C:\Users\Student\.aws\config
Sample Results
PS > Get-Content C:\Users\Student\.aws\config
[default]
region = us-east-2
output = json
[profile demo]
region = us-west-1
output = table

The credential file separates your credentials in the same way:

Get-Content C:\Users\Student\.aws\credentials
Sample Results
PS > Get-Content C:\Users\Student\.aws\credentials
[default]
aws_access_key_id = ####################
aws_secret_access_key = ########################################
[demo]
aws_access_key_id = ####################
aws_secret_access_key = ########################################

If you were to use the aws sts get-caller-identity command for each profile, you would see that the same user is connecting (since you used the same credentials), but the default output format of the command will vary according to the profile settings. The default profile uses JSON:

aws sts get-caller-identity --profile default 
Sample Results
PS > aws sts get-caller-identity --profile default
{
    "UserId": "#####################",
    "Account": "############",
    "Arn": "arn:aws:iam::###############################"
}

The demo profile uses table output by default:

aws sts get-caller-identity --profile demo 
Sample Results
PS > aws sts get-caller-identity --profile demo
-------------------------------------------------------------
|                     GetCallerIdentity                     |
+---------+-------------------------------------------------+
|  Account|  ############                                   |
|  Arn    |  arn:aws:iam::###############################   |
|  UserId |  #####################                          |
+---------+-------------------------------------------------+

The demo profile is also configured to query the APIs for the us-west-1 region. We don't have any EC2 instances running in that region, so a query for virtual machine instances should come back empty and be presented in table format:

aws ec2 describe-instances --profile demo
Sample Results
PS > aws ec2 describe-instances --profile demo
-------------------
|DescribeInstances|
+-----------------+

Many of the AWS CLI commands will return large data sets, which by default will run through a paging tool in your console (like more). We often do not want to repeatedly hit the spacebar to move through pages. You can change some CLI settings in your profile, so we will configure our default profile to use no pager:

aws configure set cli_pager " " --profile default

You can check that the settings are applied to the profile by viewing the config file. Note that the default profile now has an empty cli_pager setting, which serves to turn off the paging function in results.

Get-Content C:\Users\Student\.aws\config
Sample Results
PS > Get-Content C:\Users\Student\.aws\config.
[default]
region = us-east-2
output = json
cli_pager =
[profile demo]
region = us-west-1
output = table

Test your pager setting by running the same command against the us-east-1 region by using your default profile. This command should return a good bit of JSON data with no paging.

aws ec2 describe-instances --profile default
Sample Results
PS > aws ec2 describe-instances --profile default
{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-09c08b542a3df6eac",
                    "InstanceId": "i-094c10ef3ad15d6d3",

AWS PowerShell Commands

Many of the AWS CLI commands have equivalent PowerShell cmdlets. The cmdlets make calls directly to the associated AWS service API and then convert the results to PowerShell objects. In many cases, this automatic conversion saves us a step in developing scripts to automate activities. Note that you receive the same user information as you got from the CLI, just in a slightly different format (actually, it's formatted as a fully functional PowerShell object, which can be quite powerful to use).

Begin by importing the AWS PowerShell modules, first import the AWS PowerShell module. Importing may take some time, as the AWS meta-module imports several PowerShell modules.

Import-Module AWSPowerShell.NetCore

Run the PowerShell command to retrieve your connected user information:

Get-STSCallerIdentity 
Sample Results
PS > Get-STSCallerIdentity

Account      Arn                                          UserId
-------      ---                                          ------
############ arn:aws:iam::############:user/############# #####################

The PowerShell object contains properties, which are the data inside the object, in this case, details about the connected user. You can view the properties of an object by piping it into the Get-Member cmdlet. The properties highlighted in the screenshot are the ones that are returned by the equivalent CLI command.

Get-STSCallerIdentity | Get-Member
Sample Results
PS > Get-STSCallerIdentity | Get-Member

    TypeName: Amazon.SecurityToken.Model.GetCallerIdentityResponse

Name             MemberType   Definition
----             ----------   ----------
Equals           Method       bool Equals(System.Object obj)
GetHashCode      Method       int GetHashCode()
GetType          Method       type GetType()
ToString         Method       string ToString()
LoggedAt         NoteProperty datetime LoggedAt=3/13/2024 12:43:06 AM
Account          Property     string Account {get;set;}
Arn              Property     string Arn {get;set;}
ContentLength    Property     long ContentLength {get;set;}
HttpStatusCode   Property     System.Net.HttpStatusCode HttpStatusCode {get;set;}
ResponseMetadata Property     Amazon.Runtime.ResponseMetadata ResponseMetadata {get;set…
UserId           Property     string UserId {get;set;}

Because the cmdlets return PowerShell Objects, we can access individual properties in each one. Take a look at the properties being returned when we query for EC2 instances:

Get-EC2Instance | Get-Member
Sample Results
PS > Get-EC2Instance | Get-Member

    TypeName: Amazon.EC2.Model.Reservation

Name            MemberType    Definition
----            ----------    ----------
RunningInstance AliasProperty RunningInstance = Instances
Equals          Method        bool Equals(System.Object obj)
GetHashCode     Method        int GetHashCode()
GetType         Method        type GetType()
ToString        Method        string ToString()
GroupNames      Property      System.Collections.Generic.List[string] GroupNames {get;s…
Groups          Property      System.Collections.Generic.List[Amazon.EC2.Model.GroupIde…
Instances       Property      System.Collections.Generic.List[Amazon.EC2.Model.Instance…
OwnerId         Property      string OwnerId {get;set;}
RequesterId     Property      string RequesterId {get;set;}
ReservationId   Property      string ReservationId {get;set;}

The Instances property has the important information about the instances, so we can query for only that property on all the objects in the array of objects returned by the cmdlet:

(Get-EC2Instance).Instances
Sample Results
PS > (Get-EC2Instance).Instances

InstanceId          InstanceType Platform PrivateIpAddress PublicIpAddress SecurityGroups
----------          ------------ -------- ---------------- --------------- --------------
i-094c10ef3ad15d6d3 m5.large     Windows  10.55.7.100                      {terraform-2…
i-0bc17737bf7fc8d2f t2.micro              10.55.7.69       3.142.111.88    {default}
i-074ac9bda221abfe9 t2.micro              10.55.7.68       18.223.72.229   {default}
i-0c1fa1f4bbf653025 t2.micro              10.55.7.15       18.190.54.147   {default}
i-064c394e2892fb0de t2.large              10.55.0.89       52.15.49.110    {event-1032-…

Because the objects are in a PowerShell array, we could also specify which individual object we want to interrogate using array indexes:

(Get-EC2Instance)[0].Instances
Sample Results
PS > (Get-EC2Instance)[0].Instances

InstanceId          InstanceType Platform PrivateIpAddress PublicIpAddress SecurityGroups
----------          ------------ -------- ---------------- --------------- --------------
i-094c10ef3ad15d6d3 m5.large     Windows  10.55.7.100                      {terraform-2…
(Get-EC2Instance | Select-Object -First 1).Instances
Sample Results
InstanceId          InstanceType Platform PrivateIpAddress PublicIpAddress SecurityGroups
----------          ------------ -------- ---------------- --------------- --------------
i-094c10ef3ad15d6d3 m5.large     Windows  10.55.7.100                      {terraform-202…

Mapping PowerShell Cmdlets to CLI calls

The AWS PowerShell module offers a cmdlet called Get-AWSCmdletName to map API services and CLI commands to their equivalent PowerShell command.

Above, you used the aws ec2 describe-instances to get a list of EC2 instances. You could use the Get-AWSCmdletName command to find the equivalent PowerShell command. One way is to use the -ApiOperation parameter to search for the relevant cmdlet. Note that the API operation does not have the embedded hyphens used in the CLI command:

Get-AWSCmdletName -ApiOperation describeinstances
Sample Results
PS > Get-AWSCmdletName -ApiOperation describeinstances

CmdletName      ServiceOperation  ServiceName
----------      ----------------  -----------
Get-EC2Instance DescribeInstances Amazon Elastic Compute Cloud (EC2)
Get-GMLInstance DescribeInstances Amazon GameLift Service
Get-OPSInstance DescribeInstances AWS OpsWorks

If you know which service you are interested in, you can search for it using the -Service parameter. This parameter will search the entire service name using the keywords you supply, so it is not necessary to give the full-service name. The following two commands should give the same results (although, if AWS added another service with "compute" in the name, the first command might retrieve more results than the second):

Get-AWSCmdletName -ApiOperation describeinstances -Service compute
Sample Results
PS > Get-AWSCmdletName -ApiOperation describeinstances -Service compute

CmdletName      ServiceOperation  ServiceName
----------      ----------------  -----------
Get-EC2Instance DescribeInstances Amazon Elastic Compute Cloud (EC2)
Get-AWSCmdletName -ApiOperation describeinstances -Service "Amazon Elastic Compute Cloud"

From the output of any of the above commands, you learn that Get-EC2Instance would be the appropriate cmdlet to use.

Sample Results
PS > Get-AWSCmdletName -ApiOperation describeinstances -Service "Amazon Elastic Compute Cloud"

CmdletName      ServiceOperation  ServiceName
----------      ----------------  -----------
Get-EC2Instance DescribeInstances Amazon Elastic Compute Cloud (EC2)

The Get-AWSCmdletName command also has a feature to make a "best-effort" mapping of a CLI command to the PowerShell equivalent. We've found that in practice, it is not perfect, but it can be a good way to quickly translate a CLI command to PowerShell. The following commands demonstrate this feature:

Get-AWSCmdletName -AwsCliCommand "aws iam list-users"
Sample Results
PS > Get-AWSCmdletName -AwsCliCommand "aws iam list-users"
WARNING: Parameter 'AwsCliCommand' is obsolete. This parameter is deprecated and will be removed in a future version. Use Service and ApiOperation instead.

CmdletName      ServiceOperation ServiceName
----------      ---------------- -----------
Get-IAMUserList ListUsers        AWS Identity and Access Management
Get-AWSCmdletName -AwsCliCommand "aws ec2 describe-instances"
Sample Results
PS > Get-AWSCmdletName -AwsCliCommand "aws ec2 describe-instances"
WARNING: Parameter 'AwsCliCommand' is obsolete. This parameter is deprecated and will be removed in a future version. Use Service and ApiOperation instead.

CmdletName      ServiceOperation  ServiceName
----------      ----------------  -----------
Get-EC2Instance DescribeInstances Amazon Elastic Compute Cloud (EC2)

PowerShell offers "tab-completion," allowing you to type a partial command name and hit Tab to have PowerShell complete the name for you. This also works with profile names in the AWS module commands. Paste or type in the command below, which contains a partial profile name, and hit the Tab key to see tab-completion in action.

Get-STSCallerIdentity -ProfileName def
Sample Results
PS > Get-STSCallerIdentity -ProfileName default

Account      Arn                                          UserId
-------      ---                                          ------
############ arn:aws:iam::############:user/student-#### #####################

Part 2: Processing JSON with jq

Environment Check

Before proceeding, ensure that you are working in Windows Terminal in PowerShell Core.

Background: You may have noticed that much of the cloud provider data we will work with is in the JSON format. In this section of the lab, you will learn some of the tools that can help you to filter and "slice and dice" JSON formatted data, beginning with jq.

Instructions: Begin by getting some JSON data into a PowerShell object. In this case, you will work with a list of Azure VMs retrieved using the Azure CLI. The $azvm in the command is a PowerShell variable, which will save your command results and allow you to access them later. We often use variables to avoid round-trip connections to the cloud service provider (CSP) for the same data.

Live Data in Use!

Remember that your data may differ from these results, since you have retrieved live data from the API!

$azvm = get-content c:\labfiles\config\azvm.json

Because you stored the command results in a variable, you will not have seen them on the console. You can check the contents of the variable by invoking it in the PowerShell console:

$azvm
Sample Results
PS > $azvm = az vm list
PS > $azvm
[
    {
        "additionalCapabilities": null,
        "applicationProfile": null,
        "availabilitySet": null,
        "billingProfile": null,
        "capacityReservation": null,
        "diagnosticsProfile": {
        "bootDiagnostics": {
            "enabled": false,
            "storageUri": null
        }
    },
...
[Results Truncated]

Live Data in Use!

Remember that your data may differ from these results!

At its simplest, jq is a JSON pretty printer. It will parse and display any JSON piped through it. It can even colorize the output using the -C flag.

$azvm | jq -C '.'
Sample Results
PS > $azvm | jq -C '.'
[
    {
        "additionalCapabilities": null,
        "applicationProfile": null,
        "availabilitySet": null,
        "billingProfile": null,
        "capacityReservation": null,
        "diagnosticsProfile": {
        "bootDiagnostics": {
            "enabled": false,
            "storageUri": null
        }
    },
...
[Results Truncated]

The data in our variable is a JSON array. Note the square brackets around the data - this indicates an array, whose elements are separated by commas. The following command instructs jq to display the full contents of the array:

$azvm | jq '.[]'
Sample Results
PS > $azvm | jq '.[]'
{
    "additionalCapabilities": null,
    "applicationProfile": null,
    "availabilitySet": null,
    "billingProfile": null,
    "capacityReservation": null,
    "diagnosticsProfile": {
        "bootDiagnostics": {
        "enabled": false,
        "storageUri": null
        }
    },
...
[Results Truncated]

Just like you did with AWS CLI JMESPath queries earlier in the lab, you can select individual array elements using jq. This command will return only the first object in the array:

$azvm | jq '.[0]'
Sample Results
PS > $azvm | jq '.[0]'
{
    "additionalCapabilities": null,
    "applicationProfile": null,
    "availabilitySet": null,
    "billingProfile": null,
    "capacityReservation": null,
    "diagnosticsProfile": {
        "bootDiagnostics": {
        "enabled": false,
        "storageUri": null
        }
    },
...
[Results Truncated]

Each array element is a JSON object with its own properties. You can tell jq to return only properties of interest by piping the array into another jq command specifying the properties you want. Note the leading dot before the property name (.name).

$azvm | jq '.[] | .name'
Sample Results
PS > $azvm | jq '.[] | .name'
"event-1032-aud1-range-azure-x0xut-bastion"
"event-1032-aud1-range-azure-x0xut-catapp"
"event-1032-aud1-range-azure-x0xut-windows"

If we wish to retrieve more than one property, we can list the ones we want. We can even choose sub-properties as many levels deep as we want. The JSON data returned above contains a property called storageProfile that contains information about the disks used by the VM. StorageProfile is actually an object with properties of its own. We can drill down to the .storageProfile.osDisk.osType property to learn what OS is in use on the VM:

$azvm | jq '.[] | .name, .storageProfile.osDisk.osType'
Sample Results
PS > $azvm | jq '.[] | .name, .storageProfile.osDisk.osType'
"event-1032-aud1-range-azure-x0xut-bastion"
"Linux"
"event-1032-aud1-range-azure-x0xut-catapp"
"Linux"
"event-1032-aud1-range-azure-x0xut-windows"
"Windows"

If we had a list of properties we want to analyze, then it is simply a matter of putting the path for each into the jq command. This command retrieves four properties from the original object array.

$azvm | jq '.[] | .name, .storageProfile.osDisk.osType, .hardwareProfile.vmSize, .tags'
Sample Results
PS > $azvm | jq '.[] | .name, .storageProfile.osDisk.osType, .hardwareProfile.vmSize, .tags'
"event-1032-aud1-range-azure-x0xut-bastion"
"Linux"
"Standard_D2s_v3"
{
    "Attributes": "bastion",
    "Environment": "aud1-range-azure",
    "Name": "event-1032-aud1-range-azure-x0xut-bastion",
    "Namespace": "event-1032",
    "Stage": "x0xut",
    "rci:course-id": "aud1",
    "rci:created-by": "5a5b1646-771f-4464-b8a7-323d09ddf330",
    "rci:creation-method": "terraform",
    "rci:event-id": "1032",
    "rci:event-product-id": "aud1-i01-gen"
}
...
[Results Truncated]

Live Data in Use!

Remember that your data may differ from these results!

While the command above DOES get all the information we asked for, it's not really organized in a structured way. We can join the requested properties into a JSON object by including curly braces around the query and adding property names.

$azvm | jq '.[] | { vmname: .name, os: .storageProfile.osDisk.osType, vmsize: .hardwareProfile.vmSize, tags: .tags }'
Sample Results
PS > $azvm | jq '.[] | { vmname: .name, os: .storageProfile.osDisk.osType, vmsize: .hardwareProfile.vmSize, tags: .tags }'
{
    "vmname": "event-1032-aud1-range-azure-x0xut-bastion",
    "os": "Linux",
    "vmsize": "Standard_D2s_v3",
    "tags": {
        "Attributes": "bastion",
        "Environment": "aud1-range-azure",
        "Name": "event-1032-aud1-range-azure-x0xut-bastion",
        "Namespace": "event-1032",
        "Stage": "x0xut",
        "rci:course-id": "aud1",
        "rci:created-by": "5a5b1646-771f-4464-b8a7-323d09ddf330",
        "rci:creation-method": "terraform",
        "rci:event-id": "1032",
        "rci:event-product-id": "aud1-i01-gen"
    }
}
...
[Results Truncated]

Live Data in Use!

Remember that your data may differ from these results!

The previous command created multiple JSON objects, but if we wanted to further process this data, we would probably need to create a JSON array for our data. This can be done by adding square brackets around our jq command to form an array. The tool will automatically separate array elements with commas.

$azvm | jq '[ .[] | { vmname: .name, os: .storageProfile.osDisk.osType, vmsize: .hardwareProfile.vmSize, tags: .tags }]' 
Sample Results
PS > $azvm | jq '[ .[] | { vmname: .name, os: .storageProfile.osDisk.osType, vmsize: .hardwareProfile.vmSize, tags: .tags }]'
[
    {
        "vmname": "event-1032-aud1-range-azure-x0xut-bastion",
        "os": "Linux",
        "vmsize": "Standard_D2s_v3",
        "tags": {
            "Attributes": "bastion",
            "Environment": "aud1-range-azure",
            "Name": "event-1032-aud1-range-azure-x0xut-bastion",
            "Namespace": "event-1032",
            "Stage": "x0xut",
            "rci:course-id": "aud1",
            "rci:created-by": "5a5b1646-771f-4464-b8a7-323d09ddf330",
            "rci:creation-method": "terraform",
            "rci:event-id": "1032",
            "rci:event-product-id": "aud1-i01-gen"
        }
    },
...
[Results Truncated]

Live Data in Use!

Remember that your data may differ from these results!

Part 3: Processing JSON with PowerShell

Environment Check

Before proceeding, ensure that you are working in Windows Terminal in PowerShell Core.

Background: PowerShell has built-in tools to deal with structured data like JSON. In this section of the lab, you will use PowerShell to manipulate JSON data.

Instructions: Verify that the variable you created above has JSON data in it:

$azvm
Sample Results
PS > $azvm
[
    {
        "additionalCapabilities": null,
        "applicationProfile": null,
        "availabilitySet": null,
        "billingProfile": null,
        "capacityReservation": null,
        "diagnosticsProfile": {
        "bootDiagnostics": {
            "enabled": false,
            "storageUri": null
        }
    },
...
[Results Truncated]

The ConvertFrom-Json cmdlet in PowerShell will take in JSON data and output a PowerShell object with properties that represent the data from the original JSON. Test this cmdlet using the following command.

$azvm | ConvertFrom-Json
Sample Results
PS > $azvm | ConvertFrom-Json

additionalCapabilities  :
applicationProfile      :
availabilitySet         :
billingProfile          :
capacityReservation     :
diagnosticsProfile      : @{bootDiagnostics=}
evictionPolicy          :
extendedLocation        :
extensionsTimeBudget    : PT1H30M
hardwareProfile         : @{vmSize=Standard_D2s_v3; vmSizeProperties=}
...
[Results Truncated]

Each line in the output above is a PowerShell property that you can access directly. One way to access the properties is to wrap the previous command in parentheses (this tells PowerShell to treat the output of everything in the parentheses as an object) and then use a dot to specify which property you wish to view.

($azvm | ConvertFrom-Json).StorageProfile
Sample Results
PS > ($azvm | ConvertFrom-Json).StorageProfile

dataDisks diskControllerType imageReference
--------- ------------------ --------------
{}        SCSI               @{communityGalleryImageId=; exactVersion=20.04.202301130; …
{}        SCSI               @{communityGalleryImageId=; exactVersion=20.04.202301130; …
{}        SCSI               @{communityGalleryImageId=; exactVersion=20348.887.220806;…

The PowerShell objects created by ConvertFrom-Json can have objects nested as properties, just like the original JSON data did. You can view all of the properties nested in the StorageProfile object using this command. Note the OSDisk and OSType properties that you found before using jq.

($azvm | ConvertFrom-Json).StorageProfile | Format-List
Sample Results
PS > ($azvm | ConvertFrom-Json).StorageProfile | Format-List

dataDisks          : {}
diskControllerType : SCSI
imageReference     : @{communityGalleryImageId=; exactVersion=20.04.202301130; id=;
                    offer=0001-com-ubuntu-server-focal; publisher=canonical;
                    sharedGalleryImageId=; sku=20_04-lts-gen2; version=20.04.202301130}
osDisk             : @{caching=None; createOption=FromImage; deleteOption=Detach;
                    diffDiskSettings=; diskSizeGb=30; encryptionSettings=; image=;
                    managedDisk=; name=event-1032-aud1-range-azure-x0xut-bastiOS__1_a
                    3819530e32a4e4c8b88a64f6c633950; osType=Linux; vhd=;
                    writeAcceleratorEnabled=False}

dataDisks          : {}
diskControllerType : SCSI
imageReference     : @{communityGalleryImageId=; exactVersion=20.04.202301130; id=;
                    offer=0001-com-ubuntu-server-focal; publisher=canonical;
                    sharedGalleryImageId=; sku=20_04-lts-gen2; version=20.04.202301130}
osDisk             : @{caching=None; createOption=FromImage; deleteOption=Detach;
                    diffDiskSettings=; diskSizeGb=30; encryptionSettings=; image=;
                    managedDisk=; name=event-1032-aud1-range-azure-x0xut-catapOS__1_2
                    bfd325c4dc643d8b769f24c3121aa0e; osType=Linux; vhd=;
                    writeAcceleratorEnabled=False}
...
[Results Truncated]

You can stack as many dotted properties together as you need in order to get the data you want. This command will drill down to the OSType for each VM in Azure:

($azvm | ConvertFrom-Json).StorageProfile.osDisk.osType
Sample Results
PS > ($azvm | ConvertFrom-Json).StorageProfile.osDisk.osType
Linux
Linux
Windows

The PowerShell Select-Object cmdlet also allows you to specify which properties you want to get from an object. In this command, PowerShell will return only the name property for each VM:

($azvm | ConvertFrom-Json) | Select-Object Name
Sample Results
PS > ($azvm | ConvertFrom-Json) | Select-Object Name

name
----
event-1032-aud1-range-azure-x0xut-bastion
event-1032-aud1-range-azure-x0xut-catapp
event-1032-aud1-range-azure-x0xut-windows

Live Data in Use!

Remember that your data may differ from these results!

Select-Object also allows for "calculated properties," which allow us to manipulate the data into entirely new properties. This command creates a new property named 'os' with a value taken from each object defined by the embedded expression value (the $_ variable represents the currently evaluated object).

($azvm | ConvertFrom-Json) | Select-Object Name, @{name='os';expression={$_.storageProfile.osDisk.osType}}
Sample Results
PS > ($azvm | ConvertFrom-Json) | Select-Object Name, @{name='os';expression={$_.storageProfile.osDisk.osType}}

name                                        os
----                                        --
event-1032-aud1-range-azure-x0xut-bastion Linux
event-1032-aud1-range-azure-x0xut-catapp  Linux
event-1032-aud1-range-azure-x0xut-windows Windows

Live Data in Use!

Remember that your data may differ from these results!

The name and expression keywords in a calculated property can also be abbreviated to n and e. This command builds calculated properties with the osType and vmSize sub-properties and adds to the array of tags associated with the VM.

($azvm | ConvertFrom-Json) | Select-Object Name, @{name='os';expression={$_.storageProfile.osDisk.osType}}, @{n='vmsize';e={$_.hardwareProfile.vmSize}}, tags
Sample Results
PS > ($azvm | ConvertFrom-Json) | Select-Object Name, @{name='os';expression={$_.storageProfile.osDisk.osType}}, @{n='vmsize';e={$_.hardwareProfile.vmSize}}, tags

name                                        os      vmsize          tags
----                                        --      ------          ----
event-1032-aud1-range-azure-x0xut-bastion Linux   Standard_D2s_v3 @{Attributes=bastio…
event-1032-aud1-range-azure-x0xut-catapp  Linux   Standard_D2s_v3 @{Attributes=catapp…
event-1032-aud1-range-azure-x0xut-windows Windows Standard_D2s_v3 @{Attributes=window…

Live Data in Use!

Remember that your data may differ from these results!

Congratulations! You have successfully queried and parsed data from the cloud service providers (CSPs) used in the lab! You can close all your open Windows Terminal tabs after you have finished.