forked from OCram85/PSCredentialStore
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:
@ -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 {}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
||||
}
|
||||
|
140
src/Store/Update-CredentialStore.ps1
Normal file
140
src/Store/Update-CredentialStore.ps1
Normal 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 {
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user