module.psm1
<#
REST API Wrappers for the Azure Key Vault Service #> $Script:DefaultVaultDomain = 'vault.azure.net' $Script:UnixEpoch = New-Object DateTime(1970, 1, 1, 0, 0, 0, 0, [System.DateTimeKind]::Utc) $Script:KeyTypes=@{EllipticalCurve='EC';RSA='RSA';HSM='RSA-HSM';Octet='oct'} $Script:IssuerCertTypes=@('OV-SSL','EV-SSL') $Script:ExpirationActionTypes=@{'AutoRenew'='AutoRenew';'EmailContacts'='EmailContacts'} $Script:KeyUsageTypes=@{ DigitalSignature = "digitalSignature" NonRepudiation = "nonRepudiation" KeyEncipherment = "keyEncipherment" DataEncipherment = "dataEncipherment" KeyAgreement = "keyAgreement" KeyCertSign = "keyCertSign" CrlSign = "cRLSign" EncipherOnly = "encipherOnly" DecipherOnly = "decipherOnly"} $Script:EncryptionAlgorithms=@{ rsa_oaep = "RSA-OAEP" rsa_oaep_256 = "RSA-OAEP-256" rsa1_5 = "RSA1_5" } $Script:KeyOperations=@{ encrypt = 'encrypt'; decrypt = 'decrypt'; sign = 'sign'; verify = 'verify'; wrapKey = 'wrapKey'; unwrapKey = 'unwrapKey' } $Script:SigningAlgorithms=@{ PS256 = "PS256" PS384 = "PS384" PS512 = "PS512" RS256 = "RS256" RS384 = "RS384" RS512 = "RS512" RSNULL = "RSNULL" } $Global:Azure_Vault_Values=@{ KeyTypes=$Script:KeyTypes; ExpirationActionTypes=$Script:ExpirationActionTypes; SigningAlgorithms=$Script:SigningAlgorithms; EncryptionAlgorithms=$Script:EncryptionAlgorithms; KeyOperations=$Script:KeyOperations; } #region Helpers Function ConvertToBase64UrlString { [CmdletBinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [byte[]]$InputObject ) PROCESS { $EncodedValue=[Convert]::ToBase64String($InputObject) $Result=$EncodedValue.TrimEnd('=').Replace('+', '-').Replace('/', '_'); Write-Output $Result } } Function ConvertFromBase64UrlString { [CmdletBinding()] param ( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string[]]$InputObject ) PROCESS { foreach ($item in $InputObject) { $item=$item.Replace('-', '+').Replace('_', '/') $count = 3 - (($item.Length + 3) % 4); if ($count -ne 0) { $item+=New-Object string('=', $count); } $Result=[Convert]::FromBase64String($item); Write-Output $Result } } } <# .SYNOPSIS Generic request wrapper for the Key Vault Service API .PARAMETER Uri The full request URI .PARAMETER AccessToken The OAuth bearer token .PARAMETER AdditionalHeaders Additional Headers for the request .PARAMETER Method The method to be executed .PARAMETER NextLinkProperty The name of any OData continuation token property .PARAMETER ValueProperty The name of any OData value property .PARAMETER ErrorProperty The name of any OData error value property .PARAMETER Body The request body object .PARAMETER ContentType The content type for the request .PARAMETER AggregateResponses Whether to Aggregate OData continuation Responses .PARAMETER ReturnHeaders Whether to return the response headers .PARAMETER RequestDelayMilliseconds The amount of time in milliseconds to wait between concurrent requests #> Function Invoke-AzureVaultRequest { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$Uri, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$AccessToken, [ValidateNotNull()] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Collections.IDictionary] $AdditionalHeaders, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [Microsoft.PowerShell.Commands.WebRequestMethod] $Method = "GET", [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$NextLinkProperty = 'nextLink', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$ValueProperty = 'value', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$ErrorProperty = 'error', [ValidateNotNull()] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [object]$Body, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$ContentType = 'application/json', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [switch]$AggregateResponses, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [switch]$ReturnHeaders, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [switch]$DontExpand, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$RequestDelayMilliseconds = 100 ) $TotalItems = 0 $RequestHeaders = $AdditionalHeaders $RequestHeaders['client-request-id'] = [Guid]::NewGuid().ToString() $RequestHeaders['User-Agent'] = "PowerShell $($PSVersionTable.PSVersion.ToString())" $RequestHeaders['Authorization'] = "Bearer $AccessToken" $BaseUri = "$($Uri.Scheme)://$($Uri.Host)" $RequestParams = @{ Headers = $RequestHeaders; Uri = $Uri; ContentType = $ContentType; Method = $Method; } if ($Body -ne $null) { $RequestParams['Body'] = $($Body|ConvertTo-Json -Depth 10) } $RequestResult = $null try { $Response = Invoke-WebRequest @RequestParams -UseBasicParsing -ErrorAction Stop Write-Verbose "[Invoke-AzureVaultRequest]$Method $Uri Response:$($Response.StatusCode)-$($Response.StatusDescription) Content-Length:$($Response.RawContentLength)" if (-not [String]::IsNullOrEmpty($Response.Content)) { $RequestResult = $Response.Content|ConvertFrom-Json } if ($ReturnHeaders.IsPresent) { Write-Output $Response.Headers } } catch { #See if we can unwind an exception from a response if ($_.Exception.Response -ne $null) { Write-Verbose "[Invoke-AzureVaultRequest] Unwinding Exception Response..." $ExceptionResponse = $_.Exception.Response $ErrorStream = $ExceptionResponse.GetResponseStream() $ErrorStream.Position = 0 $StreamReader = New-Object System.IO.StreamReader($ErrorStream) try { $ErrorContent = $StreamReader.ReadToEnd() $StreamReader.Close() if (-not [String]::IsNullOrEmpty($ErrorContent)) { $ErrorObject = $ErrorContent|ConvertFrom-Json if (-not [String]::IsNullOrEmpty($ErrorProperty) -and $ErrorObject.PSobject.Properties.name -match $ErrorProperty) { $ErrorContent = ($ErrorObject|Select-Object -ExpandProperty $ErrorProperty)|ConvertTo-Json } } } catch { Write-Warning "[Invoke-AzureVaultRequest] Error occurred reading exception stream! $_" } finally { $StreamReader.Close() } $ErrorMessage = "Error: $($ExceptionResponse.Method) $($ExceptionResponse.ResponseUri) Returned $($ExceptionResponse.StatusCode) $ErrorContent" } else { $ErrorMessage = "An error occurred $_" } Write-Verbose "[Invoke-AzureVaultRequest] $ErrorMessage" throw $ErrorMessage } #Should never get here null if ($RequestResult -ne $null) { if ($RequestResult.PSobject.Properties.name -match $ValueProperty -and (-not $DontExpand.IsPresent)) { $Result = $RequestResult|Select-Object -ExpandProperty $ValueProperty $TotalItems += $Result.Count Write-Output $Result } else { Write-Output $RequestResult $TotalItems++ #not sure why I am incrementing.. } #Loop to aggregate OData continutation tokens while ($RequestResult.PSobject.Properties.name -match $NextLinkProperty) { #Throttle the requests a bit.. Start-Sleep -Milliseconds $RequestDelayMilliseconds $ResultPages++ $UriBld = New-Object System.UriBuilder($BaseUri) $NextUri = $RequestResult|Select-Object -ExpandProperty $NextLinkProperty if ($LimitResultPages -gt 0 -and $ResultPages -eq $LimitResultPages -or [String]::IsNullOrEmpty($NextUri)) { break } Write-Verbose "[Invoke-AzureVaultRequest] Item Count:$TotalItems Page:$ResultPages More Items available @ $NextUri" #Is this an absolute or relative uri? if ($NextUri -match "$BaseUri*") { $UriBld = New-Object System.UriBuilder($NextUri) } else { $Path = $NextUri.Split('?')|Select-Object -First 1 $NextQuery = [Uri]::UnescapeDataString(($NextUri.Split('?')|Select-Object -Last 1)) $UriBld.Path = $Path $UriBld.Query = $NextQuery } try { $RequestParams['Uri'] = $UriBld.Uri $Response = Invoke-WebRequest @RequestParams -UseBasicParsing -ErrorAction Stop Write-Verbose "[Invoke-AzureVaultRequest]$Method $Uri Response:$($Response.StatusCode)-$($Response.StatusDescription) Content-Length:$($Response.RawContentLength)" $RequestResult = Invoke-Command -ScriptBlock $ContentAction -ArgumentList $Response.Content|ConvertFrom-Json if ($RequestResult.PSobject.Properties.name -match $ValueProperty) { $Result = $RequestResult|Select-Object -ExpandProperty $ValueProperty $TotalItems += $Result.Count Write-Output $Result } else { Write-Output $RequestResult $TotalItems++ #not sure why I am incrementing.. } } catch { #See if we can unwind an exception from a response if ($_.Exception.Response -ne $null) { $ExceptionResponse = $_.Exception.Response $ErrorStream = $ExceptionResponse.GetResponseStream() $ErrorStream.Position = 0 $StreamReader = New-Object System.IO.StreamReader($ErrorStream) try { $ErrorContent = $StreamReader.ReadToEnd() $StreamReader.Close() if (-not [String]::IsNullOrEmpty($ErrorContent)) { $ErrorObject = $ErrorContent|ConvertFrom-Json if (-not [String]::IsNullOrEmpty($ErrorProperty) -and $ErrorObject.PSobject.Properties.name -match $ErrorProperty) { $ErrorContent = ($ErrorObject|Select-Object -ExpandProperty $ErrorProperty)|ConvertTo-Json } } } catch { } finally { $StreamReader.Close() } $ErrorMessage = "Error: $($ExceptionResponse.Method) $($ExceptionResponse.ResponseUri) Returned $($ExceptionResponse.StatusCode) $ErrorContent" } else { $ErrorMessage = "An error occurred $_" } Write-Verbose "[Invoke-AzureVaultRequest] $ErrorMessage" throw $ErrorMessage } } } } <# .SYNOPSIS Creates a parameter object for new/updated key requests .DESCRIPTION Creates a parameter object for new/updated key requests .PARAMETER KeyType The key type ('EC', 'RSA', 'RSA-HSM', 'oct') .PARAMETER KeyName The key name .PARAMETER AccessToken The OAuth bearer token .PARAMETER KeyOperations The allowed key operations .PARAMETER ExpiryInDays The vailidity length for the key .PARAMETER NotBefore The validity start date for the key .PARAMETER KeySize The KeySize (1024,2048) .PARAMETER Tags Key-value metadata pairs #> Function New-AzureVaultKeyParameters { [CmdletBinding()] param ( [ValidateSet('EC', 'RSA', 'RSA-HSM', 'oct')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$KeyType = 'RSA', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$KeyName, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$KeyOperations, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$NotBefore = [datetime]::UtcNow, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$ExpiryInDays = 365, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$Epoch = $Script:UnixEpoch, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [ValidateSet(1024,2048)] [int]$KeySize, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Collections.IDictionary]$Tags ) $NewKeyAttributes = New-Object PSObject -Property @{ 'enabled' = $true; 'nbf' = $(($NotBefore - $Epoch).TotalSeconds); 'exp' = $((($NotBefore.AddDays($ExpiryInDays)) - $Epoch).TotalSeconds); } $KeyProperties = [ordered]@{ 'attributes' = $NewKeyAttributes; 'key_ops' = $KeyOperations; 'key_size' = $KeySize; 'kty' = $KeyType; 'tags' = $Tags; } $NewKeyParams = New-Object PSObject -Property $KeyProperties Write-Output $NewKeyParams } Function New-AzureVaultCertificateParameters { [CmdletBinding()] param ( [ValidateSet('EC', 'RSA', 'RSA-HSM', 'oct')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$KeyType = 'RSA', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$KeyUsage, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$EnhancedKeyUsage, #[ValidateSet('Self','Unknown','DigiCert','GlobalSign','WoSign')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$Issuer = 'Self', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$Enabled = $true, [ValidateSet('OV-SSL','EV-SSL')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$IssuerCertType = 'OV-SSL', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$Subject, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$SubjectAlternateNameEmails, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$SubjectAlternateNameUpns, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$SubjectAlternateNameDnsNames, [ValidateSet('EmailContacts', 'AutoRenew')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$LifetimeExpireActionType = 'AutoRenew', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$NotBefore = [datetime]::UtcNow, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$ExpiryInDays = 365, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$Epoch = $Script:UnixEpoch, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$Exportable = $false, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$ReuseKey = $true, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [ValidateRange(1,99)] [int]$LifetimeExpirePercentage = 90, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [ValidateRange(1,90)] [int]$LifetimeDaysBeforeExpire = 7, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [ValidateSet(1024,2048,4096)] [int]$KeySize = 2048, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Collections.IDictionary]$Tags ) begin { $ExpireTime = $NotBefore.AddDays($ExpiryInDays) $ValidityInMonths = ($ExpireTime.Month - $NotBefore.Month) + (12 * ($ExpireTime.Year - $NotBefore.Year)) $NotBeforeUnix = $(($NotBefore - $Epoch).TotalSeconds) $ExpiryUnix = $(($ExpireTime - $Epoch).TotalSeconds) } process { $IssuerProperties = [ordered]@{ 'name' = $Issuer; } if ($Issuer -notin 'Self','Unknown') { $IssuerProperties['cty'] = $IssuerCertType } $X509Properties = [ordered]@{ 'subject' = $Subject; 'ekus' = @($EnhancedKeyUsage); 'sans' = [ordered]@{ 'emails' = @($SubjectAlternateNameEmails); 'dns_names' = @($SubjectAlternateNameDnsNames); 'upns' = @($SubjectAlternateNameUpns); } } $LifetimeActionProperties = [ordered]@{ 'trigger' = @{'lifetime_percentage' = $LifetimeExpirePercentage;'days_before_expiry' = $LifetimeDaysBeforeExpire}; 'action' = @{'action_type' = $LifetimeExpireActionType}; } $AttributeProperties = [ordered]@{ 'enabled' = $Enabled; 'nbf' = $NotBeforeUnix; 'exp' = $ExpiryUnix; } $KeyProperties = [ordered]@{ 'exportable' = $Exportable; 'kty' = $KeyType; 'key_size' = $KeySize; 'reuse_key' = $ReuseKey; } $PolicyProps = [ordered]@{ 'key_props' = $KeyProperties; 'secret_props' = @{'contentType' = ""}; 'x509_props' = $X509Properties; 'key_usage' = @($KeyUsage); 'validity_months' = $ValidityInMonths; 'lifetime_actions' = $LifetimeActionProperties; 'issuer' = $IssuerProperties; 'attributes' = $AttributeProperties; 'tags' = $Tags; } $CertParams = New-Object psobject -Property $PolicyProps Write-Output $CertParams } } Function New-AzureVaultSecretParameters { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$Value, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Collections.IDictionary]$Tags, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$ContentType = 'password', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$Enabled = $true, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$NotBefore = [datetime]::UtcNow, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$ExpiryInDays = 90, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$Epoch = $Script:UnixEpoch ) begin { $ExpireTime = $NotBefore.AddDays($ExpiryInDays) $NotBeforeUnix = $(($NotBefore - $Epoch).TotalSeconds) $ExpiryUnix = $(($ExpireTime - $Epoch).TotalSeconds) } process { $SecretAttributeProperties = [ordered]@{ 'enabled' = $Enabled; 'nbf' = $NotBeforeUnix; 'exp' = $ExpiryUnix; } $VaultSecretProperties = [ordered]@{ 'value' = $Value; 'tags' = $Tags; 'contentType' = $ContentType; 'attributes' = $SecretAttributeProperties; } $VaultSecret = New-Object PSobject -Property $VaultSecretProperties Write-Output $VaultSecret } } #endregion #region Keys <# .SYNOPSIS Retrieves key(s) from the specified vault .DESCRIPTION Retrieves key(s) from the specified vault .PARAMETER KeyName The key name .PARAMETER MaxResults Limit the maximum results returned .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token #> Function Get-AzureVaultKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $false,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$MaxResults ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $Headers = @{Accept = 'application/json'} $RequestParams = @{ Method = 'GET' AdditionalHeaders = $Headers; ContentType = 'application/json'; } Write-Verbose "[Get-AzureVaultKey] Retrieving key(s) from ${VaultBaseUri}" } PROCESS { if ($KeyName -ne $null) { foreach ($item in $KeyName) { $VaultUriBld.Path = "/keys/${item}" Write-Verbose "[Get-AzureVaultKey] Retreiving Key ${VaultBaseUri} -> ${item}" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Output $Result } } } else { if ($MaxResults -gt 0) { Write-Verbose "[Get-AzureVaultKey] Listing All Keys ${VaultBaseUri} -> MaxResults=${MaxResults}" } else { Write-Verbose "[Get-AzureVaultKey] Listing All Keys ${VaultBaseUri}" } $VaultUriBld.Path = "/keys" $VaultUriBld.Query = "api-version=${ApiVersion}&MaxResults=${MaxResults}" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Output $Result } } } } <# .SYNOPSIS Creates a new key .DESCRIPTION Creates a new key .PARAMETER KeyType The key type ('EC', 'RSA', 'RSA-HSM', 'oct') .PARAMETER KeyName The key name .PARAMETER KeyOperations The allowed key operations .PARAMETER ExpiryInDays The vailidity length for the key .PARAMETER NotBefore The validity start date for the key .PARAMETER KeySize The KeySize (1024,2048) .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER Tags Key-value metadata pairs .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token #> Function New-AzureVaultKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [ValidateSet('EC', 'RSA', 'RSA-HSM', 'oct')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$KeyType = 'RSA', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$KeyOperations = @("sign", "verify", "wrapKey", "unwrapKey", "encrypt", "decrypt"), [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$NotBefore = [datetime]::UtcNow, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$ExpiryInDays = 365, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [ValidateSet(1024,2048)] [int]$KeySize, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Collections.IDictionary]$Tags, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01' ) BEGIN { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" $VaultUriBld.Path = "/keys/${KeyName}/create" } PROCESS { $KeyParams = @{ KeyName = $KeyName; KeyType = $KeyType; KeySize = $KeySize; ExpiryInDays = $ExpiryInDays; KeyOperations = $KeyOperations; NotBefore = $NotBefore } $NewKeyBody = New-AzureVaultKeyParameters @KeyParams $RequestParams = @{ Uri = $VaultUriBld.Uri; AdditionalHeaders = @{Accept = 'application/json'} Body = $NewKeyBody; Method = 'POST'; ContentType = 'application/json'; ErrorAction = 'STOP'; AccessToken = $AccessToken; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { Write-Output $Result } } } <# .SYNOPSIS Removes key(s) from the specified vault .DESCRIPTION Retrieves key(s) from the specified vault .PARAMETER KeyName The key name .PARAMETER ApiVersion The vault api version .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER AccessToken The OAuth bearer token #> Function Remove-AzureVaultKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $RequestParams = @{ AdditionalHeaders = @{Accept = 'application/json'} ContentType = 'application/json' AccessToken = $AccessToken; Method = 'DELETE'; ErrorAction = 'Stop'; } Write-Verbose "[Remove-AzureVaultKey] Removing key(s) from ${VaultBaseUri}" } PROCESS { foreach ($item in $KeyName) { $VaultUriBld.Path = "/keys/${item}" Write-Verbose "[Remove-AzureVaultKey] Removing key ${item} from ${VaultBaseUri}" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Verbose "[Remove-AzureVaultKey] Successfully Removed key ${item} from ${VaultBaseUri}!" Write-Output $Result } } } } #Encrypt function New-AzureVaultEncryptedValue { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$KeyVersion, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [byte[]]$Value, [ValidateSet('RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' )] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$Algorithm = 'RSA-OAEP256', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [Switch]$AsString ) begin { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" if ([String]::IsNullOrEmpty($KeyVersion)) { $VaultUriBld.Path = "/keys/${KeyName}/encrypt" } else { $VaultUriBld.Path = "/keys/${KeyName}/${KeyVersion}/encrypt" } $RequestParams = @{ Uri = $VaultUriBld.Uri; Method = 'POST'; AdditionalHeaders = @{Accept = 'application/json; charset=utf-8'}; AccessToken = $AccessToken; ContentType = 'application/json; charset=utf-8' } } process { #$Bas64String=[Convert]::ToBase64String($Value) #$UrlString=$($Bas64String.TrimEnd('=').Replace('+', '-').Replace('/', '_')) $UrlString=ConvertToBase64UrlString -InputObject $Value $RequestParams['Body'] = [ordered]@{ 'alg' = $Algorithm; 'value' = $UrlString; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { $ResultBytes=$Result|ConvertFromBase64UrlString Write-Output $ResultBytes } } } #Decrypt function Get-AzureVaultDecryptedValue { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$KeyVersion, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [byte[]]$Value, [ValidateSet('RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' )] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$Algorithm = 'RSA-OAEP256', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) begin { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" if ([String]::IsNullOrEmpty($KeyVersion)) { $VaultUriBld.Path = "/keys/${KeyName}/decrypt" } else { $VaultUriBld.Path = "/keys/${KeyName}/${KeyVersion}/decrypt" } $RequestParams = @{ Uri = $VaultUriBld.Uri; Method = 'POST'; AdditionalHeaders = @{Accept = 'application/json; charset=utf-8'}; AccessToken = $AccessToken; ContentType = 'application/json; charset=utf-8' } } process { $UrlString=ConvertToBase64UrlString -InputObject $Value $RequestParams['Body'] = [ordered]@{ 'alg' = $Algorithm; 'value' = $UrlString; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { $ResultBytes=$Result|ConvertFromBase64UrlString Write-Output $ResultBytes } } } #Sign function New-AzureVaultSignedValue { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$KeyVersion, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [byte[]]$Value, [ValidateSet('PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$Algorithm = 'RS256', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) begin { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" if ([String]::IsNullOrEmpty($KeyVersion)) { $VaultUriBld.Path = "/keys/${KeyName}/sign" } else { $VaultUriBld.Path = "/keys/${KeyName}/${KeyVersion}/sign" } $RequestParams = @{ Uri = $VaultUriBld.Uri; Method = 'POST'; AdditionalHeaders = @{Accept = 'application/json'}; AccessToken = $AccessToken; ContentType = 'application/json' } } process { $UriString=ConvertToBase64UrlString -InputObject $Value $RequestParams['Body'] = [ordered]@{ 'alg' = $Algorithm; 'value' = $UriString; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { $ResultBytes=$Result|ConvertFromBase64UrlString Write-Output $ResultBytes } } } #Verify function Test-AzureVaultSignedValue { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$KeyVersion, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [byte[]]$Value, [ValidateSet('PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$Algorithm = 'RS256', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) begin { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" if ([String]::IsNullOrEmpty($KeyVersion)) { $VaultUriBld.Path = "/keys/${KeyName}/verify" } else { $VaultUriBld.Path = "/keys/${KeyName}/${KeyVersion}/verify" } $RequestParams = @{ Uri = $VaultUriBld.Uri; Method = 'POST'; AdditionalHeaders = @{Accept = 'application/json'}; AccessToken = $AccessToken; ContentType = 'application/json' } } process { $UriString=ConvertToBase64UrlString -InputObject $Value $RequestParams['Body'] = [ordered]@{ 'alg' = $Algorithm; 'value' = $UriString; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { Write-Output $Result } } } #Unwrap Key function New-AzureVaultUnwrappedKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$KeyVersion, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [byte[]]$Value, [ValidateSet('RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' )] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$Algorithm = 'RSA-OAEP256', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) begin { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" if ([String]::IsNullOrEmpty($KeyVersion)) { $VaultUriBld.Path = "/keys/${KeyName}/unwrap" } else { $VaultUriBld.Path = "/keys/${KeyName}/${KeyVersion}/unwrap" } $RequestParams = @{ Uri = $VaultUriBld.Uri; Method = 'POST'; AdditionalHeaders = @{Accept = 'application/json'}; AccessToken = $AccessToken; ContentType = 'application/json' } } process { $UriString=ConvertToBase64UrlString -InputObject $Value $RequestParams['Body'] = [ordered]@{ 'alg' = $Algorithm; 'value' = $UriString; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { $ResultBytes=$Result|ConvertFromBase64UrlString Write-Output $ResultBytes } } } #Wrap Key function New-AzureVaultWrappedKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [string]$KeyName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$KeyVersion, [Parameter(Mandatory = $true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName = $true)] [string[]]$Value, [ValidateSet('RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' )] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [string]$Algorithm = 'RSA-OAEP256', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) begin { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" if ([String]::IsNullOrEmpty($KeyVersion)) { $VaultUriBld.Path = "/keys/${KeyName}/wrap" } else { $VaultUriBld.Path = "/keys/${KeyName}/${KeyVersion}/wrap" } $RequestParams = @{ Uri = $VaultUriBld.Uri; Method = 'POST'; AdditionalHeaders = @{Accept = 'application/json'}; AccessToken = $AccessToken; ContentType = 'application/json' } } process { foreach ($item in $Value) { $RequestParams['Body'] = [ordered]@{ 'alg' = $Algorithm; 'value' = $item; } $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { Write-Output $Result } } } } #endregion #region Secrets <# .SYNOPSIS Retrieves secret(s) from the specified vault .DESCRIPTION Retrieves secret(s) from the specified vault .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER SecretName The secret name(s) .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token .PARAMETER MaxResults Limit the number of results returned #> Function Get-AzureVaultSecret { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $false,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$SecretName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$MaxResults ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $Headers = @{Accept = 'application/json'} $RequestParams = @{ Method = 'GET' AdditionalHeaders = $Headers; ContentType = 'application/json'; AccessToken = $AccessToken; ErrorAction = 'Stop'; } Write-Verbose "[Get-AzureVaultSecret] Retrieving secret(s) from ${VaultBaseUri}" } PROCESS { if ($SecretName -ne $null) { foreach ($item in $SecretName) { $VaultUriBld.Path = "/secrets/${item}" Write-Verbose "[Get-AzureVaultSecret] Retreiving Secret ${VaultBaseUri} -> ${item}" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Output $Result } } } else { if ($MaxResults -gt 0) { Write-Verbose "[Get-AzureVaultSecret] Listing All Secrets ${VaultBaseUri} -> MaxResults=${MaxResults}" } else { Write-Verbose "[Get-AzureVaultSecret] Listing All Secrets ${VaultBaseUri}" } $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Output $Result } } } } #Create Secret Function New-AzureVaultSecret { [CmdletBinding(DefaultParameterSetName='string')] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [String]$SecretName, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [string]$Value, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [System.IO.FileInfo]$PfxFile, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [securestring]$CertificatePassword, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [System.Collections.IDictionary]$Tags, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [string]$ContentType = 'password', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [bool]$Enabled = $true, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [datetime]$NotBefore = [datetime]::UtcNow, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [int]$ExpiryInDays = 90, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='certfile')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='string')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='cert')] [String]$AccessToken ) BEGIN { $VaultUriBld = New-Object System.UriBuilder("https://${VaultName}.${VaultDomain}") $VaultUriBld.Query = "api-version=${ApiVersion}" $VaultUriBld.Path = "/secrets/$SecretName" $RequestParams = @{ Method = 'PUT' AdditionalHeaders = @{Accept = 'application/json'}; ContentType = 'application/json'; Uri = $VaultUriBld.Uri; ErrorAction = 'Stop'; AccessToken = $AccessToken; } } PROCESS { if($PSCmdlet.ParameterSetName -eq 'cert') { if($ContentType -ne 'application/x-pkcs12') { $ContentType = 'application/x-pkcs12'; } #'Export' the cert $RawCertBytes=$Certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12,$CertificatePassword) $Value=[System.Convert]::ToBase64String($RawCertBytes) } elseif ($PSCmdlet.ParameterSetName -eq 'certfile') { if($ContentType -ne 'application/x-pkcs12') { $ContentType = 'application/x-pkcs12'; } if(-not $PfxFile.Exists){ throw "Unable to find the certificate file $($PfxFile.FullName)!" } #Export it without the private key $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($CertificatePassword) $ClearPassword= [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) $CertCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection $CertCollection.Import($PfxFile.FullName,$ClearPassword,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable) $CertBytes=$CertCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12) $Value=[System.Convert]::ToBase64String($CertBytes) } #Build the object $SecretParams = @{ Value = $Value ContentType = $ContentType; NotBefore = $NotBefore; ExpiryInDays = $ExpiryInDays; Tags = $Tags; } $NewSecret = New-AzureVaultSecretParameters @SecretParams $RequestParams['Body'] = $NewSecret $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { Write-Output $Result } } } <# .SYNOPSIS Removes secret(s) from the specified vault .DESCRIPTION Removes secret(s) from the specified vault .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER SecretName The secret name(s) .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token #> Function Remove-AzureVaultSecret { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$SecretName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $RequestParams = @{ AdditionalHeaders = @{Accept = 'application/json'} ContentType = 'application/json' AccessToken = $AccessToken; Method = 'DELETE'; ErrorAction = 'Stop'; } Write-Verbose "[Remove-AzureVaultSecret] Removing secret(s) from ${VaultBaseUri}" } PROCESS { foreach ($item in $SecretName) { $VaultUriBld.Path = "/secrets/${item}" Write-Verbose "[Remove-AzureVaultSecret] Removing secret ${item} from ${VaultBaseUri}" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Verbose "[Remove-AzureVaultSecret] Successfully Removed secret ${item} from ${VaultBaseUri}!" Write-Output $Result } } } } #endregion #region Certificates #Get Certificate Function Get-AzureVaultCertificate { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $false,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$CertificateName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$MaxResults ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $Headers = @{Accept = 'application/json'} $RequestParams = @{ Method = 'GET' AdditionalHeaders = $Headers; ContentType = 'application/json'; } Write-Verbose "[Get-AzureVaultCertificate] Retrieving certficate(s) from ${VaultBaseUri}" } PROCESS { if ($CertificateName -ne $null) { foreach ($item in $CertificateName) { $VaultUriBld.Path = "/certificates/${item}" Write-Verbose "[Get-AzureVaultCertificate] Retreiving Certificate ${VaultBaseUri} -> ${item}" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Output $Result } } } else { $VaultUriBld.Path = "/certificates" if ($MaxResults -gt 0) { Write-Verbose "[Get-AzureVaultCertificate] Listing All Certificates ${VaultBaseUri} -> MaxResults=${MaxResults}" } else { Write-Verbose "[Get-AzureVaultCertificate] Listing All Certificates ${VaultBaseUri}" } $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Output $Result } } } } #Create Certificate Function New-AzureVaultCertificate { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$CertificateName, [ValidateSet('EC', 'RSA', 'RSA-HSM', 'oct')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$KeyType = 'RSA', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$KeyUsage = @("sign", "verify", "wrapKey", "unwrapKey", "encrypt", "decrypt"), [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$EnhancedKeyUsage, #[ValidateSet('Self','Unknown','DigiCert','GlobalSign','WoSign')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$Issuer = 'Self', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$Enabled = $true, [ValidateSet('OV-SSL','EV-SSL')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$IssuerCertType = 'OV-SSL', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$Subject, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$SubjectAlternateNameEmails, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$SubjectAlternateNameUpns, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String[]]$SubjectAlternateNameDnsNames, [ValidateSet('EmailContacts', 'AutoRenew')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$LifetimeExpireActionType = 'AutoRenew', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [datetime]$NotBefore = [datetime]::UtcNow, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [int]$ExpiryInDays = 365, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$Exportable = $false, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [bool]$ReuseKey = $true, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [ValidateRange(1,99)] [int]$LifetimeExpirePercentage = 90, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [ValidateRange(1,90)] [int]$LifetimeDaysBeforeExpire = 7, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [ValidateSet(1024,2048,4096)] [int]$KeySize = 2048, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Collections.IDictionary]$Tags, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $VaultUriBld.Path = "/certificates/${CertificateName}/create" $RequestParams = @{ AdditionalHeaders = @{Accept = 'application/json'}; Method = 'POST'; ContentType = 'application/json'; ErrorAction = 'STOP'; AccessToken = $AccessToken; Uri = $VaultUriBld.Uri; } } PROCESS { #Build the object $CertificateParams = [ordered]@{ KeyType = $KeyType; KeyUsage = $KeyUsage; KeySize = $KeySize; EnhancedKeyUsage = $EnhancedKeyUsage; Issuer = $Issuer; Enabled = $Enabled; IssuerCertType = $IssuerCertType; Subject = $Subject; SubjectAlternateNameEmails = $SubjectAlternateNameEmails; SubjectAlternateNameUpns = $SubjectAlternateNameUpns; SubjectAlternateNameDnsNames = $SubjectAlternateNameDnsNames LifetimeExpireActionType = $LifetimeExpireActionType; LifetimeExpirePercentage = $LifetimeExpirePercentage LifetimeDaysBeforeExpire = $LifetimeDaysBeforeExpire NotBefore = $NotBefore; ExpiryInDays = $ExpiryInDays; Exportable = $Exportable; ReuseKey = $ReuseKey; Tags = $Tags; } $NewCertificate = New-AzureVaultCertificateParameters @CertificateParams $RequestParams['Body'] = $NewCertificate $Result = Invoke-AzureVaultRequest @RequestParams if ($Result -ne $null) { Write-Output $Result } } } #Delete Certficate Function Remove-AzureVaultCertificate { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$CertificateName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) BEGIN { $VaultBaseUri = "https://${VaultName}.${VaultDomain}" $VaultUriBld = New-Object System.UriBuilder($VaultBaseUri) $VaultUriBld.Query = "api-version=${ApiVersion}" $RequestParams = @{ AdditionalHeaders = @{Accept = 'application/json'}; ContentType = 'application/json' AccessToken = $AccessToken; Method = 'DELETE'; ErrorAction = 'Stop'; } Write-Verbose "[Remove-AzureVaultCertificate] Removing certificate(s) from ${VaultBaseUri}" } PROCESS { foreach ($item in $CertificateName) { $VaultUriBld.Path = "/certificates/${item}" Write-Verbose "[Remove-AzureVaultCertificate] Removing certificate ${item} from ${VaultBaseUri}!" $Result = Invoke-AzureVaultRequest @RequestParams -Uri $VaultUriBld.Uri if ($Result -ne $null) { Write-Verbose "[Remove-AzureVaultCertificate] Successfully removed certificate ${item} from ${VaultBaseUri}!" Write-Output $Result } } } } #endregion #region Secret Helpers <# .SYNOPSIS Uses a secret within the specified vault to create a securestring .DESCRIPTION Uses a secret within the specified vault to create a securestring .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER SecretName The secret name(s) .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token #> Function ConvertFrom-AzureVaultSecretToSecureString { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$SecretName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) PROCESS { foreach ($item in $SecretName) { $SecurePassword=New-Object securestring $SecretParams=@{ VaultName=$VaultName; VaultDomain=$VaultDomain; ApiVersion=$ApiVersion; AccessToken=$AccessToken; SecretName=$item; } #Retreive the secret from the vault $PasswordSecret=Get-AzureVaultSecret @SecretParams -ErrorAction Stop if(-not [string]::IsNullOrEmpty($PasswordSecret)) { $PasswordSecret.ToCharArray()|ForEach-Object{$SecurePassword.AppendChar($_)} } Write-Output $SecurePassword } } } <# .SYNOPSIS Uses a secret within the specified vault to create a PSCredential .DESCRIPTION Uses a secret within the specified vault to create a PSCredential .PARAMETER UserName The username for the Credential .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER SecretName The secret name(s) .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token #> Function ConvertTo-CredentialFromAzureVaultSecret { [CmdletBinding(DefaultParameterSetName='NoUserSecret')] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName='NoUserSecret')] [string]$UserName, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='NoUserSecret')] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [String]$UserVaultName=$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='NoUserSecret')] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='NoUserSecret')] [String]$SecretName, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [String]$UserSecretName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='NoUserSecret')] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true,ParameterSetName='UserSecret')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='NoUserSecret')] [String]$AccessToken ) process { if ($PSCmdlet.ParameterSetName -eq 'UserSecret') { $UserParams=@{ VaultName=$UserVaultName; VaultDomain=$VaultDomain; ApiVersion=$ApiVersion; AccessToken=$AccessToken; SecretName=$UserSecretName; } $UserName=Get-AzureVaultSecret @UserParams -ErrorAction Stop } $SecretParams=@{ VaultName=$VaultName; VaultDomain=$VaultDomain; ApiVersion=$ApiVersion; AccessToken=$AccessToken; SecretName=$SecretName; } $SecurePassword=ConvertFrom-AzureVaultSecretToSecureString @SecretParams -ErrorAction Stop $Credential=New-Object PSCredential($UserName,$SecurePassword) Write-Output $Credential } } <# .SYNOPSIS Retrieves a certificate from an Azure Key Vault secret store .DESCRIPTION Retrieves a certificate from an Azure Key Vault secret store .PARAMETER VaultName The vault name .PARAMETER VaultDomain The vault FQDN .PARAMETER SecretName The secret name(s) .PARAMETER ApiVersion The vault api version .PARAMETER AccessToken The OAuth bearer token #> Function ConvertFrom-AzureVaultSecretToCertificate { [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] [CmdletBinding()] param ( [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$VaultName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [System.Uri]$VaultDomain = $Script:DefaultVaultDomain, [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String[]]$SecretName, [Parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)] [String]$ApiVersion = '2016-10-01', [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)] [String]$AccessToken ) process { foreach ($item in $SecretName) { $SecretParams=@{ VaultName=$VaultName; VaultDomain=$VaultDomain; ApiVersion=$ApiVersion; AccessToken=$AccessToken; SecretName=$item; } #Retreive the secret from the vault $SecretResult=Get-AzureVaultSecret @SecretParams -ErrorAction Stop if($SecretResult -ne $null -and (-not [string]::IsNullOrEmpty($SecretResult))) { #Convert the certficate reference... $SecretBytes=[Convert]::FromBase64String($SecretResult) $Cert=[System.Security.Cryptography.X509Certificates.X509Certificate2]::new($SecretBytes) Write-Output $Cert } } } } #endregion |