diff --git a/src/KeyVault/KeyVault.Test/ScenarioTests/KeyVaultTestRunner.cs b/src/KeyVault/KeyVault.Test/ScenarioTests/KeyVaultTestRunner.cs new file mode 100644 index 000000000000..d28f6d701d4e --- /dev/null +++ b/src/KeyVault/KeyVault.Test/ScenarioTests/KeyVaultTestRunner.cs @@ -0,0 +1,41 @@ +using Microsoft.Azure.Commands.TestFx; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit.Abstractions; + +namespace Microsoft.Azure.Commands.KeyVault.Test.ScenarioTests +{ + public class KeyVaultTestRunner + { + protected readonly ITestRunner TestRunner; + + protected KeyVaultTestRunner(ITestOutputHelper output) + { + TestRunner = TestManager.CreateInstance(output) + .WithNewPsScriptFilename($"{GetType().Name}.ps1") + .WithProjectSubfolderForTests("ScenarioTests") + .WithCommonPsScripts(new[] + { + @"Common.ps1", + @"../AzureRM.Resources.ps1", + }) + .WithNewRmModules(helper => new[] + { + helper.RMProfileModule, + helper.GetRMModulePath("AzureRM.KeyVault.psd1"), + }) + .WithNewRecordMatcherArguments( + userAgentsToIgnore: new Dictionary + { + {"Microsoft.Azure.Management.Resources.ResourceManagementClient", "2016-02-01"}, + }, + resourceProviders: new Dictionary + { + {"Microsoft.KeyVault", null}, + } + ) + .Build(); + } + } +} diff --git a/src/KeyVault/KeyVault.Test/ScenarioTests/SecretManagementExtensionTests.cs b/src/KeyVault/KeyVault.Test/ScenarioTests/SecretManagementExtensionTests.cs new file mode 100644 index 000000000000..2315a387a88c --- /dev/null +++ b/src/KeyVault/KeyVault.Test/ScenarioTests/SecretManagementExtensionTests.cs @@ -0,0 +1,43 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using Xunit; + +namespace Microsoft.Azure.Commands.KeyVault.Test.ScenarioTests +{ + public class SecretManagementExtensionTests : KeyVaultTestRunner + { + public SecretManagementExtensionTests(Xunit.Abstractions.ITestOutputHelper output) + :base(output) + { + } + + [Fact] + [Trait(Category.AcceptanceType, Category.LiveOnly)] + // Test case cannot be recorded + public void TestExtensionRegister() + { + TestRunner.RunTestScript("Test-ExtensionRegister"); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.LiveOnly)] + // Test case cannot be recorded + public void TestSecretManagementExtension() + { + TestRunner.RunTestScript("Test-SecretManagementExtension"); + } + } +} diff --git a/src/KeyVault/KeyVault.Test/ScenarioTests/SecretManagementExtensionTests.ps1 b/src/KeyVault/KeyVault.Test/ScenarioTests/SecretManagementExtensionTests.ps1 new file mode 100644 index 000000000000..baa541b0c519 --- /dev/null +++ b/src/KeyVault/KeyVault.Test/ScenarioTests/SecretManagementExtensionTests.ps1 @@ -0,0 +1,47 @@ +# ---------------------------------------------------------------------------------- +# +# Copyright Microsoft Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------------- + +<# +.SYNOPSIS +Test register secret management extension +#> +function Test-ExtensionRegister +{ + Register-SecretVault -Name AzKeyVault -ModuleName Az.KeyVault -VaultParameters @{ AZKVaultName = 'xdmkv'; SubscriptionId = '' } + + Get-SecretVault + + Unregister-SecretVault -Name AzKeyVault +} + +<# +.SYNOPSIS +Test secret management extension function +#> +function Test-SecretManagementExtension +{ + Register-SecretVault -Name AzKeyVault -ModuleName Az.KeyVault -VaultParameters @{ AZKVaultName = 'xdmkv'; SubscriptionId = '' } + + Get-SecretInfo -Vault AzKeyVault + + Get-Secret -Vault AzKeyVault -Name secret1 + + $secure = ConvertTo-SecureString -String "test" -AsPlainText -Force + Set-Secret -Vault AzKeyVault -Name secret3 -SecureStringSecret $secure + + Get-SecretInfo -Vault AzKeyVault + Remove-Secret -Vault AzKeyVault -Name secret3 + + +} \ No newline at end of file diff --git a/src/KeyVault/KeyVault/ChangeLog.md b/src/KeyVault/KeyVault/ChangeLog.md index 7e0d9df9b248..1e765e7681fa 100644 --- a/src/KeyVault/KeyVault/ChangeLog.md +++ b/src/KeyVault/KeyVault/ChangeLog.md @@ -18,9 +18,9 @@ - Additional information about change #1 --> ## Upcoming Release +* Added support to Microsoft.PowerShell.SecretManagement [#11178] ## Version 1.5.2 - * Added breaking change attributes to `New-AzKeyVault` ## Version 1.5.1 diff --git a/src/KeyVault/KeyVault/KeyVault.csproj b/src/KeyVault/KeyVault/KeyVault.csproj index 05742ea938f3..1aa1fcc947f6 100644 --- a/src/KeyVault/KeyVault/KeyVault.csproj +++ b/src/KeyVault/KeyVault/KeyVault.csproj @@ -16,5 +16,9 @@ + + + + \ No newline at end of file diff --git a/src/KeyVault/KeyVault/SecretManagementExtension/SecretManagementExtension.psd1 b/src/KeyVault/KeyVault/SecretManagementExtension/SecretManagementExtension.psd1 new file mode 100644 index 000000000000..23af8ba0bae0 --- /dev/null +++ b/src/KeyVault/KeyVault/SecretManagementExtension/SecretManagementExtension.psd1 @@ -0,0 +1,5 @@ +@{ + ModuleVersion = '1.0' + RootModule = '.\SecretManagementExtension.psm1' + FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault') +} diff --git a/src/KeyVault/KeyVault/SecretManagementExtension/SecretManagementExtension.psm1 b/src/KeyVault/KeyVault/SecretManagementExtension/SecretManagementExtension.psm1 new file mode 100644 index 000000000000..4b3770006fc1 --- /dev/null +++ b/src/KeyVault/KeyVault/SecretManagementExtension/SecretManagementExtension.psm1 @@ -0,0 +1,123 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +function Check-SubscriptionLogIn +{ + param ( + [string] $SubscriptionId, + [string] $AzKVaultName + ) + + Import-Module -Name Az.Accounts + + $azContext = Az.Accounts\Get-AzContext + if (($azContext -eq $null) -or ($azContext.Subscription.Id -ne $SubscriptionId)) + { + throw "To use ${AzKVaultName} Azure vault, the current user must be logged into Azure account subscription ${SubscriptionId}. Run 'Connect-AzAccount -SubscriptionId ${SubscriptionId}'." + } +} + +function Get-Secret +{ + param ( + [string] $Name, + [string] $VaultName, + [hashtable] $AdditionalParameters + ) + + Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName + + Import-Module -Name Az.KeyVault + + $secret = Az.KeyVault\Get-AzKeyVaultSecret -Name $Name -VaultName $AdditionalParameters.AZKVaultName + if ($secret -ne $null) + { + return $secret.SecretValue + } +} + +function Set-Secret +{ + param ( + [string] $Name, + [object] $Secret, + [string] $VaultName, + [hashtable] $AdditionalParameters + ) + + Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName + + Import-Module -Name Az.KeyVault + + $null = Az.KeyVault\Set-AzKeyVaultSecret -Name $Name -SecretValue $Secret -VaultName $AdditionalParameters.AZKVaultName + return $? +} + +function Remove-Secret +{ + param ( + [string] $Name, + [string] $VaultName, + [hashtable] $AdditionalParameters + ) + + Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName + + Import-Module -Name Az.KeyVault + + $null = Az.KeyVault\Remove-AzKeyVaultSecret -Name $Name -VaultName $AdditionalParameters.AZKVaultName -Force + return $? +} + +function Get-SecretInfo +{ + param ( + [string] $Filter, + [string] $VaultName, + [hashtable] $AdditionalParameters + ) + + Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName + + Import-Module -Name Az.KeyVault + + if ([string]::IsNullOrEmpty($Filter)) + { + $Filter = "*" + } + + $pattern = [WildcardPattern]::new($Filter) + $vaultSecretInfos = Az.KeyVault\Get-AzKeyVaultSecret -VaultName $AdditionalParameters.AZKVaultName + foreach ($vaultSecretInfo in $vaultSecretInfos) + { + if ($pattern.IsMatch($vaultSecretInfo.Name)) + { + Write-Output ( + [Microsoft.PowerShell.SecretManagement.SecretInformation]::new( + $vaultSecretInfo.Name, + [Microsoft.PowerShell.SecretManagement.SecretType]::SecureString, + $VaultName) + ) + } + } +} + +function Test-SecretVault +{ + param ( + [string] $VaultName, + [hashtable] $AdditionalParameters + ) + + try + { + Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName + } + catch + { + Write-Error $_ + return $false + } + + return $true +} diff --git a/tools/CleanupBuild.ps1 b/tools/CleanupBuild.ps1 index 38cd16c67c27..d5c5ccab95b1 100644 --- a/tools/CleanupBuild.ps1 +++ b/tools/CleanupBuild.ps1 @@ -62,13 +62,17 @@ foreach($RMPath in $resourceManagerPaths) $acceptedDlls += $assembly.Split("\")[-1] } - Write-Verbose "Removing redundant dlls in $($RMFolder.Name)" + Write-Host "Removing redundant dlls in $($RMFolder.Name)" $removedDlls = Get-ChildItem -Path $RMFolder.FullName -Filter "*.dll" -Recurse | where { $acceptedDlls -notcontains $_.Name -and !$_.FullName.Contains("Assemblies") } - $removedDlls | % { Write-Verbose "Removing $($_.Name)"; Remove-Item $_.FullName -Force } + $removedDlls | % { Write-Host "Removing $($_.Name)"; Remove-Item $_.FullName -Force } - Write-Verbose "Removing scripts and psd1 in $($RMFolder.FullName)" + Write-Host "Removing scripts and psd1 in $($RMFolder.FullName)" - $removedPsd1 = Get-ChildItem -Path "$($RMFolder.FullName)" -Include "*.psd1" -Exclude "PsSwaggerUtility*.psd1" -Recurse | where { $_.FullName -ne "$($RMFolder.FullName)$([IO.Path]::DirectorySeparatorChar)$($RMFolder.Name).psd1" } - $removedPsd1 | % { Write-Verbose "Removing $($_.FullName)"; Remove-Item $_.FullName -Force } + $exludedPsd1 = @( + "PsSwaggerUtility*.psd1", + "SecretManagementExtension.psd1" + ) + $removedPsd1 = Get-ChildItem -Path "$($RMFolder.FullName)" -Include "*.psd1" -Exclude $exludedPsd1 -Recurse | where { $_.FullName -ne "$($RMFolder.FullName)$([IO.Path]::DirectorySeparatorChar)$($RMFolder.Name).psd1" } + $removedPsd1 | % { Write-Host "Removing $($_.FullName)"; Remove-Item $_.FullName -Force } } } diff --git a/tools/NewHelpIndex.ps1 b/tools/NewHelpIndex.ps1 index cf1d149eb0d6..30702bca62be 100644 --- a/tools/NewHelpIndex.ps1 +++ b/tools/NewHelpIndex.ps1 @@ -68,7 +68,9 @@ $HelpFolders = @() $resourceManagerPath = "$PSScriptRoot/../artifacts/$BuildConfig/" -$RMpsd1s += Get-ChildItem -Path $resourceManagerPath -Depth 2 | Where-Object { $_.Name -like "*.psd1" -and $_.FullName -notlike "*dll-Help*" } +$RMpsd1s += Get-ChildItem -Path $resourceManagerPath -Depth 2 | Where-Object { + $_.Name -like "*.psd1" -and $_.FullName -notlike "*dll-Help*" -and $_.Name -ne "SecretManagementExtension.psd1" +} $HelpFolders += Get-ChildItem -Path "$PSScriptRoot/../src" -Recurse -Directory | where { $_.Name -eq "help" -and $_.FullName -notlike "*\Stack\*" -and $_.FullName -notlike "*\bin\*"} @@ -93,7 +95,11 @@ $RMpsd1s | ForEach-Object { $outputCmdlets = @{} - $parsedPsd1.CmdletsToExport | ForEach-Object { + $cmdletsToExport = $parsedPsd1.CmdletsToExport | Where-Object { $_ } + $functionsToExport = $parsedPsd1.FunctionsToExport | Where-Object { $_ } + $cmdletsToExport = $cmdletsToExport + $functionsToExport + + $cmdletsToExport | ForEach-Object { $cmdletHelpFile = $HelpFileMapping["$_.md"] if ($cmdletHelpFile -eq $null -and $Target -eq "Latest") {