Can anyone explain me how to mock cmdlet Update-AzTag
within a ForEach-Object -Parallel
ScriptBlock?
I’m trying to mock the cmdlet, which is within a ForEach-Object -Parallel
ScriptBlock (see Update-ResourceTag
). However, the defined mock (see UnitTest
) isn’t used.
All tests are successful when I remove switch -Parallel
(and key word using
).
‘Update-ResourceTag’
function Update-ResourceTag {
<#
.SYNOPSIS
Update resource tag(s) on all resources.
.DESCRIPTION
Update-ResourceTag adds new tags, or updates existing tags, to all resources within the specified subscription.
When a resource group name is specified only the resources within the resource group will be updated.
.PARAMETER ResourceGroupName
Name of the resource group in where the resources are to receive the new/updated tag(s).
.PARAMETER Tag
Hashtable of tag(s). E.g. "@{ "Name"="Value" }"
.EXAMPLE
Update-ResourceTag -Tag @{ 'test1'='testValue' }
This command will add the specified tag to all resources within the current context.
.EXAMPLE
Update-ResourceTag -ResourceGroupName MyResourceGroup -Tag @{ 'test1'='testValue' }
This command will add the specified tag to all resources within resource group MyResourceGroup.
#>
[CmdletBinding()]
param (
[Parameter(
Mandatory = $false,
HelpMessage = 'Name of the resource group in where the resources are to receive the new/updated tag(s).'
)]
[string]$ResourceGroupName = '*',
[Parameter(
Mandatory = $true,
HelpMessage = 'Hashtable of tag(s). E.g. "@{ "Name"="Value" }".'
)]
[hashtable]$Tag
)
#Requires -Modules @{ ModuleName='Az.Resources'; ModuleVersion='4.3.1' }
Write-Host 'Retrieving all resources'
$Resources = Get-AzResource -ResourceGroupName $ResourceGroupName -ErrorAction Stop
$Resources | ForEach-Object -Parallel {
$ResourceMessage = "`nName: $($PSItem.Name)`nType: $($PSItem.ResourceType)"
Write-Host "`nUpdating tag(s) on resource: $ResourceMessage"
Update-AzTag -ResourceId $PSItem.ResourceId -Tag $Using:Tag -Operation Merge -ErrorAction SilentlyContinue -ErrorVariable UpdateError | Out-Null
if ($UpdateError) {
Write-Warning "`nFailed to update tag on resource! $ResourceMessage"
}
}
}
UnitTest
$ModuleName = 'MyUtils'
$ModulePath = Join-Path -Path $PSScriptRoot -ChildPath "..\modules\$ModuleName"
Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue
Import-Module -Name $ModulePath
Describe 'Function Update-ResourceTag' {
InModuleScope -ModuleName 'MyUtils' {
BeforeAll {
[string]$Type = 'Microsoft.Resources/mockType'
[string]$ResourceId = "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/mock/providers/$Type/mockName"
[array]$MockData = @(
@{
ResourceId = $ResourceId
Name = 'mockName1'
ResourceType = $Type
},
@{
ResourceId = $ResourceId
Name = 'mockName2'
ResourceType = $Type
}
)
[hashtable]$Tag = @{ 'test1' = 'testValue' }
Mock -CommandName Get-AzResource -MockWith { $MockData }
Mock -CommandName Update-AzTag -MockWith { return $true }
Mock -CommandName Write-Host -MockWith { return $null }
}
Context 'with valid parameters' {
It 'should call mock Get-AzResource exactly once' {
Update-ResourceTag -Tag $Tag
Assert-MockCalled -CommandName Get-AzResource -Exactly 1
}
It 'should call mock Update-AzTag exactly twice' {
Update-ResourceTag -Tag $Tag
Assert-MockCalled -CommandName Update-AzTag -Exactly 2
}
}
Context 'with invalid parameters' {
It "should throw 'ParameterArgumentTransformationError' exception on wrong ResourceGroupName parameter input" {
[array]$WrongValue = @( 'WrongValue' )
$sut = { Update-ResourceTag -ResourceGroupName $WrongValue -Tag $Tag }
$sut | Should -Throw "Cannot process argument transformation on parameter 'ResourceGroupName'*"
}
It "should throw 'ParameterArgumentTransformationError' exception on wrong Tag parameter input" {
$sut = { Update-ResourceTag -Tag WrongValue }
$sut | Should -Throw "Cannot process argument transformation on parameter 'Tag'*"
}
}
}
}