Saturday, August 29, 2020
Azure: Azure Resource Manager (ARM) templates for creating Virtual Machines for Standard Window's SKU's
Friday, August 28, 2020
PowerShell: Two Interview Questions
During a recent interview I was asked the following questions.
How do you remove duplicates from an array?
How do you read the first five lines of a file?
Tuesday, August 25, 2020
Azure/PowerShell: Cmdlet Parameter and Result Complexity (Get-AzHost, Get-AzVM, New-AzVM)
Overview
In order to better understand cmdlet parameter sets and there complexity consider the documentation of several Azure related cmdlets:
- Get-AzHost: retrieves a host or a list of all hosts if no host name is specified
- Get-AzVM: retrieves the properties of an Azure VM
- New-AzVM: creates an Azure VM
Get-AzHost
- ResourceGroupName
- HostGroupName
- ResourceId
Get-AzVM
New-AzVM
The New-AzVM cmdlet defines the following multiple parameters sets and takes over a dozen potential parameters including complex types built up by invoking multiple setup cmdlets.
The unique parameter for this New-AzVm parameter set is -Credential:
New-AzVM and PSVirtualMachine Configuration
Monday, August 17, 2020
PowerShell: Cmdlet Parameter Sets
PowerShell cmdlet parameter sets are documented at Cmdlet parameter sets where they are defined as follows:
Each parameter set must contain a unique parameter that allows the PowerShell runtime to identify which parameter set is being used. In order to demonstrate parameter sets consider the Get-Depth function from the post PowerShell: Converting Json-Formatted Strings to/from Json-Objects and Json-Object Depth. The Get-Depth function has been modified as follows, GetDepthEx, to take two parameters where each parameter belongs to a separate parameter set (see the attribute property, ParameterSetName, below):
function Get-DepthEx()
{
param (
[Parameter(
Mandatory=$true,
ParameterSetName='FormattedJsonString')]
[string] $json,
[Parameter(
Mandatory=$true,
ParameterSetName='JsonObject')]
[PSCustomObject] $jsonObject
)
The code for GetDepthEx is the original GetDepth code save it has been modified (see text demarcated by boldface) to work with a Json-formatted string parameter (parameter set name, FormattedJsonString) or with Json-Object (parameter set name, JsonObject):
function Get-DepthEx()
{
param (
[Parameter(
Mandatory=$true,
ParameterSetName='FormattedJsonString')]
[string] $json,
[Parameter(
Mandatory=$true,
ParameterSetName='JsonObject')]
[PSCustomObject] $jsonObject
)
if (($null -ne $json) -and ($json.Length -gt 0))
{
# This step verifies that $json is a valid Json object
$jsonObject = ConvertFrom-Json $json
if ($null -eq $jsonObject)
{
return 0
}
}
if ($null -ne $jsonObject)
{
# As of PowerShell 7.0 the max -Depth is 100
$json = ConvertTo-Json $jsonObject -Depth 100
}
[int] $maximumDepth = -1
[int] $depth = 0
[char[]] $startingBrackets = '[', '{'
[char[]] $endingBrackets = @(']', '}')
foreach ($c in $json.ToCharArray())
{
if ($c -in $startingBrackets)
{
++$depth
$maximumDepth = if ($maximumDepth -ge $depth)
{ $maximumDepth } else { $depth }
}
elseif ($c -in $endingBrackets)
{
--$depth
}
}
return $maximumDepth
}
The GetDepthEx method is invoked as follows where each invocation uses a different parameter set as is show using the code from the previous post "PowerShell: Reading, Modifying, and Saving Json Files":
[string] $sourceWindowsVmTemplateFilename =
'Template2019.json'
[string] $destinationWindowsVmTemplateFilename =
'TemplateAnyWindowsVM.json'
[string] $content =
Get-Content -Raw -Path $sourceWindowsVmTemplateFilename
[PSCustomObject] $jsonObject =
$content |
ConvertFrom-Json
[int] $depthParameterSetFormattedJsonString =
Get-DepthEx -Json $content
[int] $depthParameterSetJsonObject =
Get-DepthEx -JsonObject $jsonObject
There are many permutations to parameter sets. For example it possible for a parameter to be included in multiple parameter sets. As a feature of PowerShell, parameter sets are not part of the day-to-day coding performed by most developers. It is more likely that a developer will have to read the documentation associated with a cmdlet that supports multiple parameter sets. Cmdlets that contain multiple parameters sets include;
- Add-AzVMNetworkInterface
- Get-AzGallery
- Get-AzHost
- Get-AzHostGroup
- New-AzVM
- New-AzVMConfig
- New-AzVMSqlServerAutoBackupConfig
- Publish-AzVMDscConfiguration
- Remove-AzGallery
- Remove-AzHost
- Remove-AzHostGroup
Sunday, August 16, 2020
PowerShell: Reading, Modifying, and Saving Json Files
In the previous blog entry, PowerShell: Converting Json-Formatted Strings to/from Json-Objects and Json-Object Depth, it was shown how to correctly create Json-objects from Json-formatted strings and how to create Json-formatted strings from Json-objects by taking into account the depth of the underlying Json-object being manipulated. This post expands on the manipulation of Json-object with PowerShell by demonstrating how to:
- read a Json-formatted string from a file
- convert the Json-formatted string to a Json-object
- modify the Json-object
- covert the Json-object to a Json-formatted string
- save the Json-formatted string to a file
[string] $destinationWindowsVmTemplateFilename =
'TemplateAnyWindowsVM.json'
[string] $content =
Get-Content -Raw -Path $sourceWindowsVmTemplateFilename
[int] $depth = Get-Depth $content
[PSCustomObject] $jsonObject = $content |
if ($jsonObject.resources.properties.
storageProfile.imageReference.sku -ne $windowsSku)
{
$jsonObject.resources.properties.
storageProfile.imageReference.sku = $windowsSku
$jsonObject |
ConvertTo-Json -Depth $depth |
Set-Content $destinationWindowsVmTemplateFilename
}
Get-Content -Raw -Path $sourceWindowsVmTemplateFilename
A culled version of the Json identifies the Windows Sku is as follows:
<#
"resources": [
{
{
"properties": {
"storageProfile": {
"imageReference": {
"sku": "2012-R2-Datacenter",
#>
Based on the pseudo-Json above the sku is accessible as follows:
resources.properties.storageProfile.imageReference.sku
storageProfile.imageReference.sku -ne $windowsSku)
{
$jsonObject.resources.properties.
storageProfile.imageReference.sku = $windowsSku
$jsonObject | ConvertTo-Json -Depth $depth
- 2012-R2-Datacenter
- 2016-Datacenter
- 2019-Datacenter
The Window's SKU returned is simply a string that depends on the version of SharePoint to be installed on the virtual machine (SharePoint 2013, SharePoint 2016 or SharePoint 2019). The function used to return the appropriate Windows SKU is Get-WindowsSku:
function Get-WindowsSku()
{
param (
[ValidateSet(2013, 2016, 2019)]
[Parameter(Mandatory)]
[int] $sharePointVersionYear
)
[string] $sku
switch($sharePointVersionYear){
2013 { $sku = '2012-R2-Datacenter'}
2016 { $sku = '2016-Datacenter'}
2019 { $sku = '2019-Datacenter'}
}
return $sku
}
Saturday, August 15, 2020
PowerShell: Converting Json-Formatted Strings to/from Json-Objects and Json-Object Depth
PowerShell has extremely versatile cmdlets for converting Json-formatted strings to Json-objects (ConvertFrom-Json) and converting Json-objects to Json-formatted strings (ConvertTo-Json). A real world case where such cmdlets come in handy is when working with Azure Resource Manger (ARM) templates (JSON formatted files) in order to create virtual machines from standard SKU's and from images. The ConvertTo-Json cmdlet has a default behavior that needs to be accounted for when using it in real world applications. There are too many online blogs that fail to demonstrate that by default ConvertTo-Json only works on Jason objects with a maximum depth of 2. This blog post shows the correct use of ConvertTo-Json.
The PowerShell cmdlet that converts a Json-formatted string to a Json object or, when the -AsHashtable command-line option is specified, to a HashTable, is ConvertFrom-Json:
The PowerShell cmdlet that converts an object to a Json-formatted string is ConvertTo-Json:
The CovertFrom-Json cmdlet has a -Depth command-line option that defaults to a value of 1024 while the ConvertTo-Json cmdlet has a -Depth command-line option that defaults to a value of two. The depth of a Json object is defined as the maximum nested level of each property (starting with a { bracket and ending in a } bracket) and each nested level of an array (starting with a [ bracket and ending in a ] bracket).
Consider a case where a Json-formatted string with a depth of nine is converted to Json-object. There would be no need to set the -Depth parameter when invoking CovertFrom-Json as the default depth is 1024. If the Json-object is edited and then converted to a string using the CovertTo-Json cmdlet, there would be a problem unless the -Depth command-line option was set to at least a value of nine (as computed by the Get-Depth method below). Since CovertTo-Json default -Depth defaults to two, then the Json-formatted string would be malformed since the Json-object converted has a depth of nine.
The Get-Depth function takes as a parameter a Json-formatted string and returns the Json's depth:
function Get-Depth()
{
param (
[Parameter(Mandatory=$true)]
[string] $json
)
# This step verifies that $json is a valid Json object
$jsonObject = ConvertFrom-Json $json
if ($null -eq $jsonObject)
{
return 0
}
[int] $maximumDepth = -1
[int] $depth = 0
[char[]] $startingBrackets = '[', '{'
[char[]] $endingBrackets = @(']', '}')
foreach ($c in $json.ToCharArray())
{
if ($c -in $startingBrackets)
{
++$depth
$maximumDepth = if ($maximumDepth -ge $depth)
{ $maximumDepth } else { $depth }
}
elseif ($c -in $endingBrackets)
{
--$depth
}
}
return $maximumDepth
}
The following snippet of PowerShell shows CovertFrom-Json being used to convert a Json-formatted string to a Json-object. ConvertTo-Json is used with the -Depth command-line parameter assigned using a value return by the Get-Depth function and ConvertTo-Json is used without the -Depth command-line parameter assigned:
[string] $content = <getting content shown in future blog>
[int] $jsonDepth = Get-Depth $content
[PSCustomObject] $jsonObject = $content | ConvertFrom-Json
[string] $updatedContent = $jsonObject |
ConvertTo-Json -Depth $jsonDepth
[string] $updatedContentDefaultDepth = $jsonObject | ConvertTo-Json