From 86fa13f36d314b45c8e24aade266c9b27282d3d9 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 14:20:34 +0200 Subject: [PATCH 01/37] adds basic module layout --- .vscode/cSpell.json | 39 +++++++ .vscode/settings.json | 50 +++++++++ appveyor.yml | 54 +++++++++ bin/.gitignore | 1 + resources/.gitignore | 0 resources/cs/Broken_CS.json | 3 + resources/cs/Challenge.bin | 1 + resources/cs/CredentialStore.json | Bin 0 -> 2084 bytes src/PSCredentialStore.psd1 | 123 +++++++++++++++++++++ tests/.gitignore | 0 tools/AppVeyor.psm1 | 178 ++++++++++++++++++++++++++++++ 11 files changed, 449 insertions(+) create mode 100644 .vscode/cSpell.json create mode 100644 .vscode/settings.json create mode 100644 appveyor.yml create mode 100644 bin/.gitignore create mode 100644 resources/.gitignore create mode 100644 resources/cs/Broken_CS.json create mode 100644 resources/cs/Challenge.bin create mode 100644 resources/cs/CredentialStore.json create mode 100644 src/PSCredentialStore.psd1 create mode 100644 tests/.gitignore create mode 100644 tools/AppVeyor.psm1 diff --git a/.vscode/cSpell.json b/.vscode/cSpell.json new file mode 100644 index 0000000..ed2510a --- /dev/null +++ b/.vscode/cSpell.json @@ -0,0 +1,39 @@ +// cSpell Settings +{ + // Version of the setting file. Always 0.1 + "version": "0.1", + // language - current active spelling language + "language": "en", + // words - list of words to be always considered correct + "words": [ + "Ponduit", + "NTFS", + "Repo", + "Hashtable", + "googlemail", + "Cmdlet", + "appveyor", + "GUID", + "wildcards", + "Cmdlets", + "codecoverage", + "notmatch", + "Httpclient", + "Multipart", + "formdata", + "callsign", + "Veyor", + "notlike", + "Params", + "testresults", + "powershellgallery", + "chocolatey", + "choco" + ], + // flagWords - list of words to be always considered incorrect + // This is useful for offensive words and common spelling errors. + // For example "hte" should be "the" + "flagWords": [ + "hte" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..05e9a14 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,50 @@ +// Place your settings in this file to overwrite default and user settings. +{ + // Set basic file related options: + "files.encoding": "utf8", + "files.eol": "\r\n", + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + // Formation and editor options + "editor.renderWhitespace": "boundary", + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.rulers": [ + 116 + ], + // powershell general + "powershell.startAutomatically": true, + "powershell.useX86Host": false, + "powershell.enableProfileLoading": true, + "powershell.scriptAnalysis.enable": true, + // powershell code Formatting + "powershell.codeFormatting.openBraceOnSameLine": true, + "powershell.codeFormatting.newLineAfterOpenBrace": true, + "powershell.codeFormatting.newLineAfterCloseBrace": true, + "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, + "powershell.codeFormatting.whitespaceBeforeOpenParen": true, + "powershell.codeFormatting.whitespaceAroundOperator": true, + "powershell.codeFormatting.whitespaceAfterSeparator": true, + "powershell.codeFormatting.ignoreOneLineBlock": true, + "powershell.codeFormatting.alignPropertyValuePairs": false, + // cspell spellchecker options + "cSpell.enabledLanguageIds": [ + "c", + "cpp", + "csharp", + "go", + "javascript", + "javascriptreact", + "json", + "latex", + "markdown", + "php", + "plaintext", + "powershell", + "python", + "text", + "typescript", + "typescriptreact", + "yml" + ] +} diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..4b42772 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,54 @@ +version: 0.1.{build} + +branches: + only: + - master + - dev + - debug + +skip_tags: true + +#image: WMF 5 +# Test ne build image: +image: Visual Studio 2017 + +# Install pester module and init the Appveyor support. +install: + - ps: Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force -Verbose + - ps: Import-PackageProvider NuGet -MinimumVersion '2.8.5.201' -Force +# - ps: Install-Module -Name 'Pester' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber +# - ps: Update-Module 'Pester' +# - ps: Install-Module -Name 'posh-git' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber +# - ps: Update-Module 'posh-git' + - ps: Import-Module .\tools\AppVeyor.psm1 + +environment: + NuGetToken: + secure: 835qfZIkC9mE7QhkYfOZVAdR8rZhPvxG8BO4CbeaelRQOhlqmaSr8G1DWRJzZ/bS + CoverallsToken: + secure: eTjWqHL48MBr8wp1rSgLrXHdtpfDV/uClacP3svlWJfCvn/zVokpuaMnWM5RoyIY + +build: false + +before_build: + - ps: Invoke-AppVeyorBumpVersion + +build_script: + - ps: Invoke-AppVeyorBuild + +test_script: + - ps: Invoke-AppVeyorTests + - ps: Invoke-CoverageReport + +deploy: + - provider: GitHub + auth_token: + secure: M+bBX5/nKdJB0eViP7xtrLVTwf3vGDUA9N2MMprZp2i+9ZR3CBVcJnSzJWUmalhB + artifact: PSCredentialStore.zip # upload all NuGet packages to release assets + draft: false + prerelease: false + on: + branch: master # release from master branch only + +after_deploy: + - ps: Invoke-AppVeyorPSGallery diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 0000000..7756187 --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1 @@ +This is a placeholder file. The build Server will create all bin files here. diff --git a/resources/.gitignore b/resources/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/resources/cs/Broken_CS.json b/resources/cs/Broken_CS.json new file mode 100644 index 0000000..23e8eee --- /dev/null +++ b/resources/cs/Broken_CS.json @@ -0,0 +1,3 @@ +{ + "Version": "1.2.0", + "Creation": "2016-06-14 08:41:10" diff --git a/resources/cs/Challenge.bin b/resources/cs/Challenge.bin new file mode 100644 index 0000000..3b80551 --- /dev/null +++ b/resources/cs/Challenge.bin @@ -0,0 +1 @@ +!pH4"=wS2 \ No newline at end of file diff --git a/resources/cs/CredentialStore.json b/resources/cs/CredentialStore.json new file mode 100644 index 0000000000000000000000000000000000000000..4d45b386150656d9a9c66102720bfe29dfa7623e GIT binary patch literal 2084 zcmeH{%Wl*_5JhW^#6Lt{1Mze0$(A3;0@&MaTgrx@nFti2{5o)MbtcnxX2B4aQOW(N zuGek%t>3?X+FN^L7mt$J7n^Knd%Lk)`)Zk8`AKGleef?w_ip9$5s%4wyL;wUT8`Jo z-ZN_~tR`M=9dT=RSA3@;ezJS}M$BXWYjWJ!ch4gIx`vs0Z*Aaw_vE$2cEEUg&g?U& zh5eW_#$4w*?SIf_c1;a?(-W?vUbfHbqu{vy+OS_alU4)_pk2LvI=M<0iCoXtJrHAPSa2%#7+^>ImYp_TrEFgjlEk(XdjlQFp93U9wiy$!5e;cp|rix_kz1TcC yL$_GTx?>a*#pkWZi(XpS=o +$CALLSIGN = 'PSCoverage' +Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Yellow + +Function Invoke-AppVeyorBumpVersion() { + [CmdletBinding()] + Param() + + Write-Host "Listing Env Vars for debugging:" -ForegroundColor 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 '\$Env:APPVEYOR_BUILD_VERSION', "'$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 + } + Catch { + $MsgParams = @{ + Message = 'Could not bump current version into module manifest.' + Category = 'Error' + Details = $_.Exception.Message + } + Add-AppveyorMessage @MsgParams + Throw $MsgParams.Message + } +} + +Function Invoke-AppVeyorBuild() { + [CmdletBinding()] + Param() + $MsgParams = @{ + Message = 'Creating build artifacts' + Category = 'Information' + Details = 'Extracting source files and compressing them into zip file.' + } + Add-AppveyorMessage @MsgParams + $CompParams = @{ + Path = "{0}\src\*" -f $env:APPVEYOR_BUILD_FOLDER + DestinationPath = "{0}\bin\{1}.zip" -f $env:APPVEYOR_BUILD_FOLDER, $CALLSIGN + Update = $True + Verbose = $True + } + Compress-Archive @CompParams + $MsgParams = @{ + Message = 'Pushing artifacts' + Category = 'Information' + Details = 'Pushing artifacts to AppVeyor store.' + } + Add-AppveyorMessage @MsgParams + Push-AppveyorArtifact (".\bin\{0}.zip" -f $CALLSIGN) +} + +Function Invoke-AppVeyorTests() { + [CmdletBinding()] + Param() + + $MsgParams = @{ + Message = 'Starting Pester tests' + Category = 'Information' + Details = 'Now running all test found in .\tests\ dir.' + } + Add-AppveyorMessage @MsgParams + $testresults = Invoke-Pester -Path ".\tests\*" -ExcludeTag 'Disabled' -PassThru + ForEach ($Item in $testresults.TestResult) { + Switch ($Item.Result) { + "Passed" { + $TestParams = @{ + Name = "{0}: {1}" -f $Item.Context, $Item.Name + Framework = "NUnit" + Filename = $Item.Describe + Outcome = "Passed" + Duration = $Item.Time.Milliseconds + } + Add-AppveyorTest @TestParams + } + "Failed" { + $TestParams = @{ + Name = "{0}: {1}" -f $Item.Context, $Item.Name + Framework = "NUnit" + Filename = $Item.Describe + Outcome = "Failed" + Duration = $Item.Time.Milliseconds + ErrorMessage = $Item.FailureMessage + ErrorStackTrace = $Item.StackTrace + } + Add-AppveyorTest @TestParams + } + Default { + $TestParams = @{ + Name = "{0}: {1}" -f $Item.Context, $Item.Name + Framework = "NUnit" + Filename = $Item.Describe + Outcome = "None" + Duration = $Item.Time.Milliseconds + ErrorMessage = $Item.FailureMessage + ErrorStackTrace = $Item.StackTrace + } + Add-AppveyorTest @TestParams + } + } + } + If ($testresults.FailedCount -gt 0) { + $MsgParams = @{ + Message = 'Pester Tests failed.' + Category = 'Error' + Details = "$($testresults.FailedCount) tests failed." + } + Add-AppveyorMessage @MsgParams + Throw $MsgParams.Message + } + +} + +Function Invoke-CoverageReport() { + [CmdletBinding()] + Param( + [Parameter(Mandatory = $False)] + [ValidateNotNullOrEmpty()] + [String]$RepoToken = $Env:CoverallsToken + ) + + Import-Module '.\src\PSCoverage.psm1' -Verbose -Force + $FileMap = New-PesterFileMap -SourceRoot '.\src' -PesterRoot '.\tests' + $CoverageReport = New-CoverageReport -PesterFileMap $FileMap -RepoToken $RepoToken + Write-Host "CoverageReport JSON:" -ForegroundColor Yellow + $CoverageReport | Out-String | Write-Host + Publish-CoverageReport -CoverageReport $CoverageReport +} + +Function Invoke-AppVeyorPSGallery() { + [CmdletBinding()] + Param() + 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 + Get-PackageProvider -ListAvailable + Write-Host "Available Package Sources:" -ForegroundColor Yellow + Get-PackageSource + Try { + Write-Host "Try to get NuGet Provider:" -ForegroundColor Yellow + Get-PackageProvider -Name NuGet -ErrorAction Stop + } + Catch { + Write-Host "Installing NuGet..." -ForegroundColor 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 + } + Else { + Write-Host "Skip publishing to PS Gallery because we are on $($env:APPVEYOR_REPO_BRANCH) branch." -ForegroundColor 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 + } + } + Catch { + $MsgParams = @{ + Message = 'Could not deploy module to PSGallery.' + Category = 'Error' + Details = $_.Exception.Message + } + Add-AppveyorMessage @MsgParams + Throw $MsgParams.Message + } +} -- 2.47.2 From 53ebbb28276550f51a045dd22f2608b0c183f7fb Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 14:25:50 +0200 Subject: [PATCH 02/37] fix module manifest encoding --- src/PSCredentialStore.psd1 | 6 +++--- src/PSCredentialStore.psm1 | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/PSCredentialStore.psm1 diff --git a/src/PSCredentialStore.psd1 b/src/PSCredentialStore.psd1 index 8900b1b..0498f08 100644 --- a/src/PSCredentialStore.psd1 +++ b/src/PSCredentialStore.psd1 @@ -9,10 +9,10 @@ @{ # Script module or binary module file associated with this manifest. - # RootModule = '' + RootModule = 'PSCredentialStore' # Version number of this module. - ModuleVersion = '1.0' + ModuleVersion = $Env:APPVEYOR_BUILD_VERSION # Supported PSEditions # CompatiblePSEditions = @() @@ -33,7 +33,7 @@ # Description = '' # Minimum version of the Windows PowerShell engine required by this module - # PowerShellVersion = '' + PowerShellVersion = '4.0' # Name of the Windows PowerShell host required by this module # PowerShellHostName = '' diff --git a/src/PSCredentialStore.psm1 b/src/PSCredentialStore.psm1 new file mode 100644 index 0000000..61866b5 --- /dev/null +++ b/src/PSCredentialStore.psm1 @@ -0,0 +1,10 @@ +$Items = (Get-ChildItem -Path ("{0}\*.ps1" -f $PSScriptRoot ) -Recurse ).FullName | Where-Object { + $_ -notmatch "(Classes|Init)" +} +ForEach ($Item in $Items) { + # Write-Verbose ("dot sourcing file {0}" -f $Item) + . $Item +} + +# Exports are now controlled by module manifest +# Export-ModuleMember -Function * -- 2.47.2 From dce3fe65300655f0d19aaa7498a666f2e2e0abea Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 14:26:14 +0200 Subject: [PATCH 03/37] fix callsign in appveyor helper --- appveyor.yml | 2 ++ tools/AppVeyor.psm1 | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 4b42772..3db0538 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,6 +20,8 @@ install: # - ps: Update-Module 'Pester' # - ps: Install-Module -Name 'posh-git' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber # - ps: Update-Module 'posh-git' + - ps: Install-Module -Name 'PSCoverage' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber + - ps: Import-Module 'PSCoverage' - ps: Import-Module .\tools\AppVeyor.psm1 environment: diff --git a/tools/AppVeyor.psm1 b/tools/AppVeyor.psm1 index 4026add..63d5343 100644 --- a/tools/AppVeyor.psm1 +++ b/tools/AppVeyor.psm1 @@ -6,7 +6,7 @@ - Git repository name - Module name #> -$CALLSIGN = 'PSCoverage' +$CALLSIGN = 'PSCredentialStore' Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Yellow Function Invoke-AppVeyorBumpVersion() { @@ -128,7 +128,7 @@ Function Invoke-CoverageReport() { [String]$RepoToken = $Env:CoverallsToken ) - Import-Module '.\src\PSCoverage.psm1' -Verbose -Force + Import-Module ('.\src\{0}.psm1' -f $CALLSIGN) -Verbose -Force $FileMap = New-PesterFileMap -SourceRoot '.\src' -PesterRoot '.\tests' $CoverageReport = New-CoverageReport -PesterFileMap $FileMap -RepoToken $RepoToken Write-Host "CoverageReport JSON:" -ForegroundColor Yellow -- 2.47.2 From e682e94aa9010fc7174bcdfe1832335032aa1582 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 15:01:23 +0200 Subject: [PATCH 04/37] adds challenge file related functions --- src/ChallengeFile/Get-ChallengeFile.ps1 | 44 +++++++++++++++ src/ChallengeFile/Set-ChallengeFile.ps1 | 72 +++++++++++++++++++++++++ src/Helper/Get-RandomKey.ps1 | 47 ++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 src/ChallengeFile/Get-ChallengeFile.ps1 create mode 100644 src/ChallengeFile/Set-ChallengeFile.ps1 create mode 100644 src/Helper/Get-RandomKey.ps1 diff --git a/src/ChallengeFile/Get-ChallengeFile.ps1 b/src/ChallengeFile/Get-ChallengeFile.ps1 new file mode 100644 index 0000000..e4062f0 --- /dev/null +++ b/src/ChallengeFile/Get-ChallengeFile.ps1 @@ -0,0 +1,44 @@ +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 + } + } +} diff --git a/src/ChallengeFile/Set-ChallengeFile.ps1 b/src/ChallengeFile/Set-ChallengeFile.ps1 new file mode 100644 index 0000000..7024daa --- /dev/null +++ b/src/ChallengeFile/Set-ChallengeFile.ps1 @@ -0,0 +1,72 @@ +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-ErrorErrorAction Stop + } +} diff --git a/src/Helper/Get-RandomKey.ps1 b/src/Helper/Get-RandomKey.ps1 new file mode 100644 index 0000000..b1ea7e3 --- /dev/null +++ b/src/Helper/Get-RandomKey.ps1 @@ -0,0 +1,47 @@ +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)] + [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 +} -- 2.47.2 From bf54bf762d243ad9a211a54035913eecfe8cb05a Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 15:19:41 +0200 Subject: [PATCH 05/37] adds connection manager functions --- src/Connection/Connect-To.ps1 | 210 +++++++++++++++++++++++++++++ src/Connection/Disconnect-From.ps1 | 147 ++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 src/Connection/Connect-To.ps1 create mode 100644 src/Connection/Disconnect-From.ps1 diff --git a/src/Connection/Connect-To.ps1 b/src/Connection/Connect-To.ps1 new file mode 100644 index 0000000..6176f20 --- /dev/null +++ b/src/Connection/Connect-To.ps1 @@ -0,0 +1,210 @@ +function Connect-To { + <# + .SYNOPSIS + Connects to the given host using the stored CredentialStoreItem. + + .DESCRIPTION + Establish a connection to the selected host using a stored CredentialStoreItem. + + .PARAMETER RemoteHost + Specify the host, for which you would like to change the credentials. + + .PARAMETER Identifier + Defaults to "". Specify a string, which separates two CredentialStoreItems for the + same hostname. + + .PARAMETER Type + Specify the host type of the target. Currently implemented targets are: + - CiscoUcs Establish a connection to a Cisco UCS fabric interconnect. + - FTP Establish a connection to a FTP host. + - NetAppFAS Establish a connection to a NetApp Clustered ONTAP filer. + - VMware Establish a connection to a VMware vCenter or ESXi host. + + .PARAMETER Credentials + Use this parameter to bypass the stored credentials. Without this parameter Connect-To tries to read the + needed credentials from the CredenialStore. If you provide this parameter you skip this lookup behavior. + So you can use it to enable credentials without preparing any user interaction. + + .PARAMETER Path + Define a custom path to a shared CredentialStore. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + Connect-To -RemoteHost "ucs.myside.local" -Type CiscoUcs + Connect-To -RemoteHost "ftp.myside.local" -Type FTP + Connect-To -RemoteHost "fas.myside.local" -Type NetAppFAS + Connect-To -RemoteHost "esx01.myside.local" -Type VMware + + .EXAMPLE + $MyCreds = Get-Credential + Connect-To -RemoteHost "vcr01.myside.local" -Type VMware -Credentials $MyCreds + Get-VM -Name "*vlm*" | Select-Object -Property Name + Disconnect-From -RemoteHost "vcr01.myside.local" -Type VMware + + .NOTES + File Name : Connect-To.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : PSFTP, PowerCLI + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [CmdletBinding(DefaultParameterSetName = "Private")] + param( + [Parameter(Mandatory = $true, ParameterSetName = "Shared")] + [Parameter(Mandatory = $true, ParameterSetName = "Private")] + [String]$RemoteHost, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [String]$Identifier, + + [Parameter(Mandatory = $true, ParameterSetName = "Shared")] + [Parameter(Mandatory = $true, ParameterSetName = "Private")] + [ValidateSet("CiscoUcs", "FTP", "NetAppFAS", "VMware")] + [String]$Type, + + [Parameter(Mandatory = $False, ParameterSetName = "Shared")] + [Parameter(Mandatory = $False, ParameterSetName = "Private")] + [PSCredential]$Credentials, + + [Parameter(Mandatory = $False, ParameterSetName = "Shared")] + [ValidateNotNullOrEmpty()] + [String]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData, + + [Parameter(Mandatory = $false, ParameterSetNAme = "Shared")] + [Switch]$Shared + ) + + begin { + switch ($Type) { + "VMware" { + # Disable the yellow certificate warning, since we haven't replaced the SSL certs for vCenter/ESXi + $null = Set-PowerCLIConfiguration -Scope Session -InvalidCertificateAction Ignore -Confirm:$false + + # Disable connecting through proxy, since vCenter isn't somewhere we need a proxy for. + $null = Set-PowerCLIConfiguration -Scope Session -ProxyPolicy NoProxy -Confirm:$false + } + } + } + + 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. + + # Check if $Identifier has been defined, in which case we need to use different name for + # the lookup of the CredentialStoreItem. + try { + if ($Identifier -ne "") { + $RemoteHostIdentifier = "{0}/{1}" -f $Identifier, $RemoteHost + $creds = Get-CredentialStoreItem -RemoteHost $RemoteHostIdentifier -Path $Path + } + else { + $creds = Get-CredentialStoreItem -RemoteHost $RemoteHost -Path $Path + } + } + + catch { + Write-Message2 ("Unable to look up credential store item for RemoteHost {0}/Identifier {1}!" -f $RemoteHost, $Identifier) -ErrorAction Stop + } + } + else { + $creds = $Credentials + } + + if ($creds.UserName -eq "" -or $creds.Password.GetType().Name -ne "SecureString") { + # Write a error message to the log. + Write-Message2 ("Please provide valid credentials for RemoteHost {0}!" -f $RemoteHost) -ErrorAction Stop + } + else { + switch ($Type) { + "CiscoUcs" { + try { + $handle = Connect-Ucs -Name $RemoteHost -Credential $creds -ErrorAction Stop + $ExecutionContext.SessionState.PSVariable.Set("DefaultUcs", $handle) + } + + catch { + # Write a error message to the log. + Write-Message2 ("Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type) -ErrorAction Stop + } + } + "FTP" { + # First establish the FTP session + $WinSCPConParams = @{ + Credential = $creds + Hostname = $RemoteHost + Protocol = 'Ftp' + FtpMode = 'Passive' + } + try { + $Global:WinSCPSession = New-WinSCPSession @WinSCPConParams + } + catch { + throw "Could not connect to {0} using {1} protocol!" -f $RemoteHost, $Type + } + # Check the Connection State + if (!($WinSCPSession.Opened)) { + # Check the connection state and find out if the session is still open. + $MessageParams = @{ + Message = "Connection to {0} using Type {1} was established. But now it seems to be lost!" -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + "NetAppFAS" { + try { + $null = Connect-NcController -Name $RemoteHost -Credential $creds -ErrorAction Stop -HTTPS + } + + catch { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + "VMware" { + try { + Connect-VIServer -Server $RemoteHost -Credential $creds -ErrorAction Stop | Out-Null + } + + catch { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + default { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + } + } +} diff --git a/src/Connection/Disconnect-From.ps1 b/src/Connection/Disconnect-From.ps1 new file mode 100644 index 0000000..8fa8c2b --- /dev/null +++ b/src/Connection/Disconnect-From.ps1 @@ -0,0 +1,147 @@ +function Disconnect-From { + <# + .SYNOPSIS + Terminates a session established with Connect-To using a CredentialStoreItem. + + .DESCRIPTION + Terminates a session established with Connect-To using a CredentialStoreItem. + + .PARAMETER RemoteHost + Specify the remote endpoint, whose session you would like to terminate. + + .PARAMETER Identifier + Defaults to "". Specify a string, which separates two CredentialStoreItems for the + same hostname. + + .PARAMETER Type + Specify the host type of the target. Currently implemented targets are: + - CiscoUcs Establish a connection to a Cisco UCS Fabric Interconnect. + - FTP Establish a connection to a FTP host. + - NetAppFAS Establish a connection to a NetApp Clustered ONTAP filer. + - VMware Establish a connection to a VMware vCenter or ESXi host. + + .PARAMETER Force + Force the disconnect, even if the disconnect would fail. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + Disconnect-From -RemoteHost "ucs.myside.local" -Type CiscoUcs + + .EXAMPLE + Disconnect-From -RemoteHost "ftp.myside.local" -Type FTP + + .EXAMPLE + Disconnect-From -RemoteHost "fas.myside.local" -Type NetAppFAS + + .EXAMPLE + Disconnect-From -RemoteHost "esx01.myside.local" -Type VMware + + .EXAMPLE + Disconnect-From -RemoteHost "esx01.myside.local" -Type VMware -Force:$True + + .NOTES + File Name : Disconnect-To.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$RemoteHost, + + [Parameter(Mandatory = $true)] + [ValidateSet("CiscoUcs", "FTP", "NetAppFAS", "VMware")] + [string]$Type, + + [Parameter(Mandatory = $false)] + [switch]$Force + ) + + switch ($Type) { + "VMware" { + try { + if ($Force) { + Disconnect-VIServer -Server $RemoteHost -Confirm:$false -ErrorAction Stop -Force:$true + } + else { + Disconnect-VIServer -Server $RemoteHost -Confirm:$false -ErrorAction Stop + } + } + + catch { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to disconnect from {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + + } + # Check for an existing WinSCP Session var + "FTP" { + if ($Global:WinSCPSession.Opened) { + Remove-WinSCPSession -WinSCPSession $Global:WinSCPSession + } + else { + $MessageParams = @{ + Message = "There is no open WinSCP Session" + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + # DataONTAP doesn't have a CmdLet `Disconnect-NcController`. + # So we go ahead and clear the CurrentNcController variable. + "NetAppFAS" { + try { + $MessageParams = @{ + Message = "Setting {0} to `$null, which will disconnect NetAppFAS" -f $Global:CurrentNcController + ErrorAction = "Continue" + } + Write-Verbose @MessageParams + $Global:CurrentNcController = $null + } + catch { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to disconnect from {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + + } + "CiscoUcs" { + try { + Disconnect-Ucs -Ucs $RemoteHost + } + + catch { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to disconnect from {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + default { + # Write a error message to the log. + $MessageParams = @{ + Message = "Unable to disconnect from {0} using Type {1}." -f $RemoteHost, $Type + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } +} -- 2.47.2 From 571566b618e36884470ddb59730dbb6a6e686351 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 15:21:14 +0200 Subject: [PATCH 06/37] adds Test-ChallengeFile --- src/ChallengeFile/Test-ChallengeFile.ps1 | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/ChallengeFile/Test-ChallengeFile.ps1 diff --git a/src/ChallengeFile/Test-ChallengeFile.ps1 b/src/ChallengeFile/Test-ChallengeFile.ps1 new file mode 100644 index 0000000..77eaa06 --- /dev/null +++ b/src/ChallengeFile/Test-ChallengeFile.ps1 @@ -0,0 +1,48 @@ +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 + } +} -- 2.47.2 From 7416c2e5d3988fcf4adf79f022c4b9e4b899deb4 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 15:35:31 +0200 Subject: [PATCH 07/37] adds item related functions --- src/Item/Get-CredentialStoreItem.ps1 | 109 +++++++++++++++++++ src/Item/New-CredentialStoreItem.ps1 | 135 ++++++++++++++++++++++++ src/Item/Remove-CredentialStoreItem.ps1 | 94 +++++++++++++++++ src/Item/Set-CredentialStoreItem.ps1 | 114 ++++++++++++++++++++ src/Item/Test-CredentialStoreItem.ps1 | 93 ++++++++++++++++ 5 files changed, 545 insertions(+) create mode 100644 src/Item/Get-CredentialStoreItem.ps1 create mode 100644 src/Item/New-CredentialStoreItem.ps1 create mode 100644 src/Item/Remove-CredentialStoreItem.ps1 create mode 100644 src/Item/Set-CredentialStoreItem.ps1 create mode 100644 src/Item/Test-CredentialStoreItem.ps1 diff --git a/src/Item/Get-CredentialStoreItem.ps1 b/src/Item/Get-CredentialStoreItem.ps1 new file mode 100644 index 0000000..4236c50 --- /dev/null +++ b/src/Item/Get-CredentialStoreItem.ps1 @@ -0,0 +1,109 @@ +function Get-CredentialStoreItem { + <# + .SYNOPSIS + Returns the Credential from a given remote host item. + + .DESCRIPTION + Return the credential as PSCredential object. + + + .PARAMETER RemoteHost + Specify the host, for which you would like to change the credentials. + + .PARAMETER Identifier + Provide a custom identifier to the given remote host key. This enables you to store multiple credentials + for a single remote host entry. For example ad/sys1, ftp/sys1, mssql/sys1 + + .PARAMETER Path + Define a custom path to a shared CredentialStore. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .INPUTS + [None] + + .OUTPUTS + [System.Management.Automation.PSCredential] + + .EXAMPLE + $myCreds = Get-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" + + .NOTES + File Name : Get-CredentialStoreItem.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [CmdletBinding(DefaultParameterSetName = "Private")] + [OutputType([System.Management.Automation.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()] + [string]$RemoteHost, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [ValidateNotNullOrEmpty()] + [string]$Identifier, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + # First set a constand path for private CredentialStore mode. + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $env:APPDATA + } + + if ($Identifier -ne "") { + $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost + } + else { + $CredentialName = $RemoteHost + } + + if (Test-CredentialStore -Path $Path) { + $CS = Get-CredentialStore -Path $Path + $CSMembers = Get-Member -InputObject $CS + # Let`s first check if the given remote host exists as object property + if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -eq $CredentialName)) { + if ($CS.Type -eq "Private") { + $CSItem = [ordered]@{ + User = $CS.$CredentialName.User + Password = ConvertTo-SecureString -String $CS.$CredentialName.Password + } + } + 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" + Message = "Could not find credentials for the given remote host: {0}" -f $RemoteHost + } + Write-Error @MsgParams + } + } + else { + $MsgParams = @{ + ErrorAction = "Stop" + Message = "The given credential store ({0}) does not exist!" -f $Path + } + Write-Error @MsgParams + } +} diff --git a/src/Item/New-CredentialStoreItem.ps1 b/src/Item/New-CredentialStoreItem.ps1 new file mode 100644 index 0000000..b643659 --- /dev/null +++ b/src/Item/New-CredentialStoreItem.ps1 @@ -0,0 +1,135 @@ +function New-CredentialStoreItem { + <# + .SYNOPSIS + Adds a credential store item containing host, user and password to the given store. + + .DESCRIPTION + The credentials are stored without any relations to it's further use. If you need to change an existing + item please use Set-CredentialStoreItem. You need to decide afterwards, whether to use the credential for + a VIConnection, NetApp FAS or UCS Fabric Interconnect. + + .PARAMETER Path + Define the store in which you would like to add a new item. + + .PARAMETER RemoteHost + The identifier or rather name for the given credentials. + + .PARAMETER Identifier + Provide a custom identifier to the given remote host key. This enables you to store multiple credentials + for a single remote host entry. For example ad/sys1, ftp/sys1, mssql/sys1 + + .PARAMETER Credential + You can provide credentials optionally as pre existing pscredential object. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + New-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" + + .NOTES + File Name : New-CredentialStoreItem.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [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()] + [string]$RemoteHost, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [ValidateNotNullOrEmpty()] + [string]$Identifier, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [pscredential]$Credential, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + # First set a constand path for private CredentialStore mode. + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $env:APPDATA + } + + # Lets do a quick test on the given CredentialStore. + if (-not(Test-CredentialStore -Path $Path)) { + $MessageParams = @{ + Message = "Could not add anything into the given CredentailStore." + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + + # Read the file content based on the given ParameterSetName + $CSContent = Get-CredentialStore -Path $Path + + $CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S" + + if ($Identifier -ne "") { + $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost + } + else { + $CredentialName = $RemoteHost + } + + if (-not($Credential)) { + $Credential = Get-Credential -Message $CredentialName + } + + if ($Credential.UserName) { + if ($CSContent.Type -eq "Shared") { + $Key = Get-ChallengeFile + $encypted = ConvertFrom-SecureString -SecureString $Credential.Password -Key $Key + } + else { + $encypted = ConvertFrom-SecureString -SecureString $Credential.Password + } + if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype Properties) { + $MessageParams = @{ + Message = "The given host already exists. Nothing to do here." + } + Write-Warning @MessageParams + } + else { + $CredentialHash = [ordered]@{ + User = $Credential.UserName + Password = $encypted + Creation = $CurrentDate + } + Add-Member -InputObject $CSContent -Name $CredentialName -MemberType NoteProperty -Value $CredentialHash + try { + ConvertTo-Json -InputObject $CSContent | Out-File -FilePath $Path + } + catch [System.Exception] { + $MessageParams = @{ + Message = "Couldn't add item into credential store!" + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + } + else { + $MessageParams = @{ + Message = "Please Provide at least a valid user!" + ErrorAction = "Stop" + } + Write-Error @MessageParams + } +} diff --git a/src/Item/Remove-CredentialStoreItem.ps1 b/src/Item/Remove-CredentialStoreItem.ps1 new file mode 100644 index 0000000..b82cd27 --- /dev/null +++ b/src/Item/Remove-CredentialStoreItem.ps1 @@ -0,0 +1,94 @@ +function Remove-CredentialStoreItem { + <# + .SYNOPSIS + Remove the given credentials from the credential store. + + .DESCRIPTION + Use this CMDLet to completely remove an credential store item. + + .PARAMETER Path + Define the store in which your given host entry already exists. + + .PARAMETER RemoteHost + Specify the host you for which you would like to change the credentials. + + .PARAMETER Identifier + Defaults to "". Specify a string, which separates two CredentialStoreItems for the + same hostname. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .INPUTS + [None] + + .OUTPUTS + [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 + + .NOTES + File Name : Remove-CredentialStoreItem.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [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, + + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [string]$Identifier, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + # First set a constand path for private CredentialStore mode. + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $env:APPDATA + } + + # Lets do a quick test on the given CredentialStore. + if (-not(Test-CredentialStore -Path $Path)) { + $MessageParams = @{ + Message = "Could not add anything into the given CredentailStore." + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + + # Read the file content based on the given ParameterSetName + $CSContent = Get-CredentialStore -Path $Path + + if ($Identifier -ne "") { + $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost + } + else { + $CredentialName = $RemoteHost + } + + if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype Properties) { + # 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 + } + else { + $MessageParams = @{ + Message = "The given CredentailStoreItem does not exist." + } + Write-Warning @MessageParams + } +} diff --git a/src/Item/Set-CredentialStoreItem.ps1 b/src/Item/Set-CredentialStoreItem.ps1 new file mode 100644 index 0000000..6f35fe8 --- /dev/null +++ b/src/Item/Set-CredentialStoreItem.ps1 @@ -0,0 +1,114 @@ +function Set-CredentialStoreItem { + <# + .SYNOPSIS + Changes the credentials for the given remote host in the store. + + .DESCRIPTION + + .PARAMETER Path + Define the store in which your given host entry already exists. + + .PARAMETER RemoteHost + Specify the host you for which you would like to change the credentials. + + .PARAMETER Identifier + Defaults to "". Specify a string, which separates two CredentialStoreItems for the + same hostname. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + Set-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" + Set-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" -Identifier svc + + .NOTES + File Name : Set-CredentialStoreItem.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [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, + + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [string]$Identifier, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + # First set a constant path for private CredentialStore mode. + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $env:APPDATA + } + + # Lets do a quick test on the given CredentialStore. + if (-not(Test-CredentialStore -Path $Path)) { + $MessageParams = @{ + Message = "Could not add anything into the given CredentailStore." + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + + # Read the file content based on the given ParameterSetName + $CSContent = Get-CredentialStore -Path $Path + + $CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S" + + if ($Identifier -ne "") { + $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost + } + else { + $CredentialName = $RemoteHost + } + + $Creds = Get-Credential -Message $CredentialName + + if ($Creds.UserName) { + if ($CSContent.Type -eq "Shared") { + $Key = Get-ChallengeFile + $encypted = ConvertFrom-SecureString -SecureString $Creds.Password -Key $Key + } + else { + $encypted = ConvertFrom-SecureString -SecureString $Creds.Password + } + if (Get-Member -InputObject $CSContent -Name $CredentialName -Membertype Properties) { + $CSContent.$CredentialName.User = $Creds.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 + } + } + Else { + $MessageParams = @{ + Message = "Please Provide at least a valid user!" + ErrorAction = "Stop" + } + Write-Error @MessageParams + } +} diff --git a/src/Item/Test-CredentialStoreItem.ps1 b/src/Item/Test-CredentialStoreItem.ps1 new file mode 100644 index 0000000..56e9c9d --- /dev/null +++ b/src/Item/Test-CredentialStoreItem.ps1 @@ -0,0 +1,93 @@ +function Test-CredentialStoreItem() { + <# + .SYNOPSIS + Checks if the given RemoteHost identifier combination exists in the credential store. + + .DESCRIPTION + Use this cmdlet for basic checks with a single item. Check the item first with this function before + you try to interact with it. + + .PARAMETER Path + Define a custom credential store you try to read from. Without the `-Path` parameter + `Test-CredentialStoreItem` tries to read from the default private store. + + .PARAMETER RemoteHost + Specify the host, for which you would like to change the credentials. + + .PARAMETER Identifier + Adds an optional identifier to the given RemoteHost. Makes it possible to store multiple credentials + for a single host. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + If (Test-CredentialStoreItem -RemoteHost "Default") { + Get-CredentialStoreItem -RemoteHost "Default" + } + Else { + Write-Warning ("The given Remote Host {0} does not exist in the credential Store!" -f $RemoteHost) + } + + .NOTES + File Name : Test-CredentialStoreItem.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [CmdletBinding(DefaultParameterSetName = "Private")] + [OutputType([Boolean])] + param( + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$RemoteHost, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string]$Identifier, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $env:APPDATA + } + + if ($Identifier -ne "") { + $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost + } + else { + $CredentialName = $RemoteHost + } + + if (Test-CredentialStore -Path $Path) { + $CS = Get-CredentialStore -Path $Path + $CSMembers = Get-Member -InputObject $CS + if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -eq $CredentialName)) { + return $true + } + else { + return $false + } + } + else { + $MsgParams = @{ + ErrorAction = "Stop" + Message = "The given credential store ({0}) does not exist!" -f $Path + } + Write-Error @MsgParams + } +} -- 2.47.2 From 7122c2afa432b19d3c16ec5b19abdfd168d7594a Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 15:43:37 +0200 Subject: [PATCH 08/37] adds store related functions --- src/Store/Get-CredentialStore.ps1 | 69 ++++++++++++++++++ src/Store/New-CredentialStore.ps1 | 111 +++++++++++++++++++++++++++++ src/Store/Test-CredentialStore.ps1 | 61 ++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 src/Store/Get-CredentialStore.ps1 create mode 100644 src/Store/New-CredentialStore.ps1 create mode 100644 src/Store/Test-CredentialStore.ps1 diff --git a/src/Store/Get-CredentialStore.ps1 b/src/Store/Get-CredentialStore.ps1 new file mode 100644 index 0000000..8828d92 --- /dev/null +++ b/src/Store/Get-CredentialStore.ps1 @@ -0,0 +1,69 @@ +function Get-CredentialStore { + <# + .SYNOPSIS + Reads the complete content of the credential store and returns it as a new object. + + .DESCRIPTION + The content is in a raw format. It means there is no transformation to the different credential types. + You can not use the object properties to connect with remote host. Therefore please use + Get-CredentialStoreItem. + + .PARAMETER Path + Define a custom path to a shared CredentialStore. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .INPUTS + [None] + + .OUTPUTS + [PSObject] Returns the credential store content as PSObject. + + .EXAMPLE + $CSContent = Get-CredentialStore -Path "C:\TMP\mystore.json" + + .NOTES + File Name : Get-CredentialStore.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [CmdletBinding(DefaultParameterSetName = "Private")] + param( + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + if ($PSCmdlet.ParameterSetName -eq 'Private') { + $Path = "{0}\CredentialStore.json" -f $env:APPDATA + } + + if (Test-CredentialStore -Path $Path) { + try { + $FileContent = Get-Content -Path $Path -Raw + ConvertFrom-Json $FileContent + } + catch [System.Exception] { + $MessageParams = @{ + Message = "Unknown CredentialStore format. Invalid JSON file." + ErrorAction = "Stop" + } + Write-Error @MessageParams + } + } + else { + $MessageParams = @{ + Message = "Could not find the CredentialStore." + ErrorAction = "Stop" + } + Write-Error @MessageParams + } +} diff --git a/src/Store/New-CredentialStore.ps1 b/src/Store/New-CredentialStore.ps1 new file mode 100644 index 0000000..3aa3398 --- /dev/null +++ b/src/Store/New-CredentialStore.ps1 @@ -0,0 +1,111 @@ +function New-CredentialStore { + <# + .SYNOPSIS + Creates a new credential store File + + .DESCRIPTION + You need to run this script first to create a new credential store before you try to + save new credentials with New-CredentialStoreItem. + + .PARAMETER Path + Define a location for the new shared CredentialStore. The default store will be created in + $Env:ProgramData\PSCredentialStore dir. + + .PARAMETER Shared + Creates a CredentialStore in the Shared mode. This enables you to read the CredentialStore Items on + different systems or profiles. In addition you can optionally provide a custom path wit the -Path parameter. + + .PARAMETER Force + Use this switch to reset an existing store. The complete content will be wiped. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + New-CredentialStore + # Creates a new private CredentialStore + + .EXAMPLE + New-CredentialStore -Force + # Resets an existing private CredentialStore + + .EXAMPLE + New-CredentialStore -Shared + # Creates a new shead CredentialStore + + .EXAMPLE + New-CredentialStore -Shared -Path "C:\TMP\CredentialStore.json" + # Creates a new shared CredentialStore in the given location. + + .NOTES + File Name : New-CredentialStore.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + + [CmdletBinding(DefaultParameterSetName = "Private")] + param( + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [ValidateNotNullOrEmpty()] + [string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData, + + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Force + ) + + # Lets get the current Date in a human readable format. + $CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S" + + # Set latest Credential Store version + Set-Variable -Name "CSVersion" -Value "1.2.0" -Option Constant + + # Set the CredentialStore path for private mode. + Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $Env:APPDATA + } + + # Test if in the given store already a CredentialStore exists. + Write-Verbose "Test if there is already a credential store." + if ((Test-CredentialStore -Path $Path) -and ($Force -ne $true)) { + $MessageParam = @{ + Message = "The given file already exists. Use the 'Force' switch to override the existing store." + ErrorAction = "Stop" + } + Write-Error @MessageParam + } + # We need to use the IDictionary to keep the property sorting in the object. + $ObjProperties = [ordered]@{ + Version = $CSVersion + Creation = $CurrentDate + } + if ($PSCmdlet.ParameterSetName -eq "Shared") { + $ObjProperties.Type = "Shared" + # Check if a ChallengeFile already exists. We don't want to overide it. + # Otherwise previous created CredentialStores couln't be decrypted anymore. + if (-not (Test-ChallengeFile)) { + Set-ChallengeFile + } + } + else { + $ObjProperties.Type = "Private" + } + # Create a new object for easy conversion into a json file + $CredentialStoreObj = New-Object -TypeName psobject -Property $ObjProperties + try { + ConvertTo-Json -InputObject $CredentialStoreObj | Out-File -FilePath $Path + } + catch [System.Exception] { + $_.Exception | Format-List -Force | Out-String | Write-Error -ErrorAction Stop + } +} diff --git a/src/Store/Test-CredentialStore.ps1 b/src/Store/Test-CredentialStore.ps1 new file mode 100644 index 0000000..cf72109 --- /dev/null +++ b/src/Store/Test-CredentialStore.ps1 @@ -0,0 +1,61 @@ +function Test-CredentialStore { + <# + .SYNOPSIS + Returns the credential store state. + + .DESCRIPTION + Use this script to test your credential store. For now it only checks if + the file exists. + + .PARAMETER Path + Define a custom path to a shared CredentialStore. + + .PARAMETER Shared + Switch to shared mode with this param. This enforces the command to work with a shared CredentialStore which + can be decrypted across systems. + + .NOTES + File Name : Test-CredentialStore.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [CmdletBinding(DefaultParameterSetName = "Private")] + param( + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [string]$Path = "{0}\PSCredentialStore\CredentialStore.json" -f $env:ProgramData, + + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [switch]$Shared + ) + + + if ($PSCmdlet.ParameterSetName -eq "Private") { + $Path = "{0}\CredentialStore.json" -f $Env:APPDATA + } + + # Set latest Credential Store version + Set-Variable -Name "CSVersion" -Value "1.2.0" -Option Constant + + if (Test-Path $Path) { + Write-Verbose "CredentialStore in given path found." + + # try tor read the store. Removed the Get-CredentialStore function to avoid recursive calls. + try { + $FileContent = Get-Content -Path $Path -Raw + $CSContent = ConvertFrom-Json $FileContent + } + catch { + Write-Warning "Could not read or convert the given CredentialStore." + Return $False + } + Return $True + + } + Else { + Write-Verbose "The given CredentialStore does not exist!" + Return $False + } +} -- 2.47.2 From 6e442af8a42ead90c4ffb66d4ea0c4d58e436b49 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 27 Jul 2017 15:44:09 +0200 Subject: [PATCH 09/37] adds cSpell dictionary --- .vscode/cSpell.json | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/.vscode/cSpell.json b/.vscode/cSpell.json index ed2510a..40cc042 100644 --- a/.vscode/cSpell.json +++ b/.vscode/cSpell.json @@ -6,29 +6,30 @@ "language": "en", // words - list of words to be always considered correct "words": [ - "Ponduit", - "NTFS", - "Repo", - "Hashtable", - "googlemail", "Cmdlet", - "appveyor", - "GUID", - "wildcards", "Cmdlets", - "codecoverage", - "notmatch", + "GUID", + "Hashtable", "Httpclient", "Multipart", - "formdata", - "callsign", - "Veyor", - "notlike", + "NTFS", "Params", - "testresults", - "powershellgallery", + "Ponduit", + "Repo", + "Veyor", + "appveyor", + "callsign", + "choco", "chocolatey", - "choco" + "codecoverage", + "creds", + "formdata", + "googlemail", + "notlike", + "notmatch", + "powershellgallery", + "testresults", + "wildcards" ], // flagWords - list of words to be always considered incorrect // This is useful for offensive words and common spelling errors. -- 2.47.2 From 323ab64226aa0d046685de418e7a4d584d4799bb Mon Sep 17 00:00:00 2001 From: OCram85 Date: Fri, 28 Jul 2017 11:21:10 +0200 Subject: [PATCH 10/37] adds CredentialStore related Pester tests --- tests/Store/00_Get-CredentialStore.Tests.ps1 | 37 +++++++++++++++++ tests/Store/00_Test-CredentialStore.Tests.ps1 | 40 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/Store/00_Get-CredentialStore.Tests.ps1 create mode 100644 tests/Store/00_Test-CredentialStore.Tests.ps1 diff --git a/tests/Store/00_Get-CredentialStore.Tests.ps1 b/tests/Store/00_Get-CredentialStore.Tests.ps1 new file mode 100644 index 0000000..ad8e490 --- /dev/null +++ b/tests/Store/00_Get-CredentialStore.Tests.ps1 @@ -0,0 +1,37 @@ +#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 . +# . (Get-ChildItem -Path $RepoRoot -Filter ".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 + } + } +} diff --git a/tests/Store/00_Test-CredentialStore.Tests.ps1 b/tests/Store/00_Test-CredentialStore.Tests.ps1 new file mode 100644 index 0000000..693184f --- /dev/null +++ b/tests/Store/00_Test-CredentialStore.Tests.ps1 @@ -0,0 +1,40 @@ +#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 . +# . (Get-ChildItem -Path $RepoRoot -Filter ".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 + } + } +} -- 2.47.2 From dae04d72c52e1ee24cf566e1efd272dbe32ab946 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 10:58:22 +0200 Subject: [PATCH 11/37] [WIP] test Pester file --- tests/Store/00_New-CredentialStore.Tests.ps1 | 111 +++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 tests/Store/00_New-CredentialStore.Tests.ps1 diff --git a/tests/Store/00_New-CredentialStore.Tests.ps1 b/tests/Store/00_New-CredentialStore.Tests.ps1 new file mode 100644 index 0000000..9753d93 --- /dev/null +++ b/tests/Store/00_New-CredentialStore.Tests.ps1 @@ -0,0 +1,111 @@ +#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 . +# . (Get-ChildItem -Path $RepoRoot -Filter ".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 -ErrorAction SilentlyContinue | ConvertFrom-Json -ErrorAction SilentlyContinue + ($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 + } + } +} + +# 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" -- 2.47.2 From f01489fe802b85690abe35fdb259daa4ba9937d2 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 11:15:07 +0200 Subject: [PATCH 12/37] fix typo --- src/Store/New-CredentialStore.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Store/New-CredentialStore.ps1 b/src/Store/New-CredentialStore.ps1 index 3aa3398..6bbe19f 100644 --- a/src/Store/New-CredentialStore.ps1 +++ b/src/Store/New-CredentialStore.ps1 @@ -34,7 +34,7 @@ function New-CredentialStore { .EXAMPLE New-CredentialStore -Shared - # Creates a new shead CredentialStore + # Creates a new shared CredentialStore .EXAMPLE New-CredentialStore -Shared -Path "C:\TMP\CredentialStore.json" -- 2.47.2 From c86ac723cb6c302c40bce11e5ebd743b0b34e2af Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 11:15:39 +0200 Subject: [PATCH 13/37] adds file dependencies --- tests/Store/00_Get-CredentialStore.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Store/00_Get-CredentialStore.Tests.ps1 b/tests/Store/00_Get-CredentialStore.Tests.ps1 index ad8e490..5fbe500 100644 --- a/tests/Store/00_Get-CredentialStore.Tests.ps1 +++ b/tests/Store/00_Get-CredentialStore.Tests.ps1 @@ -14,7 +14,7 @@ Else { } # load additional functions defined in the repository. Replace the expression . -# . (Get-ChildItem -Path $RepoRoot -Filter ".ps1" -Recurse).FullName +. (Get-ChildItem -Path $RepoRoot -Filter "Test-CredentialStore.ps1" -Recurse).FullName #endregion HEADER -- 2.47.2 From 00190b8d8088dea437448405b996e48e704f6629 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 11:16:09 +0200 Subject: [PATCH 14/37] [WIP] fix pester tests --- tests/Store/00_New-CredentialStore.Tests.ps1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Store/00_New-CredentialStore.Tests.ps1 b/tests/Store/00_New-CredentialStore.Tests.ps1 index 9753d93..a3da36e 100644 --- a/tests/Store/00_New-CredentialStore.Tests.ps1 +++ b/tests/Store/00_New-CredentialStore.Tests.ps1 @@ -14,7 +14,9 @@ Else { } # load additional functions defined in the repository. Replace the expression . -# . (Get-ChildItem -Path $RepoRoot -Filter ".ps1" -Recurse).FullName +. (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 #endregion HEADER @@ -46,7 +48,7 @@ Describe "New-CredentialStore" { It "Test1: Create new private CredentialStore" { New-CredentialStore $result = Test-Path -Path $pCS - $CS = Get-Content -Path $pCS -Raw -ErrorAction SilentlyContinue | ConvertFrom-Json -ErrorAction SilentlyContinue + $CS = Get-Content -Path $pCS -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue ($result -eq $True) -and ($CS.Type -eq "Private") | Should Be $True } It "Test2: Try to override private Store" { -- 2.47.2 From 0f41700354ac684d27c84845886b3bca0de08919 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 11:27:24 +0200 Subject: [PATCH 15/37] fix exception state --- src/ChallengeFile/Set-ChallengeFile.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChallengeFile/Set-ChallengeFile.ps1 b/src/ChallengeFile/Set-ChallengeFile.ps1 index 7024daa..926c3f5 100644 --- a/src/ChallengeFile/Set-ChallengeFile.ps1 +++ b/src/ChallengeFile/Set-ChallengeFile.ps1 @@ -67,6 +67,6 @@ Function Set-ChallengeFile() { [io.file]::WriteAllBytes($Path, $Keys) } catch { - $_.Exception | Format-List -Force | Out-String | Write-ErrorErrorAction Stop + $_.Exception | Format-List -Force | Out-String | Write-Error -ErrorAction Stop } } -- 2.47.2 From d13e5da92cd362ed1bbf9c4a102057e70a33332a Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 11:52:31 +0200 Subject: [PATCH 16/37] [WIP] add file dependencies --- tests/Store/00_New-CredentialStore.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Store/00_New-CredentialStore.Tests.ps1 b/tests/Store/00_New-CredentialStore.Tests.ps1 index a3da36e..e633374 100644 --- a/tests/Store/00_New-CredentialStore.Tests.ps1 +++ b/tests/Store/00_New-CredentialStore.Tests.ps1 @@ -17,6 +17,7 @@ Else { . (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 -- 2.47.2 From b177e1f226677b9d55b20d7c2a44c521b86e26c7 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 13:36:28 +0200 Subject: [PATCH 17/37] fix gitkeep filename --- bin/{.gitignore => .gitkeep} | 0 resources/{.gitignore => .gitkeep} | 0 tests/{.gitignore => .gitkeep} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename bin/{.gitignore => .gitkeep} (100%) rename resources/{.gitignore => .gitkeep} (100%) rename tests/{.gitignore => .gitkeep} (100%) diff --git a/bin/.gitignore b/bin/.gitkeep similarity index 100% rename from bin/.gitignore rename to bin/.gitkeep diff --git a/resources/.gitignore b/resources/.gitkeep similarity index 100% rename from resources/.gitignore rename to resources/.gitkeep diff --git a/tests/.gitignore b/tests/.gitkeep similarity index 100% rename from tests/.gitignore rename to tests/.gitkeep -- 2.47.2 From b12a441a9277c88748d905fec9000da5ef215986 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 16 Aug 2017 13:47:41 +0200 Subject: [PATCH 18/37] set constant debug module version string --- src/PSCredentialStore.psd1 | 3 ++- tools/AppVeyor.psm1 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PSCredentialStore.psd1 b/src/PSCredentialStore.psd1 index 0498f08..69f08ce 100644 --- a/src/PSCredentialStore.psd1 +++ b/src/PSCredentialStore.psd1 @@ -12,7 +12,8 @@ RootModule = 'PSCredentialStore' # Version number of this module. - ModuleVersion = $Env:APPVEYOR_BUILD_VERSION + # Do not touch the version number. It gets replaced in the build process. + ModuleVersion = '0.0.0.9999' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/tools/AppVeyor.psm1 b/tools/AppVeyor.psm1 index 63d5343..58f916d 100644 --- a/tools/AppVeyor.psm1 +++ b/tools/AppVeyor.psm1 @@ -19,7 +19,7 @@ Function Invoke-AppVeyorBumpVersion() { Try { $ModManifest = Get-Content -Path (".\src\{0}.psd1" -f $CALLSIGN) - $BumpedManifest = $ModManifest -replace '\$Env:APPVEYOR_BUILD_VERSION', "'$Env:APPVEYOR_BUILD_VERSION'" + $BumpedManifest = $ModManifest -replace '0.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 } -- 2.47.2 From 6ef95ba299560768b9a3529168205c3c39f2e267 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Mon, 21 Aug 2017 09:13:40 +0200 Subject: [PATCH 19/37] adds Pester Tests for New-CredentialStoreItem --- .../Item/01_New-CredentialStoreItem.Tests.ps1 | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tests/Item/01_New-CredentialStoreItem.Tests.ps1 diff --git a/tests/Item/01_New-CredentialStoreItem.Tests.ps1 b/tests/Item/01_New-CredentialStoreItem.Tests.ps1 new file mode 100644 index 0000000..9624c2b --- /dev/null +++ b/tests/Item/01_New-CredentialStoreItem.Tests.ps1 @@ -0,0 +1,65 @@ +#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 . +. (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 `{ } | 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 + } + } +} -- 2.47.2 From 401830c13801cd4a02d3f619286fc7c56c89ef9b Mon Sep 17 00:00:00 2001 From: OCram85 Date: Mon, 21 Aug 2017 10:56:44 +0200 Subject: [PATCH 20/37] adds basic readme file --- README.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6bb1a66..ca7beb9 100644 --- a/README.md +++ b/README.md @@ -1 +1,76 @@ -# PSCredentialStore \ No newline at end of file +| AppVeyor Overall | AppVeyor Master | AppVeyor Dev | Coveralls.io | Download | +| :--------------: | :-------------: | :----------: | :-----------: | :--------:| +| [![Build status](https://ci.appveyor.com/api/projects/status/b4t8x88xai3ee7gk?svg=true)](https://ci.appveyor.com/project/OCram85/PSCredentialStore) | [![Build status](https://ci.appveyor.com/api/projects/status/b4t8x88xai3ee7gk/branch/master?svg=true)](https://ci.appveyor.com/project/OCram85/PSCredentialStore/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/b4t8x88xai3ee7gk/branch/dev?svg=true)](https://ci.appveyor.com/project/OCram85/PSCredentialStore/branch/dev) | [![Coverage Status](https://coveralls.io/repos/github/OCram85/PSCredentialStore/badge.svg?branch=master)](https://coveralls.io/github/OCram85/PSCredentialStore?branch=master) | [![Download](https://img.shields.io/badge/powershellgallery-PSCredentialStore-blue.svg)](https://www.powershellgallery.com/packages/PSCredentialStore) + +General +======= + +The PSCredentialStore is an simple credential manager for PSCredentials. It stores multiple credential object in a +simple json file. Either as private file in your profile or in shared mode in other locations. + +PSCredentialStore was developed to simplify the delegation of complex powershell scripts. In this case you often +need to store credentials for non interactive usage like in sheduled tasks. + +To get started read the [about_PSCredentialStore](/src/en-US/about_PSCredential.help.txt) page. + +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` +* Done. Start exploring the Module with `Import-Module PSCredentialStore ; Get-Command -Module PSCredentialStore` + +Manual Way +---------- + +* Take a look at the [Latest Release](https://github.com/OCram85/PSCredentialStore/releases/latest) page. +* Download the `PSCredentialStore.zip`. +* Unpack the Zip and put it in your Powershell Module path. + * Don't forget to change the NTFS permission flag in the context menu. +* Start with `Import-Module PSCredentialStore` + +Quick Start +----- + +**1.** First we need a blank CredentialStore. You can decide between a *private* or *shared* store. The private +Credential Store can only be accessed with your profile on the machine you created it. +```powershell +# Private Credential Store +New-CredentialStore + +# Shared Credential Store +New-CredentialStore -Shared + +#Shared CredentialStore in custom Location +New-CredentialStore -Shared -Path 'C:\CredentialStore.json' +``` + +**2.** Now you can manage your CredentialStoreItems: +```powershell +# This will prompt for credentials and stores it in a private store +New-CredentialStoreItem -RemoteHost 'dc01.myside.local' -Identifier 'AD' + +# You can now use it in other scripts like this: +$DCCreds = Get-CredentialStoreItem -RemoteHost 'dc01.myside.local' -Identifier 'AD' +Invoke-Command -ComputerName 'dc01.myside.local' -Credential $DCCreds -ScripBlock {Get-Process} +``` + +The CredentialStore contains also a simple function to establish a connection with the given remotehost in different +ways. If you have already installed the underlying framework your can conntect to: + - CiscoUcs - Establish a connection to a Cisco UCS fabric interconnect. + - FTP - Establish a connection to a FTP host. + - NetAppFAS - Establish a connection to a NetApp Clustered ONTAP filer. + - VMware - Establish a connection to a VMware vCenter or ESXi host. + +Here are some basic examples: + +```powershell +Connect-To -RemoteHost "ucs.myside.local" -Type CiscoUcs +Connect-To -RemoteHost "ftp.myside.local" -Type FTP +Connect-To -RemoteHost "fas.myside.local" -Type NetAppFAS +Connect-To -RemoteHost "esx01.myside.local" -Type VMware +``` -- 2.47.2 From 992281998f161f62d659799b8594a032d9a4b913 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Sat, 9 Sep 2017 16:43:12 +0200 Subject: [PATCH 21/37] adds functions to export; adds meta data --- src/PSCredentialStore.psd1 | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/PSCredentialStore.psd1 b/src/PSCredentialStore.psd1 index 69f08ce..52bb2ae 100644 --- a/src/PSCredentialStore.psd1 +++ b/src/PSCredentialStore.psd1 @@ -70,7 +70,22 @@ # NestedModules = @() # 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 = @() + FunctionsToExport = @( + # Connection Group + 'Connect-To', + 'Disconnect-From', + # Item Group + 'Get-CredentialStoreItem', + 'Set-CredentialStoreItem', + 'New-CredentialStoreItem', + 'Remove-CredentialStoreItem', + 'Test-CredentialStoreItem', + # Store Group + 'Get-CredentialStore', + 'New-CredentialStore', + 'Test-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. CmdletsToExport = @() @@ -96,13 +111,15 @@ PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. - # Tags = @() + Tags = @('Credential Store', + 'Credential Manager' + ) # A URL to the license for this module. - # LicenseUri = '' + LicenseUri = 'https://github.com/OCram85/PSCredentialStore/blob/master/LICENSE' # A URL to the main website for this project. - # ProjectUri = '' + ProjectUri = 'https://github.com/OCram85/PSCredentialStore' # A URL to an icon representing this module. # IconUri = '' @@ -115,10 +132,9 @@ } # End of PrivateData hashtable # HelpInfo URI of this module - # HelpInfoURI = '' + HelpInfoURI = 'https://github.com/OCram85/PSCredentialStore' # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' } - -- 2.47.2 From d246ada19f6086f33dd70fe22879ec8316892adf Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 20 Sep 2017 16:08:28 +0200 Subject: [PATCH 22/37] adds vscode debug config --- .vscode/launch.json | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a89c67e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File", + "script": "${file}", + "args": [], + "cwd": "${file}" + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File in Temporary Console", + "script": "${file}", + "args": [], + "cwd": "${file}", + "createTemporaryIntegratedConsole": true + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File w/Args Prompt", + "script": "${file}", + "args": [ + "${command:SpecifyScriptArgs}" + ], + "cwd": "${file}" + }, + { + "type": "PowerShell", + "request": "attach", + "name": "PowerShell Attach to Host Process", + "processId": "${command:PickPSHostProcess}", + "runspaceId": 1 + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Interactive Session", + "cwd": "${workspaceRoot}" + } + ] +} \ No newline at end of file -- 2.47.2 From b31c201a1c1d2903f598b7f6a74b9e623f32d933 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 20 Sep 2017 16:08:48 +0200 Subject: [PATCH 23/37] adds test for optional dependencies --- src/Dependency.json | 26 ++++++++ src/Helper/Resolve-Dependency.ps1 | 37 +++++++++++ src/Helper/Test-Module.ps1 | 105 ++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 src/Dependency.json create mode 100644 src/Helper/Resolve-Dependency.ps1 create mode 100644 src/Helper/Test-Module.ps1 diff --git a/src/Dependency.json b/src/Dependency.json new file mode 100644 index 0000000..6e1e2bd --- /dev/null +++ b/src/Dependency.json @@ -0,0 +1,26 @@ +{ + "Version": 0.1, + "Mandatory": {}, + "Optional": [ + { + "Name": "VMware", + "Modules": [ + "VMware.VimAutomation.Core" + ] + }, + { + "Name": "CiscoUCS", + "Modules": [] + }, + { + "Name": "FTP", + "Modules": [ + "WinSCP" + ] + }, + { + "Name": "NetAppFAS", + "Modules": [] + } + ] +} diff --git a/src/Helper/Resolve-Dependency.ps1 b/src/Helper/Resolve-Dependency.ps1 new file mode 100644 index 0000000..c3bb794 --- /dev/null +++ b/src/Helper/Resolve-Dependency.ps1 @@ -0,0 +1,37 @@ +function Resolve-Dependency { + [OutputType([bool])] + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$Name + ) + + begin { + $ModuleRootDir = $MyInvocation.MyCommand.Module.ModuleBase + $DepFilePath = Join-Path -Path $ModuleRootDir -ChildPath "Dependency.json" + if (Test-Path -Path $DepFilePath) { + $Dependency = Get-Content -Path $DepFilePath -Raw -Encoding UTF8 | ConvertFrom-Json + } + else { + Write-Warning ("Could not find the dependency file: {0}" -f $DepFilePath) + } + $res = @() + } + + process { + $SelectedDependency = $Dependency.Optional | Where-Object {$_.Name -match $Name} + + foreach ($Module in $SelectedDependency.Modules) { + $res += Test-Module -Name $Module + } + if ($res -contains $false) { + return $false + } + else { + return $true + } + } + + end { + } +} diff --git a/src/Helper/Test-Module.ps1 b/src/Helper/Test-Module.ps1 new file mode 100644 index 0000000..174dd32 --- /dev/null +++ b/src/Helper/Test-Module.ps1 @@ -0,0 +1,105 @@ +function Test-Module { + <# + .SYNOPSIS + Internal helper to check optional dependencies. + + .DESCRIPTION + Test-Dependency checks if the given module or pssnapin is available on the system. It returns a bool value + So it is possible to use this function in a if condition. + + .PARAMETER Name + Define a item name you need to test + + .PARAMETER Type + Define the dependency type. This could be a Module or PSnapin. + + .PARAMETER MessagePattern + You an optionally adjust the message pattern for the error message itself. + The available placeholders are: + - {0} : Type + - {1} : Name + + .PARAMETER StopIfFails + This switch forces the entire script to stop if the given dependency object fails. + + .INPUTS + [None] + + .OUTPUTS + [Bool] + + .EXAMPLE + .\Test-Dependency -Name 'VMware.PowerCLI' -Type 'Module' + + .EXAMPLE + .\Test-Dependency -Name 'VMware.PowerCLI' -Type 'Module' -StopIfFails + + .NOTES + File Name : Get-RandomKey.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [OutputType([bool])] + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$Name, + + [Parameter(Mandatory = $false)] + [ValidateSet('Module', 'PSSnapin', 'Custom')] + [string]$Type = 'Module', + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string]$MessagePattern = @" +Could not find the required {0} called {1}. Please install the required {0} to run this function! +"@, + [Parameter(Mandatory = $false)] + [switch]$StopIfFails + ) + begin { + + } + + process { + $Message = $MessagePattern -f $Type, $Name + Write-Debug $Message + switch ($Type) { + 'Module' { + if (Get-Module -Name $Name -ListAvailable) { + return $true + } + else { + if ($StopIfFails) { + Write-Error -Message $Message -ErrorAction Stop -Category NotInstalled + } + return $false + } + } + + 'PSSnapin' { + if (Get-PSSnapin -Name $Name -Registered) { + return $true + } + else { + if ($StopIfFails) { + Write-Error -Message $Message -ErrorAction Stop -Category NotInstalled + return $false + } + } + } + + 'Custom' { + Throw 'Custom tests are not implemented yet!' + } + } + } + + end { + + } +} -- 2.47.2 From 97625881e96543e834fa1926d269663832b6ae68 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 20 Sep 2017 16:09:59 +0200 Subject: [PATCH 24/37] [WIP] Implements optional dependency test --- src/Connection/Connect-To.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Connection/Connect-To.ps1 b/src/Connection/Connect-To.ps1 index 6176f20..84d9244 100644 --- a/src/Connection/Connect-To.ps1 +++ b/src/Connection/Connect-To.ps1 @@ -22,7 +22,7 @@ function Connect-To { .PARAMETER Credentials Use this parameter to bypass the stored credentials. Without this parameter Connect-To tries to read the - needed credentials from the CredenialStore. If you provide this parameter you skip this lookup behavior. + needed credentials from the CredentialStore. If you provide this parameter you skip this lookup behavior. So you can use it to enable credentials without preparing any user interaction. .PARAMETER Path @@ -86,6 +86,10 @@ function Connect-To { ) begin { + # 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' + } switch ($Type) { "VMware" { # Disable the yellow certificate warning, since we haven't replaced the SSL certs for vCenter/ESXi @@ -98,7 +102,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 -- 2.47.2 From dcc30c357de9a5b543d41d1da037c8a3e7cbd92b Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 20 Sep 2017 16:21:36 +0200 Subject: [PATCH 25/37] adds taskrunner definitions --- .vscode/tasks.json | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..25a0693 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + // Start PowerShell + "windows": { + "command": "${env:windir}/System32/WindowsPowerShell/v1.0/powershell.exe", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass" + ] + }, + "linux": { + "command": "/usr/bin/powershell", + "args": [ + "-NoProfile" + ] + }, + "osx": { + "command": "/usr/local/bin/powershell", + "args": [ + "-NoProfile" + ] + }, + "tasks": [ + { + "taskName": "Test", + "suppressTaskName": true, + "isTestCommand": true, + "args": [ + "Write-Host 'Invoking Pester...'; $ProgressPreference = 'SilentlyContinue'; Invoke-Pester -Script '.\\tests\\*' -EnableExit $flase -PesterOption @{IncludeVSCodeMarker=$true};", + "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" + ], + "problemMatcher": "$pester", + "group": { + "kind": "test", + "isDefault": true + } + } + ] +} -- 2.47.2 From f6728a747fdaedb8ed076abc1a0979bbc022643a Mon Sep 17 00:00:00 2001 From: OCram85 Date: Wed, 20 Sep 2017 16:38:57 +0200 Subject: [PATCH 26/37] adds CBH --- src/Helper/Resolve-Dependency.ps1 | 48 +++++++++++++++++++++++++++++++ src/Helper/Test-Module.ps1 | 5 ++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/Helper/Resolve-Dependency.ps1 b/src/Helper/Resolve-Dependency.ps1 index c3bb794..9d76571 100644 --- a/src/Helper/Resolve-Dependency.ps1 +++ b/src/Helper/Resolve-Dependency.ps1 @@ -1,4 +1,52 @@ function Resolve-Dependency { + <# + .SYNOPSIS + Tests defined optional dependencies and returns the result as bool. + + .DESCRIPTION + Use this function to test for optional modules. You can use it if you provide functions which needs special + modules but you don't want to make them required. + + Place a file called Dependency.json in your module root dir. The default format is: + + { + "Version": 0.1, + "Mandatory": {}, + "Optional": [ + { + "Name": "VMware", + "Modules": [ + "VMware.VimAutomation.Core" + ] + }, + { + "Name": "CiscoUCS", + "Modules": [] + } + ] + } + + .PARAMETER Name + Select the dependency item name you defined in the dependency.json. + .INPUTS + [None] + + .OUTPUTS + [bool] + + .EXAMPLE + If (-not (Resolve-Dependency -Name 'VMware')) { + Write-Error -Message ("Could not resolve the optional dependencies defined for {0}" -f 'VMware') -ErrorAction 'Stop' + } + + .NOTES + File Name : ResolveDependency.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> [OutputType([bool])] [CmdletBinding()] param ( diff --git a/src/Helper/Test-Module.ps1 b/src/Helper/Test-Module.ps1 index 174dd32..7f18f95 100644 --- a/src/Helper/Test-Module.ps1 +++ b/src/Helper/Test-Module.ps1 @@ -1,11 +1,10 @@ function Test-Module { <# .SYNOPSIS - Internal helper to check optional dependencies. + Tests if the given module exists on the local system. .DESCRIPTION - Test-Dependency checks if the given module or pssnapin is available on the system. It returns a bool value - So it is possible to use this function in a if condition. + Tests if the given module is installed on the local system. It returns a bool value as result. .PARAMETER Name Define a item name you need to test -- 2.47.2 From c3b2af7687fb6e7bac20b56b91158e5961b99738 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 08:15:04 +0200 Subject: [PATCH 27/37] add gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72269a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Don't local track test builds +bin/PSCredentialStore.zip -- 2.47.2 From d644498f1ad992a762a8f384f49def02acce41bf Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 08:42:30 +0200 Subject: [PATCH 28/37] adds basic Build tasks --- .vscode/tasks.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 25a0693..304f242 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -37,6 +37,19 @@ "kind": "test", "isDefault": true } + }, + { + "taskName": "DebugBuild", + "suppressTaskName": true, + "args": [ + "Write-Host 'Invoking Build...';", + "If (Test-Path -Path '.\\bin\\PSCredentialStore.zip') { Remove-Item -Path '.\\bin\\PSCredentialStore.zip' -Verbose};", + "Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose" + ], + "group": { + "kind": "build", + "isDefault": true + } } ] } -- 2.47.2 From 43c94f385382aa8bd10b8d02d51080677c82ff22 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 10:58:39 +0200 Subject: [PATCH 29/37] typo fixed --- src/Connection/Connect-To.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection/Connect-To.ps1 b/src/Connection/Connect-To.ps1 index 84d9244..740ee6a 100644 --- a/src/Connection/Connect-To.ps1 +++ b/src/Connection/Connect-To.ps1 @@ -87,7 +87,7 @@ function Connect-To { begin { # First check the optional modules - If (-not (Resolve-Dependency -Name $Type)) { + if (-not (Resolve-Dependency -Name $Type)) { Write-Error -Message ("Could not resolve the optional dependencies defined for {0}" -f $Type) -ErrorAction 'Stop' } switch ($Type) { -- 2.47.2 From f731d4773e844d8ecff379935db9eb6136cc339b Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 10:58:56 +0200 Subject: [PATCH 30/37] adds build folder to ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 72269a5..45b36c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ # Don't local track test builds bin/PSCredentialStore.zip +bin/PSCredentialStore/* -- 2.47.2 From a5c252c425e9caff8a8d93a83ce4f8957f43614d Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 10:59:18 +0200 Subject: [PATCH 31/37] adds Cisco and NetApp opt dependencies --- src/Dependency.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Dependency.json b/src/Dependency.json index 6e1e2bd..d76a42f 100644 --- a/src/Dependency.json +++ b/src/Dependency.json @@ -10,7 +10,10 @@ }, { "Name": "CiscoUCS", - "Modules": [] + "Modules": [ + "Cisco.UCS.Core", + "Cisco.UCSManager" + ] }, { "Name": "FTP", @@ -20,7 +23,9 @@ }, { "Name": "NetAppFAS", - "Modules": [] + "Modules": [ + "DataONTAP" + ] } ] } -- 2.47.2 From 0e1c26f3ea409eedc996d3ecd90afc8f50ae3786 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 10:59:30 +0200 Subject: [PATCH 32/37] adds build task --- .vscode/tasks.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 304f242..db4b410 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -43,8 +43,10 @@ "suppressTaskName": true, "args": [ "Write-Host 'Invoking Build...';", + "Write-Host -Object 'Test previous builds.' -ForegroundColor Blue;", "If (Test-Path -Path '.\\bin\\PSCredentialStore.zip') { Remove-Item -Path '.\\bin\\PSCredentialStore.zip' -Verbose};", - "Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose" + "Copy-Item -Path '.\\src\\' -Destination '.\\bin\\PSCredentialStore' -Recurse -Verbose -Force;", + "Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose;" ], "group": { "kind": "build", -- 2.47.2 From c238d7402db4205f1d72b4abfe06c4ba1d55607b Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 11:12:50 +0200 Subject: [PATCH 33/37] fix end of line dequence --- .vscode/tasks.json | 114 ++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index db4b410..1b864e8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,57 +1,57 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - // Start PowerShell - "windows": { - "command": "${env:windir}/System32/WindowsPowerShell/v1.0/powershell.exe", - "args": [ - "-NoProfile", - "-ExecutionPolicy", - "Bypass" - ] - }, - "linux": { - "command": "/usr/bin/powershell", - "args": [ - "-NoProfile" - ] - }, - "osx": { - "command": "/usr/local/bin/powershell", - "args": [ - "-NoProfile" - ] - }, - "tasks": [ - { - "taskName": "Test", - "suppressTaskName": true, - "isTestCommand": true, - "args": [ - "Write-Host 'Invoking Pester...'; $ProgressPreference = 'SilentlyContinue'; Invoke-Pester -Script '.\\tests\\*' -EnableExit $flase -PesterOption @{IncludeVSCodeMarker=$true};", - "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" - ], - "problemMatcher": "$pester", - "group": { - "kind": "test", - "isDefault": true - } - }, - { - "taskName": "DebugBuild", - "suppressTaskName": true, - "args": [ - "Write-Host 'Invoking Build...';", - "Write-Host -Object 'Test previous builds.' -ForegroundColor Blue;", - "If (Test-Path -Path '.\\bin\\PSCredentialStore.zip') { Remove-Item -Path '.\\bin\\PSCredentialStore.zip' -Verbose};", - "Copy-Item -Path '.\\src\\' -Destination '.\\bin\\PSCredentialStore' -Recurse -Verbose -Force;", - "Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose;" - ], - "group": { - "kind": "build", - "isDefault": true - } - } - ] -} +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + // Start PowerShell + "windows": { + "command": "${env:windir}/System32/WindowsPowerShell/v1.0/powershell.exe", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass" + ] + }, + "linux": { + "command": "/usr/bin/powershell", + "args": [ + "-NoProfile" + ] + }, + "osx": { + "command": "/usr/local/bin/powershell", + "args": [ + "-NoProfile" + ] + }, + "tasks": [ + { + "taskName": "Test", + "suppressTaskName": true, + "isTestCommand": true, + "args": [ + "Write-Host 'Invoking Pester...'; $ProgressPreference = 'SilentlyContinue'; Invoke-Pester -Script '.\\tests\\*' -EnableExit $flase -PesterOption @{IncludeVSCodeMarker=$true};", + "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" + ], + "problemMatcher": "$pester", + "group": { + "kind": "test", + "isDefault": true + } + }, + { + "taskName": "DebugBuild", + "suppressTaskName": true, + "args": [ + "Write-Host 'Invoking Build...';", + "Write-Host -Object 'Test previous builds.' -ForegroundColor Blue;", + "If (Test-Path -Path '.\\bin\\PSCredentialStore.zip') { Remove-Item -Path '.\\bin\\PSCredentialStore.zip' -Verbose};", + "Copy-Item -Path '.\\src\\' -Destination '.\\bin\\PSCredentialStore' -Recurse -Verbose -Force;", + "Compress-Archive -Path '.\\src\\*' -DestinationPath '.\\bin\\PSCredentialStore.zip' -Update -Verbose;" + ], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} -- 2.47.2 From 80a6857e4e51e257d7c890afbc4c09dd54cdfe3c Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 11:55:33 +0200 Subject: [PATCH 34/37] remove task.json error --- .vscode/tasks.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1b864e8..27bf957 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -27,7 +27,6 @@ { "taskName": "Test", "suppressTaskName": true, - "isTestCommand": true, "args": [ "Write-Host 'Invoking Pester...'; $ProgressPreference = 'SilentlyContinue'; Invoke-Pester -Script '.\\tests\\*' -EnableExit $flase -PesterOption @{IncludeVSCodeMarker=$true};", "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" -- 2.47.2 From f1026dabca33f058769a1ef617d63a0ba1c9a745 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 12:22:37 +0200 Subject: [PATCH 35/37] adds sources for optional modules --- README.md | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ca7beb9..03cfa8c 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,21 @@ General ======= -The PSCredentialStore is an simple credential manager for PSCredentials. It stores multiple credential object in a -simple json file. Either as private file in your profile or in shared mode in other locations. +The PSCredentialStore is an simple credential manager for PSCredentials. It stores multiple credential objects in a +simple json file. You can choose between a private and shared store. The private one exists in your profile and can +ony accessed by your account on the same machine. The shared store enables you to use different credentials for your +script without exposing them as plain text. + +**The shared store isn't 100% secure and I don't recommend using it in production!** PSCredentialStore was developed to simplify the delegation of complex powershell scripts. In this case you often -need to store credentials for non interactive usage like in sheduled tasks. +need to store credentials for non interactive usage like in scheduled tasks. To get started read the [about_PSCredentialStore](/src/en-US/about_PSCredential.help.txt) page. Installation ============ - PowerShellGallery.com (Recommended Way) --------------------------------------- @@ -34,7 +37,7 @@ Manual Way * Start with `Import-Module PSCredentialStore` Quick Start ------ +----------- **1.** First we need a blank CredentialStore. You can decide between a *private* or *shared* store. The private Credential Store can only be accessed with your profile on the machine you created it. @@ -59,12 +62,17 @@ $DCCreds = Get-CredentialStoreItem -RemoteHost 'dc01.myside.local' -Identifier ' Invoke-Command -ComputerName 'dc01.myside.local' -Credential $DCCreds -ScripBlock {Get-Process} ``` -The CredentialStore contains also a simple function to establish a connection with the given remotehost in different -ways. If you have already installed the underlying framework your can conntect to: - - CiscoUcs - Establish a connection to a Cisco UCS fabric interconnect. - - FTP - Establish a connection to a FTP host. - - NetAppFAS - Establish a connection to a NetApp Clustered ONTAP filer. - - VMware - Establish a connection to a VMware vCenter or ESXi host. +The CredentialStore contains also a simple function to establish a connection with several systems or protocols. +If you have already installed the underlying framework your can connect to: + +* **CiscoUcs** - Establish a connection to a Cisco UCS fabric interconnect. + * Required Modules: [`Cisco.UCS.Core`, `Cisco.UCSManager`](https://software.cisco.com/download/release.html?i=!y&mdfid=286305108&softwareid=284574017&release=2.1.1) +* **FTP** - Establish a connection to a FTP host. + * Required Modules: [`WinSCP`](https://www.powershellgallery.com/packages/WinSCP) +* **NetAppFAS** - Establish a connection to a NetApp Clustered ONTAP filer. + * Required Modules: [`DataONTAP`](http://mysupport.netapp.com/tools/info/ECMLP2310788I.html?productID=61926) +* **VMware** - Establish a connection to a VMware vCenter or ESXi host. + * Required Modules: [`VMware.VimAutomation.Core`](https://www.powershellgallery.com/packages/VMware.PowerCLI) Here are some basic examples: -- 2.47.2 From bdd8d569fdf6639e37ecb849a1db6726b4004e41 Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 12:29:05 +0200 Subject: [PATCH 36/37] enables Pester and posh-git --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 3db0538..10b2f2b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,10 +16,10 @@ image: Visual Studio 2017 install: - ps: Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force -Verbose - ps: Import-PackageProvider NuGet -MinimumVersion '2.8.5.201' -Force -# - ps: Install-Module -Name 'Pester' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber -# - ps: Update-Module 'Pester' -# - ps: Install-Module -Name 'posh-git' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber -# - ps: Update-Module 'posh-git' + - ps: Install-Module -Name 'Pester' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber + - ps: Update-Module 'Pester' + - ps: Install-Module -Name 'posh-git' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber + - ps: Update-Module 'posh-git' - ps: Install-Module -Name 'PSCoverage' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber - ps: Import-Module 'PSCoverage' - ps: Import-Module .\tools\AppVeyor.psm1 -- 2.47.2 From 26721ab0e9683940ad7174c7921b3363893c1dca Mon Sep 17 00:00:00 2001 From: OCram85 Date: Thu, 21 Sep 2017 13:28:25 +0200 Subject: [PATCH 37/37] prepare pre-release --- appveyor.yml | 4 ++-- src/PSCredentialStore.psd1 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 10b2f2b..22f5226 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,8 +47,8 @@ deploy: auth_token: secure: M+bBX5/nKdJB0eViP7xtrLVTwf3vGDUA9N2MMprZp2i+9ZR3CBVcJnSzJWUmalhB artifact: PSCredentialStore.zip # upload all NuGet packages to release assets - draft: false - prerelease: false + draft: true + prerelease: true on: branch: master # release from master branch only diff --git a/src/PSCredentialStore.psd1 b/src/PSCredentialStore.psd1 index 52bb2ae..54b8c64 100644 --- a/src/PSCredentialStore.psd1 +++ b/src/PSCredentialStore.psd1 @@ -25,13 +25,13 @@ Author = 'OCram85' # Company or vendor of this module - CompanyName = 'Unknown' + CompanyName = '' # Copyright statement for this module Copyright = '(c) 2017 OCram85. All rights reserved.' # Description of the functionality provided by this module - # Description = '' + Description = 'A simple credential manager to store and reuse multiple credential objecs' # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '4.0' @@ -125,7 +125,7 @@ # IconUri = '' # ReleaseNotes of this module - # ReleaseNotes = '' + ReleaseNotes = 'This is a draft version / pre-release. Do not use in production!' } # End of PSData hashtable -- 2.47.2