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:
OCram85 2019-01-16 12:55:29 +01:00 committed by GitHub
parent ab13962f6e
commit afab3c870c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 2465 additions and 1342 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
src/Vendor/libressl255/* filter=lfs diff=lfs merge=lfs -text
*.pfx filter=lfs diff=lfs merge=lfs -text

43
.travis.yml Normal file
View File

@ -0,0 +1,43 @@
language: csharp
dotnet: 2.2.101
mono: none
git:
depth: 1000
os:
- linux
# Disable OSX bulds for now
# - osx
sudo: required
dist: xenial
osx_image: xcode8.1
matrix:
fast_finish: true
addons:
artifacts:
#paths: $(ls ./../dist/PowerShellGet.zip | tr "\n" ":")
paths: ./dist/PowerShellGet.zip
install:
# Default 2.0.0 Ruby is buggy
# Default bundler version is buggy
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
rvm install ruby-2.3.3;
rvm --default use 2.3.3;
fi
- bash <(wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh)
- pushd tools
- chmod +x travis.sh
- popd
script:
- echo "TRAVIS_EVENT_TYPE value $TRAVIS_EVENT_TYPE"
- ./tools/travis.sh

96
.vscode/launch.json vendored
View File

@ -1,48 +1,48 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch Current File",
"script": "${file}",
"args": [],
"cwd": "${file}"
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch Current File in Temporary Console",
"script": "${file}",
"args": [],
"cwd": "${file}",
"createTemporaryIntegratedConsole": true
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch Current File w/Args Prompt",
"script": "${file}",
"args": [
"${command:SpecifyScriptArgs}"
],
"cwd": "${file}"
},
{
"type": "PowerShell",
"request": "attach",
"name": "PowerShell Attach to Host Process",
"processId": "${command:PickPSHostProcess}",
"runspaceId": 1
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Interactive Session",
"cwd": "${workspaceRoot}"
}
]
}
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch Current File",
"script": "${file}",
"args": [],
"cwd": "${file}"
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch Current File in Temporary Console",
"script": "${file}",
"args": [],
"cwd": "${file}",
"createTemporaryIntegratedConsole": true
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch Current File w/Args Prompt",
"script": "${file}",
"args": [
"${command:SpecifyScriptArgs}"
],
"cwd": "${file}"
},
{
"type": "PowerShell",
"request": "attach",
"name": "PowerShell Attach to Host Process",
"processId": "${command:PickPSHostProcess}",
"runspaceId": 1
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Interactive Session",
"cwd": ""
}
]
}

View File

@ -26,7 +26,8 @@
"powershell.codeFormatting.whitespaceAroundOperator": true,
"powershell.codeFormatting.whitespaceAfterSeparator": true,
"powershell.codeFormatting.ignoreOneLineBlock": true,
"powershell.codeFormatting.alignPropertyValuePairs": false,
"powershell.codeFormatting.alignPropertyValuePairs": true,
"powershell.codeFormatting.preset": "Custom",
// cspell spellchecker options
"cSpell.enabledLanguageIds": [
"c",

View File

@ -23,14 +23,28 @@ need to store credentials for non interactive usage like in scheduled tasks.
For more details read the [about_PSCredentialStore](/docs/about_PSCredentialStore.md) page on github or via CLI with
`Get-Help about_PSCredentialStore`.
:exclamation: Upcoming Changes :exclamation:
================
The will be some breaking changes starting with the `0.5.0.xxx`:
- **PSCredentialStore will use PFX certificates to encrypt your credentials.**
- This replaces the the current encryption methods and you need to recreate or upgrade your pre existing stores.
- The changes allows the PSCredentialStore module to support the PowerShell `Core` editions.
- Yes this means, you can use the module on any PowerShell 6 supported linux distribution.
- It's also possible to create a shared credential store and transfer it onto a another platform like:
`Windows -- to --> Linux` and vice versa.
- Automatically creates self signed certificate with 2048 bits RSA keys for encryption.
Installation
============
PowerShellGallery.com (Recommended Way)
---------------------------------------
* Make sure you use PowerShell 4.0 or higher with `$PSVersionTable`.
* Use the builtin PackageManagement and install with: `Install-Module PSCredentialStore`
* Make sure you use PowerShell 5.1 or higher with `$PSVersionTable`.
* Use the builtin PackageManagement and install with: `Import-Module PowerShellGet; Install-Module 'PSCredentialStore' -Repository 'PSGallery'`
* Additionally use the `-AllowPrerelease` switch until we publish the final release!
* Done. Start exploring the Module with `Import-Module PSCredentialStore ; Get-Command -Module PSCredentialStore`
Manual Way
@ -97,3 +111,13 @@ Connect-To -RemoteHost "fas.myside.local" -Type NetAppFAS
Connect-To -RemoteHost "esx01.myside.local" -Type VMware
Connect-To -RemoteHost "vcr.myside.local" -Type CisServer
```
Credits
-------
A huge thanks to all the people who helped with their projects and indirect contributions which made this possible!
- This module is inspired by the awesome work of @dlwyatt with articles like these:
- https://powershell.org/2013/11/24/saving-passwords-and-preventing-other-processes-from-decrypting-them/
- https://powershell.org/2014/02/01/revisited-powershell-and-encryption/
- The awesome people from [LibreSSL](http://www.libressl.org/) which publishes the [portable openssl/libressl binaries](https://github.com/libressl-portable/portable)!

View File

@ -1,4 +1,4 @@
version: 0.2.3.{build}
version: 0.5.0.{build}
#branches:
# only:
@ -20,6 +20,7 @@ image: Visual Studio 2017
install:
- ps: Import-Module .\tools\AppVeyor.psm1
- ps: Import-Module .\tools\CoverallsIO.psm1
- ps: Invoke-InstallDependencies
environment:
@ -37,10 +38,10 @@ build_script:
- ps: Invoke-AppVeyorBuild
test_script:
- ps: Invoke-AppVeyorTests
- ps: |
$CodeCoverage = Invoke-AppVeyorTests
if ($null -ne $Env:CoverallsToken) {
Invoke-CoverageReport
Invoke-CoverageReport -PesterCoverageReport $CodeCoverage
}
else {
Write-Warning "No CoverallsToken found. This build seems to be triggered by a PR. Skipping this step..."
@ -60,7 +61,7 @@ deploy:
secure: M+bBX5/nKdJB0eViP7xtrLVTwf3vGDUA9N2MMprZp2i+9ZR3CBVcJnSzJWUmalhB
artifact: PSCredentialStore.zip # upload all NuGet packages to release assets
draft: false
prerelease: false
prerelease: true
on:
branch: master # build release on master branch changes

BIN
assets/logo256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -63,7 +63,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -19,7 +19,7 @@ Get-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [<CommonPara
### Shared
```
Get-CredentialStoreItem [-Path <String>] -RemoteHost <String> [-Identifier <String>] [-Shared]
Get-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Shared] [-Path <String>]
[<CommonParameters>]
```
@ -93,7 +93,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -19,7 +19,7 @@ Get-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [<CommonPara
### Shared
```
Get-CredentialStoreItem [-Path <String>] -RemoteHost <String> [-Identifier <String>] [-Shared]
Get-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Shared] [-Path <String>]
[<CommonParameters>]
```
@ -93,7 +93,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -20,8 +20,8 @@ New-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Credential
### Shared
```
New-CredentialStoreItem [-Path <String>] -RemoteHost <String> [-Identifier <String>]
[-Credential <PSCredential>] [-Shared] [<CommonParameters>]
New-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Credential <PSCredential>] [-Shared]
[-Path <String>] [<CommonParameters>]
```
## DESCRIPTION
@ -51,7 +51,7 @@ Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```
@ -111,7 +111,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -19,7 +19,7 @@ Remove-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [<CommonP
### Shared
```
Remove-CredentialStoreItem [-Path <String>] -RemoteHost <String> [-Identifier <String>] [-Shared]
Remove-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Shared] [-Path <String>]
[<CommonParameters>]
```
@ -94,7 +94,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -14,13 +14,14 @@ Changes the credentials for the given remote host in the store.
### Private (Default)
```
Set-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [<CommonParameters>]
Set-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Credential <PSCredential>]
[<CommonParameters>]
```
### Shared
```
Set-CredentialStoreItem [-Path <String>] -RemoteHost <String> [-Identifier <String>] [-Shared]
[<CommonParameters>]
Set-CredentialStoreItem -RemoteHost <String> [-Identifier <String>] [-Credential <PSCredential>] [-Shared]
[-Path <String>] [<CommonParameters>]
```
## DESCRIPTION
@ -37,6 +38,21 @@ Set-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.lo
## PARAMETERS
### -Credential
{{Fill Credential Description}}
```yaml
Type: PSCredential
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```
### -Identifier
Defaults to "".
Specify a string, which separates two CredentialStoreItems for the
@ -94,7 +110,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -63,7 +63,7 @@ Type: SwitchParameter
Parameter Sets: Shared
Aliases:
Required: False
Required: True
Position: Named
Default value: False
Accept pipeline input: False

View File

@ -1,3 +1,3 @@
{
"Version": "1.2.0",
"Creation": "2016-06-14 08:41:10"
"Version": "2.0.0",
"Creation": "2016-06-14 08:41:10"

View File

@ -1 +0,0 @@
!マ<><EFBE8F>H4サ<34><EFBDBB>"=w肛Sヨ2

Binary file not shown.

BIN
resources/cs/PSCredentialStore.pfx (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,100 @@
function New-CRTAttribute {
<#
.SYNOPSIS
Create required data for a certificate signing request.
.DESCRIPTION
Defines the certificate related properties for an upcoming New-PfxCertificate execution.
.PARAMETER Country
Provide a two letter country code.
.PARAMETER State
Certificate state value.
.PARAMETER City
Certificate city value.
.PARAMETER Organization
Certificate organization value.
.PARAMETER OrganizationalUnitName
Certificate OrganizationalUnitName value.
.PARAMETER CommonName
The certificate common name.
.PARAMETER CSRSubject
you can provide the needed certificate properties with in one hashtable. This hashtable has to contain the
following keys: 'Country', 'State', 'City', 'Organization', 'OrganizationalUnitName', 'CommonName'.
.INPUTS
[None]
.OUTPUTS
['PSCredentialStore.Certificate.CSRDetails']
.EXAMPLE
New-CRTAttribute -CSRSubject @{Country = 'DE'; State = 'BW'; City = 'Karlsruhe'; Organization = 'AwesomeIT'; OrganizationalUnitName = '';CommonName = 'MyPrivateCert'}
.NOTES
File Name : New-CSRDetails.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding()]
[OutputType('PSCredentialStore.Certificate.Attribute')]
param(
[Parameter(Mandatory = $true)]
[ValidateLength(2, 2)]
[ValidateNotNull()]
[string]$Country,
[Parameter(Mandatory = $true)]
[ValidateNotNull()]
[string]$State,
[Parameter(Mandatory = $true)]
[ValidateNotNull()]
[string]$City,
[Parameter(Mandatory = $true)]
[ValidateNotNull()]
[string]$Organization,
[Parameter(Mandatory = $true)]
[ValidateNotNull()]
[string]$OrganizationalUnitName,
[Parameter(Mandatory = $true)]
[ValidateNotNull()]
[string]$CommonName,
[Parameter(Mandatory = $false)]
[ValidateNotNull()]
[int]$Days = 365
)
begin {
}
process {
return [PSCustomObject]@{
PSTypeName = 'PSCredentialStore.Certificate.Attribute'
Subject = [PSCustomObject]@{
PSTypeName = 'PSCredentialStore.Certificate.Attribute.Subject'
Country = $Country
State = $State
City = $City
Organization = $Organization
OrganizationalUnitName = $OrganizationalUnitName
CommonName = $CommonName
}
Days = $Days
}
}
end {
}
}

View File

@ -0,0 +1,142 @@
function New-PfxCertificate {
<#
.SYNOPSIS
Creates new PFX certificate for the CredentialStore encryption.
.DESCRIPTION
Use this function to create a custom self signed certificate used by the PSCredentialStore module.
.PARAMETER CRTAttribute
Provide certificate related attributes provided by function New-CRTAttribute.
.PARAMETER KeyName
Provide a custom full path and name for the private key. The file extension has to be `*.key`.
.PARAMETER CertName
Provide a custom full path and name for the PFX certificate file. The file extension has to be `*.pfx`
.INPUTS
[PSCredentialStore.Certificate.Attribute]
.OUTPUTS
[None]
.EXAMPLE
New-PfxCertificate -CRTAttribute $CRTAttribute -KeyName './myprivate.key' -CertName './mycert.pfx'
.NOTES
File Name : New-PfxCertificate.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding(SupportsShouldProcess = $true)]
[OutputType()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[ValidateNotNullOrEmpty()]
[PSTypeName('PSCredentialStore.Certificate.Attribute')]$CRTAttribute,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$KeyName = './private.key',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$CertName = './certificate.pfx'
)
begin {
$ModuleBase = Get-ModuleBase
if ($isLinux -or $isMacOS) {
try {
$openssl = Get-Command -Name 'openssl' -ErrorAction Stop
}
catch {
$_.Exception.Message | Write-Error
$ErrorParams = @{
Message = 'Can not find the openssl binary!'
ErrorAction = 'Stop'
Exception = [System.IO.FileNotFoundException]::new()
}
Write-Error @ErrorParams
}
}
elseif (($PSVersionTable.PSEdition -eq 'Desktop' -and $PSVersionTable.PSVersion.Major -lt 6) -or ($IsWindows -eq $true)) {
$openssl = Join-Path -Path $ModuleBase -ChildPath '/Vendor/libressl255/openssl.exe'
}
$Env:OPENSSL_CONF = Join-Path $ModuleBase -ChildPath '/openssl.conf'
}
process {
$SubjPattern = "/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}"
$SubjValues = @(
$CRTAttribute.Subject.Country,
$CRTAttribute.Subject.State,
$CRTAttribute.Subject.City,
$CRTAttribute.Subject.Organization,
$CRTAttribute.Subject.OrganizationalUnitName,
$CRTAttribute.Subject.CommonName
)
$Subj = $SubjPattern -f $SubjValues
$PEMCertName = $CertName -replace '.pfx', '.crt'
$ExpPattern = '& ''{0}'' req -x509 -sha256 -nodes -days {1} -newkey rsa:2048 -keyout {2} -out {3} -subj "{4}" *>$null'
$ExpValues = @(
$openssl,
$CRTAttribute.Days
$KeyName,
$PEMCertName,
$Subj
)
$PEMExp = $ExpPattern -f $ExpValues
Write-Verbose -Message ( 'Expr string is: {0}' -f $PEMExp)
# Edit the Error action for the openSLL command to make the redirect *>$null work.
# There is always a stderr and stdout stream!
$EAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
Invoke-Expression -Command $PEMExp
$ErrorActionPreference = $EAP
# manually testing the openssl command results
if (! (Test-Path -Path $KeyName)) {
$ErrorParams = @{
Message = 'Could not create the private key ${0}' -f $KeyName
ErrorAction = 'Stop'
Exception = [System.UnauthorizedAccessException]::new()
}
Write-Error @ErrorParams
}
if (! (Test-Path -Path $PEMCertName)) {
$ErrorParams = @{
Message = 'Could not create the PEM certificate ${0}' -f $PEMCertName
ErrorAction = 'Stop'
Exception = [System.Exception]::new()
}
Write-Error @ErrorParams
}
$PfxPattern = '& ''{0}'' pkcs12 -export -out {1} -inkey {2} -in {3} -passout pass:'
$PfxValues = @(
$openssl,
$CertName,
$KeyName,
($CertName -replace '.pfx', '.crt')
)
$PfxExp = $PfxPattern -f $PfxValues
Write-Verbose -Message ( 'PfxExp string is: {0}' -f $PfxExp)
Invoke-Expression -Command $PfxExp
# Remove private key and crt file. Always ask user
Remove-Item -Path $KeyName
Remove-Item -Path ($CertName -replace '.pfx', '.crt')
}
end {
Remove-Item Env:\OPENSSL_CONF -Confirm:$False -Force -ErrorAction SilentlyContinue
}
}

View File

@ -0,0 +1,102 @@
function Use-PfxCertificate {
<#
.SYNOPSIS
Links an existing PFX Certifiacte to a CredentialStore.
.DESCRIPTION
Linking a certificate is needed if you plan to use the same CredentialStore in cross platform scenarios.
.PARAMETER Path
Specify the path to the PFX Certificate you want to link for usage.
.INPUTS
[None]
.OUTPUTS
[None]
.EXAMPLE
.NOTES
File Name : Use-PfxCertificate.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding(DefaultParameterSetName = "Private")]
[OutputType()]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
param(
[Parameter(Mandatory = $true, ParameterSetName = "Private")]
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[ValidateNotNullOrEmpty()]
[string]$Path,
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[ValidateNotNullOrEmpty()]
[string]$CredentialStore,
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[switch]$Shared
)
begin {}
process {
try {
# We need to resolve the path to make sure it has the correct platform specific syntax.
# And it should also exist.
$validPath = Resolve-Path -Path $Path -ErrorAction Stop
$PfxCertificate = Get-PfxCertificate -FilePath $validPath -ErrorAction Stop
}
catch {
$_.Exception.Error | Write-Error
$ErrorParams = @{
Message = 'The given PFX certificate does not exist!'
ErrorAction = 'Stop'
}
Write-Error @ErrorParams
}
try {
if ($PSCmdlet.ParameterSetName -eq "Private") {
$StorePath = Get-DefaultCredentialStorePath
$CS = Get-CredentialStore
}
elseif ($PSCmdlet.ParameterSetName -eq "Shared" ) {
if (!($PSBoundParameters.ContainsKey('CredentialStore'))) {
$StorePath = Get-DefaultCredentialStorePath -Shared
$CS = Get-CredentialStore -Shared
}
else {
$StorePath = $CredentialStore
$CS = Get-CredentialStore -Shared -Path $CredentialStore
}
}
}
catch {
$_.Exception.Error | Write-Error
$ErrorParams = @{
Message = 'The given CredentialStore does not exist!'
ErrorAction = 'Stop'
}
Write-Error @ErrorParams
}
# Lets first check if the thumbprint matches
if (($CS.Thumbprint -notmatch $PfxCertificate.Thumbprint) -and ($CS.Thumbprint.Length -ne 0)) {
Write-Warning @"
You are trying to map an unknown certificate.
Make sure you used the same AES keys for encrypting!
"@
}
$CS.PfxCertificate = $validPath.Path
$CS.Thumbprint = $PfxCertificate.Thumbprint
$CS | ConvertTo-Json -Depth 5 | Out-File -FilePath $StorePath -Force -Encoding utf8
}
end {}
}

View File

@ -1,45 +0,0 @@
function Get-ChallengeFile {
<#
.SYNOPSIS
Reads the challenge file as binary content.
.DESCRIPTION
Use this function to tread a challenge file. Returns a [Byte[]] Array.
.PARAMETER Path
Specify a file to read.
.INPUTS
[None]
.OUTPUTS
[Byte[]]
.EXAMPLE
.\Get-RandomKey -Path "C:\TMP\Challenge.bin"
.NOTES
```
File Name : Get-ChallengeFile.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
```
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$Path = "{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData
)
if (Test-Path $Path) {
try {
[io.file]::ReadAllBytes($Path)
}
catch {
Write-Error ("Could not read file {0}." -f $Path) -ErrorAction Stop
}
}
}

View File

@ -1,72 +0,0 @@
Function Set-ChallengeFile() {
<#
.SYNOPSIS
Writes the given key into the challenge file
.DESCRIPTION
You can use the file content for ConvertTo-SecureString operations.
.PARAMETER Path
The file you wish to create.
.PARAMETER KeySize
Specify the key size for the encryption key.
.PARAMETER Force
Use this switch to override an older file version.
.INPUTS
[None]
.OUTPUTS
[None]
.EXAMPLE
.\Set-ChallengeFile -Path "C:\TMP\myfile.json" -Force
.NOTES
File Name : Set-ChallengeFile.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$Path = "{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData,
[Parameter(Mandatory = $false)]
[ValidateSet(16, 24, 32)]
[string]$KeySize = "24",
[switch]$Force
)
if ((Test-Path -Path $Path)) {
if ($Force -eq $true) {
Remove-Item -Path $Path -Confirm:$false -Force
}
else {
Write-Error "The given file already exists!. Use the -Force switch to override it." -ErrorAction Stop
}
}
$PSCredentialStoreDataDir = Split-Path -Path $Path -Parent
if (-not (Test-Path $PSCredentialStoreDataDir)) {
try {
New-Item -ItemType Directory -Path $PSCredentialStoreDataDir
}
catch {
Write-Error ("Could not create the parent data dir {0}" -f $PSCredentialDataDir) -ErrorAction Stop
}
}
try {
$Keys = Get-RandomKey -Size $KeySize
[io.file]::WriteAllBytes($Path, $Keys)
}
catch {
$_.Exception | Format-List -Force | Out-String | Write-Error -ErrorAction Stop
}
}

View File

@ -1,48 +0,0 @@
function Test-ChallengeFile {
<#
.SYNOPSIS
Simple path check for challenge file needed by the CredentialStores.
.DESCRIPTION
This is supposed to be a internal function to check the existence for a challenge file.
.PARAMETER Path
Specify the path to the challenge file.
.INPUTS
[None]
.OUTPUTS
[Bool].
.EXAMPLE
If (Test-ChallengeFile) {
Write-Host "The file exists."
}
Else {
Write-Warning "Couldn't find the given file!"
}
.NOTES
File Name : Test-ChallengeFile.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[String]$Path = "{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData
)
if (Test-Path $Path) {
$true
}
else {
$false
}
}

View File

@ -93,15 +93,30 @@ function Connect-To {
[Parameter(Mandatory = $False, ParameterSetName = "Private")]
[PSCredential]$Credentials,
[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 = "Shared")]
[switch]$Shared
[Parameter(Mandatory = $False, ParameterSetName = "Private")]
[Parameter(Mandatory = $False, ParameterSetName = "Shared")]
[switch]$PassThru
)
begin {
# Set the CredentialStore for private, shared or custom mode.
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = Get-DefaultCredentialStorePath
}
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
if (!($PSBoundParameters.ContainsKey('Path'))) {
$Path = Get-DefaultCredentialStorePath -Shared
}
}
# First check the optional modules
if (-not (Resolve-Dependency -Name $Type)) {
Write-Error -Message ("Could not resolve the optional dependencies defined for {0}" -f $Type) -ErrorAction 'Stop'
@ -118,10 +133,6 @@ function Connect-To {
}
process {
# Set the correct CredentialStore Path depending on the used ParameterSetName
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
}
if (-not ($Credentials)) {
# Load the credential from the CredentialStore. If the credential doesn't exist, we need to
# return 1, so a calling if statement can handle the failure detection.
@ -131,16 +142,16 @@ function Connect-To {
try {
if ($Identifier -ne "") {
$RemoteHostIdentifier = "{0}/{1}" -f $Identifier, $RemoteHost
$creds = Get-CredentialStoreItem -RemoteHost $RemoteHostIdentifier -Path $Path
$creds = Get-CredentialStoreItem -Shared -RemoteHost $RemoteHostIdentifier -Path $Path
}
else {
$creds = Get-CredentialStoreItem -RemoteHost $RemoteHost -Path $Path
$creds = Get-CredentialStoreItem -Shared -RemoteHost $RemoteHost -Path $Path
}
}
catch {
$MessageParams = @{
Message = "Unable to look up credential store item for RemoteHost {0}/Identifier {1}!" -f $RemoteHost, $Identifier
Message = "Unable to look up credential store item for RemoteHost {0}/Identifier {1}!" -f $RemoteHost, $Identifier
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -152,7 +163,7 @@ function Connect-To {
if ($creds.UserName -eq "" -or $creds.Password.GetType().Name -ne "SecureString") {
$MessageParams = @{
Message = "Please provide valid credentials for RemoteHost {0}!" -f $RemoteHost
Message = "Please provide valid credentials for RemoteHost {0}!" -f $RemoteHost
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -167,7 +178,7 @@ function Connect-To {
catch {
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -177,9 +188,9 @@ function Connect-To {
# First establish the FTP session
$WinSCPConParams = @{
Credential = $creds
Hostname = $RemoteHost
Protocol = 'Ftp'
FtpMode = 'Passive'
Hostname = $RemoteHost
Protocol = 'Ftp'
FtpMode = 'Passive'
}
try {
$FTPSessionOption = New-WinSCPSessionOption @WinSCPConParams
@ -192,7 +203,7 @@ function Connect-To {
if (!($WinSCPSession.Opened)) {
# Check the connection state and find out if the session is still open.
$MessageParams = @{
Message = "Connection to {0} using Type {1} was established. But now it seems to be lost!" -f $RemoteHost, $Type
Message = "Connection to {0} using Type {1} was established. But now it seems to be lost!" -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -206,7 +217,7 @@ function Connect-To {
catch {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -220,7 +231,7 @@ function Connect-To {
catch {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -228,13 +239,19 @@ function Connect-To {
}
"CisServer" {
try {
Connect-CisServer -Server $RemoteHost -Credential $creds -ErrorAction Stop | Out-Null
if ($PassThru.IsPresent) {
Connect-CisServer -Server $RemoteHost -Credential $creds -ErrorAction Stop
}
else {
Connect-CisServer -Server $RemoteHost -Credential $creds -ErrorAction Stop | Out-Null
}
}
catch {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -243,17 +260,17 @@ function Connect-To {
"ExchangeHTTP" {
try {
$ConnectionParams = @{
ConnectionURI = "http://{0}/powershell" -f $RemoteHost
ConnectionURI = "http://{0}/powershell" -f $RemoteHost
ConfigurationName = 'Microsoft.Exchange'
Credential = $creds
ErrorAction = 'Stop'
Credential = $creds
ErrorAction = 'Stop'
}
$Global:PSExchangeRemote = New-PSSession @ConnectionParams
}
catch {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -262,17 +279,17 @@ function Connect-To {
"ExchangeHTTPS" {
try {
$ConnectionParams = @{
ConnectionURI = "https://{0}/powershell" -f $RemoteHost
ConnectionURI = "https://{0}/powershell" -f $RemoteHost
ConfigurationName = 'Microsoft.Exchange'
Credential = $creds
ErrorAction = 'Stop'
Credential = $creds
ErrorAction = 'Stop'
}
$Global:PSExchangeRemote = New-PSSession @ConnectionParams
}
catch {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -280,9 +297,9 @@ function Connect-To {
}
"SCP" {
$WinSCPSessionParams = @{
Credential = $creds
Hostname = $RemoteHost
Protocol = 'Scp'
Credential = $creds
Hostname = $RemoteHost
Protocol = 'Scp'
GiveUpSecurityAndAcceptAnySshHostKey = $True
}
try {
@ -293,7 +310,7 @@ function Connect-To {
catch {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -302,7 +319,7 @@ function Connect-To {
if (!($WinSCPSession.Opened)) {
# Check the connection state and find out if the session is still open.
$MessageParams = @{
Message = "Connection to {0} using Type {1} was established. But now it seems to be lost!" -f $RemoteHost, $Type
Message = "Connection to {0} using Type {1} was established. But now it seems to be lost!" -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams
@ -311,7 +328,7 @@ function Connect-To {
default {
# Write a error message to the log.
$MessageParams = @{
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type
ErrorAction = "Stop"
}
Write-Error @MessageParams

View File

@ -1,50 +0,0 @@
function Get-RandomKey {
<#
.SYNOPSIS
Returns a random key
.DESCRIPTION
You can use the key for further use with SecureStrings.
.PARAMETER Size
Define the key size. You can choose between 16, 24 and 32
.INPUTS
[None]
.OUTPUTS
Returns a Random key as [Byte[]] array.
.EXAMPLE
.\Get-RandomKey -Size 24
.NOTES
```
File Name : Get-RandomKey.ps1
Author : Marco Blessing - marco.blessing@googlemail.com
Requires :
```
.LINK
https://github.com/OCram85/PSCredentialStore
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[ValidateSet(16, 24, 32)]
[string]$size
)
# Init the vars
[Byte[]]$Key = @()
$i = 0
while ($i -ne $size) {
$element = Get-Random -Minimum 0 -Maximum 255
Write-Debug ("The current element is {0}." -f $element)
$Key += $element
$i++
}
$Key
}

View File

@ -41,11 +41,8 @@ function Get-CredentialStoreItem {
#>
[CmdletBinding(DefaultParameterSetName = "Private")]
[OutputType([System.Management.Automation.PSCredential])]
[OutputType([PSCredential])]
param(
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[Parameter(Mandatory = $true, ParameterSetName = "Private")]
[ValidateNotNullOrEmpty()]
@ -56,55 +53,72 @@ function Get-CredentialStoreItem {
[ValidateNotNullOrEmpty()]
[string]$Identifier,
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[switch]$Shared,
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[switch]$Shared
[ValidateNotNullOrEmpty()]
[string]$Path
)
# First set a constand path for private CredentialStore mode.
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
begin {
# Set the CredentialStore for private, shared or custom mode.
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
if ($PSCmdlet.ParameterSetName -eq "Private") {
$Path = Get-DefaultCredentialStorePath
}
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
if (!($PSBoundParameters.ContainsKey('Path'))) {
$Path = Get-DefaultCredentialStorePath -Shared
}
}
}
if ($Identifier -ne "") {
$CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost
}
else {
$CredentialName = $RemoteHost
}
process {
if ($Identifier -ne "") {
$CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost
}
else {
$CredentialName = $RemoteHost
}
if (Test-CredentialStore -Path $Path) {
$CS = Get-CredentialStore -Path $Path
$CSMembers = Get-Member -InputObject $CS
# Let`s first check if the given remote host exists as object property
if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -eq $CredentialName)) {
if ($CS.Type -eq "Private") {
$CSItem = [ordered]@{
User = $CS.$CredentialName.User
Password = ConvertTo-SecureString -String $CS.$CredentialName.Password
if (Test-CredentialStore -Shared -Path $Path) {
$CS = Get-CredentialStore -Shared -Path $Path
$CSMembers = Get-Member -InputObject $CS
# Let's first check if the given remote host exists as object property
if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -contains $CredentialName)) {
$Cert = Get-PfxCertificate -FilePath $CS.PfXCertificate -ErrorAction Stop
$DecryptedKey = $Cert.PrivateKey.Decrypt(
[Convert]::FromBase64String($CS.$CredentialName.EncryptedKey),
[System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1
)
if (! $ExpandOutput.isPresent) {
[PSCredential]::new(
$CS.$CredentialName.User,
($CS.$CredentialName.Password | ConvertTo-SecureString -Key $DecryptedKey)
)
}
}
else {
$Key = Get-ChallengeFile
$CSItem = [ordered]@{
User = $CS.$CredentialName.User
Password = ConvertTo-SecureString -String $CS.$CredentialName.Password -Key $Key
$MsgParams = @{
ErrorAction = "Stop"
Message = "Could not find credentials for the given remote host: {0}" -f $RemoteHost
}
Write-Error @MsgParams
}
New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $CSItem.User, $CSItem.Password
}
else {
$MsgParams = @{
ErrorAction = "Stop"
Message = "Could not find credentials for the given remote host: {0}" -f $RemoteHost
Message = "The given credential store ({0}) does not exist!" -f $Path
}
Write-Error @MsgParams
}
}
else {
$MsgParams = @{
ErrorAction = "Stop"
Message = "The given credential store ({0}) does not exist!" -f $Path
}
Write-Error @MsgParams
end {
}
}

View File

@ -42,9 +42,6 @@ function New-CredentialStoreItem {
[CmdletBinding(DefaultParameterSetName = "Private")]
param(
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
[Parameter(Mandatory = $true, ParameterSetName = "Private")]
[ValidateNotNullOrEmpty()]
@ -59,78 +56,120 @@ function New-CredentialStoreItem {
[ValidateNotNullOrEmpty()]
[PSCredential]$Credential,
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]