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:
parent
ab13962f6e
commit
afab3c870c
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal 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
43
.travis.yml
Normal 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
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -42,7 +42,7 @@
|
||||
"type": "PowerShell",
|
||||
"request": "launch",
|
||||
"name": "PowerShell Interactive Session",
|
||||
"cwd": "${workspaceRoot}"
|
||||
"cwd": ""
|
||||
}
|
||||
]
|
||||
}
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -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",
|
||||
|
28
README.md
28
README.md
@ -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)!
|
||||
|
@ -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
BIN
assets/logo256.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
@ -63,7 +63,7 @@ Type: SwitchParameter
|
||||
Parameter Sets: Shared
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Required: True
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -63,7 +63,7 @@ Type: SwitchParameter
|
||||
Parameter Sets: Shared
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Required: True
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"Version": "1.2.0",
|
||||
"Version": "2.0.0",
|
||||
"Creation": "2016-06-14 08:41:10"
|
||||
|
@ -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
BIN
resources/cs/PSCredentialStore.pfx
(Stored with Git LFS)
Normal file
Binary file not shown.
100
src/Certificate/New-CRTAttribute.ps1
Normal file
100
src/Certificate/New-CRTAttribute.ps1
Normal 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 {
|
||||
}
|
||||
}
|
142
src/Certificate/New-PfxCertificate.ps1
Normal file
142
src/Certificate/New-PfxCertificate.ps1
Normal 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
|
||||
}
|
||||
}
|
102
src/Certificate/Use-PfxCertificate.ps1
Normal file
102
src/Certificate/Use-PfxCertificate.ps1
Normal 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 {}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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,10 +142,10 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,9 +239,15 @@ function Connect-To {
|
||||
}
|
||||
"CisServer" {
|
||||
try {
|
||||
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 = @{
|
||||
|
@ -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
|
||||
}
|
@ -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,15 +53,28 @@ 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.
|
||||
begin {
|
||||
# Set the CredentialStore for private, shared or custom mode.
|
||||
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
|
||||
if ($PSCmdlet.ParameterSetName -eq "Private") {
|
||||
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
if ($Identifier -ne "") {
|
||||
$CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost
|
||||
}
|
||||
@ -72,26 +82,24 @@ function Get-CredentialStoreItem {
|
||||
$CredentialName = $RemoteHost
|
||||
}
|
||||
|
||||
if (Test-CredentialStore -Path $Path) {
|
||||
$CS = Get-CredentialStore -Path $Path
|
||||
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 -eq $CredentialName)) {
|
||||
if ($CS.Type -eq "Private") {
|
||||
$CSItem = [ordered]@{
|
||||
User = $CS.$CredentialName.User
|
||||
Password = ConvertTo-SecureString -String $CS.$CredentialName.Password
|
||||
# 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
|
||||
}
|
||||
}
|
||||
New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $CSItem.User, $CSItem.Password
|
||||
}
|
||||
else {
|
||||
$MsgParams = @{
|
||||
ErrorAction = "Stop"
|
||||
@ -107,4 +115,10 @@ function Get-CredentialStoreItem {
|
||||
}
|
||||
Write-Error @MsgParams
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,26 +56,51 @@ function New-CredentialStoreItem {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCredential]$Credential,
|
||||
|
||||
[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.
|
||||
begin {
|
||||
# Set the CredentialStore for private, shared or custom mode.
|
||||
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
|
||||
if ($PSCmdlet.ParameterSetName -eq "Private") {
|
||||
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
# Lets do a quick test on the given CredentialStore.
|
||||
if (-not(Test-CredentialStore -Path $Path)) {
|
||||
if (-not(Test-CredentialStore -Shared -Path $Path)) {
|
||||
$MessageParams = @{
|
||||
Message = "Could not add anything into the given CredentailStore."
|
||||
Exception = [System.IO.FileNotFoundException]::new(
|
||||
'Could not add anything into the given CredentialStore.'
|
||||
)
|
||||
ErrorAction = "Stop"
|
||||
}
|
||||
Write-Error @MessageParams
|
||||
}
|
||||
|
||||
# Read the file content based on the given ParameterSetName
|
||||
$CSContent = Get-CredentialStore -Path $Path
|
||||
<#
|
||||
if ($PSCmdlet.ParameterSetName -eq 'Private') {
|
||||
$CSContent = Get-CredentialStore
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq 'Shared') {
|
||||
$CSContent = Get-CredentialStore -Shared -Path $Path
|
||||
}
|
||||
#>
|
||||
$CSContent = Get-CredentialStore -Shared -Path $Path
|
||||
|
||||
$CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
@ -94,13 +116,20 @@ function New-CredentialStoreItem {
|
||||
}
|
||||
|
||||
if ($Credential.UserName) {
|
||||
if ($CSContent.Type -eq "Shared") {
|
||||
$Key = Get-ChallengeFile
|
||||
$encypted = ConvertFrom-SecureString -SecureString $Credential.Password -Key $Key
|
||||
try {
|
||||
$Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop
|
||||
}
|
||||
else {
|
||||
$encypted = ConvertFrom-SecureString -SecureString $Credential.Password
|
||||
catch {
|
||||
$_.Exception.Message | Write-Error
|
||||
$ErrorParams = @{
|
||||
ErrorAction = 'Stop'
|
||||
Exception = [System.Security.Cryptography.CryptographicException]::new(
|
||||
'Could not read the given PFX certificate.'
|
||||
)
|
||||
}
|
||||
Write-Error @ErrorParams
|
||||
}
|
||||
|
||||
if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype Properties) {
|
||||
$MessageParams = @{
|
||||
Message = "The given host already exists. Nothing to do here."
|
||||
@ -108,16 +137,20 @@ function New-CredentialStoreItem {
|
||||
Write-Warning @MessageParams
|
||||
}
|
||||
else {
|
||||
$RSAKey = Get-RandomAESKey
|
||||
|
||||
$CredentialHash = [ordered]@{
|
||||
User = $Credential.UserName
|
||||
Password = $encypted
|
||||
Creation = $CurrentDate
|
||||
Password = ConvertFrom-SecureString -SecureString $Credential.Password -Key $RSAKey
|
||||
Created = $CurrentDate
|
||||
LastChange = $null
|
||||
EncryptedKey = [Convert]::ToBase64String($Cert.PublicKey.Key.Encrypt($RSAKey, [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1))
|
||||
}
|
||||
Add-Member -InputObject $CSContent -Name $CredentialName -MemberType NoteProperty -Value $CredentialHash
|
||||
try {
|
||||
ConvertTo-Json -InputObject $CSContent | Out-File -FilePath $Path
|
||||
}
|
||||
catch [System.Exception] {
|
||||
catch {
|
||||
$MessageParams = @{
|
||||
Message = "Couldn't add item into credential store!"
|
||||
ErrorAction = "Stop"
|
||||
@ -133,4 +166,10 @@ function New-CredentialStoreItem {
|
||||
}
|
||||
Write-Error @MessageParams
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,8 +27,16 @@ function Remove-CredentialStoreItem {
|
||||
[None]
|
||||
|
||||
.EXAMPLE
|
||||
Remove-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local"
|
||||
Remove-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" -Identifier svc
|
||||
Remove-CredentialStoreItem -RemoteHost "esx01.myside.local"
|
||||
|
||||
.EXAMPLE
|
||||
Remove-CredentialStoreItem -Shared -RemoteHost "esx01.myside.local"
|
||||
|
||||
.EXAMPLE
|
||||
Remove-CredentialStoreItem -Shared -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local"
|
||||
|
||||
.EXAMPLE
|
||||
Remove-CredentialStoreItem -RemoteHost "esx01.myside.local" -Identifier svc
|
||||
|
||||
.NOTES
|
||||
```
|
||||
@ -43,9 +51,6 @@ function Remove-CredentialStoreItem {
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = "Private")]
|
||||
param(
|
||||
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
|
||||
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
|
||||
|
||||
[Parameter(Mandatory = $true, ParameterSetName = "Private")]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
|
||||
[string]$RemoteHost,
|
||||
@ -54,26 +59,39 @@ function Remove-CredentialStoreItem {
|
||||
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
|
||||
[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.
|
||||
begin {
|
||||
# Set the CredentialStore for private, shared or custom mode.
|
||||
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
|
||||
if ($PSCmdlet.ParameterSetName -eq "Private") {
|
||||
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
# Lets do a quick test on the given CredentialStore.
|
||||
if (-not(Test-CredentialStore -Path $Path)) {
|
||||
if (-not(Test-CredentialStore -Shared -Path $Path)) {
|
||||
$MessageParams = @{
|
||||
Message = "Could not add anything into the given CredentailStore."
|
||||
Message = "Could not add anything into the given CredentialStore."
|
||||
ErrorAction = "Stop"
|
||||
}
|
||||
Write-Error @MessageParams
|
||||
}
|
||||
|
||||
# Read the file content based on the given ParameterSetName
|
||||
$CSContent = Get-CredentialStore -Path $Path
|
||||
$CSContent = Get-CredentialStore -Shared -Path $Path
|
||||
|
||||
if ($Identifier -ne "") {
|
||||
$CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost
|
||||
@ -82,15 +100,21 @@ function Remove-CredentialStoreItem {
|
||||
$CredentialName = $RemoteHost
|
||||
}
|
||||
|
||||
if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype Properties) {
|
||||
if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype NoteProperty) {
|
||||
# We need to use the .NET Method because there is no easier way in PowerShell.
|
||||
$CSContent.PSObject.Properties.Remove($CredentialName)
|
||||
ConvertTo-Json -InputObject $CSContent | Out-File -FilePath $Path
|
||||
ConvertTo-Json -InputObject $CSContent -Depth 5 | Out-File -FilePath $Path -Encoding utf8
|
||||
}
|
||||
else {
|
||||
$MessageParams = @{
|
||||
Message = "The given CredentailStoreItem does not exist."
|
||||
Message = "The given CredentialStoreItem does not exist."
|
||||
}
|
||||
Write-Warning @MessageParams
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,9 +42,6 @@ function Set-CredentialStoreItem {
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = "Private")]
|
||||
param(
|
||||
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
|
||||
[string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData,
|
||||
|
||||
[Parameter(Mandatory = $true, ParameterSetName = "Private")]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
|
||||
[string]$RemoteHost,
|
||||
@ -57,17 +54,30 @@ function Set-CredentialStoreItem {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCredential]$Credential,
|
||||
|
||||
[Parameter(Mandatory = $true, ParameterSetName = "Shared")]
|
||||
[switch]$Shared,
|
||||
|
||||
[Parameter(Mandatory = $false, ParameterSetName = "Shared")]
|
||||
[switch]$Shared
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
# First set a constant path for private CredentialStore mode.
|
||||
begin {
|
||||
# Set the CredentialStore for private, shared or custom mode.
|
||||
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
|
||||
if ($PSCmdlet.ParameterSetName -eq "Private") {
|
||||
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
# Lets do a quick test on the given CredentialStore.
|
||||
if (-not(Test-CredentialStore -Path $Path)) {
|
||||
if (-not(Test-CredentialStore -Shared -Path $Path)) {
|
||||
$MessageParams = @{
|
||||
Message = "Could not add anything into the given CredentailStore."
|
||||
ErrorAction = "Stop"
|
||||
@ -76,7 +86,7 @@ function Set-CredentialStoreItem {
|
||||
}
|
||||
|
||||
# Read the file content based on the given ParameterSetName
|
||||
$CSContent = Get-CredentialStore -Path $Path
|
||||
$CSContent = Get-CredentialStore -Shared -Path $Path
|
||||
|
||||
$CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
@ -92,24 +102,31 @@ function Set-CredentialStoreItem {
|
||||
}
|
||||
|
||||
if ($Credential.UserName) {
|
||||
if ($CSContent.Type -eq "Shared") {
|
||||
$Key = Get-ChallengeFile
|
||||
$encypted = ConvertFrom-SecureString -SecureString $Credential.Password -Key $Key
|
||||
try {
|
||||
$Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop
|
||||
}
|
||||
else {
|
||||
$encypted = ConvertFrom-SecureString -SecureString $Credential.Password
|
||||
catch {
|
||||
$_.Exception.Message | Write-Error
|
||||
$ErrorParams = @{
|
||||
Message = 'Could not read the given PFX certificate.'
|
||||
ErrorAction = 'Stop'
|
||||
Exception = [System.Security.Cryptography.CryptographicException]::new()
|
||||
}
|
||||
Write-Error @ErrorParams
|
||||
}
|
||||
|
||||
if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype Properties) {
|
||||
$RSAKey = Get-RandomAESKey
|
||||
$CSContent.$CredentialName.User = $Credential.UserName
|
||||
$CSContent.$CredentialName.Password = $encypted
|
||||
$CSContent.$CredentialName.Creation = $CurrentDate
|
||||
ConvertTo-Json -InputObject $CSContent | Out-File -FilePath $Path
|
||||
}
|
||||
else {
|
||||
$MessageParams = @{
|
||||
Message = "The given CredentailStoreItem does not exist."
|
||||
}
|
||||
Write-Warning @MessageParams
|
||||
$CSContent.$CredentialName.Password = ConvertFrom-SecureString -SecureString $Credential.Password -Key $RSAKey
|
||||
$CSContent.$CredentialName.LastChange = $CurrentDate
|
||||
$CSContent.$CredentialName.EncryptedKey = [Convert]::ToBase64String(
|
||||
$Cert.PublicKey.Key.Encrypt(
|
||||
$RSAKey,
|
||||
[System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1
|
||||
)
|
||||
)
|
||||
ConvertTo-Json -InputObject $CSContent -Depth 5 | Out-File -FilePath $Path -Encoding utf8
|
||||
}
|
||||
}
|
||||
Else {
|
||||
@ -119,4 +136,9 @@ function Set-CredentialStoreItem {
|
||||
}
|
||||
Write-Error @MessageParams
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
function Test-CredentialStoreItem() {
|
||||
function Test-CredentialStoreItem {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks if the given RemoteHost identifier combination exists in the credential store.
|
||||
@ -64,10 +64,20 @@ function Test-CredentialStoreItem() {
|
||||
[switch]$Shared
|
||||
)
|
||||
|
||||
begin {
|
||||
# Set the CredentialStore for private, shared or custom mode.
|
||||
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
|
||||
if ($PSCmdlet.ParameterSetName -eq "Private") {
|
||||
$Path = "{0}\CredentialStore.json" -f $env:APPDATA
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
if ($Identifier -ne "") {
|
||||
$CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost
|
||||
}
|
||||
@ -75,10 +85,10 @@ function Test-CredentialStoreItem() {
|
||||
$CredentialName = $RemoteHost
|
||||
}
|
||||
|
||||
if (Test-CredentialStore -Path $Path) {
|
||||
$CS = Get-CredentialStore -Path $Path
|
||||
if (Test-CredentialStore -Shared -Path $Path) {
|
||||
$CS = Get-CredentialStore -Shared -Path $Path
|
||||
$CSMembers = Get-Member -InputObject $CS
|
||||
if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -eq $CredentialName)) {
|
||||
if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -contains $CredentialName)) {
|
||||
return $true
|
||||
}
|
||||
else {
|
||||
@ -92,4 +102,10 @@ function Test-CredentialStoreItem() {
|
||||
}
|
||||
Write-Error @MsgParams
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,22 +1,13 @@
|
||||
#
|
||||
# Module manifest for module 'PSCredentialStore'
|
||||
#
|
||||
# Generated by: OCram85
|
||||
#
|
||||
# Generated on: 27.07.2017
|
||||
#
|
||||
|
||||
@{
|
||||
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'PSCredentialStore'
|
||||
RootModule = 'PSCredentialStore.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
# Do not touch the version number. It gets replaced in the build process.
|
||||
ModuleVersion = '0.0.0.9999'
|
||||
ModuleVersion = '0.0.9999'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
CompatiblePSEditions = 'Desktop', 'Core'
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '6800e192-9df8-4e30-b253-eb2c799bbe84'
|
||||
@ -28,18 +19,18 @@
|
||||
CompanyName = ''
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) 2017 OCram85. All rights reserved.'
|
||||
Copyright = '(c) 2019 OCram85. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'A simple credential manager to store and reuse multiple credential objects.'
|
||||
|
||||
# Minimum version of the Windows PowerShell engine required by this module
|
||||
PowerShellVersion = '4.0'
|
||||
# Minimum version of the PowerShell engine required by this module
|
||||
PowerShellVersion = '5.1'
|
||||
|
||||
# Name of the Windows PowerShell host required by this module
|
||||
# Name of the PowerShell host required by this module
|
||||
# PowerShellHostName = ''
|
||||
|
||||
# Minimum version of the Windows PowerShell host required by this module
|
||||
# Minimum version of the PowerShell host required by this module
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
@ -71,21 +62,25 @@
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @(
|
||||
# Connection Group
|
||||
# Certificate
|
||||
'New-CRTAttribute',
|
||||
'New-PfxCertificate',
|
||||
'Use-PfxCertificate',
|
||||
# Connection
|
||||
'Connect-To',
|
||||
'Disconnect-From',
|
||||
'Test-CSConnection',
|
||||
# Item Group
|
||||
# Item
|
||||
'Get-CredentialStoreItem',
|
||||
'Set-CredentialStoreItem',
|
||||
'New-CredentialStoreItem',
|
||||
'Remove-CredentialStoreItem',
|
||||
'Set-CredentialStoreItem',
|
||||
'Test-CredentialStoreItem',
|
||||
# Store Group
|
||||
# Store
|
||||
'Get-CredentialStore',
|
||||
'New-CredentialStore',
|
||||
'Test-CredentialStore'
|
||||
|
||||
'Test-CredentialStore',
|
||||
'Update-CredentialStore'
|
||||
)
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
@ -112,9 +107,7 @@
|
||||
PSData = @{
|
||||
|
||||
# Tags applied to this module. These help with module discovery in online galleries.
|
||||
Tags = @('CredentialStore',
|
||||
'CredentialManager'
|
||||
)
|
||||
Tags = 'CredentialStore', 'CredentialManager'
|
||||
|
||||
# A URL to the license for this module.
|
||||
LicenseUri = 'https://github.com/OCram85/PSCredentialStore/blob/master/LICENSE'
|
||||
@ -123,11 +116,20 @@
|
||||
ProjectUri = 'https://github.com/OCram85/PSCredentialStore'
|
||||
|
||||
# A URL to an icon representing this module.
|
||||
# IconUri = ''
|
||||
IconUri = 'https://raw.githubusercontent.com/OCram85/PSCredentialStore/master/assets/logo256.png'
|
||||
|
||||
# ReleaseNotes of this module
|
||||
ReleaseNotes = 'This is a pre-release version!. Do not use in production!'
|
||||
|
||||
# Prerelease string of this module
|
||||
Prerelease = 'alpha1'
|
||||
|
||||
# Flag to indicate whether the module requires explicit user acceptance for install/update
|
||||
# RequireLicenseAcceptance = $false
|
||||
|
||||
# External dependent modules of this module
|
||||
# ExternalModuleDependencies = @()
|
||||
|
||||
} # End of PSData hashtable
|
||||
|
||||
} # End of PrivateData hashtable
|
||||
|
@ -1,10 +1,18 @@
|
||||
$Items = (Get-ChildItem -Path ("{0}\*.ps1" -f $PSScriptRoot ) -Recurse ).FullName | Where-Object {
|
||||
#region module-definition
|
||||
|
||||
#endregion module-definition
|
||||
Set-Variable -Name "CSVersion" -Value "2.0.0" -Option Constant -Scope 'Script' -ErrorAction Stop
|
||||
|
||||
|
||||
|
||||
#region dot-sourcing
|
||||
# dot-sourcing all module functions. The export is handled via manifest file.
|
||||
|
||||
$Items = (Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath '*.ps1') -Recurse ).FullName | Where-Object {
|
||||
$_ -notmatch "(Classes|Init)"
|
||||
}
|
||||
ForEach ($Item in $Items) {
|
||||
foreach ($Item in $Items) {
|
||||
# Write-Verbose ("dot sourcing file {0}" -f $Item)
|
||||
. $Item
|
||||
}
|
||||
|
||||
# Exports are now controlled by module manifest
|
||||
# Export-ModuleMember -Function *
|
||||
#endregion dot-sourcing
|
||||
|
61
src/Private/Get-DefaultCredentialStorePath.ps1
Normal file
61
src/Private/Get-DefaultCredentialStorePath.ps1
Normal file
@ -0,0 +1,61 @@
|
||||
function Get-DefaultCredentialStorePath {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Returns the default CredentialStore path based on the current OS.
|
||||
|
||||
.DESCRIPTION
|
||||
This is a low level helper function.
|
||||
|
||||
.INPUTS
|
||||
[None]
|
||||
|
||||
.OUTPUTS
|
||||
[string]
|
||||
|
||||
.EXAMPLE
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
|
||||
.NOTES
|
||||
File Name : Get-DefaultCredentialStorePath.ps1
|
||||
Author : Marco Blessing - marco.blessing@googlemail.com
|
||||
Requires :
|
||||
|
||||
.LINK
|
||||
https://github.com/OCram85/PSCredentialStore
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
[OutputType([string])]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$Shared
|
||||
)
|
||||
|
||||
begin {}
|
||||
|
||||
process {
|
||||
if ($Shared.IsPresent) {
|
||||
if ($IsLinux) {
|
||||
return Join-Path -Path '/var/opt' -ChildPath 'PSCredentialStore/CredentialStore.json'
|
||||
}
|
||||
if ($IsMacOS) {
|
||||
return Join-Path -Path '/var/opt' -ChildPath 'PSCredentialStore/CredentialStore.json'
|
||||
}
|
||||
elseif (($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop')) {
|
||||
return Join-Path -Path $env:ProgramData -ChildPath 'PSCredentialStore/CredentialStore.json'
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($IsLinux) {
|
||||
return Join-Path -Path $Env:HOME -ChildPath 'CredentialStore.json'
|
||||
}
|
||||
if ($IsMacOS) {
|
||||
return Join-Path -Path $Env:HOME -ChildPath 'CredentialStore.json'
|
||||
}
|
||||
elseif (($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop')) {
|
||||
return Join-Path -Path $env:AppData -ChildPath 'CredentialStore.json'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {}
|
||||
}
|
44
src/Private/Get-RandomAESKey.ps1
Normal file
44
src/Private/Get-RandomAESKey.ps1
Normal file
@ -0,0 +1,44 @@
|
||||
function Get-RandomAESKey {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Generate a new 32-byte AES key.
|
||||
|
||||
.DESCRIPTION
|
||||
Uses the System.Security.Cryptography namespace for random aes key generation.
|
||||
|
||||
.INPUTS
|
||||
[None]
|
||||
|
||||
.OUTPUTS
|
||||
[byte[]]
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-RandomAESKey
|
||||
|
||||
.NOTES
|
||||
File Name : Get-RandomAESKey.ps1
|
||||
Author : Marco Blessing - marco.blessing@googlemail.com
|
||||
Requires :
|
||||
|
||||
.LINK
|
||||
https://github.com/OCram85/PSCredentialStore
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
[OutputType([byte[]])]
|
||||
param()
|
||||
|
||||
begin {}
|
||||
|
||||
process {
|
||||
$key = [byte[]]::new(32)
|
||||
$rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create()
|
||||
$rng.GetBytes($key)
|
||||
Write-Output $key
|
||||
if ($null -ne $key) {
|
||||
[array]::Clear($key, 0, $key.Length)
|
||||
}
|
||||
|
||||
}
|
||||
end {}
|
||||
}
|
44
src/Private/Get-TempDir.ps1
Normal file
44
src/Private/Get-TempDir.ps1
Normal file
@ -0,0 +1,44 @@
|
||||
function Get-TempDir {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Returns the valid temp dir of the current OS
|
||||
|
||||
.DESCRIPTION
|
||||
Returns the valid temp dir of the current OS.
|
||||
|
||||
.INPUTS
|
||||
[None]
|
||||
.OUTPUTS
|
||||
[string]
|
||||
|
||||
.EXAMPLE
|
||||
Get-TempDir
|
||||
|
||||
.NOTES
|
||||
File Name : Get-TempDir.ps1
|
||||
Author : Marco Blessing - marco.blessing@googlemail.com
|
||||
Requires :
|
||||
|
||||
.LINK
|
||||
https://github.com/OCram85/PSCredentialStore
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
[OutputType([string])]
|
||||
param()
|
||||
begin {
|
||||
|
||||
}
|
||||
process {
|
||||
if ($IsLinux) {
|
||||
return (Resolve-Path -Path '/tmp/').Path
|
||||
}
|
||||
if ($IsMacOS) {
|
||||
return (Resolve-Path -Path '/tmp/').Path
|
||||
}
|
||||
elseif (($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop')) {
|
||||
return (Resolve-Path -Path $env:TEMP).Path
|
||||
}
|
||||
}
|
||||
end {
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ function Test-Module {
|
||||
|
||||
.NOTES
|
||||
```
|
||||
File Name : Get-RandomKey.ps1
|
||||
File Name : Test-Module.ps1
|
||||
Author : Marco Blessing - marco.blessing@googlemail.com
|
||||
Requires :
|
||||
```
|
||||
@ -50,10 +50,6 @@ function Test-Module {
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$Name,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet('Module', 'PSSnapin', 'Custom')]
|
||||
[string]$Type = 'Module',
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$MessagePattern = @"
|
||||
@ -62,15 +58,12 @@ Could not find the required {0} called {1}. Please install the required {0} to r
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$StopIfFails
|
||||
)
|
||||
begin {
|
||||
|
||||
}
|
||||
begin {}
|
||||
|
||||
process {
|
||||
$Message = $MessagePattern -f $Type, $Name
|
||||
Write-Debug $Message
|
||||
switch ($Type) {
|
||||
'Module' {
|
||||
|
||||
if (Get-Module -Name $Name -ListAvailable) {
|
||||
return $true
|
||||
}
|
||||
@ -82,25 +75,5 @@ Could not find the required {0} called {1}. Please install the required {0} to r
|
||||
}
|
||||
}
|
||||
|
||||
'PSSnapin' {
|
||||
if (Get-PSSnapin -Name $Name -Registered -ErrorAction SilentlyContinue) {
|
||||
return $true
|
||||
}
|
||||
else {
|
||||
if ($StopIfFails) {
|
||||
Write-Error -Message $Message -ErrorAction Stop -Category NotInstalled
|
||||
}
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
'Custom' {
|
||||
Throw 'Custom tests are not implemented yet!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
|
||||
}
|
||||
end {}
|
||||
}
|
@ -35,22 +35,36 @@ 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 {}
|
||||
|
||||
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
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-CredentialStore -Path $Path) {
|
||||
if (Test-CredentialStore -Path $Path -Shared) {
|
||||
try {
|
||||
$FileContent = Get-Content -Path $Path -Raw
|
||||
ConvertFrom-Json $FileContent
|
||||
$CS = ConvertFrom-Json $FileContent
|
||||
$CS.PSObject.TypeNames.Insert(0, "PSCredentialStore.Store")
|
||||
return $CS
|
||||
}
|
||||
catch [System.Exception] {
|
||||
$MessageParams = @{
|
||||
@ -67,4 +81,8 @@ function Get-CredentialStore {
|
||||
}
|
||||
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
|
||||
)
|
||||
|
||||
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-Variable -Name "CSVersion" -Value "2.0.0" -Option Constant -Scope
|
||||
}
|
||||
|
||||
# Set the CredentialStore path for private mode.
|
||||
process {
|
||||
# Set the CredentialStore for private, shared or custom mode.
|
||||
Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName)
|
||||
if ($PSCmdlet.ParameterSetName -eq "Private") {
|
||||
$Path = "{0}\CredentialStore.json" -f $Env:APPDATA
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
|
||||
# Test if in the given store already a CredentialStore exists.
|
||||
# Test if in the CredentialStore already 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"
|
||||
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 @MessageParam
|
||||
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
|
||||
Creation = $CurrentDate
|
||||
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"
|
||||
# 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
|
||||
}
|
||||
}
|
||||
else {
|
||||
$ObjProperties.Type = "Private"
|
||||
}
|
||||
# Create a new object for easy conversion into a json file
|
||||
$CredentialStoreObj = New-Object -TypeName psobject -Property $ObjProperties
|
||||
|
||||
$CredentialStoreObj = [PSCustomObject]$ObjProperties
|
||||
try {
|
||||
ConvertTo-Json -InputObject $CredentialStoreObj | Out-File -FilePath $Path
|
||||
$JSON = ConvertTo-Json -InputObject $CredentialStoreObj -ErrorAction Stop
|
||||
$JSON | Out-File -FilePath $Path -ErrorAction Stop -Force
|
||||
}
|
||||
catch [System.Exception] {
|
||||
$_.Exception | Format-List -Force | Out-String | Write-Error -ErrorAction Stop
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
elseif ($PSCmdlet.ParameterSetName -eq "Shared") {
|
||||
if (!($PSBoundParameters.ContainsKey('Path'))) {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
}
|
||||
}
|
||||
Write-Verbose -Message ("Path is: {0}" -f $Path)
|
||||
|
||||
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
|
||||
return $true
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not read or convert the given CredentialStore."
|
||||
Return $False
|
||||
}
|
||||
Return $True
|
||||
|
||||
}
|
||||
Else {
|
||||
else {
|
||||
Write-Verbose "The given CredentialStore does not exist!"
|
||||
Return $False
|
||||
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 {
|
||||
}
|
||||
}
|
BIN
src/Vendor/libressl255/LICENSE
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/LICENSE
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libcrypto-41.dll
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libcrypto-41.dll
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libcrypto-41.exp
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libcrypto-41.exp
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libcrypto-41.lib
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libcrypto-41.lib
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libcrypto-41.pdb
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libcrypto-41.pdb
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libssl-43.dll
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libssl-43.dll
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libssl-43.exp
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libssl-43.exp
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libssl-43.lib
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libssl-43.lib
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libssl-43.pdb
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libssl-43.pdb
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libtls-15.dll
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libtls-15.dll
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libtls-15.exp
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libtls-15.exp
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libtls-15.lib
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libtls-15.lib
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/libtls-15.pdb
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/libtls-15.pdb
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/ocspcheck.exe
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/ocspcheck.exe
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
src/Vendor/libressl255/openssl.exe
(Stored with Git LFS)
vendored
Normal file
BIN
src/Vendor/libressl255/openssl.exe
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
245
src/openssl.conf
Normal file
245
src/openssl.conf
Normal file
@ -0,0 +1,245 @@
|
||||
#
|
||||
# OpenSSL example configuration file.
|
||||
# This is mostly being used for generation of certificate requests.
|
||||
#
|
||||
|
||||
# This definition stops the following lines choking if HOME isn't
|
||||
# defined.
|
||||
HOME = .
|
||||
RANDFILE = $ENV::HOME/.rnd
|
||||
|
||||
# Extra OBJECT IDENTIFIER info:
|
||||
#oid_file = $ENV::HOME/.oid
|
||||
oid_section = new_oids
|
||||
|
||||
# To use this configuration file with the "-extfile" option of the
|
||||
# "openssl x509" utility, name here the section containing the
|
||||
# X.509v3 extensions to use:
|
||||
# extensions =
|
||||
# (Alternatively, use a configuration file that has only
|
||||
# X.509v3 extensions in its main [= default] section.)
|
||||
|
||||
[ new_oids ]
|
||||
|
||||
# We can add new OIDs in here for use by 'ca' and 'req'.
|
||||
# Add a simple OID like this:
|
||||
# testoid1=1.2.3.4
|
||||
# Or use config file substitution like this:
|
||||
# testoid2=${testoid1}.5.6
|
||||
|
||||
####################################################################
|
||||
[ ca ]
|
||||
default_ca = CA_default # The default ca section
|
||||
|
||||
####################################################################
|
||||
[ CA_default ]
|
||||
|
||||
dir = ./demoCA # Where everything is kept
|
||||
certs = $dir/certs # Where the issued certs are kept
|
||||
crl_dir = $dir/crl # Where the issued crl are kept
|
||||
database = $dir/index.txt # database index file.
|
||||
new_certs_dir = $dir/newcerts # default place for new certs.
|
||||
|
||||
certificate = $dir/cacert.pem # The CA certificate
|
||||
serial = $dir/serial # The current serial number
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem # The private key
|
||||
RANDFILE = $dir/private/.rand # private random number file
|
||||
|
||||
x509_extensions = usr_cert # The extentions to add to the cert
|
||||
|
||||
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
|
||||
# so this is commented out by default to leave a V1 CRL.
|
||||
# crl_extensions = crl_ext
|
||||
|
||||
default_days = 365 # how long to certify for
|
||||
default_crl_days = 30 # how long before next CRL
|
||||
default_md = md5 # which md to use.
|
||||
preserve = no # keep passed DN ordering
|
||||
|
||||
# A few difference way of specifying how similar the request should look
|
||||
# For type CA, the listed attributes must be the same, and the optional
|
||||
# and supplied fields are just that :-)
|
||||
policy = policy_match
|
||||
|
||||
# For the CA policy
|
||||
[ policy_match ]
|
||||
countryName = match
|
||||
stateOrProvinceName = match
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
# For the 'anything' policy
|
||||
# At this point in time, you must list all acceptable 'object'
|
||||
# types.
|
||||
[ policy_anything ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
# Passwords for private keys if not present they will be prompted for
|
||||
# input_password = secret
|
||||
# output_password = secret
|
||||
|
||||
# This sets a mask for permitted string types. There are several options.
|
||||
# default: PrintableString, T61String, BMPString.
|
||||
# pkix : PrintableString, BMPString.
|
||||
# utf8only: only UTF8Strings.
|
||||
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
|
||||
# MASK:XXXX a literal mask value.
|
||||
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
|
||||
# so use this option with caution!
|
||||
string_mask = nombstr
|
||||
|
||||
# req_extensions = v3_req # The extensions to add to a certificate request
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_default = DE
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
stateOrProvinceName_default = BW
|
||||
|
||||
localityName = Locality Name (eg, city)
|
||||
localityName_default = PSCredentialStore
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = PSCredentialStore
|
||||
|
||||
# we can do this but it is not needed normally :-)
|
||||
#1.organizationName = Second Organization Name (eg, company)
|
||||
#1.organizationName_default = World Wide Web Pty Ltd
|
||||
|
||||
organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default = PSCRedentialStore
|
||||
|
||||
commonName = Common Name (eg, YOUR name)
|
||||
commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 40
|
||||
|
||||
# SET-ex3 = SET extension number 3
|
||||
|
||||
[ req_attributes ]
|
||||
challengePassword = A challenge password
|
||||
challengePassword_min = 0
|
||||
challengePassword_max = 20
|
||||
|
||||
unstructuredName = An optional company name
|
||||
|
||||
[ usr_cert ]
|
||||
|
||||
# These extensions are added when 'ca' signs a request.
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
# nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
# nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, codeSigning
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
nsComment = "OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid,issuer:always
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
# subjectAltName=email:copy
|
||||
|
||||
# Copy subject details
|
||||
# issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
# Extensions to add to a certificate request
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, codeSigning
|
||||
|
||||
[ v3_ca ]
|
||||
|
||||
|
||||
# Extensions for a typical CA
|
||||
|
||||
|
||||
# PKIX recommendation.
|
||||
|
||||
subjectKeyIdentifier=hash
|
||||
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
||||
|
||||
# This is what PKIX recommends but some broken software chokes on critical
|
||||
# extensions.
|
||||
#basicConstraints = critical,CA:true
|
||||
# So we do this instead.
|
||||
basicConstraints = CA:true
|
||||
|
||||
# Key usage: this is typical for a CA certificate. However since it will
|
||||
# prevent it being used as an test self-signed certificate it is best
|
||||
# left out by default.
|
||||
# keyUsage = cRLSign, keyCertSign
|
||||
|
||||
# Some might want this also
|
||||
# nsCertType = sslCA, emailCA
|
||||
|
||||
# Include email address in subject alt name: another PKIX recommendation
|
||||
# subjectAltName=email:copy
|
||||
# Copy issuer details
|
||||
# issuerAltName=issuer:copy
|
||||
|
||||
# DER hex encoding of an extension: beware experts only!
|
||||
# obj=DER:02:03
|
||||
# Where 'obj' is a standard or added object
|
||||
# You can even override a supported extension:
|
||||
# basicConstraints= critical, DER:30:03:01:01:FF
|
||||
|
||||
[ crl_ext ]
|
||||
|
||||
# CRL extensions.
|
||||
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
|
||||
|
||||
# issuerAltName=issuer:copy
|
||||
authorityKeyIdentifier = keyid:always,issuer:always
|
@ -1,15 +1,17 @@
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$RepoRoot = (Get-Item -Path (Get-GitDirectory) -Force).Parent | Select-Object -ExpandProperty 'FullName'
|
||||
Write-Verbose -Message ('RepoRoot: {0}' -f $RepoRoot) -Verbose
|
||||
|
||||
$ManifestFilePath = Join-Path -Path $RepoRoot -ChildPath '/src/PSCredentialStore.psd1'
|
||||
Write-Verbose -Message ("ManifestFilePath: {0}" -f $ManifestFilePath) -Verbose
|
||||
Describe "Pre-Flight module tests" {
|
||||
$ManifestFilePath = "{0}\src\PSCredentialstore.psd1" -f $RepoRoot
|
||||
Context "Manifest file related" {
|
||||
It "Test the parsed file itsef" {
|
||||
{ Test-ModuleManifest -Path $ManifestFilePath } | Should -Not -Throw
|
||||
It "Test the parsed file itself" {
|
||||
{ Test-ModuleManifest -Path $ManifestFilePath -Verbose } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
Context "Module consistency tests" {
|
||||
IT "Importing should work" {
|
||||
{ Import-Module -Name $ManifestFilePath -Global -Force }| Should -Not -Throw
|
||||
It "Importing should work" {
|
||||
{ Import-Module -Name $ManifestFilePath -Global -Force -Verbose } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
#region HEADER
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Get-RandomKey.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Set-ChallengeFile" {
|
||||
Context "Tests with custom path" {
|
||||
It "Working dir and path not exist" {
|
||||
{Set-ChallengeFile -Path 'C:\PSCredentialStore\Challenge.bin'} | Should -Not -Throw
|
||||
}
|
||||
It "No parameter and non file should return true" {
|
||||
if (Test-Path -Path ("{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData)) {
|
||||
Remove-Item -Path ("{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData)
|
||||
}
|
||||
Set-ChallengeFile
|
||||
Test-Path -Path ("{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData) | Should -Be $true
|
||||
}
|
||||
It "Existing Credential file should return error" {
|
||||
{ Set-ChallengeFile } | Should -Throw
|
||||
Remove-Item -Path ("{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData)
|
||||
}
|
||||
It "Use -Force switch should create a new challenge file" {
|
||||
# prepare for test and clean up old data
|
||||
if (Test-Path -Path ("{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData)) {
|
||||
Remove-Item -Path ("{0}\PSCredentialStore\Challenge.bin" -f $env:ProgramData)
|
||||
}
|
||||
Set-ChallengeFile
|
||||
{ Set-ChallengeFile -Force } | Should -Not -Throw
|
||||
}
|
||||
It "Test directory creation for shared store" {
|
||||
if (Test-Path -Path ("{0}\PSCredentialStore" -f $env:ProgramData)) {
|
||||
Remove-Item -Path ("{0}\PSCredentialStore" -f $env:ProgramData) -Force -Recurse
|
||||
}
|
||||
Set-ChallengeFile
|
||||
Test-Path -Path ("{0}\PSCredentialStore" -f $env:ProgramData) | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "General Exception handling" {
|
||||
Mock New-Item {throw "foobar exception"}
|
||||
It "Test exception handling if the root directory could not be created" {
|
||||
if (Test-Path -Path ("{0}\PSCredentialStore" -f $env:ProgramData)) {
|
||||
Remove-Item -Path ("{0}\PSCredentialStore" -f $env:ProgramData) -Force -Recurse
|
||||
}
|
||||
{ Set-ChallengeFile } | Should -Throw "Could not create the parent data dir"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#region HEADER
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "Test-ChallengeFile.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Test-ChallengeFile" {
|
||||
Context "Basic input tests" {
|
||||
Mock Test-Path {return $true}
|
||||
It "No parameter with existing challenge file" {
|
||||
{Test-ChallengeFile} | Should -Not -Throw
|
||||
}
|
||||
It "No parameter and existing file should return true" {
|
||||
Test-ChallengeFile | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Execute with parameter" {
|
||||
$TestChFile = "{0}\resources\cs\Challenge.bin" -f $RepoRoot
|
||||
It "Provide valid path" {
|
||||
Test-ChallengeFile -Path $TestChFile | Should -Be $true
|
||||
}
|
||||
It "Provide fake path" {
|
||||
Test-ChallengeFile -Path "C:\notexisting.bin" | Should -Be $false
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#region HEADER
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
# . (Get-ChildItem -Path $RepoRoot -Filter "<FunctionName>.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Get-ModuleBase" {
|
||||
Context "Basic syntax check" {
|
||||
It "Test1: Should not throw" {
|
||||
{ Get-ModuleBase } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
#region HEADER
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
# . (Get-ChildItem -Path $RepoRoot -Filter "<FunctionName>.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Get-RandomKey" {
|
||||
Context "Basic input tests" {
|
||||
It "Test1: Should throw if wrong size is given" {
|
||||
{Get-RandomKey -size 43} | Should -Throw
|
||||
}
|
||||
}
|
||||
Context "Basic syntax check" {
|
||||
It "Test1: Should return a key with a length of 16" {
|
||||
$Key = Get-RandomKey -size 16
|
||||
$Key.length | Should -Be 16
|
||||
}
|
||||
It "Test2: Should return a key with a length of 24" {
|
||||
$Key = Get-RandomKey -size 24
|
||||
$Key.length | Should -Be 24
|
||||
}
|
||||
It "Test3: Should return a key with a length of 32" {
|
||||
$Key = Get-RandomKey -size 32
|
||||
$Key.length | Should -Be 32
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
#region HEADER
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "<FunctionName>.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Test-ModuleName" {
|
||||
Context "Basic input tests" {
|
||||
It "Testing standard module should not throw" {
|
||||
{ Test-Module -Name 'PowerShellGet' -Type Module } | Should -Not -Throw
|
||||
}
|
||||
It "Existing module should return true" {
|
||||
Test-Module -Name 'PowerShellGet' -Type Module | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Custom Type tests" {
|
||||
It "Using custom type should throw" {
|
||||
{ Test-Module -Name "foobarr" -Type Custom} | Should -Throw
|
||||
}
|
||||
}
|
||||
Context "Working with PSSnapins" {
|
||||
It "Loading first PSSnaping should not throw " {
|
||||
$Snap = Get-PSSnapin -Registered | Select-Object -First 1
|
||||
{ Test-Module -Name $Snap.Name -Type PSSnapin } | Should -Not -Throw
|
||||
}
|
||||
It "Loading first PSSnaping should return true" {
|
||||
$Snap = Get-PSSnapin -Registered | Select-Object -First 1
|
||||
Test-Module -Name $Snap.Name -Type PSSnapin | Should -Be $true
|
||||
}
|
||||
It "Not existing PSSnaping should return false" {
|
||||
Test-Module -Name 'foobar2000' -Type PSSnapin | Should -Be $false
|
||||
}
|
||||
It "StopifFails switch should thrown an error" {
|
||||
{Test-Module -Name 'foobar2000' -Type PSSnapin -StopIfFails }| Should -Throw
|
||||
}
|
||||
}
|
||||
Context "Working with modules" {
|
||||
It "Loading first module should not throw " {
|
||||
$Mod = Get-Module -ListAvailable | Select-Object -First 1
|
||||
{ Test-Module -Name $Mod.Name -Type Module } | Should -Not -Throw
|
||||
}
|
||||
It "Loading first module should return true" {
|
||||
$Snap = Get-Module -ListAvailable | Select-Object -First 1
|
||||
Test-Module -Name $Snap.Name -Type Module | Should -Be $true
|
||||
}
|
||||
It "Not existing module should return false" {
|
||||
Test-Module -Name 'foobar2000' -Type Module | Should -Be $false
|
||||
}
|
||||
It "StopifFails switch should thrown an error" {
|
||||
{Test-Module -Name 'foobar2000' -Type Module -StopIfFails }| Should -Throw
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
#region HEADER
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
# $RepoRoot = (Get-Item -Path $here).Parent.Parent.FullName
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "Test-CredentialStore.ps1" -Recurse).FullName
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "New-CredentialStore.ps1" -Recurse).FullName
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "Get-CredentialStore.ps1" -Recurse).FullName
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "Get-CredentialStoreItem.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Test-ChallengeFile.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Get-ChallengeFile.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Set-ChallengeFile.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Get-RandomKey.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "New-CredentialStoreItem" {
|
||||
Context "Private Credential Store tests" {
|
||||
It "Test1: Add entry to existing private store." {
|
||||
If (-not (Test-CredentialStore)) {
|
||||
New-CredentialStore
|
||||
}
|
||||
[String]$tmp = (65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_}
|
||||
$tmp = $tmp.Replace(' ', '')
|
||||
$tmpUser = "MyUser"
|
||||
$tmpPwd = "fooobarysdfsfs" | ConvertTo-SecureString -AsPlainText -Force
|
||||
$creds = New-Object -TypeName PsCredential -ArgumentList $tmpUser, $tmpPwd
|
||||
New-CredentialStoreItem -RemoteHost $tmp -Credential $creds
|
||||
# Had to remove the `{ <exp> } | Shoud Not Throw` because the return would be empty.
|
||||
$content = Get-CredentialStoreItem -RemoteHost $tmp
|
||||
$content.UserName | Should Be "MyUser"
|
||||
#Cleanup Temp entry
|
||||
$CS = Get-CredentialStore
|
||||
$CS.PSObject.Properties.Remove($tmp)
|
||||
ConvertTo-Json -InputObject $CS | Out-File -FilePath ("{0}\CredentialStore.json" -f $env:AppData)
|
||||
}
|
||||
}
|
||||
Context "Test with new shared Credential Store" {
|
||||
It "Test2: Create new RemoteHost entry" {
|
||||
# prepare test environment
|
||||
$tmpCS = 'C:\CredentialStore.json'
|
||||
New-CredentialStore -Shared -Path $tmpCS
|
||||
|
||||
$UserName = "myuser"
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
$mycreds = New-Object -TypeName PSCredential -ArgumentList $UserName, $Password
|
||||
$RemoteHost = "foobar"
|
||||
{ New-CredentialStoreItem -Path $tmpCS -RemoteHost $RemoteHost -Credential $mycreds -Shared } | Should Not Throw
|
||||
$tmpCS = Get-Content -Path $tmpCS -Raw | ConvertFrom-Json
|
||||
$res = Get-Member -InputObject $tmpCS -Name $RemoteHost -Membertype Properties
|
||||
$res.Name | Should Be $RemoteHost
|
||||
}
|
||||
It "Adds Item with identifier to shared store" {
|
||||
$tmpCS = 'C:\CredentialStore.json'
|
||||
$UserName = "myuser"
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
$mycreds = New-Object -TypeName PSCredential -ArgumentList $UserName, $Password
|
||||
$RemoteHost = "foobar2"
|
||||
New-CredentialStoreItem -Path $tmpCS -RemoteHost $RemoteHost -Credential $mycreds -Identifier 'Foo'
|
||||
$writtenItem = Get-CredentialStoreItem -Path $tmpCS -RemoteHost $RemoteHost -Identifier 'Foo'
|
||||
($writtenItem.UserName -eq $UserName) -and ($writtenItem.Password.Length -gt 0) | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Test optional parameter lookup" {
|
||||
Mock Get-Credential {
|
||||
$UserName = 'testuser'
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
return [PSCredential]::new($UserName, $Password)
|
||||
|
||||
}
|
||||
It "Test missing Credential" {
|
||||
$tmpCS = 'C:\CredentialStore.json'
|
||||
New-CredentialStoreItem -Path $tmpCs -Shared -RemoteHost 'foobar3'
|
||||
$writtenItem = Get-CredentialStoreItem -Path $tmpCS -Shared -RemoteHost 'foobar3'
|
||||
$writtenItem.UserName | Should -Be "testuser"
|
||||
}
|
||||
}
|
||||
Context "General Exception handling" {
|
||||
Mock Test-CredentialStore {return $false}
|
||||
Mock Get-Credential {
|
||||
$UserName = 'myUser'
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
return [PSCredential]::new($UserName, $Password)
|
||||
|
||||
}
|
||||
It "Missing CredentialStore should throw" {
|
||||
{ New-CredentialStoreItem -Path 'C:\missingStore.json' -RemoteHost 'notrelevant' } | Should -Throw "Could not add anything"
|
||||
}
|
||||
}
|
||||
Context "Testing pipeline paramter" {
|
||||
It "Add the item with credential value from pipe" {
|
||||
$UserName = 'pipeUser'
|
||||
$Password = ConvertTo-SecureString -String "pipePasswd" -AsPlainText -Force
|
||||
{ [PSCredential]::new($UserName, $Password) | New-CredentialStoreItem -RemoteHost 'PipeHost' } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Testing written item" {
|
||||
(Get-CredentialStoreItem -RemoteHost 'PipeHost').UserName | Should -Be 'pipeUser'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
85
tests/Item/03_New-CredentialStoreItem.Tests.ps1
Normal file
85
tests/Item/03_New-CredentialStoreItem.Tests.ps1
Normal file
@ -0,0 +1,85 @@
|
||||
Describe "New-CredentialStoreItem" {
|
||||
Context "Private Credential Store tests" {
|
||||
It "Test1: Add entry to existing private store." {
|
||||
# Creat a fresh CredentialStore first
|
||||
New-CredentialStore -Force
|
||||
|
||||
[String]$tmp = (65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_}
|
||||
$tmp = $tmp.Replace(' ', '')
|
||||
$tmpUser = "MyUser"
|
||||
$tmpPwd = "fooobarysdfsfs" | ConvertTo-SecureString -AsPlainText -Force
|
||||
$creds = [PSCredential]::new($tmpUser, $tmpPwd)
|
||||
New-CredentialStoreItem -RemoteHost $tmp -Credential $creds
|
||||
# Had to remove the `{ <exp> } | Shoud Not Throw` because the return would be empty.
|
||||
$content = Get-CredentialStoreItem -RemoteHost $tmp
|
||||
$content.UserName | Should -Be "MyUser"
|
||||
#Cleanup Temp entry
|
||||
$CS = Get-CredentialStore
|
||||
$CS.PSObject.Properties.Remove($tmp)
|
||||
ConvertTo-Json -InputObject $CS | Out-File -FilePath (Get-DefaultCredentialStorePath)
|
||||
}
|
||||
}
|
||||
Context "Test with new shared Credential Store" {
|
||||
It "Test2: Create new RemoteHost entry" {
|
||||
# prepare test environment
|
||||
$tmpCS = Join-Path -Path (Get-TempDir) -ChildPath '/CredentialStore.json'
|
||||
New-CredentialStore -Shared -Path $tmpCS -Force
|
||||
|
||||
$UserName = "myuser"
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
$mycreds = [PSCredential]::new($UserName, $Password)
|
||||
$RemoteHost = "foobar"
|
||||
{ New-CredentialStoreItem -Shared -Path $tmpCS -RemoteHost $RemoteHost -Credential $mycreds } | Should -Not -Throw
|
||||
$tmpCS = Get-Content -Path $tmpCS -Raw | ConvertFrom-Json
|
||||
$res = Get-Member -InputObject $tmpCS -Name $RemoteHost -Membertype Properties
|
||||
$res.Name | Should -Be $RemoteHost
|
||||
}
|
||||
It "Adds Item with identifier to shared store" {
|
||||
$tmpCS = Join-Path -Path (Get-TempDir) -ChildPath '/CredentialStore.json'
|
||||
New-CredentialStore -Shared -Path $tmpCS -Force
|
||||
|
||||
$UserName = "myuser"
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
$mycreds = [PSCredential]::new($UserName, $Password)
|
||||
$RemoteHost = "foobar2"
|
||||
New-CredentialStoreItem -Shared -Path $tmpCS -RemoteHost $RemoteHost -Credential $mycreds -Identifier 'Foo'
|
||||
$writtenItem = Get-CredentialStoreItem -Shared -Path $tmpCS -RemoteHost $RemoteHost -Identifier 'Foo'
|
||||
($writtenItem.UserName -eq $UserName) -and ($writtenItem.Password.Length -gt 0) | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Test optional parameter lookup" {
|
||||
|
||||
It "Test missing Credential" {
|
||||
function global:Get-Credential ([string]$Message) {
|
||||
$UserName = 'testuser'
|
||||
$Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force
|
||||
return [PSCredential]::new($UserName, $Password)
|
||||
}
|
||||
$tmpCS = Join-Path -Path (Get-TempDir) -ChildPath '/CredentialStore.json'
|
||||
New-CredentialStoreItem -Path $tmpCs -Shared -RemoteHost 'foobar3'
|
||||
$writtenItem = Get-CredentialStoreItem -Path $tmpCS -Shared -RemoteHost 'foobar3'
|
||||
$writtenItem.UserName | Should -Be "testuser"
|
||||
|
||||
Remove-Item -Path 'Function:\Get-Credential'
|
||||
}
|
||||
|
||||
}
|
||||
Context "General Exception handling" {
|
||||
Mock Test-CredentialStore {return $false}
|
||||
It "Missing CredentialStore should throw" {
|
||||
{ New-CredentialStoreItem -Shared -Path 'C:\missingStore.json' -RemoteHost 'notrelevant' } | Should -Throw "Could not add anything"
|
||||
}
|
||||
}
|
||||
Context "Testing pipeline paramter" {
|
||||
It "Add the item with credential value from pipe" {
|
||||
$UserName = 'pipeUser'
|
||||
$Password = ConvertTo-SecureString -String "pipePasswd" -AsPlainText -Force
|
||||
{ [PSCredential]::new($UserName, $Password) | New-CredentialStoreItem -RemoteHost 'PipeHost' } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Testing written item" {
|
||||
(Get-CredentialStoreItem -RemoteHost 'PipeHost').UserName | Should -Be 'pipeUser'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
49
tests/Private/01_Get-DefaultCredentialStorePath.Tests.ps1
Normal file
49
tests/Private/01_Get-DefaultCredentialStorePath.Tests.ps1
Normal file
@ -0,0 +1,49 @@
|
||||
Describe "Get-DefaultCredentialStorePath" {
|
||||
Context "Basic syntax test" {
|
||||
It "Test1: Should not throw" {
|
||||
{ Get-DefaultCredentialStorePath } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
|
||||
Context "Private Type" {
|
||||
It "Should return correct paths" {
|
||||
$Path = Get-DefaultCredentialStorePath
|
||||
#Write-Verbose -Message ('Delivered path is: {0}' -f $Path) -Verbose
|
||||
if ($Env:APPVEYOR) {
|
||||
$PathRef = Join-Path -Path $Env:APPDATA -ChildPath 'CredentialStore.json'
|
||||
$Path | Should -Be $PathRef
|
||||
}
|
||||
elseif ($ENV:TRAVIS) {
|
||||
if ($IsLinux) {
|
||||
$PathRef = Join-Path -Path $Env:HOME -ChildPath 'CredentialStore.json'
|
||||
$Path | Should -Be $PathRef
|
||||
}
|
||||
elseif ($IsMacOS) {
|
||||
$PathRef = Join-Path -Path $Env:HOME -ChildPath 'CredentialStore.json'
|
||||
$Path | Should -Be $PathRef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "Shared Type" {
|
||||
It "Should return correct paths" {
|
||||
$Path = Get-DefaultCredentialStorePath -Shared
|
||||
#Write-Verbose -Message ('Delivered path is: {0}' -f $Path) -Verbose
|
||||
if ($Env:APPVEYOR) {
|
||||
$PathRef = Join-Path -Path $env:ProgramData -ChildPath 'PSCredentialStore/CredentialStore.json'
|
||||
$Path | Should -Be $PathRef
|
||||
}
|
||||
elseif ($ENV:TRAVIS) {
|
||||
if ($IsLinux) {
|
||||
$PathRef = Join-Path -Path '/var/opt' -ChildPath 'PSCredentialStore/CredentialStore.json'
|
||||
$Path | Should -Be $PathRef
|
||||
}
|
||||
elseif ($IsMacOS) {
|
||||
$PathRef = Join-Path -Path '/var/opt' -ChildPath 'PSCredentialStore/CredentialStore.json'
|
||||
$Path | Should -Be $PathRef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
tests/Private/01_Get-ModuleBase.Tests.ps1
Normal file
7
tests/Private/01_Get-ModuleBase.Tests.ps1
Normal file
@ -0,0 +1,7 @@
|
||||
Describe "Get-ModuleBase" {
|
||||
Context "Basic syntax check" {
|
||||
It "Test1: Should not throw" {
|
||||
{ Get-ModuleBase } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
}
|
13
tests/Private/01_Get-RandomAESKey.Tests.ps1
Normal file
13
tests/Private/01_Get-RandomAESKey.Tests.ps1
Normal file
@ -0,0 +1,13 @@
|
||||
Describe "Get-RandomKey" {
|
||||
Context "Basic input tests" {
|
||||
It "Test1: Should not throw " {
|
||||
{Get-RandomAESKey} | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
Context "Basic syntax check" {
|
||||
It "Test2: Should return a key with a length of 32 bytes" {
|
||||
$Key = Get-RandomAESKey
|
||||
$Key.length | Should -Be 32
|
||||
}
|
||||
}
|
||||
}
|
27
tests/Private/01_Get-TempDir.Tests.ps1
Normal file
27
tests/Private/01_Get-TempDir.Tests.ps1
Normal file
@ -0,0 +1,27 @@
|
||||
Describe "Get-TempDir" {
|
||||
Context "Basic tests" {
|
||||
It "Should not throw" {
|
||||
{Get-TempDir} | Should -Not -Throw
|
||||
}
|
||||
It "Should return the correct os tmp path" {
|
||||
$Path = Get-TempDir
|
||||
|
||||
if ($ENV:TRAVIS) {
|
||||
if ($IsLinux) {
|
||||
$RefPath = (Resolve-Path -Path '/tmp/').Path
|
||||
$Path | Should -Be $RefPath
|
||||
}
|
||||
if ($IsMacOS) {
|
||||
$RefPath = (Resolve-Path -Path '/tmp/').Path
|
||||
$Path | Should -Be $RefPath
|
||||
}
|
||||
}
|
||||
if ($Env:APPVEYOR) {
|
||||
if (($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop')) {
|
||||
$RefPath = (Resolve-Path -Path $env:TEMP).Path
|
||||
$Path | Should -Be $RefPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +1,6 @@
|
||||
#region HEADER
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
# $RepoRoot = (Get-Item -Path $here).Parent.Parent.FullName
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Get-ModuleBase.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Test-Module.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Resolve-Dependency" {
|
||||
Context "Basic syntax check" {
|
||||
Mock Get-ModuleBase {return "{0}\resources" -f $PWD}
|
||||
Mock Get-ModuleBase {return (Join-Path -Path $PWD -ChildPath '/resources')}
|
||||
Mock Test-Module {return $true}
|
||||
It "Test1: Should not throw" {
|
||||
{ Resolve-Dependency -Name 'foobar2000' } | Should -Not -Throw
|
||||
@ -32,7 +11,10 @@ Describe "Resolve-Dependency" {
|
||||
}
|
||||
Context "Enforce Error" {
|
||||
# Return incorrect module base to enforce there is no config file.
|
||||
Mock Get-ModuleBase {return "C:\"}
|
||||
Mock Get-ModuleBase {
|
||||
if ($IsWindows) {return "C:\"}
|
||||
elseif ($isLinux) {return "/"}
|
||||
}
|
||||
It "Missing dependency file should not cause an error" {
|
||||
{ Resolve-Dependency -Name 'awesome'} | Should -Not -Throw
|
||||
}
|
||||
@ -42,7 +24,7 @@ Describe "Resolve-Dependency" {
|
||||
}
|
||||
}
|
||||
Context "Testing input variations" {
|
||||
Mock Get-ModuleBase {return "{0}\resources" -f $PWD}
|
||||
Mock Get-ModuleBase {return (Join-Path -Path $PWD -ChildPath '/resources')}
|
||||
It "Should return true if all given dependencies exist" {
|
||||
Resolve-Dependency -Name 'Existing' | Should -Be $true
|
||||
}
|
26
tests/Private/01_Test-Module.Tests.ps1
Normal file
26
tests/Private/01_Test-Module.Tests.ps1
Normal file
@ -0,0 +1,26 @@
|
||||
Describe "Test-ModuleName" {
|
||||
Context "Basic input tests" {
|
||||
It "Testing standard module should not throw" {
|
||||
{ Test-Module -Name 'PowerShellGet' } | Should -Not -Throw
|
||||
}
|
||||
It "Existing module should return true" {
|
||||
Test-Module -Name 'PowerShellGet' | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Working with modules" {
|
||||
It "Loading first module should not throw " {
|
||||
$Mod = Get-Module -ListAvailable | Select-Object -First 1
|
||||
{ Test-Module -Name $Mod.Name } | Should -Not -Throw
|
||||
}
|
||||
It "Loading first module should return true" {
|
||||
$Snap = Get-Module -ListAvailable | Select-Object -First 1
|
||||
Test-Module -Name $Snap.Name | Should -Be $true
|
||||
}
|
||||
It "Not existing module should return false" {
|
||||
Test-Module -Name 'foobar2000' | Should -Be $false
|
||||
}
|
||||
It "StopifFails switch should thrown an error" {
|
||||
{Test-Module -Name 'foobar2000' -StopIfFails }| Should -Throw
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#region HEADER
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
# $RepoRoot = (Get-Item -Path $here).Parent.Parent.FullName
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "Test-CredentialStore.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Get-CredentialStore" {
|
||||
Context "Basic logic tests" {
|
||||
$TestCredentialStore = Resolve-Path -Path ("{0}\resources\cs\CredentialStore.json" -f $RepoRoot)
|
||||
It "Test1: Read CS without params" {
|
||||
If (Test-Path -Path ("{0}\CredentialStore.json" -f $env:APPDATA)) {
|
||||
{Get-CredentialStore} | Should Not Throw
|
||||
}
|
||||
Else {
|
||||
Write-Warning "Default private Credential Store not found. Skipping..."
|
||||
}
|
||||
}
|
||||
It "Test2: Read Credential Store with testing data" {
|
||||
|
||||
{Get-CredentialStore -Path $TestCredentialStore} | Should Not Throw
|
||||
}
|
||||
It "Test3: Not existing path should return false" {
|
||||
{ Get-CredentialStore -Path 'C:\foobar\CredentialStore.json' -Shared }| Should -Throw "Could not find the CredentialStore."
|
||||
}
|
||||
}
|
||||
Context "Testing invalid json data" {
|
||||
Mock Test-CredentialStore {return $true}
|
||||
Mock Get-Content {return '"foo":"bar",'}
|
||||
It "Should throw with invalid CredentialStore" {
|
||||
{ Get-Credentialstore -Path "C:\dummy.json"} | Should -Throw "Unknown CredentialStore format. Invalid JSON file."
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
#region HEADER
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
# $RepoRoot = (Get-Item -Path $here).Parent.Parent.FullName
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
#. (Get-ChildItem -Path $RepoRoot -Filter "Test-CredentialStore.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Test-ChallengeFile.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Set-ChallengeFile.ps1" -Recurse).FullName
|
||||
. (Get-ChildItem -Path $RepoRoot -Filter "Get-RandomKey.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
|
||||
# Backup existing credential stores
|
||||
$VerbosePreference = "Continue"
|
||||
Write-Verbose "Backup private Credential Store..."
|
||||
$CSPath = ("{0}\CredentialStore.json" -f $env:APPDATA)
|
||||
$BackupFile = "{0}.back" -f $CSPath
|
||||
If (Test-Path -Path $CSPath) {
|
||||
Move-Item -Path $CSPath -Destination $BackupFile
|
||||
}
|
||||
Write-Verbose "Backup shared CredentialStore..."
|
||||
$CSShared = ("{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData)
|
||||
$BackupSharedFile = "{0}.back" -f $CSShared
|
||||
If (Test-Path -Path $CSShared) {
|
||||
Move-Item -Path $CSShared -Destination $BackupSharedFile
|
||||
}
|
||||
Write-Verbose "Remove old CredentialStore in Temp dir"
|
||||
$CSTemp = "{0}\CredentialStore.json" -f $Env:TEMP
|
||||
If (Test-Path -Path $CSTemp) {
|
||||
Remove-Item -Path $CSTemp
|
||||
}
|
||||
$VerbosePreference = "SilentlyContinue"
|
||||
|
||||
Describe "New-CredentialStore" {
|
||||
Context "Private CS tests" {
|
||||
$pCS = Join-Path -Path $env:APPDATA -ChildPath "CredentialStore.json"
|
||||
It "Test1: Create new private CredentialStore" {
|
||||
New-CredentialStore
|
||||
$result = Test-Path -Path $pCS
|
||||
$CS = Get-Content -Path $pCS -Raw | ConvertFrom-Json
|
||||
($result -eq $True) -and ($CS.Type -eq "Private") | Should Be $True
|
||||
}
|
||||
It "Test2: Try to override private Store" {
|
||||
{New-CredentialStore} | Should Throw
|
||||
}
|
||||
It "Test3: Reset existing Credential Store" {
|
||||
$now = Get-Date
|
||||
$CS = Get-Content -Path $pCS -Raw | ConvertFrom-Json
|
||||
$CSCreation = [DateTime]$CS.Creation
|
||||
New-CredentialStore -Force
|
||||
$now -gt $csCreation | Should Be $True
|
||||
}
|
||||
}
|
||||
Context "Shared CS tests" {
|
||||
$pCS = Join-Path -Path $env:ProgramData -ChildPath "PSCredentialStore\CredentialStore.json"
|
||||
It "Test1: Create a new Shared Credential Store" {
|
||||
New-CredentialStore -Shared
|
||||
Test-Path -Path ("{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData) | Should Be $True
|
||||
}
|
||||
It "Test2: Try to override existing shared CS" {
|
||||
{New-CredentialStore -Shared} | Should Throw
|
||||
}
|
||||
It "Test3: Reset shared CredentialStore" {
|
||||
$now = Get-Date
|
||||
$CS = Get-Content -Path $pCS -Raw | ConvertFrom-Json
|
||||
$CSCreation = [DateTime]$CS.Creation
|
||||
New-CredentialStore -Force -Shared
|
||||
$now -gt $csCreation | Should Be $True
|
||||
}
|
||||
}
|
||||
Context "Custom Shared CS tests" {
|
||||
$pCS = Join-Path -Path $env:TEMP -ChildPath "CredentialStore.json"
|
||||
It "Test1: Create new custom shared" {
|
||||
{New-CredentialStore -Path $pCS -Shared} | Should Not Throw
|
||||
}
|
||||
It "Test2: Try to override exiting one" {
|
||||
{New-CredentialStore -Path $pCS -Shared} | Should Throw
|
||||
}
|
||||
It "Test3: Reset existing custom CredentialStore" {
|
||||
{New-CredentialStore -Path $pCS -Shared -Force} | Should Not Throw
|
||||
}
|
||||
}
|
||||
Context "Test exception handling" {
|
||||
Mock Out-File {throw "foobar exception"}
|
||||
It "JSON Converstion should fail and throw" {
|
||||
{ New-CredentialStore -Path "C:\dummy.json"} | Should -Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup test stores and restore existing ones.
|
||||
$VerbosePreference = "Continue"
|
||||
Write-Verbose "Restoring private CredentialStore"
|
||||
If (Test-Path -Path $BackupFile) {
|
||||
If (Test-Path -Path $CSPath) {
|
||||
Remove-Item -Path $CSPath
|
||||
Move-Item -Path $BackupFile -Destination $CSPath
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "Restoring shared CredentialStore"
|
||||
If (Test-Path -Path $BackupSharedFile) {
|
||||
If (Test-Path -Path $CSShared) {
|
||||
Remove-Item -Path $CSShared
|
||||
Move-Item -Path $BackupSharedFile -Destination $CSShared
|
||||
}
|
||||
}
|
||||
$VerbosePreference = "SilentlyContinue"
|
@ -1,49 +0,0 @@
|
||||
#region HEADER
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
# $RepoRoot = (Get-Item -Path $here).Parent.Parent.FullName
|
||||
$RepoRoot = (Get-GitDirectory).replace('\.git', '')
|
||||
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
|
||||
$sut = $sut -replace "\d{2}`_", ''
|
||||
$suthome = (Get-ChildItem -Path $RepoRoot -Exclude ".\tests\" -Filter $sut -Recurse).FullName
|
||||
# Skip try loading the source file if it doesn't exists.
|
||||
If ($suthome.Length -gt 0) {
|
||||
. $suthome
|
||||
}
|
||||
Else {
|
||||
Write-Warning ("Could not find source file {0}" -f $sut)
|
||||
}
|
||||
|
||||
# load additional functions defined in the repository. Replace the expression <FunctionName>.
|
||||
# . (Get-ChildItem -Path $RepoRoot -Filter "<Function-Name>.ps1" -Recurse).FullName
|
||||
|
||||
#endregion HEADER
|
||||
|
||||
Describe "Test-CredentialStore" {
|
||||
Context "Basic logic tests" {
|
||||
$TestCredentialStore = Resolve-Path -Path ("{0}\resources\cs\CredentialStore.json" -f $RepoRoot)
|
||||
It "Test1: Should Not Throw" {
|
||||
{ Test-CredentialStore -Path $TestCredentialStore } | Should Not Throw
|
||||
}
|
||||
It "Test2: Read valid CredentialStore" {
|
||||
$res = Test-CredentialStore -Path $TestCredentialStore
|
||||
$res | Should Be $True
|
||||
}
|
||||
It "Test3: Read a broken CredentialStore" {
|
||||
$BrokenCS = Resolve-Path -Path ("{0}\resources\cs\Broken_CS.json" -f $RepoRoot)
|
||||
$oWarningPreference = $WarningPreference
|
||||
$WarningPreference = 'SilentlyContinue'
|
||||
$res = Test-CredentialStore -Path $BrokenCS
|
||||
$res | Should Be $False
|
||||
$WarningPreference = $oWarningPreference
|
||||
}
|
||||
It "Test4: Not existing path should return false" {
|
||||
Test-CredentialStore -Path 'C:\foobar\CredentialStore.json' | Should -Be $false
|
||||
}
|
||||
It "Test5: testing private CredentialStore path" {
|
||||
if (Test-Path -Path ("{0}\CredentialStore.json" -f $env:APPDATA) ) {
|
||||
Remove-Item -Path ("{0}\CredentialStore.json" -f $env:APPDATA)
|
||||
}
|
||||
Test-CredentialStore | Should -Be $false
|
||||
}
|
||||
}
|
||||
}
|
96
tests/Store/02_New-CredentialStore.Tests.ps1
Normal file
96
tests/Store/02_New-CredentialStore.Tests.ps1
Normal file
@ -0,0 +1,96 @@
|
||||
# Backup existing credential stores
|
||||
$VerbosePreference = "Continue"
|
||||
Write-Verbose "Backup private Credential Store..."
|
||||
$CSPath = Get-DefaultCredentialStorePath
|
||||
$BackupFile = "{0}.back" -f $CSPath
|
||||
If (Test-Path -Path $CSPath) {
|
||||
Move-Item -Path $CSPath -Destination $BackupFile
|
||||
}
|
||||
Write-Verbose "Backup shared CredentialStore..."
|
||||
$CSShared = Get-DefaultCredentialStorePath -Shared
|
||||
$BackupSharedFile = "{0}.back" -f $CSShared
|
||||
If (Test-Path -Path $CSShared) {
|
||||
Move-Item -Path $CSShared -Destination $BackupSharedFile
|
||||
}
|
||||
Write-Verbose "Remove old CredentialStore in Temp dir"
|
||||
$CSTemp = Join-Path -Path (Get-TempDir) -ChildPath '/CredentialStore.json'
|
||||
If (Test-Path -Path $CSTemp) {
|
||||
Remove-Item -Path $CSTemp
|
||||
}
|
||||
$VerbosePreference = "SilentlyContinue"
|
||||
|
||||
Describe "New-CredentialStore" {
|
||||
Context "Private CS tests" {
|
||||
$pCS = Get-DefaultCredentialStorePath
|
||||
It "Test1: Create new private CredentialStore" {
|
||||
{ New-CredentialStore -Confirm:$false } | Should -Not -Throw
|
||||
$result = Test-Path -Path $pCS
|
||||
$CS = Get-Content -Path $pCS -Raw | ConvertFrom-Json
|
||||
($result -eq $true) -and ($CS.Type -eq "Private") | Should -Be $true
|
||||
}
|
||||
It "Test2: Try to override private Store" {
|
||||
{ New-CredentialStore -Confirm:$false } | Should -Throw
|
||||
}
|
||||
It "Test3: Reset existing Credential Store" {
|
||||
$now = Get-Date
|
||||
$CS = Get-Content -Path $pCS -Raw | ConvertFrom-Json
|
||||
$CSCreation = [DateTime]$CS.Created
|
||||
New-CredentialStore -Confirm:$false -Force
|
||||
$now -gt $csCreation | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Shared CS tests" {
|
||||
$sCS = Get-DefaultCredentialStorePath -Shared
|
||||
It "Test1: Create a new Shared Credential Store" {
|
||||
{ New-CredentialStore -Confirm:$false -Shared } | Should -Not -Throw
|
||||
Test-Path -Path $sCS | Should -Be $true
|
||||
}
|
||||
It "Test2: Try to override existing shared CS" {
|
||||
{New-CredentialStore -Shared -Confirm:$false} | Should -Throw
|
||||
}
|
||||
It "Test3: Reset shared CredentialStore" {
|
||||
$now = Get-Date
|
||||
$CS = Get-Content -Path $sCS -Raw | ConvertFrom-Json
|
||||
$CSCreation = [DateTime]$CS.Created
|
||||
New-CredentialStore -Force -Shared -Confirm:$false
|
||||
$now -gt $csCreation | Should -Be $true
|
||||
}
|
||||
}
|
||||
Context "Custom Shared CS tests" {
|
||||
$cCS = Join-Path -Path (Get-TempDir) -ChildPath "CredentialStore.json"
|
||||
It "Test1: Create new custom shared" {
|
||||
{New-CredentialStore -Path $cCS -Shared -Confirm:$false} | Should -Not -Throw
|
||||
}
|
||||
It "Test2: Try to override exiting one" {
|
||||
{New-CredentialStore -Path $cCS -Shared -Confirm:$false} | Should -Throw
|
||||
}
|
||||
It "Test3: Reset existing custom CredentialStore" {
|
||||
{New-CredentialStore -Path $cCS -Shared -Force -Confirm:$false} | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
Context "Test exception handling" {
|
||||
Mock Out-File {throw "foobar exception"}
|
||||
It "JSON Conversion should fail and throw" {
|
||||
{ New-CredentialStore -Path (Join-Path -Path (Get-TempDir) -ChildPath '/dummy.json') -Shared -Confirm:$false} | Should -Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup test stores and restore existing ones.
|
||||
$VerbosePreference = "Continue"
|
||||
Write-Verbose "Restoring private CredentialStore"
|
||||
If (Test-Path -Path $BackupFile) {
|
||||
If (Test-Path -Path $CSPath) {
|
||||
Remove-Item -Path $CSPath
|
||||
Move-Item -Path $BackupFile -Destination $CSPath
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "Restoring shared CredentialStore"
|
||||
If (Test-Path -Path $BackupSharedFile) {
|
||||
If (Test-Path -Path $CSShared) {
|
||||
Remove-Item -Path $CSShared
|
||||
Move-Item -Path $BackupSharedFile -Destination $CSShared
|
||||
}
|
||||
}
|
||||
$VerbosePreference = "SilentlyContinue"
|
36
tests/Store/02_Test-CredentialStore.Tests.ps1
Normal file
36
tests/Store/02_Test-CredentialStore.Tests.ps1
Normal file
@ -0,0 +1,36 @@
|
||||
$RepoRoot = (Get-Item -Path (Get-GitDirectory) -Force).Parent | Select-Object -ExpandProperty 'FullName'
|
||||
|
||||
Describe "Test-CredentialStore" {
|
||||
Context "Basic logic tests" {
|
||||
$TestCredentialStore = Join-Path -Path $RepoRoot -ChildPath '/resources/cs/CredentialStore.json'
|
||||
It "Test1: Should Not Throw" {
|
||||
{ Test-CredentialStore -Shared -Path $TestCredentialStore } | Should -Not -Throw
|
||||
}
|
||||
It "Test2: Read valid CredentialStore" {
|
||||
$res = Test-CredentialStore -Shared -Path $TestCredentialStore
|
||||
$res | Should -Be $true
|
||||
}
|
||||
It "Test3: Read a broken CredentialStore" {
|
||||
$BrokenCS = Join-Path -Path $RepoRoot -ChildPath '{0}/resources/cs/Broken_CS.json'
|
||||
$oWarningPreference = $WarningPreference
|
||||
$WarningPreference = 'SilentlyContinue'
|
||||
$res = Test-CredentialStore -Shared -Path $BrokenCS
|
||||
$res | Should -Be $false
|
||||
$WarningPreference = $oWarningPreference
|
||||
}
|
||||
It "Test4: Not existing path should return false" {
|
||||
if ($isWindows -or ($PSVersionTable.PSVersion.Major -eq 5)) {
|
||||
Test-CredentialStore -Shared -Path 'C:\foobar\CredentialStore.json' | Should -Be $false
|
||||
}
|
||||
elseif ($isWindows -or $IsMacOS) {
|
||||
Test-CredentialStore -Shared -Path '/var/opt/foo.json' | Should -Be $false
|
||||
}
|
||||
}
|
||||
It "Test5: testing private CredentialStore path" {
|
||||
if (Test-Path -Path (Get-DefaultCredentialStorePath)) {
|
||||
Remove-Item -Path (Get-DefaultCredentialStorePath)
|
||||
}
|
||||
Test-CredentialStore | Should -Be $false
|
||||
}
|
||||
}
|
||||
}
|
32
tests/Store/03_Get-CredentialStore.Tests.ps1
Normal file
32
tests/Store/03_Get-CredentialStore.Tests.ps1
Normal file
@ -0,0 +1,32 @@
|
||||
$RepoRoot = (Get-Item -Path (Get-GitDirectory) -Force).Parent | Select-Object -ExpandProperty 'FullName'
|
||||
|
||||
Describe "Get-CredentialStore" {
|
||||
Context "Basic logic tests" {
|
||||
$TestCredentialStore = Join-Path -Path $RepoRoot -ChildPath 'resources/cs/CredentialStore.json'
|
||||
$TestPfxCert = Join-Path -Path $RepoRoot -ChildPath 'resources/cs/PSCredentialStore.pfx'
|
||||
'TestCredentialStore: {0}' -f $TestCredentialStore
|
||||
It "Test1: Read CS without params" {
|
||||
if (! (Test-Path -Path (Get-DefaultCredentialStorePath)) ) {
|
||||
{ New-CredentialStore -Force } | Should -Not -Throw
|
||||
|
||||
}
|
||||
{ Get-CredentialStore } | Should -Not -Throw
|
||||
}
|
||||
It "Test2: Read Credential Store with testing data" {
|
||||
{ Use-PfxCertificate -Shared -CredentialStore $TestCredentialStore -Path $TestPfxCert } | Should -Not -Throw
|
||||
{ Get-CredentialStore -Shared -Path $TestCredentialStore } | Should -Not -Throw
|
||||
}
|
||||
It "Test3: Not existing path should return false" {
|
||||
{ Get-CredentialStore -Shared -Path './CredentialStore.json' }| Should -Throw "Could not find the CredentialStore."
|
||||
}
|
||||
}
|
||||
Context "Testing invalid json data" {
|
||||
#Mock Test-CredentialStore {return $true}
|
||||
#Mock Get-Content {return '"foo":"bar",'}
|
||||
$BrokenCS = Join-Path -Path $RepoRoot -ChildPath 'resources/cs/Broken_CS.json'
|
||||
Write-Verbose -Message ('BrokenCS Path: {0}' -f $BrokenCS) -Verbose
|
||||
It "Should throw with invalid CredentialStore" {
|
||||
{ Get-CredentialStore -Path -Shared $BrokenCS } | Should -Throw
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
- Module name
|
||||
#>
|
||||
$CALLSIGN = 'PSCredentialStore'
|
||||
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Yellow
|
||||
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Black -BackgroundColor Yellow
|
||||
|
||||
|
||||
Function Invoke-InstallDependencies() {
|
||||
@ -16,12 +16,13 @@ Function Invoke-InstallDependencies() {
|
||||
|
||||
Process {
|
||||
Try {
|
||||
Get-PackageProvider -ListAvailable
|
||||
Install-PackageProvider -Name NuGet -RequiredVersion '2.8.5.208' -Force -Verbose
|
||||
Import-PackageProvider -Name NuGet -RequiredVersion '2.8.5.208' -Force
|
||||
Install-Module -Name 'Pester' -Scope CurrentUser -RequiredVersion '4.0.8' -Force -SkipPublisherCheck -AllowClobber
|
||||
Install-Module -Name 'posh-git' -Scope CurrentUser -RequiredVersion '0.7.1' -Force -SkipPublisherCheck -AllowClobber
|
||||
Install-Module -Name 'PSCoverage' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber
|
||||
Import-Module -Name 'Pester', 'posh-git', 'PSCoverage'
|
||||
Install-Module -Name 'Pester' -Scope CurrentUser -RequiredVersion '4.4.2' -Force -SkipPublisherCheck -AllowClobber
|
||||
Install-Module -Name 'posh-git' -Scope CurrentUser -RequiredVersion '1.0.0-beta2' -Force -SkipPublisherCheck -AllowClobber -AllowPrerelease
|
||||
# Install-Module -Name 'PSCoverage' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber
|
||||
Import-Module -Name 'Pester', 'posh-git' #, 'PSCoverage'
|
||||
}
|
||||
Catch {
|
||||
$MsgParams = @{
|
||||
@ -39,13 +40,13 @@ Function Invoke-AppVeyorBumpVersion() {
|
||||
[CmdletBinding()]
|
||||
Param()
|
||||
|
||||
Write-Host "Listing Env Vars for debugging:" -ForegroundColor Yellow
|
||||
Write-Host "Listing Env Vars for debugging:" -ForegroundColor Black -BackgroundColor Yellow
|
||||
# Filter Results to prevent exposing secure vars.
|
||||
Get-ChildItem -Path "Env:*" | Where-Object { $_.name -notmatch "(NuGetToken|CoverallsToken)"} | Sort-Object -Property Name | Format-Table
|
||||
|
||||
Try {
|
||||
$ModManifest = Get-Content -Path (".\src\{0}.psd1" -f $CALLSIGN)
|
||||
$BumpedManifest = $ModManifest -replace '0.0.0.9999', $Env:APPVEYOR_BUILD_VERSION
|
||||
$BumpedManifest = $ModManifest -replace '0.0.9999', $Env:APPVEYOR_BUILD_VERSION
|
||||
Remove-Item -Path (".\src\{0}.psd1" -f $CALLSIGN)
|
||||
Out-File -FilePath (".\src\{0}.psd1" -f $CALLSIGN) -InputObject $BumpedManifest -NoClobber -Encoding utf8 -Force
|
||||
}
|
||||
@ -62,6 +63,7 @@ Function Invoke-AppVeyorBumpVersion() {
|
||||
|
||||
Function Invoke-AppVeyorBuild() {
|
||||
[CmdletBinding()]
|
||||
[OutputType([PsCustomObject])]
|
||||
Param()
|
||||
$MsgParams = @{
|
||||
Message = 'Creating build artifacts'
|
||||
@ -82,7 +84,8 @@ Function Invoke-AppVeyorBuild() {
|
||||
Details = 'Pushing artifacts to AppVeyor store.'
|
||||
}
|
||||
Add-AppveyorMessage @MsgParams
|
||||
Push-AppveyorArtifact (".\bin\{0}.zip" -f $CALLSIGN)
|
||||
$ArtifactPath = Join-Path -Path '.' -ChildPath ('bin/{0}.zip' -f $CALLSIGN)
|
||||
Push-AppveyorArtifact $ArtifactPath
|
||||
}
|
||||
|
||||
Function Invoke-AppVeyorTests() {
|
||||
@ -95,8 +98,31 @@ Function Invoke-AppVeyorTests() {
|
||||
Details = 'Now running all test found in .\tests\ dir.'
|
||||
}
|
||||
Add-AppveyorMessage @MsgParams
|
||||
$testresults = Invoke-Pester -Path ( Get-ChildItem -Path ".\tests\*.Tests.ps1" -Recurse | Sort-Object -Property Name ) -ExcludeTag 'Disabled' -PassThru
|
||||
ForEach ($Item in $testresults.TestResult) {
|
||||
|
||||
try {
|
||||
Write-Host '===== Preload internal private functions =====' -ForegroundColor Black -BackgroundColor Yellow
|
||||
|
||||
$Privates = Get-ChildItem -Path (Join-Path -Path $Env:APPVEYOR_BUILD_FOLDER -ChildPath '/src/Private/*') -Include "*.ps1" -Recurse
|
||||
foreach ($File in $Privates) {
|
||||
if (Test-Path -Path $File.FullName) {
|
||||
. $File.FullName
|
||||
Write-Verbose -Message ('Private function dot-sourced: {0}' -f $File.FullName) -Verbose
|
||||
}
|
||||
else {
|
||||
Write-Warning -Message ('Could not find file: {0} !' -f $File.FullName)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$_.Exception.Message | Write-Error
|
||||
throw 'Could not load required private functions!'
|
||||
}
|
||||
|
||||
#$testresults = Invoke-Pester -Path ( Get-ChildItem -Path ".\tests\*.Tests.ps1" -Recurse | Sort-Object -Property Name ) -ExcludeTag 'Disabled' -PassThru
|
||||
$srcFiles = Get-ChildItem -Path ".\src\*.ps1" -Recurse | Sort-Object -Property 'Name' | Select-Object -ExpandProperty 'FullName'
|
||||
$testFiles = Get-ChildItem -Path ".\tests\*.Tests.ps1" -Recurse | Sort-Object -Property 'Name' | Select-Object -ExpandProperty 'FullName'
|
||||
$TestResults = Invoke-Pester -Path $testFiles -CodeCoverage $srcFiles -PassThru
|
||||
ForEach ($Item in $TestResults.TestResult) {
|
||||
Switch ($Item.Result) {
|
||||
"Passed" {
|
||||
$TestParams = @{
|
||||
@ -134,16 +160,18 @@ Function Invoke-AppVeyorTests() {
|
||||
}
|
||||
}
|
||||
}
|
||||
If ($testresults.FailedCount -gt 0) {
|
||||
If ($TestResults.FailedCount -gt 0) {
|
||||
$MsgParams = @{
|
||||
Message = 'Pester Tests failed.'
|
||||
Category = 'Error'
|
||||
Details = "$($testresults.FailedCount) tests failed."
|
||||
Details = "$($TestResults.FailedCount) tests failed."
|
||||
}
|
||||
Add-AppveyorMessage @MsgParams
|
||||
Throw $MsgParams.Message
|
||||
}
|
||||
|
||||
return $TestResults.CodeCoverage
|
||||
|
||||
}
|
||||
|
||||
Function Invoke-CoverageReport() {
|
||||
@ -151,13 +179,17 @@ Function Invoke-CoverageReport() {
|
||||
Param(
|
||||
[Parameter(Mandatory = $False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]$RepoToken = $Env:CoverallsToken
|
||||
[String]$RepoToken = $Env:CoverallsToken,
|
||||
|
||||
[Parameter(Mandatory = $True)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCustomObject]$PesterCoverageReport
|
||||
)
|
||||
|
||||
$FileMap = New-PesterFileMap -SourceRoot '.\src' -PesterRoot '.\tests'
|
||||
$CoverageReport = New-CoverageReport -PesterFileMap $FileMap -RepoToken $RepoToken
|
||||
#$CoverageReport | Format-Custom -Depth 5 | Out-String | Write-Verbose
|
||||
$CoverageReport = New-CoverageReport -CodeCoverage $PesterCoverageReport -RepoToken $RepoToken
|
||||
Write-Host "CoverageReport JSON:" -ForegroundColor Yellow
|
||||
$CoverageReport | Out-String | Write-Host
|
||||
#$CoverageReport | ConvertTo-Json -Depth 5 | Out-String | Write-Verbose
|
||||
Publish-CoverageReport -CoverageReport $CoverageReport
|
||||
}
|
||||
|
||||
@ -170,27 +202,27 @@ Function Invoke-AppVeyorPSGallery() {
|
||||
)
|
||||
Expand-Archive -Path (".\bin\{0}.zip" -f $CALLSIGN) -DestinationPath ("C:\Users\appveyor\Documents\WindowsPowerShell\Modules\{0}\" -f $CALLSIGN) -Verbose
|
||||
Import-Module -Name $CALLSIGN -Verbose -Force
|
||||
Write-Host "Available Package Provider:" -ForegroundColor Yellow
|
||||
Write-Host "Available Package Provider:" -ForegroundColor Black -BackgroundColor Yellow
|
||||
Get-PackageProvider -ListAvailable
|
||||
Write-Host "Available Package Sources:" -ForegroundColor Yellow
|
||||
Write-Host "Available Package Sources:" -ForegroundColor Black -BackgroundColor Yellow
|
||||
Get-PackageSource
|
||||
Try {
|
||||
Write-Host "Try to get NuGet Provider:" -ForegroundColor Yellow
|
||||
Write-Host "Try to get NuGet Provider:" -ForegroundColor Black -BackgroundColor Yellow
|
||||
Get-PackageProvider -Name NuGet -ErrorAction Stop
|
||||
}
|
||||
Catch {
|
||||
Write-Host "Installing NuGet..." -ForegroundColor Yellow
|
||||
Write-Host "Installing NuGet..." -ForegroundColor Black -BackgroundColor Yellow
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force -Verbose
|
||||
Import-PackageProvider NuGet -MinimumVersion '2.8.5.201' -Force
|
||||
}
|
||||
Try {
|
||||
If ($env:APPVEYOR_REPO_BRANCH -eq 'master') {
|
||||
Write-Host "try to publish module" -ForegroundColor Yellow
|
||||
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Yellow
|
||||
Publish-Module -Name $CALLSIGN -NuGetApiKey $env:NuGetToken -Verbose -Force
|
||||
Write-Host "try to publish module" -ForegroundColor Black -BackgroundColor Yellow
|
||||
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Black -BackgroundColor Yellow
|
||||
Publish-Module -Name $CALLSIGN -NuGetApiKey $env:NuGetToken -Verbose -Force -AllowPrerelease
|
||||
}
|
||||
Else {
|
||||
Write-Host "Skip publishing to PS Gallery because we are on $($env:APPVEYOR_REPO_BRANCH) branch." -ForegroundColor Yellow
|
||||
Write-Host "Skip publishing to PS Gallery because we are on $($env:APPVEYOR_REPO_BRANCH) branch." -ForegroundColor Black -BackgroundColor Yellow
|
||||
# had to remove the publish-Module statement because it would publish although the -WhatIf is given.
|
||||
# Publish-Module -Name $CALLSIGN -NuGetApiKey $env:NuGetToken -Verbose -WhatIf
|
||||
}
|
||||
|
178
tools/CoverallsIO.psm1
Normal file
178
tools/CoverallsIO.psm1
Normal file
@ -0,0 +1,178 @@
|
||||
function Get-GitInfo {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$BranchName
|
||||
)
|
||||
|
||||
if ($Env:AppVeyor) {
|
||||
return [PSCustomObject]@{
|
||||
head = [PSCustomObject]@{
|
||||
id = $Env:APPVEYOR_REPO_COMMIT
|
||||
author_name = $Env:APPVEYOR_REPO_COMMIT_AUTHOR
|
||||
author_email = $Env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL
|
||||
comitter_name = $Env:APPVEYOR_REPO_COMMIT_AUTHOR
|
||||
comitter_email = $Env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL
|
||||
message = $Env:APPVEYOR_REPO_COMMIT_MESSAGE
|
||||
}
|
||||
branch = $Env:APPVEYOR_REPO_BRANCH
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (-not $BranchName) {
|
||||
$BranchName = (git rev-parse --abbrev-ref HEAD)
|
||||
}
|
||||
return [PSCustomObject]@{
|
||||
head = [PSCustomObject]@{
|
||||
id = (git log --format="%H" HEAD -1)
|
||||
author_name = (git log --format="%an" HEAD -1)
|
||||
author_email = (git log --format="%ae" HEAD -1)
|
||||
committer_name = (git log --format="%cn" HEAD -1)
|
||||
committer_email = (git log --format="%ce" HEAD -1)
|
||||
message = (git log --format="%s" HEAD -1)
|
||||
}
|
||||
branch = $BranchName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function New-CoverageReport {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCustomObject]$CodeCoverage,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$RepoToken,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$ModuleRoot = $(Get-Location)
|
||||
)
|
||||
begin {
|
||||
$CoverReport = [PSCustomObject]@{
|
||||
repo_token = $RepoToken
|
||||
commit_sha = (git log --format="%H" HEAD -1)
|
||||
git = Get-GitInfo
|
||||
service_name = 'appveyor'
|
||||
source_files = @()
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
# Find all files with hit commands -> These file have pester tests
|
||||
$UsedFiles = $CodeCoverage.AnalyzedFiles | Where-Object {
|
||||
$CodeCoverage.HitCommands.File -contains $_
|
||||
}
|
||||
|
||||
foreach ($SourceFile in $UsedFiles) {
|
||||
$Lines = (Get-Content -Path $SourceFile | Measure-Object).Count
|
||||
Write-Verbose ("SourceFile: {0} | LinesCount: {1}" -f $SourceFile, $Lines)
|
||||
$CoverageArray = @()
|
||||
$Hits = 0
|
||||
$Missed = 0
|
||||
|
||||
for ($LinePointer = 1; $LinePointer -le $Lines; $LinePointer++) {
|
||||
|
||||
# Get only hit commands from current src file
|
||||
$curHits = $CodeCoverage.HitCommands | Where-Object {
|
||||
$_.File -eq $SourceFile
|
||||
}
|
||||
[int]$Hits = (
|
||||
$curHits | Where-Object {
|
||||
$_.Line -eq $LinePointer
|
||||
} | Measure-Object
|
||||
).Count
|
||||
|
||||
# again filter only missed commands from the curent file
|
||||
$curMissed = $CodeCoverage.MissedCommands | Where-Object {
|
||||
$_.File -eq $SourceFile
|
||||
}
|
||||
[int]$Missed = (
|
||||
$curMissed | Where-Object {
|
||||
$_.Line -eq $LinePointer
|
||||
} | Measure-Object
|
||||
).Count
|
||||
|
||||
Write-Verbose ("SourceFile:{0} | Line: {1} | Hits: {2} | Missed: {3}" -f $SourceFile, $LinePointer, $Hits, $Missed)
|
||||
if ((-not $Hits -gt 0) -and (-not $Missed -gt 0)) {
|
||||
$CoverageArray += 'null'
|
||||
}
|
||||
else {
|
||||
if ($Hits -gt 0) {
|
||||
$CoverageArray += $Hits
|
||||
}
|
||||
elseif ($Missed -gt 0) {
|
||||
$CoverageArray += 0
|
||||
}
|
||||
}
|
||||
}
|
||||
# Get rid of the quotation
|
||||
$CoverageArray = $CoverageArray -Replace '"', ''
|
||||
$CoverageSourceFile = [PSCustomObject]@{
|
||||
name = $SourceFile.Replace($ModuleRoot, '').Replace('\', '/')
|
||||
source_digest = (Get-FileHash -Path $SourceFile -Algorithm MD5).Hash
|
||||
coverage = $CoverageArray
|
||||
}
|
||||
If ($CoverageSourceFile.Name.StartsWith('/')) {
|
||||
$CoverageSourceFile.Name = $CoverageSourceFile.Name.Remove(0, 1)
|
||||
}
|
||||
$CoverReport.source_files += $CoverageSourceFile
|
||||
}
|
||||
|
||||
# Find all untested files to create a null coverage file
|
||||
$UnUsedFiles = $CodeCoverage.AnalyzedFiles | Where-Object {
|
||||
$CodeCoverage.HitCommands.File -notcontains $_
|
||||
}
|
||||
|
||||
foreach ($UnUsedFile in $UnUsedFiles) {
|
||||
$Lines = (Get-Content -Path $UnUsedFile | Measure-Object).Count
|
||||
$CoverageArray = @()
|
||||
for ($LinePointer = 1; $LinePointer -le $Lines; $LinePointer++) {
|
||||
$CoverageArray += '0'
|
||||
}
|
||||
$CoverageSourceFile = [PSCustomObject]@{
|
||||
name = $UnUsedFile.Replace($ModuleRoot, '').Replace('\', '/')
|
||||
source_digest = (Get-FileHash -Path $UnUsedFile -Algorithm MD5).Hash
|
||||
coverage = $CoverageArray
|
||||
}
|
||||
if ($CoverageSourceFile.Name.StartsWith('/')) {
|
||||
$CoverageSourceFile.Name = $CoverageSourceFile.Name.Remove(0, 1)
|
||||
}
|
||||
$CoverReport.source_files += $CoverageSourceFile
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
Write-Output $CoverReport
|
||||
}
|
||||
}
|
||||
|
||||
function Publish-CoverageReport () {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $True)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCustomObject]$CoverageReport
|
||||
)
|
||||
begin {
|
||||
Add-Type -AssemblyName System.Net.Http
|
||||
}
|
||||
|
||||
process {
|
||||
$CoverageJSON = ConvertTo-Json $CoverageReport -Depth 5
|
||||
# Try to fix null elements in coverage array.
|
||||
$CoverageJSON = $CoverageJSON.Replace('"null"', 'null')
|
||||
$stringContent = New-Object System.Net.Http.StringContent ($CoverageJSON)
|
||||
$httpClient = New-Object System.Net.Http.Httpclient
|
||||
$formdata = New-Object System.Net.Http.MultipartFormDataContent
|
||||
$formData.Add($stringContent, "json_file", "coverage.json")
|
||||
$result = $httpClient.PostAsync('https://coveralls.io/api/v1/jobs', $formData).Result
|
||||
$content = $result.Content.ReadAsStringAsync()
|
||||
}
|
||||
|
||||
end {
|
||||
Write-Output $Content
|
||||
}
|
||||
}
|
66
tools/Travis.psm1
Normal file
66
tools/Travis.psm1
Normal file
@ -0,0 +1,66 @@
|
||||
$Global:ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
$CALLSIGN = 'PSCredentialStore'
|
||||
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Black -BackgroundColor Yellow
|
||||
|
||||
function Invoke-InstallDependencies {
|
||||
[CmdletBinding()]
|
||||
Param()
|
||||
|
||||
process {
|
||||
try {
|
||||
Write-Host '===== Environment Vars: =====' -ForegroundColor Black -BackgroundColor Yellow
|
||||
Get-ChildItem -Path Env:
|
||||
|
||||
Write-Host -Message '===== Existing Variables: =====' -ForegroundColor Black -BackgroundColor Yellow
|
||||
Get-Variable -Name * | Format-Table -AutoSize
|
||||
|
||||
Get-PackageProvider -ListAvailable
|
||||
Import-PackageProvider -Name 'NuGet' -MinimumVersion '2.8.5.208' -Verbose -Force
|
||||
|
||||
Install-Module -Name 'Pester' -Scope CurrentUser -RequiredVersion '4.4.2' -Force -SkipPublisherCheck -AllowClobber -Verbose
|
||||
Install-Module -Name 'posh-git' -Scope CurrentUser -RequiredVersion '1.0.0-beta2' -Force -SkipPublisherCheck -AllowClobber -AllowPrerelease -Verbose
|
||||
|
||||
Import-Module -Name 'Pester', 'posh-git' -Verbose
|
||||
}
|
||||
catch {
|
||||
$_.Exception.Message | Write-Error
|
||||
throw 'Could not install the required dependencies!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-UnitTests {
|
||||
[CmdletBinding()]
|
||||
Param()
|
||||
|
||||
process {
|
||||
|
||||
try {
|
||||
Write-Host '===== Preload internal private functions =====' -ForegroundColor Black -BackgroundColor Yellow
|
||||
|
||||
$Privates = Get-ChildItem -Path (Join-Path -Path $Env:TRAVIS_BUILD_DIR -ChildPath '/src/Private/*') -Include "*.ps1" -Recurse -ErrorAction Stop
|
||||
foreach ($File in $Privates) {
|
||||
if (Test-Path -Path $File.FullName) {
|
||||
. $File.FullName
|
||||
Write-Verbose -Message ('Private function dot-sourced: {0}' -f $File.FullName) -Verbose
|
||||
}
|
||||
else {
|
||||
Write-Warning -Message ('Could not find file: {0} !' -f $File.FullName)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$_.Exception.Message | Write-Error
|
||||
throw 'Could not load required private functions!'
|
||||
}
|
||||
|
||||
Write-Host '===== Running Pester =====' -ForegroundColor Black -BackgroundColor Yellow
|
||||
$TestFiles = Get-ChildItem -Path (Join-Path -Path '.' -ChildPath './tests/*.Tests.ps1') -Recurse| Sort-Object -Property Name
|
||||
$TestResults = Invoke-Pester -Script $TestFiles -ExcludeTag 'Disabled' -PassThru
|
||||
|
||||
if ($TestResults.FailedCount -gt 0) {
|
||||
throw ('{0} tests failed!' -f $TestResults.FailedCount)
|
||||
}
|
||||
}
|
||||
}
|
14
tools/travis.sh
Normal file
14
tools/travis.sh
Normal file
@ -0,0 +1,14 @@
|
||||
set -x
|
||||
ulimit -n 4096
|
||||
|
||||
echo "TRAVIS_EVENT_TYPE value $TRAVIS_EVENT_TYPE"
|
||||
|
||||
if [ $TRAVIS_EVENT_TYPE = cron ] || [ $TRAVIS_EVENT_TYPE = api ]; then
|
||||
sudo pwsh -NoProfile -NonInteractive -c "Import-Module ./tools/Travis.psm1;
|
||||
Invoke-InstallDependencies;
|
||||
Invoke-UnitTests;"
|
||||
else
|
||||
sudo pwsh -NoProfile -NonInteractive -c "Import-Module ./tools/Travis.psm1;
|
||||
Invoke-InstallDependencies;
|
||||
Invoke-UnitTests;"
|
||||
fi
|
Loading…
Reference in New Issue
Block a user