ModuleRoot.psm1
# srcFile: /drone/src/src/Store/Get-CredentialStore.ps1 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" #> [CmdletBinding(DefaultParameterSetName = 'Private')] [OutputType('PSCredentialStore.Store')] param ( [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [string]$Path, [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [switch]$Shared ) begin {} process { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } if (Test-CredentialStore -Path $Path -Shared) { try { $FileContent = Get-Content -Path $Path -Raw $CS = ConvertFrom-Json $FileContent $CS.PSObject.TypeNames.Insert(0, 'PSCredentialStore.Store') Write-Output $CS } 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 } } end {} } # srcFile: /drone/src/src/Store/New-CredentialStore.ps1 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. .PARAMETER SkipPFXCertCreation You can skip the pfx certificate creation process. This makes sense if you have a previously created cert or want to import a cert in cross-platform environments. .Parameter UseCertStore Instead of using a plain pfx file beside your CredentialStore file you can import it into the user or machine certificate store. In this case the system itself secures the cert and you don't hat to set custom NTFS permissions so secure your shared certificate. .INPUTS [None] .OUTPUTS ['PSCredentialStore.Store'] Returns the recently created CredentialStore object if the -PassThru parameter was given. .EXAMPLE New-CredentialStore # Creates a new private CredentialStore .EXAMPLE New-CredentialStore -Force # Resets an existing private CredentialStore .EXAMPLE New-CredentialStore -Shared # Creates a new shared CredentialStore .EXAMPLE New-CredentialStore -Shared -Path "C:\TMP\CredentialStore.json" # Creates a new shared CredentialStore in the given location. #> [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Private')] [OutputType('PSCredentialStore.Store')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [System.IO.FileInfo]$Path, [Parameter(Mandatory = $false, ParameterSetName = 'Private')] [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [switch]$Force, [Parameter(Mandatory = $false, ParameterSetName = 'Private')] [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [switch]$PassThru, [Parameter(Mandatory = $false, ParameterSetName = 'Private')] [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [switch]$SkipPFXCertCreation, [Parameter(Mandatory = $false, ParameterSetName = 'Private')] [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [switch]$UseCertStore ) begin { # Lets get the current Date in a human readable format. $CurrentDate = Get-Date -Format 'u' # test if the path input is a valid file path if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey('Path')) { if ($Path.Attributes -contains 'Directory') { $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.IO.InvalidDataException]::new( 'Please provide a full path containing the ' + 'credential store file name with the .json extension!' ) } Write-Error @ErrorParams } elseif ( ($null -eq $Path.Extension) -or ($Path.Extension -ne '.json')) { $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.IO.InvalidDataException]::new( 'Your provided path does not contain the required file extension .json!' ) } Write-Error @ErrorParams } } } process { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } # Test if in the CredentialStore already exists. Write-Verbose 'Test if there is already a credential store.' if ((Test-Path -Path $Path) -and ($Force -ne $true)) { $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.InvalidOperationException]::new( 'The given file already exists. Use the -Force switch to override the existing store.' ) } Write-Error @ErrorParams } if (! $SkipPFXCertCreation.IsPresent) { $CRTParams = @{ Country = 'DE' State = 'PSCredentialStore' City = 'PSCredentialStore' Organization = 'PSCredentialStore' OrganizationalUnitName = $PSCmdlet.ParameterSetName CommonName = 'PSCredentialStore' } $CRTAttribute = New-CSCertAttribute @CRTParams # If we are working with a ne shared store we have to create the location first. # Otherwise openssl fails with unknown path $StoreHome = Split-Path -Path $Path -Parent if (! (Test-Path -Path $StoreHome)) { New-Item -ItemType Directory -Path $StoreHome -ErrorAction Stop } $PfxParams = @{ CRTAttribute = $CRTAttribute KeyName = Join-Path -Path $StoreHome -ChildPath 'private.key' CertName = Join-Path -Path $StoreHome -ChildPath 'PSCredentialStore.pfx' ErrorAction = 'Stop' Confirm = $false } # test if there is already a cert if ((Test-Path $PfxParams.CertName) -and (! $Force.IsPresent)) { $ErrorParams = @{ Exception = [System.IO.InvalidDataException]::new( 'There is already a PfxCertificate for a private CredentialStore!' ) ErrorAction = 'Stop' } Write-Error @ErrorParams } try { New-CSCertificate @PfxParams } catch { $_.Exception.Message | Write-Error $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.Exception]::new( 'Could not create the private PfXCertificate!' ) } Write-Error @ErrorParams } try { $FreshCert = Get-PfxCertificate -FilePath $PfxParams.CertName -ErrorAction Stop } catch [System.Management.Automation.ItemNotFoundException] { $_.Exception.Message | Write-Error Write-Error -Message 'Could not read the new PfxCertificate.' -ErrorAction Stop } } # We need to use the IDictionary to keep the property sorting in the object. $ObjProperties = [ordered]@{ PSTypeName = 'PSCredentialStore.Store' Version = $CSVersion Created = $CurrentDate PfxCertificate = $null Thumbprint = $null Type = $null } if ($PSCmdlet.ParameterSetName -eq 'Shared') { $ObjProperties.Type = 'Shared' } else { $ObjProperties.Type = 'Private' } if (! $SkipPFXCertCreation.IsPresent) { $ObjProperties.Thumbprint = $FreshCert.Thumbprint if ($UseCertStore.IsPresent) { Write-Verbose 'Importing new PFX certificate file...' Import-CSCertificate -Type $ObjProperties.Type -Path $PfxParams.CertName } else { $ObjProperties.PfxCertificate = $PfxParams.CertName } } $CredentialStoreObj = [PSCustomObject]$ObjProperties try { $JSON = ConvertTo-Json -InputObject $CredentialStoreObj -ErrorAction Stop $JSON | Out-File -FilePath $Path -ErrorAction Stop -Force } catch { $_.Exception.Message | Write-Error $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.IO.IOException]::new( 'Unable to convert or write the CredentialStore' ) } Write-Error @ErrorParams } if ($PassThru.IsPresent) { return $CredentialStoreObj } } end {} } # srcFile: /drone/src/src/Store/Test-CredentialStore.ps1 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. .EXAMPLE Test-CredentialStore -eq $true #> [CmdletBinding(DefaultParameterSetName = 'Private')] [OutputType([bool])] param ( [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [string]$Path, [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [switch]$Shared ) begin {} process { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } Write-Verbose -Message ("Path is: {0}" -f $Path) if (Test-Path $Path) { Write-Verbose 'CredentialStore in given path found.' Write-Output $true } else { Write-Verbose 'The given CredentialStore does not exist!' Write-Output $false } } end {} } # srcFile: /drone/src/src/Certificate/Get-CSCertificate.ps1 function Get-CSCertificate { <# .SYNOPSIS Returns the current used valid PfX certificate. .DESCRIPTION Use this function to get the available pfx certificate respecting the config hierarchy. .PARAMETER Type Select the current credential store type. .PARAMETER Thumbprint Provide the credentials thumbprint for the search. .INPUTS [None] .OUTPUTS [System.Security.Cryptography.X509Certificates.X509Certificate2] .EXAMPLE Get-CSCertificate -Type 'Shared' -Thumbprint '12334456' #> [CmdletBinding()] [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet('Private', 'Shared')] [string]$Type, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Thumbprint ) begin {} process { if ($Type -eq 'Private') { Get-CSPfXCertificate -Thumbprint $Thumbprint -StoreName 'My' -StoreLocation 'CurrentUser' } elseif ($Type -eq 'Shared') { if ( $isLinux) { $cert = Get-CSPfxCertificate -Thumbprint $Thumbprint -StoreName 'My' -StoreLocation 'CurrentUser' if ($null -eq $cert) { Get-CSPfxCertificate -Thumbprint $Thumbprint -StoreName 'Root' -StoreLocation 'LocalMachine' } else { Write-Output $cert } } elseif ( (! $isLinux) -or ($isWindows) ) { $cert = Get-CSPfxCertificate -Thumbprint $Thumbprint -StoreName 'My' -StoreLocation 'LocalMachine' if ($null -eq $cert) { Get-CSPfxCertificate -Thumbprint $Thumbprint -StoreName 'Root' -StoreLocation 'LocalMachine' } else { Write-Output $cert } } } } end {} } # srcFile: /drone/src/src/Certificate/Import-CSCertificate.ps1 function Import-CSCertificate { <# .SYNOPSIS Imports a linked certificate to the valid store location. .DESCRIPTION Import-CSCertificate takes a pfx certificate file and imports it to the supposed certificate store for private and shared credential stores. .PARAMETER Type Select between the a private and shared credential store. .PARAMETER Path Provide a valid path to pfx certificate file. .INPUTS [None] .OUTPUTS [None] .EXAMPLE Import-CSCertificate -Type 'Private' -Path (Join-Path -Path $Env:APPDATA -ChildItem 'PfxCertificate.pfx') #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet('Private', 'Shared')] [string]$Type, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.IO.FileInfo]$Path ) begin { if (! (Test-Path -Path $Path)) { $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.Exception]::new( ('File {0} not found!') -f $Path ) } Write-Error @ErrorParams } } process { # Import to CurrentUser\My store for windows and linux if ($Type -eq 'Private') { Import-CSPfxCertificate -Path $Path -StoreName 'My' -StoreLocation 'CurrentUser' -OpenFlags 'ReadWrite' } elseif ( (! $isLinux ) -and ($Type -eq 'Shared') ) { Import-CSPfxCertificate -Path $Path -StoreName 'My' -StoreLocation 'LocalMachine' -OpenFlags 'ReadWrite' } elseif ( ($isLinux) -and ($Type -eq 'Shared') ) { Import-CSPfxCertificate -Path $Path -StoreName 'My' -StoreLocation 'CurrentUser' -OpenFlags 'ReadWrite' } } end { } } # srcFile: /drone/src/src/Certificate/New-CSCertAttribute.ps1 function New-CSCertAttribute { <# .SYNOPSIS Creates required data for a certificate signing request. .DESCRIPTION Defines the certificate related properties for an upcoming New-PfxCertificate execution. .PARAMETER Country County code like EN, DE, IT, FR... .PARAMETER State Certificate state value. .PARAMETER City Certificate city value. .PARAMETER Organization Certificate organization value. .PARAMETER OrganizationalUnitName Certificate OrganizationalUnitName value. .PARAMETER CommonName The certificate common name. .PARAMETER Days The validation time itself. .INPUTS [None] .OUTPUTS [PSCredentialStore.Certificate.CSRDetails] .EXAMPLE $AttribParams = @{ Country = 'DE' State = 'BW' City = 'Karlsruhe' Organization ='AwesomeIT' OrganizationalUnitName ='PSCredentialStore' CommonName ='MyPrivateCert' } New-CSCertAttribute @AttribParams #> [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Returns a new object and does not change data' )] [OutputType('PSCredentialStore.Certificate.Attribute')] param ( [Parameter(Mandatory = $true)] [ValidateLength(2, 2)] [ValidateNotNull()] [string]$Country, [Parameter(Mandatory = $true)] [ValidateNotNull()] [string]$State, [Parameter(Mandatory = $true)] [ValidateNotNull()] [string]$City, [Parameter(Mandatory = $true)] [ValidateNotNull()] [string]$Organization, [Parameter(Mandatory = $true)] [ValidateNotNull()] [string]$OrganizationalUnitName, [Parameter(Mandatory = $true)] [ValidateNotNull()] [string]$CommonName, [Parameter(Mandatory = $false)] [ValidateNotNull()] [int]$Days = 365 ) begin {} process { return [PSCustomObject]@{ PSTypeName = 'PSCredentialStore.Certificate.Attribute' Subject = [PSCustomObject]@{ PSTypeName = 'PSCredentialStore.Certificate.Attribute.Subject' Country = $Country State = $State City = $City Organization = $Organization OrganizationalUnitName = $OrganizationalUnitName CommonName = $CommonName } Days = $Days } } end {} } # srcFile: /drone/src/src/Certificate/New-CSCertificate.ps1 function New-CSCertificate { <# .SYNOPSIS Creates a new PFX certificate for the CredentialStore encryption. .DESCRIPTION Use this function to create a custom self signed certificate used by the PSCredentialStore module. .PARAMETER CRTAttribute Provide certificate related attributes provided by function New-CRTAttribute. .PARAMETER KeyName Provide a custom full path and name for the private key. The file extension has to be `*.key`. .PARAMETER CertName Provide a custom full path and name for the PFX certificate file. The file extension has to be `*.pfx` .INPUTS [PSCredentialStore.Certificate.Attribute] .OUTPUTS [None] .EXAMPLE New-CSCertificate -CRTAttribute $CRTAttribute -KeyName './myprivate.key' -CertName './mycert.pfx' #> [CmdletBinding(SupportsShouldProcess = $true)] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidUsingInvokeExpression', '', Justification = 'needed for openssl wrapping' )] [OutputType()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [PSTypeName('PSCredentialStore.Certificate.Attribute')]$CRTAttribute, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$KeyName = './private.key', [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$CertName = './certificate.pfx' ) begin { $ModuleBase = Get-ModuleBase if ($isLinux -or $isMacOS) { try { $openssl = Get-Command -Name 'openssl' -ErrorAction Stop } catch { $_.Exception.Message | Write-Error $ErrorParams = @{ Message = 'Can not find the openssl binary!' ErrorAction = 'Stop' Exception = [System.IO.FileNotFoundException]::new() } Write-Error @ErrorParams } } elseif ( ($PSVersionTable.PSEdition -eq 'Desktop' -and $PSVersionTable.PSVersion.Major -lt 6) -or ($IsWindows -eq $true) ) { $openssl = Join-Path -Path $ModuleBase -ChildPath '/Vendor/libressl255/openssl.exe' } $Env:OPENSSL_CONF = Join-Path $ModuleBase -ChildPath '/openssl.conf' } process { $SubjPattern = "/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}" $SubjValues = @( $CRTAttribute.Subject.Country, $CRTAttribute.Subject.State, $CRTAttribute.Subject.City, $CRTAttribute.Subject.Organization, $CRTAttribute.Subject.OrganizationalUnitName, $CRTAttribute.Subject.CommonName ) $Subj = $SubjPattern -f $SubjValues $PEMCertName = $CertName -replace '.pfx', '.crt' $ExpPattern = ( '& ''{0}'' req -x509 -sha256 -nodes -days {1} -newkey rsa:2048 -keyout {2} -out {3} -subj "{4}" *>$null' ) $ExpValues = @( $openssl, $CRTAttribute.Days $KeyName, $PEMCertName, $Subj ) $PEMExp = $ExpPattern -f $ExpValues Write-Verbose -Message ( 'Expr string is: {0}' -f $PEMExp) # Edit the Error action for the openSLL command to make the redirect *>$null work. # There is always a stderr and stdout stream! $EAP = $ErrorActionPreference $ErrorActionPreference = 'Continue' Invoke-Expression -Command $PEMExp $ErrorActionPreference = $EAP # manually testing the openssl command results if (! (Test-Path -Path $KeyName)) { $ErrorParams = @{ Message = 'Could not create the private key ${0}' -f $KeyName ErrorAction = 'Stop' Exception = [System.UnauthorizedAccessException]::new() } Write-Error @ErrorParams } if (! (Test-Path -Path $PEMCertName)) { $ErrorParams = @{ Message = 'Could not create the PEM certificate ${0}' -f $PEMCertName ErrorAction = 'Stop' Exception = [System.Exception]::new() } Write-Error @ErrorParams } $PfxPattern = '& ''{0}'' pkcs12 -export -out {1} -inkey {2} -in {3} -passout pass:' $PfxValues = @( $openssl, $CertName, $KeyName, ($CertName -replace '.pfx', '.crt') ) $PfxExp = $PfxPattern -f $PfxValues Write-Verbose -Message ( 'PfxExp string is: {0}' -f $PfxExp) Invoke-Expression -Command $PfxExp # Remove private key and crt file. Always ask user Remove-Item -Path $KeyName Remove-Item -Path ($CertName -replace '.pfx', '.crt') } end { Remove-Item Env:\OPENSSL_CONF -Confirm:$False -Force -ErrorAction SilentlyContinue } } # srcFile: /drone/src/src/Certificate/Test-CSCertificate.ps1 function Test-CSCertificate { <# .SYNOPSIS Tests if the linked certificate is store ein the specified cert stores. .DESCRIPTION Test-CSCertificate should be an easy high level test for the linked certificate. .PARAMETER Type Select between 'Private' or 'Shared'. .INPUTS [None] .OUTPUTS [bool] .EXAMPLE Test-CSCertificate -Type 'Shared' #> [CmdletBinding()] [OutputType([bool])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet('Private', 'Shared')] [string]$Type ) begin { if ($Type -eq 'Private') { $CS = Get-CredentialStore } elseif ($Type -eq 'Shared') { $CS = Get-CredentialStore -Shared } if ($null -ne $CS.PfxCertificate) { Write-Warning -Message ( 'There is a Pfx certificate file linked in the store. ' + 'Certificates saved in the Cert store will be ignored!' ) } } process { if ($Type -eq 'Private') { $cert = Get-CSPfXCertificate -Thumbprint $CS.Thumbprint -StoreName 'My' -StoreLocation 'CurrentUser' } elseif ($Type -eq 'Shared') { if ( $isLinux) { $cert = Get-CSPfxCertificate -Thumbprint $CS.Thumbprint -StoreName 'My' -StoreLocation 'CurrentUser' if ($null -eq $cert) { $PFXParams = @{ Thumbprint = $CS.Thumbprint StoreName = 'Root' StoreLocation = 'LocalMachine' } $cert = Get-CSPfxCertificate @PFXParams } } elseif ( (! $isLinux) -or ($isWindows) ) { $PFXParams = @{ Thumbprint = $CS.Thumbprint StoreName = 'My' StoreLocation = 'LocalMachine' } $cert = Get-CSPfxCertificate @PFXParams if ($null -eq $cert) { $PFXParams = @{ Thumbprint = $CS.Thumbprint StoreName = 'Root' StoreLocation = 'LocalMachine' } $cert = Get-CSPfxCertificate @PFXParams } } } if ($null -eq $cert) { return $false } else { return $true } } end { } } # srcFile: /drone/src/src/Certificate/Use-CSCertificate.ps1 function Use-CSCertificate { <# .SYNOPSIS Links an existing PFX Certificate to a CredentialStore. .DESCRIPTION Linking a certificate is needed if you plan to use the same CredentialStore in cross platform scenarios. .PARAMETER Path Specify the path to the PFX Certificate you want to link for usage. .PARAMETER CredentialStore Specify a custom path for a shared credential store. .PARAMETER Shared Use the credential store in shared mode. .PARAMETER UseCertStore Use the given certificate and import it into the corresponding certificate store. .INPUTS [None] .OUTPUTS [None] .EXAMPLE Use-CSCertificate -Path 'C:\cert.pfx' #> [CmdletBinding(DefaultParameterSetName = 'Private')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Private')] [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$CredentialStore, [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $false, ParameterSetName = 'Private')] [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [switch]$UseCertStore ) begin {} process { try { # We need to resolve the path to make sure it has the correct platform specific syntax. # And it should also exist. $validPath = Resolve-Path -Path $Path -ErrorAction Stop $PfxCertificate = Get-PfxCertificate -FilePath $validPath -ErrorAction Stop } catch { $_.Exception.Error | Write-Error $ErrorParams = @{ Message = 'The given PFX certificate does not exist!' ErrorAction = 'Stop' } Write-Error @ErrorParams } try { if ($PSCmdlet.ParameterSetName -eq 'Private') { $StorePath = Get-DefaultCredentialStorePath $CS = Get-CredentialStore } elseif ($PSCmdlet.ParameterSetName -eq 'Shared' ) { if (!($PSBoundParameters.ContainsKey('CredentialStore'))) { $StorePath = Get-DefaultCredentialStorePath -Shared $CS = Get-CredentialStore -Shared } else { $StorePath = $CredentialStore $CS = Get-CredentialStore -Shared -Path $CredentialStore } } } catch { $_.Exception.Error | Write-Error $ErrorParams = @{ Message = 'The given CredentialStore does not exist!' ErrorAction = 'Stop' } Write-Error @ErrorParams } # Lets first check if the thumbprint matches if (($CS.Thumbprint -notmatch $PfxCertificate.Thumbprint) -and ($CS.Thumbprint.Length -ne 0)) { Write-Warning @" You are trying to map an unknown certificate. Make sure you used the same AES keys for encrypting! "@ } if ($UseCertStore) { Import-CSCertificate -Type $PSCmdlet.ParameterSetName -Path $Path $CS.Thumbprint = $PfxCertificate.Thumbprint $CS.PfxCertificate = $null } else { $CS.PfxCertificate = $validPath.Path } $CS | ConvertTo-Json -Depth 5 | Out-File -FilePath $StorePath -Force -Encoding utf8 } end {} } # srcFile: /drone/src/src/Item/Get-CredentialStoreItem.ps1 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" #> [CmdletBinding(DefaultParameterSetName = 'Private')] [OutputType([PSCredential])] param ( [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 = $true, ParameterSetName = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$Path ) begin { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } } process { if ($Identifier -ne "") { $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost } else { $CredentialName = $RemoteHost } if (Test-CredentialStore -Shared -Path $Path) { $CS = Get-CredentialStore -Shared -Path $Path $CSMembers = Get-Member -InputObject $CS # Let's first check if the given remote host exists as object property if (($CSMembers.MemberType -eq 'NoteProperty') -and ($CSMembers.Name -contains $CredentialName)) { if ($null -eq $CS.PfxCertificate) { $Cert = Get-CSCertificate -Type $CS.Type -Thumbprint $CS.Thumbprint } else { $Cert = Get-PfxCertificate -FilePath $CS.PfxCertificate -ErrorAction Stop } $DecryptedKey = $Cert.PrivateKey.Decrypt( [Convert]::FromBase64String($CS.$CredentialName.EncryptedKey), [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1 ) if (! $ExpandOutput.isPresent) { [PSCredential]::new( $CS.$CredentialName.User, ($CS.$CredentialName.Password | ConvertTo-SecureString -Key $DecryptedKey) ) } } else { $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 } } end { } } # srcFile: /drone/src/src/Item/New-CredentialStoreItem.ps1 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. .PARAMETER Shared Define the CredentialStore where you want to add the new item. Default is always personal but can be changed to shared, or even shared with custom path. .INPUTS [None] .OUTPUTS [None] .EXAMPLE New-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" #> [CmdletBinding(DefaultParameterSetName = 'Private')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Adds data into an existing object/file' )] param ( [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, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [PSCredential]$Credential, [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$Path ) begin { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } } process { # Lets do a quick test on the given CredentialStore. if (-not(Test-CredentialStore -Shared -Path $Path)) { $MessageParams = @{ Exception = [System.IO.FileNotFoundException]::new( 'Could not add anything into the given CredentialStore.' ) ErrorAction = "Stop" } Write-Error @MessageParams } $CSContent = Get-CredentialStore -Shared -Path $Path $CurrentDate = Get-Date -Format 'u' 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 ($null -eq $CSContent.PfxCertificate) { $Cert = Get-CSCertificate -Type $CSContent.Type -Thumbprint $CSContent.Thumbprint } else { $Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop } if (Get-Member -InputObject $CSContent -Name $CredentialName -MemberType Properties) { $MessageParams = @{ Message = 'The given host already exists. Nothing to do here.' } Write-Warning @MessageParams } else { $RSAKey = Get-RandomAESKey $CredentialHash = [ordered]@{ User = $Credential.UserName Password = ConvertFrom-SecureString -SecureString $Credential.Password -Key $RSAKey Created = $CurrentDate LastChange = $null EncryptedKey = [Convert]::ToBase64String( $Cert.PublicKey.Key.Encrypt( $RSAKey, [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1 ) ) } $MemberParams = @{ InputObject = $CSContent Name = $CredentialName MemberType = 'NoteProperty' Value = $CredentialHash } Add-Member @MemberParams try { ConvertTo-Json -InputObject $CSContent | Out-File -FilePath $Path } catch { $MessageParams = @{ Message = 'Could not 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 } } end {} } # srcFile: /drone/src/src/Item/Remove-CredentialStoreItem.ps1 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 -RemoteHost "esx01.myside.local" .EXAMPLE Remove-CredentialStoreItem -Shared -RemoteHost "esx01.myside.local" .EXAMPLE Remove-CredentialStoreItem -Shared -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" .EXAMPLE Remove-CredentialStoreItem -RemoteHost "esx01.myside.local" -Identifier svc #> [CmdletBinding(DefaultParameterSetName = 'Private')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Removes data from existing store.' )] param ( [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 = $true, ParameterSetName = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$Path ) begin { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } } process { # Lets do a quick test on the given CredentialStore. if (-not(Test-CredentialStore -Shared -Path $Path)) { $MessageParams = @{ Message = 'Could not add anything into the given CredentialStore.' ErrorAction = 'Stop' } Write-Error @MessageParams } # Read the file content based on the given ParameterSetName $CSContent = Get-CredentialStore -Shared -Path $Path if ($Identifier -ne "") { $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost } else { $CredentialName = $RemoteHost } if (Get-Member -InputObject $CSContent -Name $CredentialName -MemberType NoteProperty) { # We need to use the .NET Method because there is no easier way in PowerShell. $CSContent.PSObject.Properties.Remove($CredentialName) ConvertTo-Json -InputObject $CSContent -Depth 5 | Out-File -FilePath $Path -Encoding utf8 } else { $MessageParams = @{ Message = 'The given CredentialStoreItem does not exist.' } Write-Warning @MessageParams } } end { } } # srcFile: /drone/src/src/Item/Set-CredentialStoreItem.ps1 function Set-CredentialStoreItem { <# .SYNOPSIS Changes the credentials for the given remote host in the store. .DESCRIPTION Use this function to update your already stored RemoteHost items. .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. .PARAMETER Credential Provided the new credentials you want to update inside the RemoteHost item. .INPUTS [None] .OUTPUTS [None] .EXAMPLE Set-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" .EXAMPLE Set-CredentialStoreItem -Path "C:\TMP\mystore.json" -RemoteHost "esx01.myside.local" -Identifier svc #> [CmdletBinding(DefaultParameterSetName = 'Private')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Updates existing credential object.' )] param ( [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, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [PSCredential]$Credential, [Parameter(Mandatory = $true, ParameterSetName = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $false, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$Path ) begin { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } } process { # Lets do a quick test on the given CredentialStore. if (-not(Test-CredentialStore -Shared -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 -Shared -Path $Path $CurrentDate = Get-Date -Format 'u' 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 ($null -eq $CSContent.PfxCertificate) { $Cert = Get-CSCertificate -Type $CSContent.Type -Thumbprint $CSContent.Thumbprint } else { $Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop } if (Get-Member -InputObject $CSContent -Name $CredentialName -MemberType Properties) { $RSAKey = Get-RandomAESKey $CSContent.$CredentialName.User = $Credential.UserName $ConvertParams = @{ SecureString = $Credential.Password Key = $RSAKey } $CSContent.$CredentialName.Password = ConvertFrom-SecureString @ConvertParams $CSContent.$CredentialName.LastChange = $CurrentDate $CSContent.$CredentialName.EncryptedKey = [Convert]::ToBase64String( $Cert.PublicKey.Key.Encrypt( $RSAKey, [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1 ) ) ConvertTo-Json -InputObject $CSContent -Depth 5 | Out-File -FilePath $Path -Encoding utf8 } } Else { $MessageParams = @{ Message = 'Please Provide at least a valid user!' ErrorAction = 'Stop' } Write-Error @MessageParams } } end { } } # srcFile: /drone/src/src/Item/Test-CredentialStoreItem.ps1 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) } #> [CmdletBinding(DefaultParameterSetName = 'Private')] [OutputType([bool])] 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 ) begin { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } } process { if ($Identifier -ne "") { $CredentialName = $RemoteHost = "{0}/{1}" -f $Identifier, $RemoteHost } else { $CredentialName = $RemoteHost } if (Test-CredentialStore -Shared -Path $Path) { $CS = Get-CredentialStore -Shared -Path $Path $CSMembers = Get-Member -InputObject $CS if (($CSMembers.MemberType -eq 'NoteProperty') -and ($CSMembers.Name -contains $CredentialName)) { return $true } else { return $false } } else { $MsgParams = @{ ErrorAction = 'Stop' Message = "The given credential store ({0}) does not exist!" -f $Path } Write-Error @MsgParams } } end {} } # srcFile: /drone/src/src/Private/Get-CSPfxCertificate.ps1 function Get-CSPfxCertificate { <# .SYNOPSIS Returns the certificate object given by thumbprint. .DESCRIPTION You can use this function to get a stored certificate. Search for the object by its unique thumbprint. .PARAMETER Thumbprint Provide one or more thumbprints. .PARAMETER StoreName Select the store name in which you want to search the certificates. .PARAMETER StoreLocation Select between the both available locations CurrentUser odr LocalMachine. .INPUTS [string] .OUTPUTS [System.Security.Cryptography.X509Certificates.X509Certificate2[]] .EXAMPLE Get-CSPfxCertificate -Thumbprint '12345678' -StoreName 'My' -StoreLocation 'CurrentUser' #> [CmdletBinding()] [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [string[]]$Thumbprint, [Parameter(Mandatory = $false)] [ValidateSet( 'AddressBook', 'AuthRoot', 'CertificateAuthority', 'Disallowed', 'My', 'Root', 'TrustedPeople', 'TrustedPublisher' )] [string]$StoreName = 'My', [Parameter(Mandatory = $false)] [ValidateSet( 'CurrentUser', 'LocalMachine' )] [string]$StoreLocation = 'CurrentUser' ) begin { $Store = [System.Security.Cryptography.X509Certificates.X509Store]::New($StoreName, $StoreLocation) try { $Store.Open('ReadOnly') } catch { $_.Exception.Message | Write-Error -ErrorAction Stop } } process { foreach ($Thumb in $Thumbprint) { Write-Output $Store.Certificates | Where-Object { $_.Thumbprint -eq $Thumb } } } end { $Store.Close() } } # srcFile: /drone/src/src/Private/Get-DefaultCredentialStorePath.ps1 function Get-DefaultCredentialStorePath { <# .SYNOPSIS Returns the default CredentialStore path based on the current OS. .DESCRIPTION This is a low level helper function. .INPUTS [None] .OUTPUTS [string] .EXAMPLE $Path = Get-DefaultCredentialStorePath #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(Mandatory = $false)] [switch]$Shared ) begin {} process { if ($Shared.IsPresent) { if ($IsLinux) { return Join-Path -Path '/var/opt' -ChildPath 'PSCredentialStore/CredentialStore.json' } if ($IsMacOS) { return Join-Path -Path '/var/opt' -ChildPath 'PSCredentialStore/CredentialStore.json' } elseif ( ($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop') ) { return Join-Path -Path $env:ProgramData -ChildPath 'PSCredentialStore/CredentialStore.json' } } else { if ($IsLinux) { return Join-Path -Path $Env:HOME -ChildPath 'CredentialStore.json' } if ($IsMacOS) { return Join-Path -Path $Env:HOME -ChildPath 'CredentialStore.json' } elseif ( ($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop') ) { return Join-Path -Path $env:AppData -ChildPath 'CredentialStore.json' } } } end {} } # srcFile: /drone/src/src/Private/Get-ModuleBase.ps1 function Get-ModuleBase { <# .SYNOPSIS Returns the base path of the current module. .DESCRIPTION This is just a wrapper for enabling pester tests. .OUTPUTS Returns the base path as string #> [CmdletBinding()] [OutputType([string])] param () begin {} process { return $MyInvocation.MyCommand.Module.ModuleBase } end {} } # srcFile: /drone/src/src/Private/Get-RandomAESKey.ps1 function Get-RandomAESKey { <# .SYNOPSIS Generate a new 32-byte AES key. .DESCRIPTION Uses the System.Security.Cryptography namespace for random aes key generation. .INPUTS [None] .OUTPUTS [byte[]] .EXAMPLE .\Get-RandomAESKey #> [CmdletBinding()] [OutputType([byte[]])] param () begin {} process { $key = [byte[]]::new(32) $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create() $rng.GetBytes($key) Write-Output $key if ($null -ne $key) { [array]::Clear($key, 0, $key.Length) } } end {} } # srcFile: /drone/src/src/Private/Get-TempDir.ps1 function Get-TempDir { <# .SYNOPSIS Returns the valid temp dir of the current OS .DESCRIPTION Returns the valid temp dir of the current OS. .INPUTS [None] .OUTPUTS [string] .EXAMPLE Get-TempDir #> [CmdletBinding()] [OutputType([string])] param () begin {} process { if ($IsLinux) { return (Resolve-Path -Path '/tmp/').Path } if ($IsMacOS) { return (Resolve-Path -Path '/tmp/').Path } elseif ( ($isWindows) -or ($PSVersionTable.PSVersion.Major -lt 6) -or ($PSVersionTable.PSEdition -eq 'Desktop') ) { return (Resolve-Path -Path $env:TEMP).Path } } end {} } # srcFile: /drone/src/src/Private/Import-CSPfxCertificate.ps1 function Import-CSPfxCertificate { <# .SYNOPSIS Adds a given pfx certificate file to current user's personal certificate store. .DESCRIPTION This function is used to import existing pfx certificate files. The Import-PFXCertificate cmdlet from the PKI module imports the certificate into a deprecated store. Thus you can't read the private key afterwards or using it for decrypting data. .PARAMETER Path Path to an existing *.pfx certificate file. .PARAMETER StoreName Additionally you change change the store where you want the certificate into. .INPUTS [None] .OUTPUTS [None] .EXAMPLE Import-CSPfxCertificate -Path (Join-Path -Path $Env:APPDATA -ChildPath '/PSCredentialStore.pfx') #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory = $false)] [ValidateSet( 'AddressBook', 'AuthRoot', 'CertificateAuthority', 'Disallowed', 'My', 'Root', 'TrustedPeople', 'TrustedPublisher' )] [string]$StoreName = 'My', [Parameter(Mandatory = $false)] [ValidateSet( 'CurrentUser', 'LocalMachine' )] [string]$StoreLocation = 'CurrentUser', [Parameter(Mandatory = $false)] [ValidateSet( 'ReadOnly', 'ReadWrite', 'MaxAllowed', 'OpenExistingOnly', 'IncludeArchived' )] [string]$OpenFlags = 'ReadWrite' ) begin { $Store = [System.Security.Cryptography.X509Certificates.X509Store]::new($StoreName, $StoreLocation) try { $Store.Open($OpenFlags) } catch { $_.Exception.Message | Write-Error -ErrorAction Stop } } process { try { $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new( $Path, $null, ( [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet ) ) if (Test-CSPfxCertificate -Thumbprint $cert.Thumbprint) { Write-Warning -Message ( 'The certificate with thumbprint {0} is already present!' -f $cert.Thumbprint ) } else { $Store.Add($cert) } } catch { $_.Exception.Message | Write-Error -ErrorAction Stop $ErrorParams = @{ ErrorAction = 'Stop' Exception = [System.Exception]::new( 'Could not read or add the pfx certificate!' ) } Write-Error @ErrorParams } } end { $Store.Close() } } # srcFile: /drone/src/src/Private/Resolve-Dependency.ps1 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' } #> [OutputType([bool])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Name ) begin { $ModuleRootDir = Get-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) } } process { # ScriptAnalyzer issue workaround (unused var) $null = $Name $SelectedDependency = $Dependency.Optional | Where-Object { $_.Name -match $Name } # return true if there is no dependency defined if ($null -eq $SelectedDependency) { return $true } $res = @() foreach ($Module in $SelectedDependency.Modules) { $res += Test-Module -Name $Module } # return false if there was not module at all if (($res -contains $false) -or ($res.Count -eq 0)) { return $false } else { return $true } } end {} } # srcFile: /drone/src/src/Private/Test-CSPfxCertificate.ps1 function Test-CSPfxCertificate { <# .SYNOPSIS Tests if the given certificate exists in a store. .DESCRIPTION Use this function to ensure if a certificate is already imported into a given store. .PARAMETER Thumbprint Provide one or more thumbprints. .PARAMETER StoreName Select the store name in which you want to search the certificates. .PARAMETER StoreLocation Select between the both available locations CurrentUser odr LocalMachine. .INPUTS [None] .OUTPUTS [bool] .EXAMPLE Test-CSPfxCertificate -Thumbprint '12345678' -StoreName 'My' -StoreLocation 'CurrentUser' #> [CmdletBinding()] [OutputType([bool])] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [string]$Thumbprint, [Parameter(Mandatory = $false)] [ValidateSet( 'AddressBook', 'AuthRoot', 'CertificateAuthority', 'Disallowed', 'My', 'Root', 'TrustedPeople', 'TrustedPublisher' )] [string]$StoreName = 'My', [Parameter(Mandatory = $false)] [ValidateSet( 'CurrentUser', 'LocalMachine' )] [string]$StoreLocation = 'CurrentUser' ) begin { $Store = [System.Security.Cryptography.X509Certificates.X509Store]::New($StoreName, $StoreLocation) try { $Store.Open('ReadOnly') } catch { $_.Exception.Message | Write-Error -ErrorAction Stop } } process { # Script analyzer issue (unused var) workaround $null = $Thumbprint $Cert = $Store.Certificates | Where-Object { $_.Thumbprint -eq $Thumbprint } if ($null -eq $Cert) { return $false } else { return $true } } end { $Store.Close() } } # srcFile: /drone/src/src/Private/Test-Module.ps1 function Test-Module { <# .SYNOPSIS Tests if the given module exists on the local system. .DESCRIPTION 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 .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 #> [OutputType([bool])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Name, [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 if (Get-Module -Name $Name -ListAvailable) { return $true } else { if ($StopIfFails) { Write-Error -Message $Message -ErrorAction Stop -Category NotInstalled } return $false } } end {} } # srcFile: /drone/src/src/Connection/Connect-To.ps1 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: Possible connection values are: CiscoUcs, FTP, NetAppFAS, VMware, CisServer, ExchangeHTTP, ExchangeHTTPS, SCP. .PARAMETER Credentials Use this parameter to bypass the stored credentials. Without this parameter Connect-To tries to read the 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 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. .PARAMETER PassThru Returns the value from the underlying connection type function. .INPUTS [None] .OUTPUTS [None] .EXAMPLE Connect-To -RemoteHost "ucs.myside.local" -Type CiscoUcs .EXAMPLE Connect-To -RemoteHost "ftp.myside.local" -Type FTP .EXAMPLE Connect-To -RemoteHost "fas.myside.local" -Type NetAppFAS .EXAMPLE Connect-To -RemoteHost "esx01.myside.local" -Type VMware .EXAMPLE Connect-To -RemoteHost "vCenter.myside.local" -Type CisServer .EXAMPLE Connect-To -RemoteHost "exchange01.myside.local" -Type ExchangeHTTP .EXAMPLE Connect-To -RemoteHost "exchange01.myside.local" -Type ExchangeHTTPS #> [CmdletBinding(DefaultParameterSetName = 'Private')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidGlobalVars', '', Justification = 'Wrapping existing var from WinSCP module.' )] 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', 'CisServer', 'ExchangeHTTP', 'ExchangeHTTPS', 'SCP' )] [string]$Type, [Parameter(Mandatory = $False, ParameterSetName = 'Shared')] [Parameter(Mandatory = $False, ParameterSetName = 'Private')] [PSCredential]$Credentials, [Parameter(Mandatory = $true, ParameterSetNAme = 'Shared')] [switch]$Shared, [Parameter(Mandatory = $False, ParameterSetName = 'Shared')] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory = $False, ParameterSetName = 'Private')] [Parameter(Mandatory = $False, ParameterSetName = 'Shared')] [switch]$PassThru ) begin { # Set the CredentialStore for private, shared or custom mode. Write-Debug ("ParameterSetName: {0}" -f $PSCmdlet.ParameterSetName) if ($PSCmdlet.ParameterSetName -eq 'Private') { $Path = Get-DefaultCredentialStorePath } elseif ($PSCmdlet.ParameterSetName -eq 'Shared') { if (!($PSBoundParameters.ContainsKey('Path'))) { $Path = Get-DefaultCredentialStorePath -Shared } } # First check the optional modules if (-not (Resolve-Dependency -Name $Type)) { Write-Error -Message ( "Could not resolve the optional dependencies defined for {0}" -f $Type ) -ErrorAction 'Stop' } 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 { 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 -Shared -RemoteHost $RemoteHostIdentifier -Path $Path } else { $creds = Get-CredentialStoreItem -Shared -RemoteHost $RemoteHost -Path $Path } } catch { $MessageParams = @{ Message = ( "Unable to look up credential store item for RemoteHost " + ("{0}/Identifier {1}!" -f $RemoteHost, $Identifier) ) ErrorAction = 'Stop' } Write-Error @MessageParams } } else { $creds = $Credentials } if ($creds.UserName -eq "" -or $creds.Password.GetType().Name -ne 'SecureString') { $MessageParams = @{ Message = "Please provide valid credentials for RemoteHost {0}!" -f $RemoteHost ErrorAction = 'Stop' } Write-Error @MessageParams } else { switch ($Type) { "CiscoUcs" { try { $handle = Connect-Ucs -Name $RemoteHost -Credential $creds -ErrorAction 'Stop' -NotDefault $ExecutionContext.SessionState.PSVariable.Set('DefaultUcs', $handle) } catch { $MessageParams = @{ Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type ErrorAction = 'Stop' } Write-Error @MessageParams } } "FTP" { # First establish the FTP session $WinSCPConParams = @{ Credential = $creds Hostname = $RemoteHost Protocol = 'Ftp' FtpMode = 'Passive' } try { $FTPSessionOption = New-WinSCPSessionOption @WinSCPConParams $Global:WinSCPSession = New-WinSCPSession -SessionOption $FTPSessionOption } 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} " -f $RemoteHost, $Type) + "was established. But now it seems to be lost!" ) 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 } } "CisServer" { try { if ($PassThru.IsPresent) { Connect-CisServer -Server $RemoteHost -Credential $creds -ErrorAction Stop } else { Connect-CisServer -Server $RemoteHost -Credential $creds -ErrorAction Stop | Out-Null } } catch { # Write a error message to the log. $MessageParams = @{ Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type ErrorAction = 'Stop' } Write-Error @MessageParams } } "ExchangeHTTP" { try { $ConnectionParams = @{ ConnectionURI = "http://{0}/powershell" -f $RemoteHost ConfigurationName = 'Microsoft.Exchange' Credential = $creds ErrorAction = 'Stop' } $Global:PSExchangeRemote = New-PSSession @ConnectionParams # ScriptAnalyzer issue (unused var) workaround. $null = $Global:PSExchangeRemote } 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 } } "ExchangeHTTPS" { try { $ConnectionParams = @{ ConnectionURI = "https://{0}/powershell" -f $RemoteHost ConfigurationName = 'Microsoft.Exchange' Credential = $creds ErrorAction = 'Stop' } $Global:PSExchangeRemote = New-PSSession @ConnectionParams } catch { # Write a error message to the log. $MessageParams = @{ Message = "Unable to connect to {0} using Type {1}." -f $RemoteHost, $Type ErrorAction = 'Stop' } Write-Error @MessageParams } } "SCP" { $WinSCPSessionParams = @{ Credential = $creds Hostname = $RemoteHost Protocol = 'Scp' GiveUpSecurityAndAcceptAnySshHostKey = $True } try { $SessionOption = New-WinSCPSessionOption @WinSCPSessionParams $Global:WinSCPSession = New-WinSCPSession -SessionOption $SessionOption Write-Verbose -Message ( "SCP Connection established with {0}" -f $Global:WinSCPSession.Hostname ) } 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 } # 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. " -f $RemoteHost, $Type) + "But now it seems to be lost!" ) 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 } } } } } # srcFile: /drone/src/src/Connection/Disconnect-From.ps1 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, FTP, NetAppFAS, VMware, CisServer, ExchangeHTTP, ExchangeHTTPS, SCP. .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 .EXAMPLE Disconnect-From -RemoteHost "vcenter.myside.local" -Type CisServer .EXAMPLE Disconnect-From -RemoteHost "exchange01.myside.local" -Type ExchangeHTTP .EXAMPLE Disconnect-From -RemoteHost "exchange01.myside.local" -Type ExchangeHTTPS #> [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidGlobalVars', '', Justification = 'Wrapping existing global vars from external modules' )] param ( [Parameter(Mandatory = $true)] [string]$RemoteHost, [Parameter(Mandatory = $true)] [ValidateSet( 'CiscoUcs', 'FTP', 'NetAppFAS', 'VMware', 'CisServer', 'ExchangeHTTP', 'ExchangeHTTPS', 'SCP' )] [string]$Type, [Parameter(Mandatory = $false)] [switch]$Force ) begin {} process { switch -Regex ($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 } } "CisServer" { try { if ($Force) { Disconnect-CisServer -Server $RemoteHost -Confirm:$false -ErrorAction Stop -Force:$true } else { Disconnect-CisServer -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 } } "ExchangeHTTP*" { try { Get-Variable -Name 'PSExchangeRemote' -Scope Global -ErrorAction Stop Remove-PSSession -Session $Global:PSExchangeRemote -ErrorAction Stop } catch { $MessageParams = @{ Message = "Unable to disconnect from {0} using Type {1}." -f $RemoteHost, $Type ErrorAction = 'Stop' } Write-Error @MessageParams } } "SCP" { if ($Global:WinSCPSession.Opened) { Remove-WinSCPSession -WinSCPSession $Global:WinSCPSession } else { $MessageParams = @{ Message = 'There is no open WinSCP Session' 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 } } } end {} } # srcFile: /drone/src/src/Connection/Test-CSConnection.ps1 function Test-CSConnection { <# .SYNOPSIS Returns the connection state of a given type to the remote host. .DESCRIPTION Use this script to check a connection which was established with the `Connect-To` cmdlet. .PARAMETER RemoteHost Define the remote host you would like to check. .Parameter Type Define the connection type you would like to check. See the `Connect-To` documentation for valid type values. .INPUTS [None] .OUTPUTS [bool] .EXAMPLE Test-CMConnection -RemoteHost "vcr01.internal.net" -Type VMware #> [CmdletBinding()] [OutputType([bool])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$RemoteHost, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet("CiscoUcs", "FTP", "NetAppFAS", "VMware")] [string]$Type ) switch ($Type) { 'VMware' { try { $Conn = Get-Variable -Name DefaultVIServer -Scope Global -ErrorAction Stop } catch [System.Management.Automation.ItemNotFoundException] { $MsgParams = @{ Message = "There is no open PowerCLI VMware connection bound to 'DefaultVIServer'." } Write-Verbose @MsgParams return $false } if ($Conn.Value.Name -eq $RemoteHost) { if ($Conn.Value.IsConnected) { $MsgParams = @{ Message = "'DefaultVIServer' found. Connection to given remote host already established." } Write-Verbose @MsgParams return $True } else { $MsgParams = @{ Message = "'DefaultVIServer' found. RemoteHost matches but the connection is closed." } Write-Verbose @MsgParams return $false } } } 'CiscoUcs' { $MsgParams = @{ ErrorAction = "Stop" Message = "CiscoUCS connection test is not implemented yet!" } Write-Error @MsgParams return $false } 'FTP' { $MsgParams = @{ ErrorAction = "Stop" Message = "FTP connection test is not implemented yet!" } Write-Error @MsgParams return $false } 'NetAppFAS' { $MsgParams = @{ ErrorAction = "Stop" Message = "NetAppFAS connection test is not implemented yet!" } Write-Error @MsgParams return $false } # The Default section will never be shown as long as the powershell framework isn't broken. Default { $MsgParams = @{ ErrorAction = "Stop" Message = "Panic: There is an invalid type value! This error should never be thrown." } Write-Error @MsgParams return $false } } } |