From 86de2b2238550e0e54f6dff35d0b38ee65ef2ddf Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 22 Mar 2019 19:20:19 -0400 Subject: [PATCH 1/4] Reusing Tags caused using the Length property to be used like an array instead of string --- src/PowerShellGet/private/functions/New-NuspecFile.ps1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 index 2e7fa6ef..894a1a1f 100644 --- a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 +++ b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 @@ -59,10 +59,9 @@ function New-NuspecFile { $packageElement = $xml.CreateElement("package", $nameSpaceUri) $metaDataElement = $xml.CreateElement("metadata", $nameSpaceUri) - #truncate tags if they exceed nuspec specifications for size. - $Tags = $Tags -Join " " - - if ($Tags.Length -gt 4000) { + # warn we're over 4000 characters for standard nuget servers + $tagsString = $Tags -Join " " + if ($tagsString.Length -gt 4000) { Write-Warning -Message "Tag list exceeded 4000 characters and may not be accepted by some Nuget feeds." } From 6e2e7be00d26d38d2d2dda42907b97f3e6d3da37 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 22 Mar 2019 19:21:56 -0400 Subject: [PATCH 2/4] Added EnforceMaximumTagLength switch on Publish-Module to limit tags to 4000 characters --- Tests/PSGetPublishModule.Tests.ps1 | 77 +++++++++++++++++++ .../functions/Publish-PSArtifactUtility.ps1 | 76 +++++++++--------- .../public/psgetfunctions/Publish-Module.ps1 | 39 ++++++---- 3 files changed, 140 insertions(+), 52 deletions(-) diff --git a/Tests/PSGetPublishModule.Tests.ps1 b/Tests/PSGetPublishModule.Tests.ps1 index c62a12cb..59139c55 100644 --- a/Tests/PSGetPublishModule.Tests.ps1 +++ b/Tests/PSGetPublishModule.Tests.ps1 @@ -763,6 +763,83 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { } ` -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') + # Purpose: Test Publish-Module cmdlet warns when tag length is greater than 4000 + # + # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish + # + # Expected Result: Publish operation should succeed and should have warned about tag length. + # + It PublishModuleFunctionsAsTagsWarnWithoutEnforceMaximumTagLength { + $version = "1.0.0" + $Description = "$script:PublishModuleName module" + $Tags = "PSGet","DSC" + $Author = "AuthorName" + $CompanyName = "CompanyName" + $CopyRight = "CopyRight" + + $functionNames = 1..250 | Foreach-Object { "Get-TestFunction$($_)" } + $tempFunctions = 1..250 | Foreach-Object { "function Get-TestFunction$($_) { Get-Date }" + [Environment]::NewLine } + Set-Content (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psm1") -Value $tempFunctions + + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") ` + -ModuleVersion $version ` + -Description "$script:PublishModuleName module" ` + -NestedModules "$script:PublishModuleName.psm1" ` + -Author $Author ` + -CompanyName $CompanyName ` + -Copyright $CopyRight ` + -Tags $Tags ` + -FunctionsToExport $functionNames + + Publish-Module -Path $script:PublishModuleBase ` + -NuGetApiKey $script:ApiKey ` + -Repository "PSGallery" ` + -WarningAction SilentlyContinue ` + -WarningVariable wa + + Assert ("$wa".Contains('4000 characters')) "Warning messages should include 'Tag list exceeded 4000 characters and may not be accepted by some Nuget feeds.'" + } ` + -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') + + # Purpose: Test Publish-Module cmdlet excludes functions from tags when using EnforceMaximumTagLength parameter + # + # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish with EnforceMaxmimumTagLength parameter + # + # Expected Result: Publish operation should succeed and should not have warned about tag length + # + It PublishModuleFunctionsAsTagsWithEnforceMaximumTagLength { + $version = "1.0.0" + $Description = "$script:PublishModuleName module" + $Tags = "PSGet","DSC" + $Author = "AuthorName" + $CompanyName = "CompanyName" + $CopyRight = "CopyRight" + + $functionNames = 1..250 | Foreach-Object { "Get-TestFunction$($_)" } + $tempFunctions = 1..250 | Foreach-Object { "function Get-TestFunction$($_) { Get-Date }" + [Environment]::NewLine } + Set-Content (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psm1") -Value $tempFunctions + + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") ` + -ModuleVersion $version ` + -Description "$script:PublishModuleName module" ` + -NestedModules "$script:PublishModuleName.psm1" ` + -Author $Author ` + -CompanyName $CompanyName ` + -Copyright $CopyRight ` + -Tags $Tags ` + -FunctionsToExport $functionNames + + Publish-Module -Path $script:PublishModuleBase ` + -NuGetApiKey $script:ApiKey ` + -Repository "PSGallery" ` + -EnforceMaximumTagLength ` + -WarningAction SilentlyContinue ` + -WarningVariable wa + + Assert (-not "$wa".Contains('4000 characters')) "Warning messages should not include 'Tag list exceeded 4000 characters and may not be accepted by some Nuget feeds.'" + } ` + -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') + # Purpose: Test Publish-Module cmdlet gets the PSData properties from the module manifest file and also with Uri objects specified to the cmdlet # # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish it with Uri objects to ProjectUri, IconUri and LicenseUri parameters diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 4d93943f..b52e7a69 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -53,6 +53,10 @@ function Publish-PSArtifactUtility { [string[]] $Tags, + [Parameter(ParameterSetName = 'PublishModule')] + [switch] + $EnforceMaximumTagLength, + [Parameter(ParameterSetName = 'PublishModule')] [Uri] $LicenseUri, @@ -218,7 +222,7 @@ function Publish-PSArtifactUtility { if ($PSScriptInfo) { $Tags += "PSScript" - if ($PSScriptInfo.DefinedCommands) { + if ($PSScriptInfo.DefinedCommands -and -not $EnforceMaximumTagLength) { if ($PSScriptInfo.DefinedFunctions) { $Tags += "$($script:Includes)_Function" $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } @@ -251,52 +255,54 @@ function Publish-PSArtifactUtility { $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath - if ($PSModuleInfo.ExportedCommands.Count) { - if ($PSModuleInfo.ExportedCmdlets.Count) { - $Tags += "$($script:Includes)_Cmdlet" - $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } + if (-not $EnforceMaximumTagLength) { + if ($PSModuleInfo.ExportedCommands.Count) { + if ($PSModuleInfo.ExportedCmdlets.Count) { + $Tags += "$($script:Includes)_Cmdlet" + $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } - #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage + #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice + if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { + $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } } - } - if ($PSModuleInfo.ExportedFunctions.Count) { - $Tags += "$($script:Includes)_Function" - $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + if ($PSModuleInfo.ExportedFunctions.Count) { + $Tags += "$($script:Includes)_Function" + $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage + if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { + $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } } - } - $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } - } + $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } - $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo - if ($dscResourceNames) { - $Tags += "$($script:Includes)_DscResource" + $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo + if ($dscResourceNames) { + $Tags += "$($script:Includes)_DscResource" - $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } + $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } - #If DscResourcesToExport is commented out or "*" is used, we will write-warning - if ($ModuleManifestHashTable -and - ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and - $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or - -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { - $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage + #If DscResourcesToExport is commented out or "*" is used, we will write-warning + if ($ModuleManifestHashTable -and + ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and + $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or + -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { + $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } } - } - $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo - if ($RoleCapabilityNames) { - $Tags += "$($script:Includes)_RoleCapability" + $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo + if ($RoleCapabilityNames) { + $Tags += "$($script:Includes)_RoleCapability" - $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + } } # Populate the module dependencies elements from RequiredModules and diff --git a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 index 4a3d1f4b..dd5205b8 100644 --- a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 @@ -76,7 +76,11 @@ function Publish-Module { [Parameter(ParameterSetName = "ModuleNameParameterSet")] [switch] - $AllowPrerelease + $AllowPrerelease, + + [Parameter()] + [switch] + $EnforceMaximumTagLength ) Begin { @@ -541,22 +545,23 @@ function Publish-Module { $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) if ($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) { $PublishPSArtifactUtility_Params = @{ - PSModuleInfo = $moduleInfo - ManifestPath = $manifestPath - NugetApiKey = $NuGetApiKey - Destination = $DestinationLocation - Repository = $Repository - NugetPackageRoot = $tempModulePath - FormatVersion = $FormatVersion - ReleaseNotes = $($ReleaseNotes -join "`r`n") - Tags = $Tags - LicenseUri = $LicenseUri - IconUri = $IconUri - ProjectUri = $ProjectUri - Verbose = $VerbosePreference - WarningAction = $WarningPreference - ErrorAction = $ErrorActionPreference - Debug = $DebugPreference + PSModuleInfo = $moduleInfo + ManifestPath = $manifestPath + NugetApiKey = $NuGetApiKey + Destination = $DestinationLocation + Repository = $Repository + NugetPackageRoot = $tempModulePath + FormatVersion = $FormatVersion + ReleaseNotes = $($ReleaseNotes -join "`r`n") + Tags = $Tags + EnforceMaximumTagLength = $EnforceMaximumTagLength + LicenseUri = $LicenseUri + IconUri = $IconUri + ProjectUri = $ProjectUri + Verbose = $VerbosePreference + WarningAction = $WarningPreference + ErrorAction = $ErrorActionPreference + Debug = $DebugPreference } if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential', $Credential) From 319bcd2a6da266eeebf37cc1725b356ce4cad646 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Sun, 12 May 2019 12:54:54 -0400 Subject: [PATCH 3/4] Renamed EnforceMaximumTagLength to SkipAutomaticTags --- Tests/PSGetPublishModule.Tests.ps1 | 10 ++-- .../functions/Publish-PSArtifactUtility.ps1 | 6 +-- .../public/psgetfunctions/Publish-Module.ps1 | 51 +++++++++---------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Tests/PSGetPublishModule.Tests.ps1 b/Tests/PSGetPublishModule.Tests.ps1 index 59139c55..3eb3ad21 100644 --- a/Tests/PSGetPublishModule.Tests.ps1 +++ b/Tests/PSGetPublishModule.Tests.ps1 @@ -769,7 +769,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { # # Expected Result: Publish operation should succeed and should have warned about tag length. # - It PublishModuleFunctionsAsTagsWarnWithoutEnforceMaximumTagLength { + It PublishModuleFunctionsAsTagsWarnWithoutSkipAutomaticTags { $version = "1.0.0" $Description = "$script:PublishModuleName module" $Tags = "PSGet","DSC" @@ -801,13 +801,13 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { } ` -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') - # Purpose: Test Publish-Module cmdlet excludes functions from tags when using EnforceMaximumTagLength parameter + # Purpose: Test Publish-Module cmdlet excludes functions from tags when using SkipAutomaticTags parameter # - # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish with EnforceMaxmimumTagLength parameter + # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish with SkipAutomaticTags parameter # # Expected Result: Publish operation should succeed and should not have warned about tag length # - It PublishModuleFunctionsAsTagsWithEnforceMaximumTagLength { + It PublishModuleFunctionsAsTagsWithSkipAutomaticTags { $version = "1.0.0" $Description = "$script:PublishModuleName module" $Tags = "PSGet","DSC" @@ -832,7 +832,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { Publish-Module -Path $script:PublishModuleBase ` -NuGetApiKey $script:ApiKey ` -Repository "PSGallery" ` - -EnforceMaximumTagLength ` + -SkipAutomaticTags ` -WarningAction SilentlyContinue ` -WarningVariable wa diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index b52e7a69..31e001da 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -55,7 +55,7 @@ function Publish-PSArtifactUtility { [Parameter(ParameterSetName = 'PublishModule')] [switch] - $EnforceMaximumTagLength, + $SkipAutomaticTags, [Parameter(ParameterSetName = 'PublishModule')] [Uri] @@ -222,7 +222,7 @@ function Publish-PSArtifactUtility { if ($PSScriptInfo) { $Tags += "PSScript" - if ($PSScriptInfo.DefinedCommands -and -not $EnforceMaximumTagLength) { + if ($PSScriptInfo.DefinedCommands -and -not $SkipAutomaticTags) { if ($PSScriptInfo.DefinedFunctions) { $Tags += "$($script:Includes)_Function" $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } @@ -255,7 +255,7 @@ function Publish-PSArtifactUtility { $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath - if (-not $EnforceMaximumTagLength) { + if (-not $SkipAutomaticTags) { if ($PSModuleInfo.ExportedCommands.Count) { if ($PSModuleInfo.ExportedCmdlets.Count) { $Tags += "$($script:Includes)_Cmdlet" diff --git a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 index dd5205b8..682c2b81 100644 --- a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 @@ -80,7 +80,7 @@ function Publish-Module { [Parameter()] [switch] - $EnforceMaximumTagLength + $SkipAutomaticTags ) Begin { @@ -141,8 +141,7 @@ function Publish-Module { if (-not $DestinationLocation -or (-not (Microsoft.PowerShell.Management\Test-Path $DestinationLocation) -and - -not (Test-WebUri -uri $DestinationLocation))) - { + -not (Test-WebUri -uri $DestinationLocation))) { $message = $LocalizedData.PSGalleryPublishLocationIsMissing -f ($Repository, $Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` @@ -374,12 +373,12 @@ function Publish-Module { # This finds all the items without force (leaving out hidden files and dirs) then copies them Microsoft.PowerShell.Management\Get-ChildItem $Path -recurse | Microsoft.PowerShell.Management\Copy-Item -Force -Confirm:$false -WhatIf:$false -Destination { - if ($_.PSIsContainer) { - Join-Path $tempModulePathForFormatVersion $_.Parent.FullName.substring($path.length) - } - else { - join-path $tempModulePathForFormatVersion $_.FullName.Substring($path.Length) - } + if ($_.PSIsContainer) { + Join-Path $tempModulePathForFormatVersion $_.Parent.FullName.substring($path.length) + } + else { + join-path $tempModulePathForFormatVersion $_.FullName.Substring($path.Length) + } } try { @@ -545,23 +544,23 @@ function Publish-Module { $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) if ($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) { $PublishPSArtifactUtility_Params = @{ - PSModuleInfo = $moduleInfo - ManifestPath = $manifestPath - NugetApiKey = $NuGetApiKey - Destination = $DestinationLocation - Repository = $Repository - NugetPackageRoot = $tempModulePath - FormatVersion = $FormatVersion - ReleaseNotes = $($ReleaseNotes -join "`r`n") - Tags = $Tags - EnforceMaximumTagLength = $EnforceMaximumTagLength - LicenseUri = $LicenseUri - IconUri = $IconUri - ProjectUri = $ProjectUri - Verbose = $VerbosePreference - WarningAction = $WarningPreference - ErrorAction = $ErrorActionPreference - Debug = $DebugPreference + PSModuleInfo = $moduleInfo + ManifestPath = $manifestPath + NugetApiKey = $NuGetApiKey + Destination = $DestinationLocation + Repository = $Repository + NugetPackageRoot = $tempModulePath + FormatVersion = $FormatVersion + ReleaseNotes = $($ReleaseNotes -join "`r`n") + Tags = $Tags + SkipAutomaticTags = $SkipAutomaticTags + LicenseUri = $LicenseUri + IconUri = $IconUri + ProjectUri = $ProjectUri + Verbose = $VerbosePreference + WarningAction = $WarningPreference + ErrorAction = $ErrorActionPreference + Debug = $DebugPreference } if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential', $Credential) From 022178b14ef9fa2d5238a0f7ccf9c0963a611e81 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Sun, 12 May 2019 12:56:08 -0400 Subject: [PATCH 4/4] Keep Tags as string array and make new variable for a space separated string --- src/PowerShellGet/private/functions/New-NuspecFile.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 index 894a1a1f..6ba53dbf 100644 --- a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 +++ b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 @@ -74,7 +74,7 @@ function New-NuspecFile { releaseNotes = $ReleaseNotes requireLicenseAcceptance = $RequireLicenseAcceptance.ToString().ToLower() copyright = $Copyright - tags = $Tags + tags = $tagsString } if ($LicenseUrl) { $metaDataElementsHash.Add("licenseUrl", $LicenseUrl) }