PowerShell 6 Core Support (#35)

## About
This pull request reflects all changes done in the `linuxsupport` branch.

## Content
- Enable PowerShell 6 Core support
- Use PFX Certificate for encryption ( fixes #32 )
- Updates CI / CD pipeline ( fixes #31 )
- uses portable libressl ( fixes #34 )
- adds `-PassThru` switch for returning current `VIServer` session in `Connect-To` ( fixes #34 )
- adds git lfs for embedded libressl files
- restructured internal functions into `Private` dir
- added certificate related functions
- adds travis build pipeline for tests
This commit is contained in:
2019-01-16 12:55:29 +01:00
committed by GitHub
parent ab13962f6e
commit afab3c870c
83 changed files with 2465 additions and 1342 deletions

View File

@ -35,36 +35,54 @@ function Get-CredentialStore {
#>
[CmdletBinding(DefaultParameterSetName = "Private")]
[OutputType("PSCredentialStore.Store")]
param(
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[string]$Path,
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[switch]$Shared
)
if ($PSCmdlet.ParameterSetName -eq 'Private') {
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
}
begin {}
if (Test-CredentialStore -Path $Path) {
try {
$FileContent = Get-Content -Path $Path -Raw
ConvertFrom-Json $FileContent
process {
# Set the CredentialStore for private, shared or custom mode.
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = Get-DefaultCredentialStorePath
}
catch [System.Exception] {
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
if (!($PSBoundParameters.ContainsKey('Path'))) {
$Path = Get-DefaultCredentialStorePath -Shared
}
}
if (Test-CredentialStore -Path $Path -Shared) {
try {
$FileContent = Get-Content -Path $Path -Raw
$CS = ConvertFrom-Json $FileContent
$CS.PSObject.TypeNames.Insert(0, "PSCredentialStore.Store")
return $CS
}
catch [System.Exception] {
$MessageParams = @{
Message = "Unknown CredentialStore format. Invalid JSON file."
ErrorAction = "Stop"
}
Write-Error @MessageParams
}
}
else {
$MessageParams = @{
Message = "Unknown CredentialStore format. Invalid JSON file."
Message = "Could not find the CredentialStore."
ErrorAction = "Stop"
}
Write-Error @MessageParams
}
}
else {
$MessageParams = @{
Message = "Could not find the CredentialStore."
ErrorAction = "Stop"
}
Write-Error @MessageParams
}
end {}
}

View File

@ -22,7 +22,8 @@ function New-CredentialStore {
[None]
.OUTPUTS
[None]
['PSCredentialStore.Store'] Returns the recently created CredentialStore object if the -PassThru parameter
was given.
.EXAMPLE
New-CredentialStore
@ -50,63 +51,163 @@ function New-CredentialStore {
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding(DefaultParameterSetName = "Private")]
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = "Private")]
[OutputType("PSCredentialStore.Store")]
param(
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[switch]$Shared,
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[ValidateNotNullOrEmpty()]
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
[string]$Path,
[Parameter(Mandatory = $false, ParameterSetName = "Private")]
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[switch]$Force
[switch]$Force,
[Parameter(Mandatory = $false, ParameterSetName = "Private")]
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[switch]$PassThru,
[Parameter(Mandatory = $false, ParameterSetName = "Private")]
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[Switch]$SkipPFXCertCreation
)
# Lets get the current Date in a human readable format.
$CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
begin {
# Lets get the current Date in a human readable format.
$CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
# Set latest Credential Store version
Set-Variable -Name "CSVersion" -Value "1.2.0" -Option Constant
# Set the CredentialStore path for private mode.
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = "{0}\CredentialStore.json" -f $Env:APPDATA
# Set latest Credential Store version
# Set-Variable -Name "CSVersion" -Value "2.0.0" -Option Constant -Scope
}
# Test if in the given store already a CredentialStore exists.
Write-Verbose "Test if there is already a credential store."
if ((Test-CredentialStore -Path $Path) -and ($Force -ne $true)) {
$MessageParam = @{
Message = "The given file already exists. Use the 'Force' switch to override the existing store."
ErrorAction = "Stop"
process {
# Set the CredentialStore for private, shared or custom mode.
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = Get-DefaultCredentialStorePath
}
Write-Error @MessageParam
}
# We need to use the IDictionary to keep the property sorting in the object.
$ObjProperties = [ordered]@{
Version = $CSVersion
Creation = $CurrentDate
}
if ($PSCmdlet.ParameterSetName -eq "Shared") {
$ObjProperties.Type = "Shared"
# Check if a ChallengeFile already exists. We don't want to overide it.
# Otherwise previous created CredentialStores couln't be decrypted anymore.
if (-not (Test-ChallengeFile)) {
Set-ChallengeFile
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
if (!($PSBoundParameters.ContainsKey('Path'))) {
$Path = Get-DefaultCredentialStorePath -Shared
}
}
# Test if in the CredentialStore already exists.
Write-Verbose "Test if there is already a credential store."
if ((Test-Path -Path $Path) -and ($Force -ne $true)) {
$ErrorParams = @{
ErrorAction = 'Stop'
Exception = [System.InvalidOperationException]::new(
'The given file already exists. Use the -Force switch to override the existing store.'
)
}
Write-Error @ErrorParams
}
if (! $SkipPFXCertCreation.IsPresent) {
$CRTParams = @{
Country = 'DE'
State = 'PSCredentialStore'
City = 'PSCredentialStore'
Organization = 'PSCredentialStore'
OrganizationalUnitName = ' '
CommonName = 'PrivateStore'
}
$CRTAttribute = New-CRTAttribute @CRTParams
# If we are working with a ne shared store we have to create the location first.
# Otherwise openssl fails with unknown path
$StoreHome = Split-Path -Path $Path -Parent
if (! (Test-Path -Path $StoreHome)) {
New-Item -ItemType Directory -Path $StoreHome -ErrorAction Stop
}
$PfxParams = @{
CRTAttribute = $CRTAttribute
KeyName = Join-Path -Path $StoreHome -ChildPath 'private.key'
CertName = Join-Path -Path $StoreHome -ChildPath 'PSCredentialStore.pfx'
ErrorAction = 'Stop'
Confirm = $false
}
if ((Test-Path $PfxParams.CertName) -and (! $Force.IsPresent)) {
$ErrorParams = @{
Exception = [System.IO.InvalidDataException]::new(
'There is already a PfxCertificate for a private CredentialStore!'
)
ErrorAction = 'Stop'
}
Write-Error @ErrorParams
}
try {
New-PfxCertificate @PfxParams
}
catch {
$_.Exception.Message | Write-Error
$ErrorParams = @{
ErrorAction = 'Stop'
Exception = [System.Exception]::new(
'Could not create the private PfXCertificate!'
)
}
Write-Error @ErrorParams
}
try {
$FreshCert = Get-PfxCertificate -FilePath $PfxParams.CertName -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
$_.Exception.Message | Write-Error
Write-Error -Message 'Could not read the new PfxCertificate.' -ErrorAction Stop
}
}
# We need to use the IDictionary to keep the property sorting in the object.
$ObjProperties = [ordered]@{
PSTypeName = 'PSCredentialStore.Store'
Version = $CSVersion
Created = $CurrentDate
PfxCertificate = $null
Thumbprint = $null
Type = $null
}
if (! $SkipPFXCertCreation.IsPresent) {
$ObjProperties.PfXCertificate = $PfxParams.CertName
$ObjProperties.Thumbprint = $FreshCert.Thumbprint
}
if ($PSCmdlet.ParameterSetName -eq "Shared") {
$ObjProperties.Type = "Shared"
}
else {
$ObjProperties.Type = "Private"
}
$CredentialStoreObj = [PSCustomObject]$ObjProperties
try {
$JSON = ConvertTo-Json -InputObject $CredentialStoreObj -ErrorAction Stop
$JSON | Out-File -FilePath $Path -ErrorAction Stop -Force
}
catch {
$_.Exception.Message | Write-Error
$ErrorParams = @{
ErrorAction = 'Stop'
Exception = [System.IO.IOException]::new(
'Unable to convert or write the CredentialStore'
)
}
Write-Error @ErrorParams
}
if ($PassThru.IsPresent) {
return $CredentialStoreObj
}
}
else {
$ObjProperties.Type = "Private"
}
# Create a new object for easy conversion into a json file
$CredentialStoreObj = New-Object -TypeName psobject -Property $ObjProperties
try {
ConvertTo-Json -InputObject $CredentialStoreObj | Out-File -FilePath $Path
}
catch [System.Exception] {
$_.Exception | Format-List -Force | Out-String | Write-Error -ErrorAction Stop
end {
}
}

View File

@ -26,37 +26,40 @@ function Test-CredentialStore {
[CmdletBinding(DefaultParameterSetName = "Private")]
param(
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
[string]$Path,
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[switch]$Shared
)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = "{0}\CredentialStore.json" -f $Env:APPDATA
begin {
# Set latest Credential Store version
#Set-Variable -Name "CSVersion" -Value "2.0.0" -Option Constant
}
# Set latest Credential Store version
Set-Variable -Name "CSVersion" -Value "1.2.0" -Option Constant
if (Test-Path $Path) {
Write-Verbose "CredentialStore in given path found."
# try tor read the store. Removed the Get-CredentialStore function to avoid recursive calls.
try {
$FileContent = Get-Content -Path $Path -Raw
$CSContent = ConvertFrom-Json $FileContent
process {
# Set the CredentialStore for private, shared or custom mode.
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = Get-DefaultCredentialStorePath
}
catch {
Write-Warning "Could not read or convert the given CredentialStore."
Return $False
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
if (!($PSBoundParameters.ContainsKey('Path'))) {
$Path = Get-DefaultCredentialStorePath -Shared
}
}
Return $True
Write-Verbose -Message ("Path is: {0}" -f $Path)
if (Test-Path $Path) {
Write-Verbose "CredentialStore in given path found."
return $true
}
else {
Write-Verbose "The given CredentialStore does not exist!"
return $false
}
}
Else {
Write-Verbose "The given CredentialStore does not exist!"
Return $False
}
end {}
}

View File

@ -0,0 +1,140 @@
function Update-CredentialStore {
<#
.SYNOPSIS
A brief description of the function or script.
.DESCRIPTION
Describe the function of the script using a single sentence or more.
.PARAMETER One
Description of the Parameter (what it does)
.INPUTS
Describe the script input parameters (if any), otherwise it may also list the word "[None]".
.OUTPUTS
Describe the script output parameters (if any), otherwise it may also list the word "[None]".
.EXAMPLE
.\Remove-Some-Script.ps1 -One content
.NOTES
File Name : Update-CredentialStore.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding()]
[OutputType()]
param(
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[Version]$From = '1.2.0',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[Version]$To = '2.0.0',
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$Path,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$PfxCertificate
)
begin {
}
process {
if (Test-Path -Path $Path) {
$CSOld = Get-CredentialStore -Shared -Path $Path -ErrorAction Stop
if ($CSOld.Version -ne $From) {
$ErrorParams = @{
Message = 'Can not migrate CredentialStore from version {0} to {1}' -f $From, $To
ErrorAction = 'Stop'
Exception = [System.Exception]::new()
}
Write-Error @ErrorParams
}
$CSNew = [PSCustomObject]@{
PSTypeName = 'PSCredentialStore.Store'
Version = $To
Created = $CurrentDate
PfxCertificate = $null
Thumbprint = $null
Type = $null
}
if ($PWD -eq (Get-DefaultCredentialStorePath)) {
$CSNew.Type = 'Private'
}
elseif ($PWD -eq (Get-DefaultCredentialStorePath -Shared)) {
$CSNew.Type = 'Shared'
}
else {
$ErrorParams = @{
Message = 'Can not determine a valid CredentialStore Type!'
ErrorAction = 'Stop'
Exception = [System.Exception]::new()
}
Write-Error @ErrorParams
}
$Cert = Get-PfxCertificate -FilePath $PfxCertificate -ErrorAction Stop
$CSNew.PfxCertificate = Join-Path -Path $PfxCertificate
$CSNew.Thumbprint = $Cert.Thumbprint
$CredentialItems = $CSOld | Get-Member -MemberType NoteProperty | Where-Object {
$_.Definition -like "*.PSCustomObject*"
} | Select-Object -ExpandProperty Name
# iterate through all existing items
foreach ($Item in $CredentialItems) {
$CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
$RSAKey = Get-RandomAESKey
$CredentialObj = [PSCustomObject]@{
User = $Item.UserName
Password = $null
Created = $CurrentDate
LastChange = $null
EncryptedKey = [Convert]::ToBase64String(
$Cert.PublicKey.Key.Encrypt(
$RSAKey,
[System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1
)
)
}
if ($CSOld.Type -eq 'Private') {
$CredentialObject.Password = ConvertTo-SecureString -SecureString $Item.Password | ConvertFrom-SecureString -Key $RSAKey
}
elseif ($CSNew.Type -eq 'Shared') {
$ChallengeKey = [io.file]::ReadAllBytes((Join-Path -Path $PWD -ChildPath '/Challenge.bin'))
$CredentialObject.Password = ConvertTo-SecureString -SecureString $Item.Password -Key $ChallengeKey | ConvertFrom-SecureString -Key $RSAKey
}
Add-Member -InputObject $CSNew -Name (
($Item | Get-Variable).Name
) -MemberType NoteProperty -Value $CredentialObj
}
$CSNew | ConvertTo-Json -Depth 5 | Out-File -LiteralPath (
Join-Path -Path $PWD -ChildPath './CredentialStore.json'
) -Encoding utf8 -Confirm:$true
}
else {
$ErrorParams = @{
Message = 'Could not find the given CredentialStore path!'
ErrorAction = 'Stop'
Exception = [System.IO.FileNotFoundException]::new()
}
Write-Error @ErrorParams
}
}
end {
}
}