├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── Tests ├── Add-ObjectDetail.Tests.ps1 ├── ConvertTo-InsecureString.Tests.ps1 ├── Get-PARComponent.Tests.ps1 ├── Get-PARComponentConfig.Tests.ps1 ├── Get-PARComponentLog.Tests.ps1 ├── Get-PARServer.Tests.ps1 ├── Get-PARServerLog.Tests.ps1 ├── Get-PARService.Tests.ps1 ├── Invoke-PARClient.Tests.ps1 ├── Restart-PARComponent.Tests.ps1 ├── Restart-PARServer.Tests.ps1 ├── Set-PARComponentConfig.Tests.ps1 ├── Set-PARConfiguration.Tests.ps1 ├── Start-PARClientProcess.Tests.ps1 ├── Start-PARComponent.Tests.ps1 ├── Stop-PARComponent.Tests.ps1 └── VaultControl.Tests.ps1 ├── VaultControl ├── Functions │ ├── Get-PARComponent.ps1 │ ├── Get-PARComponentConfig.ps1 │ ├── Get-PARComponentLog.ps1 │ ├── Get-PARServer.ps1 │ ├── Get-PARServerLog.ps1 │ ├── Get-PARService.ps1 │ ├── Restart-PARComponent.ps1 │ ├── Restart-PARServer.ps1 │ ├── Set-PARComponentConfig.ps1 │ ├── Set-PARConfiguration.ps1 │ ├── Start-PARComponent.ps1 │ └── Stop-PARComponent.ps1 ├── Private │ ├── Add-ObjectDetail.ps1 │ ├── ConvertTo-InsecureString.ps1 │ ├── Invoke-PARClient.ps1 │ └── Start-PARClientProcess.ps1 ├── VaultControl.Formats.ps1xml ├── VaultControl.psd1 └── VaultControl.psm1 ├── appveyor.yml └── build ├── build.ps1 ├── deploy-github.ps1 ├── deploy-psgallery.ps1 ├── install.ps1 └── test.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: pspete # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [1.1.54] - 2020-02-12 6 | 7 | - Update `Get-PARServer` 8 | - Corrected property name in output & description in help text. 9 | - Updated to show disk data for any partitions additional to `C:\` 10 | 11 | ## [1.0.46] - 2019-02-18 12 | 13 | - 1.0 Release 14 | - Published to PowerShell Gallery -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behaviour that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behaviour by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviours that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at VaultControl@virtualreal.it. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributions welcomed and are appreciated. 4 | 5 | ## PowerShell Styleguide 6 | 7 | Use the standard *Verb*-*Noun* convention, and only use approved verbs. 8 | 9 | All Functions must have Comment Based Help. 10 | 11 | [K&R (One True Brace Style variant)](https://github.com/PoshCode/PowerShellPracticeAndStyle/issues/81) preferred. 12 | 13 | ## Contributing Code 14 | 15 | - Fork the repo. 16 | - Push your changes to your fork. 17 | - Write a [good commit message][commit] 18 | - Submit a pull request 19 | - Keep pull requests limited to a single issue 20 | - Discussion, or necessary changes may be needed before merging the contribution. 21 | 22 | [commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 Pete Maan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VaultControl 2 | 3 | | Master Branch | Latest Build | CodeFactor | Coverage | PowerShell Gallery | License | 4 | |--------------------------|-------------------------|---------------------------|-----------------------------|---------------------------|----------------------------| 5 | |[![appveyor][]][av-site] |[![tests][]][tests-site] | [![codefactor][]][cf-site]| [![codecov][]][codecov-link]| [![psgallery][]][ps-site] |[![license][]][license-link]| 6 | | | | | [![coveralls][]][cv-site] | [![downloads][]][ps-site] | | 7 | 8 | 9 | [appveyor]:https://ci.appveyor.com/api/projects/status/svnyleaaupspfk1q/branch/master?svg=true 10 | [av-site]:https://ci.appveyor.com/project/pspete/vaultcontrol/branch/master 11 | [tests]:https://img.shields.io/appveyor/tests/pspete/vaultcontrol.svg 12 | [tests-site]:https://ci.appveyor.com/project/pspete/vaultcontrol 13 | [coveralls]:https://coveralls.io/repos/github/pspete/VaultControl/badge.svg 14 | [cv-site]:https://coveralls.io/github/pspete/VaultControl 15 | [psgallery]:https://img.shields.io/powershellgallery/v/VaultControl.svg 16 | [ps-site]:https://www.powershellgallery.com/packages/VaultControl 17 | [license]:https://img.shields.io/github/license/pspete/vaultcontrol.svg 18 | [license-link]:https://github.com/pspete/VaultControl/blob/master/LICENSE.md 19 | [downloads]:https://img.shields.io/powershellgallery/dt/vaultcontrol.svg?color=blue 20 | [cf-site]:https://www.codefactor.io/repository/github/pspete/vaultcontrol 21 | [codefactor]:https://www.codefactor.io/repository/github/pspete/vaultcontrol/badge 22 | [codecov]:https://codecov.io/gh/pspete/VaultControl/branch/master/graph/badge.svg 23 | [codecov-link]:https://codecov.io/gh/pspete/VaultControl 24 | 25 | Invoke CyberArk PARClient.exe Utility Commands with PowerShell 26 | 27 | ## Getting Started 28 | 29 | - `import-module VaultControl` 30 | - Run `Set-PARConfiguration` to set the path to the `PARClient.exe` utility on your computer, and any non-default port used for PARClient operations. 31 | 32 | ### List of Commands 33 | 34 | - `Get-PARServer` - Gets resource and component information from a vault 35 | - `Get-PARComponent` - Gets vault component status 36 | - `Get-PARComponentLog` - Gets component log content 37 | - `Get-PARComponentConfig` - Gets DBParm/PADR parameter values 38 | - `Get-PARServerLog` - Gets OS event logs from vault server 39 | - `Get-PARService` - Gets status of monitored Operating System services 40 | - `Restart-PARComponent` - Restarts CyberArk Vault/PADR/ENE/CVM component 41 | - `Restart-PARServer` - Initiates reboot of Vault server 42 | - `Set-PARComponentConfig` - Updates DBParm/PADR parameter values 43 | - `Start-PARComponent` - Starts CyberArk Vault/PADR/ENE/CVM component 44 | - `Stop-PARComponent` - Stops CyberArk Vault/PADR/ENE/CVM component 45 | - `Set-PARConfiguration` - Sets default values for path to PARClient.exe & PARClient Port 46 | 47 | ## Installation 48 | 49 | ### Prerequisites 50 | 51 | - Requires Powershell v3 (minimum) 52 | - CyberArk PARClient.exe utility 53 | - CyberArk Vault/PADR/ENE with which to interact 54 | 55 | ### Install Options 56 | 57 | This repository contains a folder named ```VaultControl```. 58 | 59 | The folder and it's contents needs to be present in one of your PowerShell Module Directories. 60 | 61 | Use one of the following methods: 62 | 63 | #### Option 1: Install from PowerShell Gallery 64 | 65 | Download the module from the [PowerShell Gallery](https://www.powershellgallery.com/packages/VaultControl/). 66 | 67 | - PowerShell 5.0 or above required. 68 | 69 | From a PowerShell prompt, run: 70 | 71 | ````powershell 72 | Install-Module -Name VaultControl -Scope CurrentUser 73 | ```` 74 | 75 | #### Option 2: Manual Install 76 | 77 | Find your PowerShell Module Paths with the following command: 78 | 79 | ```powershell 80 | 81 | $env:PSModulePath.split(';') 82 | 83 | ``` 84 | [Download a Release](https://github.com/pspete/VaultControl/releases) or the [```master``` branch](https://github.com/pspete/VaultControl/archive/master.zip) 85 | 86 | Extract the archive 87 | 88 | Copy the ```VaultControl``` folder to your "Powershell Modules" directory of choice. 89 | 90 | ## Changelog 91 | 92 | All notable changes to this project will be documented in the [Changelog](CHANGELOG.md) 93 | 94 | ## Author 95 | 96 | - **Pete Maan** - [pspete](https://github.com/pspete) 97 | 98 | ## License 99 | 100 | This project is [licensed under the MIT License](LICENSE.md). 101 | 102 | ## Contributing 103 | 104 | Feedback, Issues and Pull Requests are encouraged. 105 | -------------------------------------------------------------------------------- /Tests/Add-ObjectDetail.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "General" { 39 | 40 | BeforeEach { 41 | 42 | $InputObj = [pscustomobject]@{} 43 | $InputObj | Add-ObjectDetail -TypeName SomeType -PropertyToAdd @{"SomeProperty" = "SomeValue"} -DefaultProperties SomeProperty 44 | 45 | } 46 | 47 | It "Adds Expected Type to Object" { 48 | 49 | $InputObj | get-member | select-object -expandproperty typename -Unique | Should Be "SomeType" 50 | 51 | } 52 | 53 | It "Adds Expected Property to Object" { 54 | 55 | $InputObj.SomeProperty | Should Be "SomeValue" 56 | 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /Tests/ConvertTo-InsecureString.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'SecureString'} 41 | 42 | It "specifies parameter as mandatory" -TestCases $Parameters { 43 | 44 | param($Parameter) 45 | 46 | (Get-Command ConvertTo-InsecureString).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 47 | 48 | } 49 | 50 | } 51 | 52 | Context "General" { 53 | 54 | BeforeEach { 55 | 56 | $InputObj = [pscustomobject]@{ 57 | SecureString = ConvertTo-SecureString SomeSecureString -AsPlainText -Force 58 | } 59 | 60 | } 61 | 62 | It "converts securestring to plaintext" { 63 | 64 | ConvertTo-InsecureString -SecureString $InputObj.SecureString| Should Be "SomeSecureString" 65 | 66 | } 67 | 68 | } 69 | 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /Tests/Get-PARComponent.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Get-PARComponent).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{} 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | Server = "SomeServer" 66 | Component = "Vault" 67 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 68 | } 69 | 70 | } 71 | 72 | It "executes command" { 73 | 74 | $InputObj | Get-PARComponent -verbose 75 | 76 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 77 | 78 | } 79 | 80 | It "executes command with expected parameters" { 81 | 82 | $InputObj | Get-PARComponent -verbose 83 | 84 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 85 | 86 | $CommandParameters -eq "Status Vault" 87 | 88 | } -Times 1 -Exactly -Scope It 89 | 90 | } 91 | 92 | It "does not throw if no result on StdOut" { 93 | 94 | {$InputObj | Get-PARComponent -Verbose} | Should Not throw 95 | 96 | } 97 | 98 | It "reports running status" { 99 | 100 | $InputObj = [pscustomobject]@{ 101 | Server = "SomeServer" 102 | Component = "Vault" 103 | PassFile = (Join-Path $pwd "README.md") 104 | } 105 | 106 | Mock Invoke-PARClient -MockWith { 107 | Write-Output @{"StdOut" = "The vault service is running"} 108 | } 109 | 110 | $InputObj | Get-PARComponent -Verbose | Select-Object -ExpandProperty Status | Should Be "Running" 111 | 112 | } 113 | 114 | It "reports starting status" { 115 | 116 | $InputObj = [pscustomobject]@{ 117 | Server = "SomeServer" 118 | Component = "Vault" 119 | PassFile = (Join-Path $pwd "README.md") 120 | } 121 | 122 | Mock Invoke-PARClient -MockWith { 123 | Write-Output @{"StdOut" = "The vault service is starting"} 124 | } 125 | 126 | $InputObj | Get-PARComponent -Verbose | Select-Object -ExpandProperty Status | Should Be "Starting" 127 | 128 | } 129 | 130 | It "reports stopped status" { 131 | 132 | $InputObj = [pscustomobject]@{ 133 | Server = "SomeServer" 134 | Component = "Vault" 135 | PassFile = (Join-Path $pwd "README.md") 136 | } 137 | 138 | Mock Invoke-PARClient -MockWith { 139 | Write-Output @{"StdOut" = "The vault service is stopped"} 140 | } 141 | 142 | $InputObj | Get-PARComponent -Verbose | Select-Object -ExpandProperty Status | Should Be "Stopped" 143 | 144 | } 145 | 146 | It "reports unknown status in full" { 147 | 148 | $InputObj = [pscustomobject]@{ 149 | Server = "SomeServer" 150 | Component = "Vault" 151 | PassFile = (Join-Path $pwd "README.md") 152 | } 153 | 154 | Mock Invoke-PARClient -MockWith { 155 | @{"StdOut" = "The vault said something else"} 156 | } 157 | 158 | $InputObj | Get-PARComponent -Verbose | Select-Object -ExpandProperty Status | Should Be "The vault said something else" 159 | 160 | } 161 | 162 | 163 | } 164 | 165 | Context "Output" { 166 | 167 | 168 | 169 | } 170 | 171 | } 172 | 173 | } -------------------------------------------------------------------------------- /Tests/Get-PARComponentConfig.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Get-PARComponentConfig).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{} 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | Server = "SomeServer" 66 | Component = "Vault" 67 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 68 | Parameter = "DebugLevel" 69 | } 70 | 71 | } 72 | 73 | It "executes command" { 74 | 75 | $InputObj | Get-PARComponentConfig -verbose 76 | 77 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 78 | 79 | } 80 | 81 | It "executes command with expected parameters" { 82 | 83 | $InputObj | Get-PARComponentConfig 84 | 85 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 86 | 87 | $CommandParameters -eq "GetParm Vault DebugLevel" 88 | 89 | } -Times 1 -Exactly -Scope It 90 | 91 | } 92 | 93 | It "reports returned value status" { 94 | 95 | Mock Invoke-PARClient -MockWith { 96 | Write-Output @{"StdOut" = "DebugLevel=PE(1),PERF(1)"} 97 | } 98 | 99 | $InputObj | Get-PARComponentConfig | Select-Object -ExpandProperty Value | Should Be "PE(1),PERF(1)" 100 | 101 | } 102 | 103 | It "reports returned value status" { 104 | 105 | Mock Invoke-PARClient -MockWith { 106 | Write-Output @{"StdOut" = "DebugLevel"} 107 | } 108 | 109 | $InputObj | Get-PARComponentConfig | Select-Object -ExpandProperty Value | Should Be "DebugLevel" 110 | 111 | } 112 | 113 | It "throws if invalid vault parameter specified" { 114 | $InputObj = [pscustomobject]@{ 115 | Server = "SomeServer" 116 | Component = "Vault" 117 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 118 | Parameter = "FailoverMode" 119 | } 120 | 121 | {$InputObj | Get-PARComponentConfig} | Should throw 122 | 123 | } 124 | 125 | It "throws if invalid PADR parameter specified" { 126 | $InputObj = [pscustomobject]@{ 127 | Server = "SomeServer" 128 | Component = "PADR" 129 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 130 | Parameter = "DebugLevel" 131 | } 132 | 133 | {$InputObj | Get-PARComponentConfig} | Should throw 134 | 135 | } 136 | 137 | 138 | } 139 | 140 | Context "Output" { 141 | 142 | 143 | 144 | } 145 | 146 | } 147 | 148 | } -------------------------------------------------------------------------------- /Tests/Get-PARComponentLog.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Get-PARComponentLog).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{"StdOut" = "04/05/2018 16:01:40 ITAIGM03I DebugLevel 1 ACTIVATED for Class PE"} 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | Server = "SomeServer" 66 | Component = "Vault" 67 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 68 | } 69 | 70 | } 71 | 72 | It "executes command" { 73 | 74 | $InputObj | Get-PARComponentLog -verbose 75 | 76 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 77 | 78 | } 79 | 80 | It "executes command with expected parameters" { 81 | 82 | $InputObj | Get-PARComponentLog -verbose 83 | 84 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 85 | 86 | $CommandParameters -eq "GetLog Vault" 87 | 88 | } -Times 1 -Exactly -Scope It 89 | 90 | } 91 | 92 | It "reports returned event time" { 93 | 94 | $InputObj = [pscustomobject]@{ 95 | Server = "SomeServer" 96 | Component = "Vault" 97 | PassFile = (Join-Path $pwd "README.md") 98 | } 99 | 100 | $InputObj | Get-PARComponentLog -Verbose | Select-Object -ExpandProperty Time | Should Be "04/05/2018 16:01:40" 101 | 102 | } 103 | 104 | It "reports returned event code" { 105 | 106 | $InputObj | Get-PARComponentLog -Verbose | Select-Object -ExpandProperty Code | Should Be "ITAIGM03I" 107 | 108 | } 109 | 110 | It "reports returned event message" { 111 | 112 | $InputObj | Get-PARComponentLog -Verbose | Select-Object -ExpandProperty Message | Should Be "DebugLevel 1 ACTIVATED for Class PE" 113 | 114 | } 115 | 116 | It "sends correct format of timefrom" { 117 | 118 | $InputObj = [pscustomobject]@{ 119 | Server = "SomeServer" 120 | Component = "PADR" 121 | PassFile = (Join-Path $pwd "README.md") 122 | TimeFrom = (Get-Date 01/01/1970) 123 | } 124 | 125 | $InputObj | Get-PARComponentLog 126 | 127 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 128 | 129 | $CommandParameters -eq "GetLog PADR /TimeFrom 01011970:0000" 130 | 131 | } -Times 1 -Exactly -Scope It 132 | 133 | } 134 | 135 | It "sends correct format of lines" { 136 | 137 | $InputObj = [pscustomobject]@{ 138 | Server = "SomeServer" 139 | Component = "Vault" 140 | PassFile = (Join-Path $pwd "README.md") 141 | Lines = 66 142 | } 143 | 144 | $InputObj | Get-PARComponentLog 145 | 146 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 147 | 148 | $CommandParameters -eq "GetLog Vault /Lines 66" 149 | 150 | } -Times 1 -Exactly -Scope It 151 | 152 | } 153 | 154 | It "sends correct command format for console logfile" { 155 | 156 | $InputObj = [pscustomobject]@{ 157 | Server = "SomeServer" 158 | Component = "ENE" 159 | PassFile = (Join-Path $pwd "README.md") 160 | LogFile = "Console" 161 | } 162 | 163 | $InputObj | Get-PARComponentLog 164 | 165 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 166 | 167 | $CommandParameters -eq "GetLog ENE /LogFile Console" 168 | 169 | } -Times 1 -Exactly -Scope It 170 | 171 | } 172 | 173 | It "sends correct command format for trace logfile" { 174 | 175 | $InputObj = [pscustomobject]@{ 176 | Server = "SomeServer" 177 | Component = "ENE" 178 | PassFile = (Join-Path $pwd "README.md") 179 | LogFile = "Trace" 180 | } 181 | 182 | $InputObj | Get-PARComponentLog 183 | 184 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 185 | 186 | $CommandParameters -eq "GetLog ENE /LogFile Trace" 187 | 188 | } -Times 1 -Exactly -Scope It 189 | 190 | } 191 | 192 | It "has placeholder logic for cvm" { 193 | 194 | $InputObj = [pscustomobject]@{ 195 | Server = "SomeServer" 196 | Component = "CVM" 197 | PassFile = (Join-Path $pwd "README.md") 198 | LogFile = "Trace" 199 | } 200 | 201 | $InputObj | Get-PARComponentLog 202 | 203 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 204 | 205 | $CommandParameters -eq "GetLog CVM /LogFile Trace" 206 | 207 | } -Times 1 -Exactly -Scope It 208 | 209 | } 210 | 211 | } 212 | 213 | Context "Output" { 214 | 215 | 216 | 217 | } 218 | 219 | } 220 | 221 | } -------------------------------------------------------------------------------- /Tests/Get-PARServer.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Password'}, 42 | @{Parameter = 'Credential'}, 43 | @{Parameter = 'PassFile'} 44 | 45 | It "specifies parameter as mandatory" -TestCases $Parameters { 46 | 47 | param($Parameter) 48 | 49 | (Get-Command Get-PARServer).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 50 | 51 | } 52 | 53 | } 54 | 55 | Context "Error Actions" { 56 | 57 | BeforeEach { 58 | 59 | Mock Invoke-PARClient -MockWith { 60 | write-Error "some error" 61 | } 62 | 63 | $InputObj = [pscustomobject]@{ 64 | Server = "SomeServer" 65 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 66 | } 67 | 68 | } 69 | 70 | It "stops on error" { 71 | 72 | try { 73 | $InputObj | Get-PARServer 74 | } catch {"catch test exception"} 75 | Finally { 76 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 77 | } 78 | } 79 | 80 | It "outputs no object on error" { 81 | 82 | try { 83 | $Result = $InputObj | Get-PARServer 84 | } catch {"catch test exception"} 85 | Finally { 86 | $Result | Should BeNullOrEmpty 87 | } 88 | } 89 | 90 | } 91 | 92 | Context "Command Execution" { 93 | 94 | 95 | BeforeEach { 96 | 97 | Mock Invoke-PARClient -MockWith { 98 | } 99 | 100 | $InputObj = [pscustomobject]@{ 101 | Server = "SomeServer" 102 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 103 | } 104 | 105 | } 106 | 107 | It "executes expected commands" { 108 | 109 | $InputObj | Get-PARServer -Verbose 110 | 111 | Assert-MockCalled Invoke-PARClient -Times 4 -Exactly -Scope It 112 | 113 | } 114 | 115 | It "executes GetCPU command" { 116 | 117 | $InputObj | Get-PARServer -verbose 118 | 119 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 120 | 121 | $CommandParameters -eq "GetCPU" 122 | 123 | } -Times 1 -Scope It 124 | 125 | } 126 | 127 | It "executes GetDiskUsage command" { 128 | 129 | $InputObj | Get-PARServer -verbose 130 | 131 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 132 | 133 | $CommandParameters -eq "GetDiskUsage" 134 | 135 | } -Times 1 -Scope It 136 | 137 | } 138 | 139 | It "executes GetMemoryUsage command" { 140 | 141 | $InputObj | Get-PARServer -verbose 142 | 143 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 144 | 145 | $CommandParameters -eq "GetMemoryUsage" 146 | 147 | } -Times 1 -Scope It 148 | 149 | } 150 | 151 | It "executes List command" { 152 | 153 | 154 | $InputObj | Get-PARServer -verbose 155 | 156 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 157 | 158 | $CommandParameters -eq "List" 159 | 160 | } -Times 1 -Scope It 161 | 162 | } 163 | 164 | } 165 | 166 | Context "Return Value Parsing" { 167 | 168 | BeforeEach { 169 | 170 | $Script:counter = 0 171 | Mock Invoke-PARClient -MockWith { 172 | 173 | $Script:counter++ 174 | 175 | if ($Script:counter -eq 1) { 176 | # GetCPU 177 | [PSCustomObject]@{ 178 | "StdOut" = "%12.34" 179 | } 180 | } 181 | 182 | if($Script:counter -eq 2) { 183 | # GetDisk 184 | [PSCustomObject]@{"StdOut" = "C:\ 35336MB (69.92%)"} 185 | } 186 | 187 | if($Script:counter -eq 3) { 188 | # GetMemory 189 | [PSCustomObject]@{"StdOut" = @" 190 | Physical memory: Total=1047580K, Free=434336K, Utilized=58.54% 191 | Swap memory: Total=1834012K, Free=479088K, Utilized=73.88% 192 | "@ 193 | } 194 | } 195 | 196 | if($Script:counter -eq 4) { 197 | # List 198 | [PSCustomObject]@{"StdOut" = @" 199 | Vault module dbmain.exe 10.2.3.4 200 | ENE module ENE.exe 10.2.3.4 201 | PADR module PADR.exe 10.2.3.4 202 | "@ 203 | } 204 | } 205 | 206 | } 207 | 208 | 209 | $InputObj = [pscustomobject]@{ 210 | Server = "SomeServer" 211 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 212 | } 213 | 214 | } 215 | 216 | It "reports expected cpu info" { 217 | 218 | $InputObj | Get-PARServer | Select-Object -ExpandProperty "CPU(%)" | Should Be "12.34" 219 | 220 | } 221 | 222 | It "reports expected disk info" { 223 | $Output = $InputObj | Get-PARServer 224 | $Output.Disk.Drive | Should Be "C:\" 225 | $Output.Disk."FreeSpace(MB)" | Should Be "35336" 226 | $Output.Disk."FreeSpace(%)" | Should Be "69.92" 227 | 228 | } 229 | 230 | It "reports expected memory info" { 231 | $Output = $InputObj | Get-PARServer 232 | $Output.Memory[0].MemoryType | Should Be "Physical" 233 | $Output.Memory[0]."Total(K)" | Should Be "1047580" 234 | $Output.Memory[0]."Free(K)" | Should Be "434336" 235 | $Output.Memory[0]."Used(%)" | Should Be "58.54" 236 | $Output.Memory[1].MemoryType | Should Be "Swap" 237 | $Output.Memory[1]."Total(K)" | Should Be "1834012" 238 | $Output.Memory[1]."Free(K)" | Should Be "479088" 239 | $Output.Memory[1]."Used(%)" | Should Be "73.88" 240 | 241 | } 242 | 243 | It "reports expected component info" { 244 | $Output = $InputObj | Get-PARServer 245 | $Output.Components[0].Component | Should Be "Vault" 246 | $Output.Components[0].Version | Should Be "10.2.3.4" 247 | $Output.Components[1].Component | Should Be "ENE" 248 | $Output.Components[1].Version | Should Be "10.2.3.4" 249 | $Output.Components[2].Component | Should Be "PADR" 250 | $Output.Components[2].Version | Should Be "10.2.3.4" 251 | 252 | } 253 | 254 | } 255 | 256 | } 257 | 258 | } -------------------------------------------------------------------------------- /Tests/Get-PARServerLog.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Password'}, 42 | @{Parameter = 'Credential'}, 43 | @{Parameter = 'PassFile'}, 44 | @{Parameter = "LogName"} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Get-PARServerLog).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{ 62 | "StdOut" = @" 63 | EventLogRecordTime: Wed May 09 20:03:13 2018 64 | Source: Microsoft-Windows-Security-SPP 65 | Computer: zEPV1 66 | Event ID: 1073742727 67 | Event Type: 0 68 | Description: The Software Protection service has stopped. 69 | "@ 70 | 71 | } 72 | 73 | } 74 | 75 | $InputObj = [pscustomobject]@{ 76 | Server = "SomeServer" 77 | Component = "Vault" 78 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 79 | LogName = "Application" 80 | TimeFrom = (Get-Date 1/1/1970 -Hour 12 -Minute 34 -Second 56) 81 | } 82 | 83 | } 84 | 85 | It "executes command" { 86 | 87 | $InputObj | Get-PARServerLog -verbose 88 | 89 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 90 | 91 | } 92 | 93 | It "executes command with expected parameters" { 94 | $InputObj = [pscustomobject]@{ 95 | Server = "SomeServer" 96 | Component = "Vault" 97 | PassFile = (Join-Path $pwd README.md) 98 | LogName = "Application" 99 | TimeFrom = (Get-Date 1/1/1970 -Hour 12 -Minute 34 -Second 56) 100 | } 101 | 102 | $InputObj | Get-PARServerLog -verbose 103 | 104 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 105 | 106 | $CommandParameters -eq "GetOSLog /Name Application /TimeFrom 01011970:1234" 107 | 108 | } -Times 1 -Exactly -Scope It 109 | } 110 | 111 | } 112 | 113 | Context "Output" { 114 | 115 | 116 | 117 | } 118 | 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /Tests/Get-PARService.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Password'}, 42 | @{Parameter = 'Credential'}, 43 | @{Parameter = 'PassFile'} 44 | 45 | It "specifies parameter as mandatory" -TestCases $Parameters { 46 | 47 | param($Parameter) 48 | 49 | (Get-Command Get-PARService).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 50 | 51 | } 52 | 53 | } 54 | 55 | Context "Input" { 56 | 57 | BeforeEach { 58 | 59 | Mock Invoke-PARClient -MockWith { 60 | Write-Output @{"StdOut" = "PrivateArk Database is running"} 61 | } 62 | 63 | $InputObj = [pscustomobject]@{ 64 | Server = "SomeServer" 65 | Component = "Vault" 66 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 67 | } 68 | 69 | } 70 | 71 | It "executes command" { 72 | 73 | $InputObj | Get-PARService -verbose 74 | 75 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 76 | 77 | } 78 | 79 | It "executes command with expected parameters" { 80 | 81 | $InputObj = [pscustomobject]@{ 82 | Server = "SomeServer" 83 | Component = "Vault" 84 | PassFile = (Join-Path $pwd README.md) 85 | 86 | } 87 | 88 | $InputObj | Get-PARService -verbose 89 | 90 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 91 | 92 | $CommandParameters -eq 'ServiceStatus /ServiceName \"*\"' 93 | 94 | } -Times 1 -Exactly -Scope It 95 | } 96 | 97 | } 98 | 99 | Context "Output" { 100 | 101 | 102 | 103 | } 104 | 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /Tests/Invoke-PARClient.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | #Preference file must be removed and module must be re-imported for tests to complete 17 | Remove-Item -Path "$env:HOMEDRIVE$env:HomePath\PARConfiguration.xml" -Force -ErrorAction SilentlyContinue 18 | Remove-Module -Name $ModuleName -Force -ErrorAction SilentlyContinue 19 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 20 | 21 | BeforeAll { 22 | 23 | #$Script:RequestBody = $null 24 | 25 | } 26 | 27 | AfterAll { 28 | 29 | #$Script:RequestBody = $null 30 | 31 | } 32 | 33 | Describe $FunctionName { 34 | 35 | InModuleScope $ModuleName { 36 | 37 | Context "Mandatory Parameters" { 38 | 39 | $Parameters = @{Parameter = 'Server'}, 40 | @{Parameter = 'CommandParameters'}, 41 | @{Parameter = 'Password'}, 42 | @{Parameter = 'Credential'}, 43 | @{Parameter = 'PassFile'} 44 | 45 | It "specifies parameter as mandatory" -TestCases $Parameters { 46 | 47 | param($Parameter) 48 | 49 | (Get-Command Invoke-PARClient).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 50 | 51 | } 52 | 53 | 54 | 55 | } 56 | 57 | Context "Default" { 58 | 59 | BeforeEach { 60 | 61 | Mock Start-PARClientProcess -MockWith { 62 | Write-Output @{} 63 | } 64 | 65 | $InputObj = [pscustomobject]@{ 66 | Server = "SomeServer" 67 | CommandParameters = "Some Command Parameters" 68 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 69 | Port = 1234 70 | } 71 | 72 | 73 | } 74 | 75 | It "tests path" { 76 | 77 | {$InputObj | Invoke-PARClient -ClientPath .\RandomFile.exe} | Should Throw 78 | 79 | } 80 | 81 | It "throws if `$PAR variable not set in script scope" { 82 | 83 | {$InputObj | Invoke-PARClient} | Should Throw 84 | 85 | } 86 | 87 | It "throws if `$PAR variable does not have ClientPath property" { 88 | 89 | $object = [PSCustomObject]@{ 90 | prop1 = "Value1" 91 | prop2 = "Value2" 92 | } 93 | New-Variable -Name PAR -Value $object 94 | 95 | {$InputObj | Invoke-PARClient} | Should Throw 96 | 97 | } 98 | 99 | It "throws if `$PAR.ClientPath is not resolvable" { 100 | 101 | $object = [PSCustomObject]@{ 102 | ClientPath = ".\RandomFile.Exe" 103 | prop2 = "Value2" 104 | } 105 | New-Variable -Name PAR -Value $object 106 | 107 | {$InputObj | Invoke-PARClient} | Should Throw 108 | 109 | } 110 | 111 | It "no throw if `$PAR.ClientPath is resolvable" { 112 | 113 | $object = [PSCustomObject]@{ 114 | ClientPath = ".\README.md" 115 | prop2 = "Value2" 116 | } 117 | New-Variable -Name PAR -Value $object 118 | 119 | {$InputObj | Invoke-PARClient} | Should Throw 120 | 121 | } 122 | 123 | 124 | } 125 | 126 | Context "ParameterSets" { 127 | 128 | BeforeEach { 129 | 130 | Mock Test-Path -MockWith { 131 | $true 132 | } 133 | 134 | Mock Start-PARClientProcess -MockWith { 135 | Write-Output @{} 136 | } 137 | 138 | $InputObj = [pscustomobject]@{ 139 | Server = "SomeServer" 140 | CommandParameters = "Some Command Parameters" 141 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 142 | Port = 1234 143 | } 144 | 145 | 146 | } 147 | 148 | it "does not throw after Set-PARConfiguration has set the `$PAR variable" { 149 | 150 | Set-PARConfiguration -ClientPath "C:\SomePath\PARClient.exe" 151 | {$InputObj | Invoke-PARClient} | Should Not throw 152 | 153 | } 154 | 155 | it "does not require Set-PARConfiguration to be run more than once" { 156 | 157 | {$InputObj | Invoke-PARClient} | Should Not throw 158 | 159 | } 160 | 161 | It "executes command with password" { 162 | 163 | $InputObj | Invoke-PARClient 164 | 165 | Assert-MockCalled Start-PARClientProcess -Times 1 -Exactly -Scope It 166 | 167 | } 168 | 169 | It "executes command with credential" { 170 | 171 | $InputObj = [pscustomobject]@{ 172 | Server = "SomeServer" 173 | CommandParameters = "Some Command Parameters" 174 | Credential = New-Object System.Management.Automation.PSCredential ("username", $(ConvertTo-SecureString "SomePassword" -AsPlainText -Force)) 175 | } 176 | 177 | $InputObj | Invoke-PARClient 178 | 179 | Assert-MockCalled Start-PARClientProcess -Times 1 -Exactly -Scope It 180 | 181 | } 182 | 183 | It "executes command with credential" { 184 | 185 | $InputObj = [pscustomobject]@{ 186 | Server = "SomeServer" 187 | CommandParameters = "Some Command Parameters" 188 | PassFile = "SomeFile" 189 | } 190 | 191 | $InputObj | Invoke-PARClient 192 | 193 | Assert-MockCalled Start-PARClientProcess -Times 1 -Exactly -Scope It 194 | 195 | } 196 | 197 | } 198 | 199 | Context "Reporting Errors" { 200 | 201 | BeforeEach { 202 | 203 | $InputObj = [pscustomobject]@{ 204 | Server = "SomeServer" 205 | CommandParameters = "Some Command Parameters" 206 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 207 | Port = 1234 208 | } 209 | 210 | 211 | } 212 | 213 | it "reports 'ErrorCode Message' format errors on stdout" { 214 | 215 | Mock Start-PARClientProcess -MockWith { 216 | [pscustomobject]@{ 217 | "ExitCode" = 0 218 | "StdOut" = "PARCL002S Authentication failure." 219 | "StdErr" = $null 220 | } 221 | 222 | } 223 | 224 | {$InputObj | Invoke-PARClient -ErrorAction Stop} | Should Throw "Authentication failure." 225 | 226 | } 227 | 228 | it "reports '(ErrorCode) Message' format errors on stdout" { 229 | 230 | Mock Start-PARClientProcess -MockWith { 231 | [pscustomobject]@{ 232 | "ExitCode" = 0 233 | "StdOut" = "ERROR (999) Something Awful." 234 | "StdErr" = $null 235 | } 236 | 237 | } 238 | 239 | {$InputObj | Invoke-PARClient -ErrorAction Stop} | Should Throw "Something Awful." 240 | 241 | } 242 | 243 | it "reports 'Message (ErrorCode)' format errors on stdout" { 244 | 245 | Mock Start-PARClientProcess -MockWith { 246 | [pscustomobject]@{ 247 | "ExitCode" = 0 248 | "StdOut" = "Cannot get parameter DisableExceptionHandling. (Reason: 7)" 249 | "StdErr" = $null 250 | } 251 | 252 | } 253 | 254 | {$InputObj | Invoke-PARClient -ErrorAction Stop} | Should Throw "Cannot get parameter DisableExceptionHandling." 255 | 256 | } 257 | 258 | } 259 | 260 | Context "Command Arguments" { 261 | Mock Test-Path -MockWith { 262 | $true 263 | } 264 | 265 | Mock Start-PARClientProcess -MockWith { 266 | Write-Output @{} 267 | } 268 | 269 | $InputObj = [pscustomobject]@{ 270 | Server = "SomeServer" 271 | CommandParameters = "Some Command Parameters" 272 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 273 | Port = 1234 274 | } 275 | 276 | It "executes command with expected arguments" { 277 | 278 | $InputObj | Invoke-PARClient 279 | 280 | Assert-MockCalled Start-PARClientProcess -Times 1 -Exactly -Scope It -ParameterFilter { 281 | 282 | $Process.StartInfo.Arguments -eq $('SomeServer/SomePassword /Port 1234 /StateFileName ' + $(Join-Path $env:temp "$PID.tmp") + ' /Q /C "Some Command Parameters"') 283 | 284 | } 285 | 286 | } 287 | 288 | } 289 | 290 | } 291 | 292 | } -------------------------------------------------------------------------------- /Tests/Restart-PARComponent.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Restart-PARComponent).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{"StdOut" = "restarted"} 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | Server = "SomeServer" 66 | Component = "Vault" 67 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 68 | } 69 | 70 | } 71 | 72 | It "executes command" { 73 | 74 | $InputObj | Restart-PARComponent -verbose 75 | 76 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 77 | 78 | } 79 | 80 | It "executes command with expected parameters" { 81 | 82 | $InputObj = [pscustomobject]@{ 83 | Server = "SomeServer" 84 | Component = "Vault" 85 | PassFile = (Join-Path $pwd README.md) 86 | } 87 | #$DebugPreference = "Continue" 88 | $InputObj | Restart-PARComponent -verbose 89 | 90 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 91 | 92 | $CommandParameters -eq "Restart Vault" 93 | 94 | } -Times 1 -Exactly -Scope It 95 | } 96 | 97 | } 98 | 99 | Context "Output" { 100 | 101 | 102 | 103 | } 104 | 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /Tests/Restart-PARServer.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Password'}, 42 | @{Parameter = 'Credential'}, 43 | @{Parameter = 'PassFile'} 44 | 45 | It "specifies parameter as mandatory" -TestCases $Parameters { 46 | 47 | param($Parameter) 48 | 49 | (Get-Command Restart-PARServer).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 50 | 51 | } 52 | 53 | } 54 | 55 | Context "Input" { 56 | 57 | BeforeEach { 58 | 59 | Mock Invoke-PARClient -MockWith { 60 | Write-Output @{ 61 | "Server" = "Some Server" 62 | "StdOut" = "Some Message" 63 | } 64 | } 65 | 66 | $InputObj = [pscustomobject]@{ 67 | Server = "SomeServer" 68 | Component = "Vault" 69 | PassFile = (Join-Path $pwd "README.md") 70 | } 71 | 72 | } 73 | 74 | It "executes command" { 75 | 76 | $InputObj | Restart-PARServer -verbose 77 | 78 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 79 | 80 | } 81 | 82 | It "executes command with expected parameters" { 83 | 84 | $InputObj | Restart-PARServer -verbose 85 | 86 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 87 | 88 | $CommandParameters -eq "REBOOT" 89 | 90 | } -Times 1 -Exactly -Scope It 91 | } 92 | 93 | } 94 | 95 | Context "Output" { 96 | 97 | 98 | 99 | } 100 | 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /Tests/Set-PARComponentConfig.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Set-PARComponentConfig).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | Server = "SomeServer" 66 | Component = "Vault" 67 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 68 | Parameter = "DefaultTimeout" 69 | Value = "SomeValue" 70 | Mode = "Temporary" 71 | } 72 | 73 | } 74 | 75 | It "executes command" { 76 | 77 | $InputObj | Set-PARComponentConfig -verbose 78 | 79 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 80 | 81 | } 82 | 83 | It "executes command with expected parameters" { 84 | 85 | 86 | $InputObj | Set-PARComponentConfig -verbose 87 | 88 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 89 | 90 | $CommandParameters -eq "SetParm Vault DefaultTimeout=SomeValue /Temporary" 91 | 92 | } -Times 1 -Exactly -Scope It 93 | } 94 | 95 | } 96 | 97 | Context "Output" { 98 | 99 | BeforeEach { 100 | 101 | Mock Invoke-PARClient -MockWith { 102 | Write-Output @{"StdOut" = "Something Something Success Something"} 103 | } 104 | 105 | $InputObj = [pscustomobject]@{ 106 | Server = "SomeServer" 107 | Component = "Vault" 108 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 109 | Parameter = "DefaultTimeout" 110 | Value = "SomeValue" 111 | Mode = "Temporary" 112 | } 113 | 114 | } 115 | 116 | It "reports success" { 117 | $InputObj | Set-PARComponentConfig | Select-Object -ExpandProperty Status | Should Be "Success" 118 | } 119 | 120 | It "reports failure" { 121 | Mock Invoke-PARClient -MockWith { 122 | Write-Output @{"StdOut" = "Something Something extremely bad error"} 123 | } 124 | 125 | $InputObj | Set-PARComponentConfig | Select-Object -ExpandProperty Status | Should Be "Error" 126 | } 127 | 128 | } 129 | 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /Tests/Set-PARConfiguration.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "General" { 39 | 40 | BeforeEach { 41 | 42 | Mock Test-Path -MockWith { 43 | $true 44 | } 45 | 46 | $InputObj = [pscustomobject]@{ 47 | ClientPath = "SomePath" 48 | Port = 666 49 | } 50 | 51 | } 52 | 53 | it "sets value of script scope variable" { 54 | 55 | $InputObj | Set-PARConfiguration 56 | $Script:PAR | Should Not BeNullOrEmpty 57 | } 58 | 59 | it "sets client path property value" { 60 | $InputObj | Set-PARConfiguration 61 | $($Script:PAR.ClientPath) | Should Be "SomePath" 62 | } 63 | 64 | it "sets client path property value" { 65 | $InputObj | Set-PARConfiguration 66 | $($Script:PAR.Port) | Should Be 666 67 | } 68 | 69 | } 70 | 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /Tests/Start-PARClientProcess.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | #Preference file must be removed and module must be re-imported for tests to complete 17 | Remove-Item -Path "$env:HOMEDRIVE$env:HomePath\PARConfiguration.xml" -Force -ErrorAction SilentlyContinue 18 | Remove-Module -Name $ModuleName -Force -ErrorAction SilentlyContinue 19 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 20 | 21 | BeforeAll { 22 | 23 | #$Script:RequestBody = $null 24 | 25 | } 26 | 27 | AfterAll { 28 | 29 | #$Script:RequestBody = $null 30 | 31 | } 32 | 33 | Describe $FunctionName { 34 | 35 | InModuleScope $ModuleName { 36 | 37 | Context "Mandatory Parameters" { 38 | 39 | $Parameters = @{Parameter = 'Process'} 40 | 41 | It "specifies parameter as mandatory" -TestCases $Parameters { 42 | 43 | param($Parameter) 44 | 45 | (Get-Command Start-PARClientProcess).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 46 | 47 | } 48 | 49 | 50 | 51 | } 52 | 53 | Context "Default" { 54 | 55 | BeforeEach { 56 | 57 | $Process = New-MockObject -Type "System.Diagnostics.Process" 58 | $StandardOutput = New-Object -TypeName PSObject 59 | $StandardError = New-Object -TypeName PSObject 60 | 61 | $StandardOutput | Add-Member -MemberType ScriptMethod -Name ReadToEnd -Value {"Standard Output String"} -Force 62 | $StandardError | Add-Member -MemberType ScriptMethod -Name ReadToEnd -Value {"Standard Error String"} -Force 63 | 64 | $Process | Add-Member -MemberType ScriptMethod -Name Start -Value {$true} -Force 65 | $Process | Add-Member -MemberType ScriptMethod -Name WaitForExit -Value {$true} -Force 66 | $Process | Add-Member -MemberType NoteProperty -Name ExitCode -Value 9876 -Force 67 | $Process | Add-Member -MemberType ScriptMethod -Name Dispose -Value {$true} -Force 68 | $Process | Add-Member -MemberType NoteProperty -Name StandardOutput -Value $StandardOutput -Force 69 | $Process | Add-Member -MemberType NoteProperty -Name StandardError -Value $StandardError -Force 70 | 71 | $InputObj = [pscustomobject]@{ 72 | Process = $Process 73 | } 74 | 75 | 76 | } 77 | 78 | It "executes without exception" { 79 | 80 | {$InputObj | Start-PARClientProcess} | Should Not throw 81 | 82 | 83 | } 84 | 85 | 86 | 87 | 88 | } 89 | 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /Tests/Start-PARComponent.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Start-PARComponent).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{} 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | Server = "SomeServer" 66 | Component = "Vault" 67 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 68 | } 69 | 70 | } 71 | 72 | It "executes command" { 73 | 74 | $InputObj | Start-PARComponent 75 | 76 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 77 | 78 | } 79 | 80 | It "executes command with expected parameters" { 81 | 82 | $InputObj | Start-PARComponent -Last 83 | 84 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 85 | 86 | $CommandParameters -eq "Start Vault /Last" 87 | 88 | } -Times 1 -Exactly -Scope It 89 | } 90 | 91 | } 92 | 93 | Context "Output" { 94 | 95 | BeforeEach { 96 | 97 | Mock Invoke-PARClient -MockWith { 98 | Write-Output @{"StdOut" = "Huge Massive Big Ugly error"} 99 | } 100 | 101 | $InputObj = [pscustomobject]@{ 102 | Server = "SomeServer" 103 | Component = "Vault" 104 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 105 | } 106 | 107 | } 108 | 109 | It "reports failure" { 110 | $DebugPreference = "Continue" 111 | $Output = $InputObj | Start-PARComponent 112 | 113 | $Output.Status | Should Be "Error" 114 | 115 | } 116 | 117 | It "reports success" { 118 | Mock Invoke-PARClient -MockWith { 119 | Write-Output @{"StdOut" = "well that started something"} 120 | } 121 | $Output = $InputObj | Start-PARComponent 122 | 123 | $Output.Status | Should Be "Started" 124 | 125 | } 126 | 127 | } 128 | 129 | } 130 | 131 | } -------------------------------------------------------------------------------- /Tests/Stop-PARComponent.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Get Current Directory 2 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 3 | 4 | #Get Function Name 5 | $FunctionName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 6 | 7 | #Assume ModuleName from Repository Root folder 8 | $ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf 9 | 10 | #Resolve Path to Module Directory 11 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 12 | 13 | #Define Path to Module Manifest 14 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 15 | 16 | if( -not (Get-Module -Name $ModuleName -All)) { 17 | 18 | Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop 19 | 20 | } 21 | 22 | BeforeAll { 23 | 24 | #$Script:RequestBody = $null 25 | 26 | } 27 | 28 | AfterAll { 29 | 30 | #$Script:RequestBody = $null 31 | 32 | } 33 | 34 | Describe $FunctionName { 35 | 36 | InModuleScope $ModuleName { 37 | 38 | Context "Mandatory Parameters" { 39 | 40 | $Parameters = @{Parameter = 'Server'}, 41 | @{Parameter = 'Component'}, 42 | @{Parameter = 'Password'}, 43 | @{Parameter = 'Credential'}, 44 | @{Parameter = 'PassFile'} 45 | 46 | It "specifies parameter as mandatory" -TestCases $Parameters { 47 | 48 | param($Parameter) 49 | 50 | (Get-Command Stop-PARComponent).Parameters["$Parameter"].Attributes.Mandatory | Should Be $true 51 | 52 | } 53 | 54 | } 55 | 56 | Context "Input" { 57 | 58 | BeforeEach { 59 | 60 | Mock Invoke-PARClient -MockWith { 61 | Write-Output @{} 62 | } 63 | 64 | $InputObj = [pscustomobject]@{ 65 | 66 | Server = "SomeServer" 67 | Component = "Vault" 68 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 69 | ShutdownMode = "Terminate" 70 | 71 | } 72 | 73 | } 74 | 75 | It "executes command" { 76 | 77 | $InputObj | Stop-PARComponent -verbose 78 | 79 | Assert-MockCalled Invoke-PARClient -Times 1 -Exactly -Scope It 80 | 81 | } 82 | 83 | It "executes command with expected parameters" { 84 | 85 | $InputObj | Stop-PARComponent -verbose 86 | 87 | Assert-MockCalled Invoke-PARClient -ParameterFilter { 88 | 89 | $CommandParameters -eq "Stop Vault /Terminate" 90 | 91 | } -Times 1 -Exactly -Scope It 92 | } 93 | 94 | } 95 | 96 | Context "Output" { 97 | 98 | BeforeEach { 99 | 100 | Mock Invoke-PARClient -MockWith { 101 | Write-Output @{"StdOut" = "Huge Massive Big Ugly error"} 102 | } 103 | 104 | $InputObj = [pscustomobject]@{ 105 | Server = "SomeServer" 106 | Component = "Vault" 107 | Password = ConvertTo-SecureString "SomePassword" -AsPlainText -Force 108 | } 109 | 110 | } 111 | 112 | It "reports failure" { 113 | $DebugPreference = "Continue" 114 | $Output = $InputObj | Stop-PARComponent 115 | 116 | $Output.Status | Should Be "Error" 117 | 118 | } 119 | 120 | It "reports success" { 121 | Mock Invoke-PARClient -MockWith { 122 | Write-Output @{"StdOut" = "something stopped something"} 123 | } 124 | $Output = $InputObj | Stop-PARComponent 125 | 126 | $Output.Status | Should Be "Stopped" 127 | 128 | } 129 | 130 | } 131 | 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /Tests/VaultControl.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Pester, PSScriptAnalyzer 2 | <# 3 | .SYNOPSIS 4 | Tests module for consistency, expected structures, settings, components & files. 5 | .EXAMPLE 6 | Invoke-Pester 7 | .NOTES 8 | A generic set of tests to apply to a module 9 | #> 10 | 11 | #Get Current Directory 12 | $Here = Split-Path -Parent $MyInvocation.MyCommand.Path 13 | 14 | #Assume ModuleName from Test File Name 15 | $ModuleName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -Replace ".Tests.ps1" 16 | 17 | #Resolve Path to Module Directory 18 | $ModulePath = Resolve-Path "$Here\..\$ModuleName" 19 | 20 | #Define Path to Module Manifest 21 | $ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1" 22 | 23 | Get-Module -Name $ModuleName -All | Remove-Module -Force -ErrorAction Ignore 24 | $Module = Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop -PassThru 25 | 26 | Describe "Module" { 27 | 28 | Context "Module Consistency Tests" { 29 | 30 | It "has a valid manifest" { 31 | 32 | {$null = Test-ModuleManifest -Path $ManifestPath -ErrorAction Stop -WarningAction SilentlyContinue} | 33 | Should Not Throw 34 | 35 | } 36 | 37 | It "specifies valid root module" { 38 | 39 | $Module.RootModule | Should Be "$ModuleName.psm1" 40 | 41 | } 42 | 43 | It "has a valid description" { 44 | 45 | $Module.Description | Should Not BeNullOrEmpty 46 | 47 | } 48 | 49 | It "has a valid guid" { 50 | 51 | $Module.Guid | Should Be 'fba9035e-5d32-4a7f-ab91-5658c84e0668' 52 | 53 | } 54 | 55 | It "has a valid copyright" { 56 | 57 | $Module.Copyright | Should Not BeNullOrEmpty 58 | 59 | } 60 | 61 | Context "Files To Process" { 62 | 63 | #validate formats 64 | ($Module.FormatsToProcess).foreach{ 65 | 66 | $FormatFilePath = (Join-Path $ModulePath $_) 67 | 68 | #File Exists 69 | It "$_ exists" { 70 | 71 | $FormatFilePath | Should Exist 72 | 73 | } 74 | 75 | #file contains valid format data 76 | It "$_ is valid" { 77 | 78 | {Update-FormatData -AppendPath $FormatFilePath -ErrorAction Stop -WarningAction SilentlyContinue} | 79 | Should Not Throw 80 | 81 | } 82 | 83 | } 84 | 85 | #validate types 86 | ($Module.TypesToProcess).foreach{ 87 | 88 | $TypesFilePath = (Join-Path $ModulePath $_) 89 | 90 | #file exists 91 | It "$_ exists" { 92 | 93 | $TypesFilePath | Should Exist 94 | 95 | } 96 | 97 | #file contains valid type data 98 | It "$_ is valid" { 99 | 100 | {Update-TypeData -AppendPath $TypesFilePath -ErrorAction Stop -WarningAction SilentlyContinue} | 101 | Should Not Throw 102 | 103 | } 104 | 105 | } 106 | 107 | } 108 | 109 | #Get Public Function Names 110 | $PublicFunctions = Get-ChildItem "$ModulePath\Functions" -Filter *.ps1 -Recurse | 111 | Select-Object -ExpandProperty BaseName 112 | 113 | Context "Exported Function Analysis" { 114 | 115 | #Get Exported Function Names 116 | $ExportedFunctions = $Module.ExportedFunctions.Values.name 117 | 118 | It 'exports the expected number of functions' { 119 | 120 | ($PublicFunctions | Measure-Object | Select-Object -ExpandProperty Count) | 121 | 122 | Should be ($ExportedFunctions | Measure-Object | Select-Object -ExpandProperty Count) 123 | 124 | } 125 | 126 | $ExportedFunctions.foreach{ 127 | 128 | Context "$_" { 129 | 130 | It 'is a public function' { 131 | 132 | $PublicFunctions -contains $_ | Should Be $true 133 | 134 | } 135 | 136 | It 'has a related pester tests file' { 137 | Test-Path (Join-Path $here "$_.Tests.ps1") | Should Be $true 138 | } 139 | 140 | Context "Help" { 141 | 142 | $help = Get-Help $_ -Full 143 | 144 | It 'has synopsis' { 145 | 146 | $help.synopsis | Should Not BeNullOrEmpty 147 | 148 | } 149 | 150 | It 'has description' { 151 | 152 | $help.description | Should Not BeNullOrEmpty 153 | 154 | } 155 | 156 | It 'has example code' { 157 | 158 | $help.examples.example.code | Should Not BeNullOrEmpty 159 | 160 | } 161 | 162 | $HelpParameters = $help.parameters.parameter | Where-Object name -NotIn @("WhatIf", "Confirm") 163 | 164 | $HelpParameters.foreach{ 165 | 166 | It "has description of parameter $($_.name)" { 167 | 168 | $_.description | Should Not BeNullOrEmpty 169 | } 170 | 171 | } 172 | 173 | } 174 | 175 | } 176 | 177 | } 178 | 179 | } 180 | 181 | Context "Exported Alias Analysis" { 182 | 183 | $ExportedAliases = $Module.ExportedAliases.Values.name 184 | 185 | $ExportedAliases.foreach{ 186 | 187 | Context "$_" { 188 | 189 | It "Resolves to Public Function" { 190 | 191 | $PublicFunctions -contains $((Get-Alias $_).ResolvedCommand) | Should Be $true 192 | 193 | } 194 | 195 | 196 | } 197 | 198 | } 199 | 200 | 201 | } 202 | 203 | } 204 | 205 | Describe 'PSScriptAnalyzer' { 206 | 207 | $Scripts = Get-ChildItem "$ModulePath" -Filter '*.ps1' -Exclude '*.ps1xml' -Recurse 208 | 209 | $Rules = Get-ScriptAnalyzerRule 210 | 211 | foreach ($Script in $scripts) { 212 | 213 | Context "Checking: $($script.BaseName)" { 214 | 215 | foreach ($rule in $rules) { 216 | 217 | It "passes rule $rule" { 218 | 219 | (Invoke-ScriptAnalyzer -Path $script.FullName -IncludeRule $rule.RuleName ).Count | Should Be 0 220 | 221 | } 222 | 223 | } 224 | 225 | } 226 | 227 | } 228 | 229 | } 230 | 231 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Get-PARComponent.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PARComponent { 2 | <# 3 | .SYNOPSIS 4 | Queries the status of a component running on a remote vault server 5 | 6 | .DESCRIPTION 7 | Gets status of remote Vault, PADR, CVM or ENE component 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to query. Vault, PADR, CVM or ENE are the accepted values 24 | 25 | .EXAMPLE 26 | Get-PARComponent -Server 10.10.10.10 -Password $SecureString -Component Vault 27 | 28 | Returns status of Vault service on remote vault with address 10.10.10.10 29 | 30 | #> 31 | [CmdletBinding()] 32 | Param( 33 | [Parameter( 34 | Mandatory = $true, 35 | ValueFromPipelineByPropertyName = $true 36 | )] 37 | [string]$Server, 38 | 39 | [Parameter( 40 | Mandatory = $true, 41 | ValueFromPipelineByPropertyName = $true, 42 | ParameterSetName = "Password" 43 | )] 44 | [securestring]$Password, 45 | 46 | [Parameter( 47 | Mandatory = $true, 48 | ValueFromPipelineByPropertyName = $true, 49 | ParameterSetName = "Credential" 50 | )] 51 | [pscredential]$Credential, 52 | 53 | [Parameter( 54 | Mandatory = $True, 55 | ValueFromPipelineByPropertyName = $True, 56 | ParameterSetName = "PassFile" 57 | )] 58 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 59 | [string]$PassFile, 60 | 61 | [Parameter( 62 | Mandatory = $true, 63 | ValueFromPipelineByPropertyName = $true 64 | )] 65 | [ValidateSet("Vault", "PADR", "ENE", "CVM")] 66 | [string]$Component 67 | ) 68 | 69 | Process { 70 | 71 | $PSBoundParameters.Add("CommandParameters", "Status $Component") 72 | 73 | $Result = Invoke-PARClient @PSBoundParameters 74 | 75 | If($Result.StdOut) { 76 | 77 | switch -regex ($Result.StdOut) { 78 | 79 | 'running' {$Status = "Running"; break} 80 | 'starting' {$Status = "Starting"; break} 81 | 'stopped' {$Status = "Stopped"; break} 82 | default {$Status = $Result.StdOut; break} 83 | 84 | } 85 | 86 | [PSCustomObject]@{ 87 | 88 | "Server" = $Result.Server 89 | "Component" = $Component 90 | "Status" = $Status 91 | 92 | } 93 | 94 | } 95 | 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Get-PARComponentConfig.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PARComponentConfig { 2 | <# 3 | .SYNOPSIS 4 | Gets values set in component configuration files 5 | 6 | .DESCRIPTION 7 | Queries remote vault server for values contained in component configuration files DBPARM.ini or PADR.ini. 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to query. Vault or PADR are the accepted values 24 | 25 | .PARAMETER Parameter 26 | The name of the Parameter to get the value of. 27 | For Vault Components, the valid parameter names are: 28 | "DefaultTimeout", "MTU", "SecurityNotification", "DebugLevel", "DisableExceptionHandling" 29 | For Disaster Recovery Components, the valid parameter names are: 30 | "EnableCheck", "EnableReplicate", "EnableFailover", "EnableDBSync", "FailoverMode" 31 | 32 | .EXAMPLE 33 | Get-PARComponentConfig -Server EPV1 -Credential $credential -Component Vault -Parameter DebugLevel 34 | 35 | Returns the DebugLevel parameter value configured in the dbparm.ini file on vault server EPV1 36 | #> 37 | [CmdletBinding()] 38 | Param( 39 | [Parameter( 40 | Mandatory = $true, 41 | ValueFromPipelineByPropertyName = $true 42 | )] 43 | [string]$Server, 44 | 45 | [Parameter( 46 | Mandatory = $true, 47 | ValueFromPipelineByPropertyName = $true, 48 | ParameterSetName = "Password" 49 | )] 50 | [securestring]$Password, 51 | 52 | [Parameter( 53 | Mandatory = $true, 54 | ValueFromPipelineByPropertyName = $true, 55 | ParameterSetName = "Credential" 56 | )] 57 | [pscredential]$Credential, 58 | 59 | [Parameter( 60 | Mandatory = $True, 61 | ValueFromPipelineByPropertyName = $True, 62 | ParameterSetName = "PassFile" 63 | )] 64 | [string]$PassFile, 65 | 66 | [Parameter( 67 | Mandatory = $true, 68 | ValueFromPipelineByPropertyName = $true 69 | )] 70 | [ValidateSet("Vault", "PADR")] 71 | [string]$Component, 72 | 73 | [Parameter( 74 | Mandatory = $true, 75 | ValueFromPipelineByPropertyName = $true 76 | )] 77 | [ValidateSet("DefaultTimeout", "MTU", "SecurityNotification", "DebugLevel", "DisableExceptionHandling", 78 | "EnableCheck", "EnableReplicate", "EnableFailover", "EnableDBSync", "FailoverMode")] 79 | [string]$Parameter 80 | 81 | ) 82 | 83 | Begin { 84 | $VaultSet = "DefaultTimeout", "MTU", "SecurityNotification", "DebugLevel", "DisableExceptionHandling" 85 | $PADRSet = "EnableCheck", "EnableReplicate", "EnableFailover", "EnableDBSync", "FailoverMode" 86 | } 87 | Process { 88 | 89 | Switch($Component) { 90 | "Vault" { 91 | If($VaultSet -notcontains $Parameter) {throw "Not a valid DBPARM.ini Parameter"} 92 | } 93 | "PADR" { 94 | If($PADRSet -notcontains $Parameter) {throw "Not a valid PADR.ini Parameter"} 95 | } 96 | } 97 | 98 | $PSBoundParameters.Add("CommandParameters", "GetParm $Component $($PSBoundParameters["Parameter"])") 99 | 100 | $Result = Invoke-PARClient @PSBoundParameters 101 | 102 | If($Result.StdOut) { 103 | 104 | If($Result.StdOut -match "=") { 105 | 106 | $Value = ($Result.StdOut).Split("=")[1] 107 | 108 | } Else {$Value = $Result.StdOut} 109 | 110 | [PSCustomObject]@{ 111 | 112 | "Server" = $Result.Server 113 | "Component" = $Component 114 | "Parameter" = $($PSBoundParameters["Parameter"]) 115 | "Value" = $Value.Trim() 116 | 117 | } 118 | 119 | } 120 | 121 | } 122 | 123 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Get-PARComponentLog.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PARComponentLog { 2 | <# 3 | .SYNOPSIS 4 | Returns events from remote component log. 5 | 6 | .DESCRIPTION 7 | Gets events from logs for remote Vault, PADR, CVM or ENE. 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to query. Vault, PADR, CVM or ENE are the accepted values 24 | 25 | .PARAMETER LogFile 26 | For ENE & CVM Logs, the log file to return must be specified. Accepted values are "Console" or "Trace" 27 | 28 | .PARAMETER TimeFrom 29 | For Vault or PADR log queries, optionally provide a datetime from which to return the logs from. 30 | 31 | .PARAMETER Lines 32 | For Vault log queries, optionally provide the number of log lines to return. 33 | 34 | .EXAMPLE 35 | Get-PARComponentLog -Server EPV1 -Password $SecureString -Component Vault -TimeFrom (Get-Date).AddDays(-1) 36 | 37 | Show events from the ITALOG file on Vault EPV1 from the last 24 hours 38 | 39 | .EXAMPLE 40 | Get-PARComponentLog -Server EPV1 -Password $SecureString -Component ENE -LogFile Trace 41 | 42 | Show events from the ENE Trace log on vault EPV1 43 | 44 | .EXAMPLE 45 | Get-PARComponentLog -Server EPV1 -Password $SecureString -Component Vault -Lines 10 46 | 47 | Show the last 10 lines of the ITALOG file on vault EPV1 48 | 49 | #> 50 | [CmdletBinding()] 51 | Param( 52 | [Parameter( 53 | Mandatory = $true, 54 | ValueFromPipelineByPropertyName = $true 55 | )] 56 | [string]$Server, 57 | 58 | [Parameter( 59 | Mandatory = $true, 60 | ValueFromPipelineByPropertyName = $true, 61 | ParameterSetName = "Password" 62 | )] 63 | [securestring]$Password, 64 | 65 | [Parameter( 66 | Mandatory = $true, 67 | ValueFromPipelineByPropertyName = $true, 68 | ParameterSetName = "Credential" 69 | )] 70 | [pscredential]$Credential, 71 | 72 | [Parameter( 73 | Mandatory = $True, 74 | ValueFromPipelineByPropertyName = $True, 75 | ParameterSetName = "PassFile" 76 | )] 77 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 78 | [string]$PassFile, 79 | 80 | [Parameter( 81 | Mandatory = $true, 82 | ValueFromPipelineByPropertyName = $true 83 | )] 84 | [ValidateSet("Vault", "PADR", "ENE", "CVM")] 85 | [string]$Component, 86 | 87 | [Parameter( 88 | Mandatory = $false, 89 | ValueFromPipelineByPropertyName = $true 90 | )] 91 | [ValidateSet("Console", "Trace")] 92 | [string]$LogFile = "Console", 93 | 94 | [Parameter( 95 | Mandatory = $false, 96 | ValueFromPipelineByPropertyName = $true 97 | )] 98 | [datetime]$TimeFrom, 99 | 100 | [Parameter( 101 | Mandatory = $false, 102 | ValueFromPipelineByPropertyName = $true 103 | )] 104 | [int]$Lines 105 | ) 106 | 107 | Begin { 108 | 109 | $PADR = '^\[(\d+\/\d+\/\d+\s+\d+\:\d+\:\d+\.\d+)\]\W+([A-Z]+\d+[A-Z](?:\s))?(.+)$' 110 | $Vault = '^(\d+\/\d+\/\d+ \d+:\d+:\d+) ([A-Z]+[0-9]+[A-Z]) (.+)$' 111 | $ENEConsole = '^\[(\d+\/\d+\/\d+\s\W\s\d+\:\d+\:\d+)\]\W+([A-Z]+\d+[A-Z])\s(.+)$' 112 | $ENETrace = '^\[(\d+\/\d+\/\d+(?:\s\W)\s\d+\:\d+\:\d+)\.\d+\].+\|\s([A-Z]+(?:[A-Z]|\d)[A-Z]\d+[A-Z](?:\s))?(.+)$' 113 | 114 | } 115 | 116 | Process { 117 | 118 | $Command = "GetLog $Component" 119 | 120 | if(($Component -eq "VAULT") -or ($Component -eq "PADR")) { 121 | 122 | if($PSBoundParameters.ContainsKey("TimeFrom")) { 123 | 124 | $DateStamp = (Get-Date $($PSBoundParameters["TimeFrom"]) -Format ddMMyyyy:HHmm) 125 | $Command = "$Command /TimeFrom $DateStamp" 126 | 127 | } 128 | 129 | } 130 | 131 | if($Component -eq "VAULT") { 132 | 133 | if($PSBoundParameters.ContainsKey("Lines")) { 134 | 135 | $Command = "$Command /Lines $($PSBoundParameters["Lines"])" 136 | 137 | } 138 | 139 | } 140 | 141 | if(($Component -eq "ENE") -or ($Component -eq "CVM")) { 142 | 143 | $Command = "$Command /LogFile $($PSBoundParameters["LogFile"])" 144 | 145 | } 146 | 147 | $PSBoundParameters.Add("CommandParameters", "$Command") 148 | 149 | switch ($Component) { 150 | 151 | "PADR" {$Pattern = $PADR; break} 152 | 153 | "Vault" {$Pattern = $Vault; break} 154 | 155 | "ENE" { 156 | 157 | if ($($PSBoundParameters["LogFile"]) -eq "Console") { 158 | 159 | $Pattern = $ENEConsole; break 160 | 161 | } elseif ($($PSBoundParameters["LogFile"]) -eq "Trace") { 162 | 163 | $Pattern = $ENETrace; break 164 | 165 | } 166 | 167 | } 168 | 169 | default {$Pattern = '(.+)'; break} 170 | 171 | } 172 | 173 | $Result = Invoke-PARClient @PSBoundParameters 174 | 175 | If($Result.StdOut) { 176 | 177 | ($Result.StdOut).Split("`n") | ForEach-Object { 178 | 179 | $event = ($_ | Select-String $Pattern -AllMatches) 180 | 181 | if($event -match '\S') { 182 | 183 | [PSCustomObject]@{ 184 | 185 | "Time" = $event.Matches.Groups[1].Value -replace '(\s\W\s)', ' ' 186 | "Code" = $event.Matches.Groups[2].Value 187 | "Message" = $event.Matches.Groups[3].Value 188 | 189 | } | Add-ObjectDetail -typename VaultControl.Log.Component 190 | 191 | } 192 | 193 | } 194 | 195 | } 196 | 197 | } 198 | 199 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Get-PARServer.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PARServer { 2 | <# 3 | .SYNOPSIS 4 | Gets OS resource information from remote vault 5 | 6 | .DESCRIPTION 7 | Returns details of CPU, Memory & Free Disk space from remote vault, as well as details of installed components. 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .EXAMPLE 23 | Get-PARServer -Server EPV1 24 | 25 | Returns object containing current resource consumption & installed component names & versions. 26 | #> 27 | [CmdletBinding()] 28 | Param( 29 | [Parameter( 30 | Mandatory = $true, 31 | ValueFromPipelineByPropertyName = $true 32 | )] 33 | [string]$Server, 34 | 35 | [Parameter( 36 | Mandatory = $true, 37 | ValueFromPipelineByPropertyName = $true, 38 | ParameterSetName = "Password" 39 | )] 40 | [securestring]$Password, 41 | 42 | [Parameter( 43 | Mandatory = $true, 44 | ValueFromPipelineByPropertyName = $true, 45 | ParameterSetName = "Credential" 46 | )] 47 | [pscredential]$Credential, 48 | 49 | [Parameter( 50 | Mandatory = $True, 51 | ValueFromPipelineByPropertyName = $True, 52 | ParameterSetName = "PassFile" 53 | )] 54 | [string]$PassFile 55 | 56 | ) 57 | 58 | Process { 59 | 60 | Try { 61 | 62 | $ErrorActionPreference = "Stop" 63 | 64 | $PSBoundParameters["CommandParameters"] = "GetCPU" 65 | 66 | $CPU = Invoke-PARClient @PSBoundParameters 67 | 68 | $PSBoundParameters["CommandParameters"] = "GetDiskUsage" 69 | 70 | $Disk = Invoke-PARClient @PSBoundParameters 71 | 72 | $PSBoundParameters["CommandParameters"] = "GetMemoryUsage" 73 | 74 | $Memory = Invoke-PARClient @PSBoundParameters 75 | 76 | $PSBoundParameters["CommandParameters"] = "List" 77 | 78 | $Components = Invoke-PARClient @PSBoundParameters 79 | 80 | 81 | 82 | If($CPU.StdOut) { 83 | 84 | $CPU = ($CPU.StdOut | Select-String '(\d+\.\d+)' -AllMatches).Matches.Value 85 | 86 | } 87 | 88 | Else {$CPU = $null} 89 | 90 | If($Disk.StdOut) { 91 | 92 | $Disk = $Disk.StdOut | Select-String '(.+)' -AllMatches | ForEach-Object { 93 | 94 | $DiskInfo = $_.Line.Split(" ") 95 | 96 | For ($i = 0 ; $i -lt $DiskInfo.count ; $i += 3) { 97 | 98 | $Drive = $DiskInfo[$i..($i + 3)] 99 | 100 | [PSCustomObject]@{ 101 | 102 | "Drive" = $Drive[0] 103 | "FreeSpace(MB)" = ($Drive[1] | Select-String '(\d+)' -AllMatches).Matches.Value 104 | "FreeSpace(%)" = ($Drive[2] | Select-String '(\d+\.\d+)' -AllMatches).Matches.Value 105 | 106 | } 107 | 108 | } 109 | 110 | } 111 | 112 | } Else {$Disk = $null} 113 | 114 | If($Memory.StdOut) { 115 | 116 | $Memory = ($Memory.StdOut | Select-String '(.+)' -AllMatches).Matches.Value | ForEach-Object { 117 | 118 | $MemoryInfo = $_.Split(":") 119 | 120 | $MemoryData = ($MemoryInfo[1] | Select-String '(\S+)' -AllMatches).Matches.Value 121 | 122 | [PSCustomObject]@{ 123 | 124 | "MemoryType" = ($MemoryInfo[0].Split(" "))[0] 125 | "Total(K)" = (($MemoryData[0]).Split("=")[1] | Select-String '(\d+)' -AllMatches).Matches.Value 126 | "Free(K)" = (($MemoryData[1]).Split("=")[1] | Select-String '(\d+)' -AllMatches).Matches.Value 127 | "Used(%)" = (($MemoryData[2]).Split("=")[1] | Select-String '(\d+\.\d+)' -AllMatches).Matches.Value 128 | 129 | } 130 | 131 | } 132 | 133 | } 134 | 135 | Else {$Memory = $null} 136 | 137 | If($Components.StdOut) { 138 | 139 | $Components = ($Components.StdOut | Select-String '(.+)' -AllMatches).Matches.Value | ForEach-Object { 140 | 141 | $Component = $_.Split(" ") 142 | 143 | $Version = ($_ | Select-String "(\d+\D\d+\D\d+\D\d+)" -AllMatches).Matches.Value 144 | 145 | [PSCustomObject]@{ 146 | 147 | Component = $Component[0] 148 | Version = $Version 149 | 150 | } 151 | 152 | } 153 | 154 | } 155 | 156 | Else {$Components = $null} 157 | 158 | [PSCustomObject]@{ 159 | 160 | "Server" = $Server.ToUpper() 161 | "CPU(%)" = $CPU 162 | "Disk" = $Disk 163 | "Memory" = $Memory 164 | "Components" = $Components 165 | 166 | } 167 | 168 | } Catch {throw $_} 169 | 170 | } 171 | 172 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Get-PARServerLog.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PARServerLog { 2 | <# 3 | .SYNOPSIS 4 | Returns events from Server Event Logs 5 | 6 | .DESCRIPTION 7 | Queries remote vault server and returns events from specified OS Logs. 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER LogName 23 | The name of the event log to return events from. 24 | Application, Security & System are the accepted values. 25 | 26 | .PARAMETER TimeFrom 27 | A date time to return events from. 28 | 29 | .EXAMPLE 30 | Get-PARServerLog -Server EPV1 -Credential $Cred -LogName Application 31 | 32 | Get events from Application log on vault EPV1 33 | 34 | .EXAMPLE 35 | Get-PARServerLog -Server zEPV1 -Credential $Cred -LogName System -TimeFrom (Get-Date 5/5/2018) 36 | 37 | Get all events from the System log since Cinco de Mayo 2018 on vault EPV1 38 | #> 39 | [CmdletBinding()] 40 | Param( 41 | [Parameter( 42 | Mandatory = $true, 43 | ValueFromPipelineByPropertyName = $true 44 | )] 45 | [string]$Server, 46 | 47 | [Parameter( 48 | Mandatory = $true, 49 | ValueFromPipelineByPropertyName = $true, 50 | ParameterSetName = "Password" 51 | )] 52 | [securestring]$Password, 53 | 54 | [Parameter( 55 | Mandatory = $true, 56 | ValueFromPipelineByPropertyName = $true, 57 | ParameterSetName = "Credential" 58 | )] 59 | [pscredential]$Credential, 60 | 61 | [Parameter( 62 | Mandatory = $True, 63 | ValueFromPipelineByPropertyName = $True, 64 | ParameterSetName = "PassFile" 65 | )] 66 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 67 | [string]$PassFile, 68 | 69 | [Parameter( 70 | Mandatory = $true, 71 | ValueFromPipelineByPropertyName = $true 72 | )] 73 | [ValidateSet("Application", "Security", "System")] 74 | [string]$LogName, 75 | 76 | [Parameter( 77 | Mandatory = $false, 78 | ValueFromPipelineByPropertyName = $true 79 | )] 80 | [datetime]$TimeFrom #= (Get-Date (Get-Date).AddMinutes(-10) -Format ddMMyyyy:HHmm) 81 | ) 82 | 83 | Begin { 84 | 85 | $Pattern = 'EventLogRecordTime:(.+\s)Source:(.+\s)Computer:(.+\s)Event ID:(.+\s)Event Type:(.+\s)Description:(.+(?:[\S\s]+?))(?=\Z|EventLogRecordTime)' 86 | 87 | } 88 | Process { 89 | 90 | $Command = "GetOSLog /Name $LogName" 91 | 92 | if($PSBoundParameters.ContainsKey("TimeFrom")) { 93 | 94 | $DateStamp = (Get-Date $($PSBoundParameters["TimeFrom"]) -Format ddMMyyyy:HHmm) 95 | $Command = "$Command /TimeFrom $DateStamp" 96 | 97 | } 98 | 99 | $PSBoundParameters.Add("CommandParameters", "$Command") 100 | 101 | $Result = Invoke-PARClient @PSBoundParameters 102 | 103 | If($Result.StdOut) { 104 | 105 | $Logs = $Result.StdOut | Select-String $Pattern -AllMatches 106 | 107 | $Logs.Matches | ForEach-Object { 108 | 109 | [PSCustomObject]@{ 110 | 111 | "EventLogRecordTime" = ($_.Groups[1].Value).Trim() 112 | "Source" = ($_.Groups[2].Value).Trim() 113 | "Computer" = ($_.Groups[3].Value).Trim() 114 | "EventID" = ($_.Groups[4].Value).Trim() 115 | "EventType" = ($_.Groups[5].Value).Trim() 116 | "Description" = ($_.Groups[6].Value).Trim() 117 | 118 | } | Add-ObjectDetail -typename VaultControl.Log.Server 119 | 120 | } 121 | 122 | } 123 | 124 | } 125 | 126 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Get-PARService.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PARService { 2 | <# 3 | .SYNOPSIS 4 | Gets status of Operating System Services on Vault Server. 5 | 6 | .DESCRIPTION 7 | For services listed as allowed to be monitored with PARClient, returns the running status of the service. 8 | By default returns the status of all monitored services. 9 | 10 | .PARAMETER Server 11 | The name or address of the remote Vault server to target with PARClient 12 | 13 | .PARAMETER Password 14 | The password for remote operations via PARClient as a secure string 15 | 16 | .PARAMETER Credential 17 | The password for remote operations via PARClient held in a credential object 18 | 19 | .PARAMETER PassFile 20 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 21 | operations via PARClient 22 | 23 | .PARAMETER ServiceName 24 | The service to return the status of 25 | 26 | .EXAMPLE 27 | Get-PARService -Server EPV1 -Password $SecureString 28 | 29 | Returns details of all monitored services 30 | 31 | .EXAMPLE 32 | Get-PARService -Server EPV1 -Password $SecureString -ServiceName "PrivateArk Database" 33 | 34 | Returns details of PrivateArk Database service 35 | #> 36 | [CmdletBinding()] 37 | Param( 38 | [Parameter( 39 | Mandatory = $true, 40 | ValueFromPipelineByPropertyName = $true 41 | )] 42 | [string]$Server, 43 | 44 | [Parameter( 45 | Mandatory = $true, 46 | ValueFromPipelineByPropertyName = $true, 47 | ParameterSetName = "Password" 48 | )] 49 | [securestring]$Password, 50 | 51 | [Parameter( 52 | Mandatory = $true, 53 | ValueFromPipelineByPropertyName = $true, 54 | ParameterSetName = "Credential" 55 | )] 56 | [pscredential]$Credential, 57 | 58 | [Parameter( 59 | Mandatory = $True, 60 | ValueFromPipelineByPropertyName = $True, 61 | ParameterSetName = "PassFile" 62 | )] 63 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 64 | [string]$PassFile, 65 | 66 | [Parameter( 67 | Mandatory = $false, 68 | ValueFromPipelineByPropertyName = $true 69 | )] 70 | [string]$ServiceName = "*" 71 | ) 72 | 73 | Process { 74 | 75 | $ServiceName = $ServiceName -replace '(.+)', '\"$&\"' 76 | 77 | $PSBoundParameters.Add("CommandParameters", "ServiceStatus /ServiceName $ServiceName") 78 | 79 | $Result = Invoke-PARClient @PSBoundParameters 80 | 81 | If($Result.StdOut) { 82 | 83 | ($Result.StdOut).Split("`n") | ForEach-Object { 84 | 85 | $Service = ($_ | Select-String '^(.+)is\s([a-z]+)' -AllMatches) 86 | 87 | If($Service -match '\S') { 88 | 89 | [PSCustomObject]@{ 90 | 91 | "Server" = $Result.Server 92 | "Service" = $Service.Matches.Groups[1].Value 93 | "Status" = $($Service.Matches.Groups[2].Value).Substring(0, 1).ToUpper() + $($Service.Matches.Groups[2].Value).Substring(1) 94 | 95 | } 96 | 97 | } 98 | 99 | } 100 | 101 | } 102 | 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Restart-PARComponent.ps1: -------------------------------------------------------------------------------- 1 | Function Restart-PARComponent { 2 | <# 3 | .SYNOPSIS 4 | Restarts a Vault or PADR Component 5 | 6 | .DESCRIPTION 7 | Issues a restart command to a remote Vault or DR Vault component 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to restart. Vault or PADR are the accepted values 24 | 25 | .EXAMPLE 26 | Restart-PARComponent -Server EPV1 -Credential $cred -Component Vault 27 | 28 | Restarts the Vault service on Server EPV1 29 | 30 | .EXAMPLE 31 | Restart-PARComponent -Server EPV2 -PassFile C:\PassFile.pass -Component PADR 32 | 33 | Restarts the PADR service on Server EPV2, using encrypted password contained in C:\PassFile.pass 34 | #> 35 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] 36 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "ShouldProcess handling is in Invoke-PARClient")] 37 | Param( 38 | [Parameter( 39 | Mandatory = $true, 40 | ValueFromPipelineByPropertyName = $true 41 | )] 42 | [string]$Server, 43 | 44 | [Parameter( 45 | Mandatory = $true, 46 | ValueFromPipelineByPropertyName = $true, 47 | ParameterSetName = "Password" 48 | )] 49 | [securestring]$Password, 50 | 51 | [Parameter( 52 | Mandatory = $true, 53 | ValueFromPipelineByPropertyName = $true, 54 | ParameterSetName = "Credential" 55 | )] 56 | [pscredential]$Credential, 57 | 58 | [Parameter( 59 | Mandatory = $True, 60 | ValueFromPipelineByPropertyName = $True, 61 | ParameterSetName = "PassFile" 62 | )] 63 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 64 | [string]$PassFile, 65 | 66 | [Parameter( 67 | Mandatory = $true, 68 | ValueFromPipelineByPropertyName = $true 69 | )] 70 | [ValidateSet("Vault", "PADR")] 71 | [string]$Component 72 | ) 73 | 74 | Process { 75 | 76 | $PSBoundParameters.Add("CommandParameters", "Restart $Component") 77 | 78 | $Result = Invoke-PARClient @PSBoundParameters 79 | 80 | If($Result.StdOut) { 81 | 82 | $Service = ($Result.StdOut | Select-String '(restarted|Error)' -AllMatches) 83 | 84 | [PSCustomObject]@{ 85 | 86 | "Server" = $Result.Server 87 | "Component" = $Component 88 | "Status" = $($Service.Matches.Groups[1].Value).Substring(0, 1).ToUpper() + $($Service.Matches.Groups[1].Value).Substring(1) 89 | 90 | } 91 | 92 | } 93 | 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Restart-PARServer.ps1: -------------------------------------------------------------------------------- 1 | Function Restart-PARServer { 2 | <# 3 | .SYNOPSIS 4 | Reboots a remote Vault Server 5 | 6 | .DESCRIPTION 7 | Initiates a reboot of a remote vault server 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .EXAMPLE 23 | Restart-PARServer -Server EPV1 -Password $SecureString 24 | 25 | Initiates Reboot of EPV1 26 | #> 27 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] 28 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "ShouldProcess handling is in Invoke-PARClient")] 29 | Param( 30 | [Parameter( 31 | Mandatory = $true, 32 | ValueFromPipelineByPropertyName = $true 33 | )] 34 | [string]$Server, 35 | 36 | [Parameter( 37 | Mandatory = $true, 38 | ValueFromPipelineByPropertyName = $true, 39 | ParameterSetName = "Password" 40 | )] 41 | [securestring]$Password, 42 | 43 | [Parameter( 44 | Mandatory = $true, 45 | ValueFromPipelineByPropertyName = $true, 46 | ParameterSetName = "Credential" 47 | )] 48 | [pscredential]$Credential, 49 | 50 | [Parameter( 51 | Mandatory = $True, 52 | ValueFromPipelineByPropertyName = $True, 53 | ParameterSetName = "PassFile" 54 | )] 55 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 56 | [string]$PassFile 57 | 58 | ) 59 | 60 | Process { 61 | 62 | $PSBoundParameters.Add("CommandParameters", "REBOOT") 63 | 64 | $Result = Invoke-PARClient @PSBoundParameters 65 | 66 | If($Result.StdOut) { 67 | 68 | [PSCustomObject]@{ 69 | 70 | "Server" = $Result.Server 71 | "Status" = $Result.StdOut 72 | 73 | } 74 | 75 | } 76 | 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Set-PARComponentConfig.ps1: -------------------------------------------------------------------------------- 1 | Function Set-PARComponentConfig { 2 | <# 3 | .SYNOPSIS 4 | Sets values set in component configuration files 5 | 6 | .DESCRIPTION 7 | Sets values contained in component configuration files DBPARM.ini or PADR.ini on remote vault server. 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to query. Vault or PADR are the accepted values 24 | 25 | .PARAMETER Parameter 26 | The name of the Parameter to set the value for. 27 | For Vault Components, valid parameter names are: 28 | "DefaultTimeout", "MTU", "SecurityNotification", "DebugLevel", "DisableExceptionHandling" 29 | For Disaster Recovery Components, valid parameter names are: 30 | "EnableCheck", "EnableReplicate", "EnableFailover", "EnableDBSync", "FailoverMode" 31 | 32 | .PARAMETER Value 33 | The value to set for the parameter in the configuration file 34 | 35 | .PARAMETER Mode 36 | Specify how or when the paramater value change will take effect. 37 | For Vault parameter value changes "Temporary", "Permanent" or "Immediate" modes can be specified. 38 | 39 | For Disaster Recovery parameter value changes only "Permanent" mode can be specified. 40 | 41 | .EXAMPLE 42 | Set-PARComponentConfig -Server EPV1 -Credential $credential -Component Vault -Parameter DefaultTimeout -Value 300 43 | 44 | 45 | #> 46 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] 47 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "ShouldProcess handling is in Invoke-PARClient")] 48 | Param( 49 | [Parameter( 50 | Mandatory = $true, 51 | ValueFromPipelineByPropertyName = $true 52 | )] 53 | [string]$Server, 54 | 55 | [Parameter( 56 | Mandatory = $true, 57 | ValueFromPipelineByPropertyName = $true, 58 | ParameterSetName = "Password" 59 | )] 60 | [securestring]$Password, 61 | 62 | [Parameter( 63 | Mandatory = $true, 64 | ValueFromPipelineByPropertyName = $true, 65 | ParameterSetName = "Credential" 66 | )] 67 | [pscredential]$Credential, 68 | 69 | [Parameter( 70 | Mandatory = $true, 71 | ValueFromPipelineByPropertyName = $true 72 | )] 73 | [ValidateSet("Vault", "PADR")] 74 | [string]$Component, 75 | 76 | [Parameter( 77 | Mandatory = $True, 78 | ValueFromPipelineByPropertyName = $True, 79 | ParameterSetName = "PassFile" 80 | )] 81 | [string]$PassFile, 82 | 83 | [Parameter( 84 | Mandatory = $true, 85 | ValueFromPipelineByPropertyName = $true 86 | )] 87 | [ValidateSet("DefaultTimeout", "MTU", "SecurityNotification", "DebugLevel", "DisableExceptionHandling", 88 | "EnableCheck", "EnableReplicate", "EnableFailover", "EnableDBSync", "FailoverMode")] 89 | [string]$Parameter, 90 | 91 | [Parameter( 92 | Mandatory = $true, 93 | ValueFromPipelineByPropertyName = $true 94 | )] 95 | [string]$Value, 96 | 97 | [Parameter( 98 | Mandatory = $true, 99 | ValueFromPipelineByPropertyName = $true 100 | )] 101 | [ValidateSet("Temporary", "Permanent", "Immediate")] 102 | [string]$Mode 103 | 104 | ) 105 | 106 | Process { 107 | 108 | $PSBoundParameters.Add("CommandParameters", "SetParm $Component $Parameter=$Value /$Mode") 109 | 110 | $Result = Invoke-PARClient @PSBoundParameters 111 | 112 | If($Result.StdOut) { 113 | 114 | $Update = ($Result.StdOut | Select-String '(success|Error)' -AllMatches) 115 | 116 | [PSCustomObject]@{ 117 | 118 | "Server" = $Result.Server 119 | "Component" = $Component 120 | "Parameter" = $($PSBoundParameters["Parameter"]) 121 | "Value" = $Value 122 | "Mode" = $($PSBoundParameters["Mode"]) 123 | "Status" = $($Update.Matches.Groups[1].Value).Substring(0, 1).ToUpper() + $($Update.Matches.Groups[1].Value).Substring(1) 124 | "Message" = $Result.StdOut 125 | 126 | } 127 | 128 | } 129 | 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Set-PARConfiguration.ps1: -------------------------------------------------------------------------------- 1 | Function Set-PARConfiguration { 2 | <# 3 | .SYNOPSIS 4 | Sets a variable in the script scope which holds default values for PARClient operations. 5 | Must be run prior to other module functions if path to PARClient has not been previously set. 6 | 7 | .DESCRIPTION 8 | Sets properties on an object which is set as the value of a variable in the script scope. 9 | The created variable can be queried and used by other module functions to provide default values. 10 | Creates a file in the logged on users home folder named PARConfiguration.xml. This file contains the variable 11 | used by the module, and will be imported with the module. 12 | 13 | .PARAMETER ClientPath 14 | The path to the PARClient.exe utility 15 | 16 | .PARAMETER Port 17 | The number of any custom port configured for use between PARClient & a vault 18 | 19 | .EXAMPLE 20 | Set-PARConfiguration -ClientPath D:\Path\To\PARClient.exe 21 | 22 | Sets default path to PARClient to D:\Path\To\PARClient.exe. 23 | This is accessed via the variable property $Script:PAR.ClientPath 24 | Creates C:\users\user\PARConfiguration.xml file to hold values for persistence. 25 | 26 | .EXAMPLE 27 | Set-PARConfiguration -ClientPath D:\Path\To\PARClient.exe -Port 9023 28 | 29 | Sets default path to PARClient to D:\Path\To\PARClient.exe. 30 | This is accessed via the variable property $Script:PAR.ClientPath 31 | Sets default PARClient port to 9023 32 | This is accessed via the variable property $Script:PAR.Port 33 | Creates C:\users\user\PARConfiguration.xml file to hold values for persistence. 34 | #> 35 | [CmdletBinding(SupportsShouldProcess)] 36 | Param( 37 | [Parameter( 38 | Mandatory = $false, 39 | ValueFromPipelineByPropertyName = $true 40 | )] 41 | [ValidateScript( {Test-Path $_ -PathType Leaf})] 42 | [ValidateNotNullOrEmpty()] 43 | [string]$ClientPath, 44 | 45 | [Parameter( 46 | Mandatory = $false, 47 | ValueFromPipelineByPropertyName = $true 48 | )] 49 | [ValidateNotNullOrEmpty()] 50 | [int]$Port 51 | ) 52 | 53 | Begin { 54 | 55 | $Defaults = [pscustomobject]@{} 56 | 57 | } 58 | 59 | Process { 60 | 61 | If($PSBoundParameters.Keys -contains "ClientPath") { 62 | 63 | $Defaults | Add-Member -MemberType NoteProperty -Name ClientPath -Value $ClientPath 64 | 65 | } 66 | 67 | If($PSBoundParameters.Keys -contains "Port") { 68 | 69 | $Defaults | Add-Member -MemberType NoteProperty -Name Port -Value $Port 70 | 71 | } 72 | 73 | } 74 | 75 | End { 76 | 77 | Set-Variable -Name PAR -Value $Defaults -Scope Script 78 | 79 | $Script:PAR | Select-Object -Property * | Export-Clixml -Path "$env:HOMEDRIVE$env:HomePath\PARConfiguration.xml" -Force 80 | 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Start-PARComponent.ps1: -------------------------------------------------------------------------------- 1 | Function Start-PARComponent { 2 | <# 3 | .SYNOPSIS 4 | Starts a component service 5 | 6 | .DESCRIPTION 7 | Starts a stopped Vault, CVM, PADR or ENE component on a remote server 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to query. Vault, PADR, CVM or ENE are the accepted values 24 | 25 | .PARAMETER Last 26 | For the Vault component, start with the last known good configuration. 27 | 28 | .EXAMPLE 29 | Start-PARComponent -Server EPV1 -Component Vault 30 | 31 | Starts the Vault service on Vault Server EPV1 32 | 33 | .EXAMPLE 34 | Start-PARComponent -Server EPV1 -Component PADR 35 | 36 | Starts the PADR service on Vault Server EPV2 37 | 38 | .EXAMPLE 39 | Start-PARComponent -Server EPV1 -Component ENE 40 | 41 | Starts the ENE service on Vault Server EPV1 42 | #> 43 | [CmdletBinding(SupportsShouldProcess)] 44 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "ShouldProcess handling is in Invoke-PARClient")] 45 | Param( 46 | [Parameter( 47 | Mandatory = $true, 48 | ValueFromPipelineByPropertyName = $true 49 | )] 50 | [string]$Server, 51 | 52 | [Parameter( 53 | Mandatory = $true, 54 | ValueFromPipelineByPropertyName = $true, 55 | ParameterSetName = "Password" 56 | )] 57 | [securestring]$Password, 58 | 59 | [Parameter( 60 | Mandatory = $true, 61 | ValueFromPipelineByPropertyName = $true, 62 | ParameterSetName = "Credential" 63 | )] 64 | [pscredential]$Credential, 65 | 66 | [Parameter( 67 | Mandatory = $True, 68 | ValueFromPipelineByPropertyName = $True, 69 | ParameterSetName = "PassFile" 70 | )] 71 | [string]$PassFile, 72 | 73 | [Parameter( 74 | Mandatory = $true, 75 | ValueFromPipelineByPropertyName = $true 76 | )] 77 | [ValidateSet("Vault", "PADR", "ENE", "CVM")] 78 | [string]$Component, 79 | 80 | [Parameter( 81 | Mandatory = $false, 82 | ValueFromPipelineByPropertyName = $false 83 | )] 84 | [switch]$Last 85 | ) 86 | 87 | Process { 88 | 89 | $Command = "Start $Component" 90 | 91 | if($Component -eq "Vault") { 92 | 93 | if($PSBoundParameters.ContainsKey("Last")) { 94 | 95 | $Command = "$Command /Last" 96 | 97 | } 98 | 99 | } 100 | 101 | $PSBoundParameters.Add("CommandParameters", "$Command") 102 | 103 | $Result = Invoke-PARClient @PSBoundParameters 104 | 105 | If($Result.StdOut) { 106 | 107 | $Service = ($Result.StdOut | Select-String '(started|Error)' -AllMatches) 108 | 109 | [PSCustomObject]@{ 110 | 111 | "Server" = $Result.Server 112 | "Component" = $Component 113 | "Status" = $($Service.Matches.Groups[1].Value).Substring(0, 1).ToUpper() + $($Service.Matches.Groups[1].Value).Substring(1) 114 | 115 | } 116 | 117 | } 118 | 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /VaultControl/Functions/Stop-PARComponent.ps1: -------------------------------------------------------------------------------- 1 | Function Stop-PARComponent { 2 | <# 3 | .SYNOPSIS 4 | Stops a component service 5 | 6 | .DESCRIPTION 7 | Stops a running Vault, CVM, PADR or ENE component on a remote server 8 | 9 | .PARAMETER Server 10 | The name or address of the remote Vault server to target with PARClient 11 | 12 | .PARAMETER Password 13 | The password for remote operations via PARClient as a secure string 14 | 15 | .PARAMETER Credential 16 | The password for remote operations via PARClient held in a credential object 17 | 18 | .PARAMETER PassFile 19 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 20 | operations via PARClient 21 | 22 | .PARAMETER Component 23 | The name of the component to query. Vault, PADR, CVM or ENE are the accepted values. 24 | 25 | .PARAMETER ShutdownMode 26 | Specify "Normal", "Immediate" or "Terminate" shutdown mode for stop operation against Vault service. 27 | 28 | .EXAMPLE 29 | Stop-PARComponent -Server EPV1 -Component Vault 30 | 31 | Stops the Vault service on Vault Server EPV1 32 | 33 | .EXAMPLE 34 | Stop-PARComponent -Server EPV1 -Component PADR 35 | 36 | Stops the PADR service on Vault Server EPV2 37 | 38 | .EXAMPLE 39 | Stop-PARComponent -Server EPV1 -Component ENE 40 | 41 | Stops the ENE service on Vault Server EPV1 42 | #> 43 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] 44 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "ShouldProcess handling is in Invoke-PARClient")] 45 | Param( 46 | [Parameter( 47 | Mandatory = $true, 48 | ValueFromPipelineByPropertyName = $true 49 | )] 50 | [string]$Server, 51 | 52 | [Parameter( 53 | Mandatory = $true, 54 | ValueFromPipelineByPropertyName = $true, 55 | ParameterSetName = "Password" 56 | )] 57 | [securestring]$Password, 58 | 59 | [Parameter( 60 | Mandatory = $true, 61 | ValueFromPipelineByPropertyName = $true, 62 | ParameterSetName = "Credential" 63 | )] 64 | [pscredential]$Credential, 65 | 66 | [Parameter( 67 | Mandatory = $True, 68 | ValueFromPipelineByPropertyName = $True, 69 | ParameterSetName = "PassFile" 70 | )] 71 | [string]$PassFile, 72 | 73 | [Parameter( 74 | Mandatory = $true, 75 | ValueFromPipelineByPropertyName = $true 76 | )] 77 | [ValidateSet("Vault", "PADR", "ENE", "CVM")] 78 | [string]$Component, 79 | 80 | [Parameter( 81 | Mandatory = $false, 82 | ValueFromPipelineByPropertyName = $true 83 | )] 84 | [ValidateSet("Normal", "Immediate", "Terminate")] 85 | [string]$ShutdownMode 86 | ) 87 | 88 | Process { 89 | 90 | $Command = "Stop $Component" 91 | 92 | If($Component -eq "Vault") { 93 | 94 | if($PSBoundParameters.ContainsKey("ShutdownMode")) { 95 | 96 | $Command = "$Command /$($PSBoundParameters["ShutdownMode"])" 97 | 98 | } 99 | 100 | } 101 | 102 | $PSBoundParameters.Add("CommandParameters", "$Command") 103 | 104 | $Result = Invoke-PARClient @PSBoundParameters 105 | 106 | If($Result.StdOut) { 107 | 108 | $Service = ($Result.StdOut | Select-String '(stopped|Error)' -AllMatches) 109 | 110 | [PSCustomObject]@{ 111 | 112 | "Server" = $Result.Server 113 | "Component" = $Component 114 | "Status" = $($Service.Matches.Groups[1].Value).Substring(0, 1).ToUpper() + $($Service.Matches.Groups[1].Value).Substring(1) 115 | 116 | } 117 | 118 | } 119 | 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /VaultControl/Private/Add-ObjectDetail.ps1: -------------------------------------------------------------------------------- 1 | function Add-ObjectDetail { 2 | <# 3 | .SYNOPSIS 4 | Decorate an object with 5 | - A TypeName 6 | - New properties 7 | - Default parameters 8 | .DESCRIPTION 9 | Helper function to decorate an object with 10 | - A TypeName 11 | - New properties 12 | - Default parameters 13 | .PARAMETER InputObject 14 | Object to decorate. Accepts pipeline input. 15 | .PARAMETER TypeName 16 | Typename to insert. 17 | 18 | This will show up when you use Get-Member against the resulting object. 19 | 20 | .PARAMETER PropertyToAdd 21 | Add these noteproperties. 22 | 23 | Format is a hashtable with Key (Property Name) = Value (Property Value). 24 | Example to add a One and Date property: 25 | -PropertyToAdd @{ 26 | One = 1 27 | Date = (Get-Date) 28 | } 29 | .PARAMETER DefaultProperties 30 | Change the default properties that show up 31 | .PARAMETER Passthru 32 | Whether to pass the resulting object on. Defaults to true 33 | .EXAMPLE 34 | # 35 | # Create an object to work with 36 | $Object = [PSCustomObject]@{ 37 | First = 'Cookie' 38 | Last = 'Monster' 39 | Account = 'CMonster' 40 | } 41 | #Add a type name and a random property 42 | Add-ObjectDetail -InputObject $Object -TypeName 'ApplicationX.Account' -PropertyToAdd @{ AnotherProperty = 5 } 43 | # First Last Account AnotherProperty 44 | # ----- ---- ------- --------------- 45 | # Cookie Monster CMonster 5 46 | #Verify that get-member shows us the right type 47 | $Object | Get-Member 48 | # TypeName: ApplicationX.Account ... 49 | .EXAMPLE 50 | # 51 | # Create an object to work with 52 | $Object = [PSCustomObject]@{ 53 | First = 'Cookie' 54 | Last = 'Monster' 55 | Account = 'CMonster' 56 | } 57 | #Add a random property, set a default property set so we only see two props by default 58 | Add-ObjectDetail -InputObject $Object -PropertyToAdd @{ AnotherProperty = 5 } -DefaultProperties Account, AnotherProperty 59 | # Account AnotherProperty 60 | # ------- --------------- 61 | # CMonster 5 62 | #Verify that the other properties are around 63 | $Object | Select -Property * 64 | # First Last Account AnotherProperty 65 | # ----- ---- ------- --------------- 66 | # Cookie Monster CMonster 5 67 | .NOTES 68 | This breaks the 'do one thing' rule from certain perspectives... 69 | The goal is to decorate an object all in one shot 70 | 71 | This abstraction simplifies decorating an object, with a slight trade-off in performance. For example: 72 | 10,000 objects, add a property and typename: 73 | Add-ObjectDetail: ~4.6 seconds 74 | Add-Member + PSObject.TypeNames.Insert: ~3 seconds 75 | Initial code borrowed from Shay Levy: 76 | http://blogs.microsoft.co.il/scriptfanatic/2012/04/13/custom-objects-default-display-in-powershell-30/ 77 | 78 | .LINK 79 | http://ramblingcookiemonster.github.io/Decorating-Objects/ 80 | .FUNCTIONALITY 81 | PowerShell Language 82 | #> 83 | [CmdletBinding()] 84 | param( 85 | [Parameter( Mandatory = $true, 86 | Position = 0, 87 | ValueFromPipeline = $true )] 88 | [ValidateNotNullOrEmpty()] 89 | [psobject[]]$InputObject, 90 | 91 | [Parameter( Mandatory = $false, 92 | Position = 1)] 93 | [string]$TypeName, 94 | 95 | [Parameter( Mandatory = $false, 96 | Position = 2)] 97 | [System.Collections.Hashtable]$PropertyToAdd, 98 | 99 | [Parameter( Mandatory = $false, 100 | Position = 3)] 101 | [ValidateNotNullOrEmpty()] 102 | [Alias('dp')] 103 | [System.String[]]$DefaultProperties, 104 | 105 | [boolean]$Passthru = $True 106 | ) 107 | 108 | Begin { 109 | if($PSBoundParameters.ContainsKey('DefaultProperties')) { 110 | # define a subset of properties 111 | $ddps = New-Object System.Management.Automation.PSPropertySet DefaultDisplayPropertySet, $DefaultProperties 112 | $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]$ddps 113 | } 114 | } 115 | Process { 116 | foreach($Object in $InputObject) { 117 | switch ($PSBoundParameters.Keys) { 118 | 'PropertyToAdd' { 119 | foreach($Key in $PropertyToAdd.Keys) { 120 | #Add some noteproperties. Slightly faster than Add-Member. 121 | $Object.PSObject.Properties.Add( ( New-Object System.Management.Automation.PSNoteProperty($Key, $PropertyToAdd[$Key]) ) ) 122 | } 123 | } 124 | 'TypeName' { 125 | #Add specified type 126 | [void]$Object.PSObject.TypeNames.Insert(0, $TypeName) 127 | } 128 | 'DefaultProperties' { 129 | # Attach default display property set 130 | Add-Member -InputObject $Object -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers 131 | } 132 | } 133 | if($Passthru) { 134 | $Object 135 | } 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /VaultControl/Private/ConvertTo-InsecureString.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertTo-InsecureString { 2 | <# 3 | .SYNOPSIS 4 | Returns string value from SecureString input 5 | 6 | .DESCRIPTION 7 | Gets the decoded string value of an encoded SecureString 8 | 9 | .PARAMETER SecureString 10 | The SecureString to decode 11 | 12 | .EXAMPLE 13 | ConvertTo-InsecureString $SecureStringValue 14 | #> 15 | [CmdLetBinding()] 16 | [OutputType('System.String')] 17 | Param ( 18 | 19 | [Parameter( 20 | Mandatory = $True)] 21 | [System.Security.SecureString]$SecureString 22 | ) 23 | 24 | Try { 25 | 26 | $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($SecureString) 27 | [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr) 28 | 29 | } 30 | 31 | Finally { 32 | 33 | [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($ptr) 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /VaultControl/Private/Invoke-PARClient.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-PARClient { 2 | 3 | <# 4 | .SYNOPSIS 5 | Defines specified PARClient command and arguments 6 | 7 | .DESCRIPTION 8 | Defines a PARClient process object with arguments required for specific command. 9 | 10 | .PARAMETER PARClient 11 | The Path to PARClient.exe. 12 | Defaults to value of $Script:PAR.ClientPath, which is set during module import or via Set-PARConfiguration. 13 | 14 | .PARAMETER Server 15 | The name or address of the Vault server to target 16 | 17 | .PARAMETER Password 18 | SecureString of password used for PARClient operations 19 | 20 | .PARAMETER Credential 21 | A credential object containing the password used for PARClient operations 22 | 23 | .PARAMETER PassFile 24 | The path to a "password" file created by PARClient.exe, containing the encrypted password value used for remote 25 | operations via PARClient 26 | 27 | .PARAMETER CommandParameters 28 | The PARClient command to execute 29 | 30 | .PARAMETER PAROptions 31 | Additional command parameters. By default specifies /Q /C and /StateFileName. 32 | StateFileName is set to a file named after the process ID of the script, and with the local temp directory path 33 | 34 | .PARAMETER RemainingArgs 35 | A catch all parameter, accepts any remaining values from pipeline. 36 | Intended to suppress errors when piping in an object. 37 | 38 | .EXAMPLE 39 | Invoke-PARClient -Server EPV1 -Password $SecureString -CommandParameters "GetParm Vault DebugLevel" 40 | 41 | Invokes the GetParm action against the Vault on EPV1 and returns the DebugLevel parameter value. 42 | 43 | .NOTES 44 | AUTHOR: Pete Maan 45 | 46 | #> 47 | 48 | [CmdLetBinding(SupportsShouldProcess)] 49 | param( 50 | 51 | [Parameter( 52 | Mandatory = $False, 53 | ValueFromPipelineByPropertyName = $True 54 | )] 55 | [string]$PARClient = $Script:PAR.ClientPath, 56 | 57 | [Parameter( 58 | Mandatory = $False, 59 | ValueFromPipelineByPropertyName = $True 60 | )] 61 | [int]$Port = $Script:PAR.Port, 62 | 63 | [Parameter( 64 | Mandatory = $True, 65 | ValueFromPipelineByPropertyName = $True 66 | )] 67 | [string]$Server, 68 | 69 | [Parameter( 70 | Mandatory = $True, 71 | ValueFromPipelineByPropertyName = $True, 72 | ParameterSetName = "Password" 73 | )] 74 | [securestring]$Password, 75 | 76 | [Parameter( 77 | Mandatory = $True, 78 | ValueFromPipelineByPropertyName = $True, 79 | ParameterSetName = "Credential" 80 | )] 81 | [pscredential]$Credential, 82 | 83 | [Parameter( 84 | Mandatory = $True, 85 | ValueFromPipelineByPropertyName = $True, 86 | ParameterSetName = "PassFile" 87 | )] 88 | [ValidateScript( {Test-Path $_})] 89 | [string]$PassFile, 90 | 91 | [Parameter( 92 | Mandatory = $True, 93 | ValueFromPipelineByPropertyName = $True 94 | )] 95 | [string]$CommandParameters, 96 | 97 | [Parameter(Mandatory = $False, 98 | ValueFromPipelineByPropertyName = $True 99 | )] 100 | [string]$PAROptions = "/StateFileName $(Join-Path $env:temp "$PID.tmp") /Q /C", 101 | 102 | [Parameter(Mandatory = $False, 103 | ValueFromPipelineByPropertyName = $False, 104 | ValueFromRemainingArguments = $true 105 | )] 106 | $RemainingArgs 107 | ) 108 | 109 | Begin { 110 | 111 | Try { 112 | 113 | Get-Variable -Name PAR -ErrorAction Stop 114 | 115 | if($PAR.PSObject.Properties.Name -notcontains "ClientPath") { 116 | 117 | Write-Error "Heads Up!" -ErrorAction Stop 118 | 119 | } 120 | 121 | } Catch {throw "PARClient.exe not found `nRun Set-PARConfiguration to set path to PARClient"} 122 | 123 | #Create process 124 | $Process = New-Object System.Diagnostics.Process 125 | 126 | } 127 | 128 | Process { 129 | 130 | Switch($PSCmdlet.ParameterSetName) { 131 | 132 | "Credential" { 133 | 134 | $ClearTextPassword = $($Credential.GetNetworkCredential().Password) 135 | $PARCommand = "$Server/$ClearTextPassword"; break 136 | 137 | } 138 | 139 | "Password" { 140 | 141 | $ClearTextPassword = ConvertTo-InsecureString -SecureString $Password 142 | $PARCommand = "$Server/$ClearTextPassword"; break 143 | 144 | } 145 | 146 | "PassFile" {$PARCommand = "$Server /UsePassFile $PassFile"; break} 147 | 148 | } 149 | 150 | If($Port -gt 0) { 151 | 152 | $PARCommand = "$PARCommand /Port $Port" 153 | 154 | } 155 | 156 | $CommandParameters = $CommandParameters -replace ('^', '"') 157 | $CommandParameters = $CommandParameters -replace ('$', '"') 158 | 159 | if ($PSCmdlet.ShouldProcess($Server, "$CommandParameters")) { 160 | 161 | Write-Debug "Command Arguments: $PARCommand $PAROptions $CommandParameters" 162 | 163 | #Assign process parameters 164 | 165 | $Process.StartInfo.WorkingDirectory = "$(Split-Path $PARClient -Parent)" 166 | $Process.StartInfo.Filename = $PARClient 167 | $Process.StartInfo.Arguments = "$PARCommand $PAROptions $CommandParameters" 168 | $Process.StartInfo.RedirectStandardOutput = $True 169 | $Process.StartInfo.RedirectStandardError = $True 170 | $Process.StartInfo.UseShellExecute = $False 171 | $Process.StartInfo.CreateNoWindow = $True 172 | $Process.StartInfo.WindowStyle = "hidden" 173 | 174 | #Start Process 175 | $Result = Start-PARClientProcess -Process $Process 176 | 177 | $Result | Add-Member -MemberType NoteProperty -Name Server -Value $Server 178 | 179 | if($Result.StdOut -match '((?:^[A-Z]{5}[0-9]{3}[A-Z])|(?:ERROR \(\d+\)))(?::)? (.+)$') { 180 | 181 | #PARCL002S Authentication failure. 182 | Write-Error -Message $Matches[2] -ErrorId $Matches[1] 183 | 184 | } ElseIf($Result.StdOut -match '(.+) \((.+: \d)\)') { 185 | 186 | #Cannot get parameter DisableExceptionHandling. (Reason: 7) 187 | Write-Error -Message $Matches[1] -ErrorId $Matches[2] 188 | 189 | } Else {$Result} 190 | 191 | } 192 | 193 | } 194 | 195 | End { 196 | 197 | $Process.Dispose() 198 | 199 | } 200 | 201 | } -------------------------------------------------------------------------------- /VaultControl/Private/Start-PARClientProcess.ps1: -------------------------------------------------------------------------------- 1 | Function Start-PARClientProcess { 2 | 3 | <# 4 | .SYNOPSIS 5 | Starts PARClient process 6 | 7 | .DESCRIPTION 8 | Designed to receive PARClient process object from Invoke-PARClient. 9 | 10 | Returns Object containing ExitCode, StdOut & StdErr 11 | 12 | .PARAMETER Process 13 | System.Diagnostics.Process object containing PARClient parameters 14 | 15 | .EXAMPLE 16 | Start-PARClientProcess -Process $Process 17 | 18 | Invokes the Start method on the $Process object 19 | 20 | .NOTES 21 | AUTHOR: Pete Maan 22 | 23 | #> 24 | 25 | [CmdLetBinding(SupportsShouldProcess)] 26 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "ShouldProcess handling is in Invoke-PARClient")] 27 | param( 28 | 29 | [Parameter( 30 | Mandatory = $True, 31 | ValueFromPipelineByPropertyName = $True 32 | )] 33 | [System.Diagnostics.Process]$Process 34 | ) 35 | 36 | Begin { 37 | 38 | } 39 | 40 | Process { 41 | 42 | #Start Process 43 | $Process.start() | Out-Null 44 | 45 | #Read Output Stream First 46 | $StdOut = $Process.StandardOutput.ReadToEnd() 47 | $StdErr = $Process.StandardError.ReadToEnd() 48 | 49 | #If you wait for the process to exit before reading StandardOutput 50 | #the process can block trying to write to it, so the process never ends. 51 | $Process.WaitForExit() 52 | 53 | [PSCustomObject] @{ 54 | 55 | "ExitCode" = $Process.ExitCode 56 | "StdOut" = $StdOut 57 | "StdErr" = $StdErr 58 | 59 | } 60 | 61 | } 62 | 63 | End { 64 | 65 | $Process.Dispose() 66 | 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /VaultControl/VaultControl.Formats.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | VaultControl.Log.Component 6 | 7 | VaultControl.Log.Component 8 | 9 | 10 | 11 | 12 | 13 | 20 14 | left 15 | 16 | 17 | 18 | 10 19 | left 20 | 21 | 22 | 23 | 85 24 | left 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | if ($host.UI.SupportsVirtualTerminal){ 33 | $ESC = [char]27 34 | $o = "$ESC[0m" 35 | $f = $_.Time + $o 36 | $e = "$ESC[38;5;" 37 | switch -regex ($_.Code) 38 | { 39 | '.+E$' # Errors 40 | { 41 | "${e}196m$f" 42 | } 43 | '.+W$' # Warnings 44 | { 45 | "${e}226m$f" 46 | } 47 | '.+S$' # System Errors 48 | { 49 | "${e}202m$f" 50 | } 51 | default{ 52 | "$o$f" 53 | } 54 | } 55 | return 56 | } 57 | $_.Time 58 | 59 | 60 | 61 | 62 | if ($host.UI.SupportsVirtualTerminal){ 63 | $ESC = [char]27 64 | $o = "$ESC[0m" 65 | $f = $_.Code + $o 66 | $e = "$ESC[38;5;" 67 | switch -regex ($_.Code) 68 | { 69 | '.+E$' # Errors 70 | { 71 | "${e}196m$f" 72 | } 73 | '.+W$' # Warnings 74 | { 75 | "${e}226m$f" 76 | } 77 | '.+S$' # System Errors 78 | { 79 | "${e}202m$f" 80 | } 81 | default{ 82 | "$o$f" 83 | } 84 | } 85 | return 86 | } 87 | $_.Code 88 | 89 | 90 | 91 | 92 | if ($host.UI.SupportsVirtualTerminal){ 93 | $ESC = [char]27 94 | $o = "$ESC[0m" 95 | $f = $_.Message + $o 96 | $e = "$ESC[38;5;" 97 | switch -regex ($_.Code) 98 | { 99 | '.+E$' # Errors 100 | { 101 | "${e}196m$f" 102 | } 103 | '.+W$' # Warnings 104 | { 105 | "${e}226m$f" 106 | } 107 | '.+S$' # System Errors 108 | { 109 | "${e}202m$f" 110 | } 111 | default{ 112 | "$o$f" 113 | } 114 | } 115 | return 116 | } 117 | $_.Message 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | VaultControl.Log.Server 127 | 128 | VaultControl.Log.Server 129 | 130 | 131 | 132 | 133 | 134 | 25 135 | left 136 | 137 | 138 | 139 | 10 140 | left 141 | 142 | 143 | 144 | 15 145 | left 146 | 147 | 148 | 149 | 15 150 | left 151 | 152 | 153 | 154 | 10 155 | right 156 | 157 | 158 | 159 | 85 160 | left 161 | 162 | 163 | 164 | 165 | 166 | 167 | EventLogRecordTime 168 | 169 | 170 | Source 171 | 172 | 173 | Computer 174 | 175 | 176 | EventID 177 | 178 | 179 | EventType 180 | 181 | 182 | Description 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /VaultControl/VaultControl.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | 3 | # Script module or binary module file associated with this manifest. 4 | RootModule = 'VaultControl.psm1' 5 | 6 | # Version number of this module. 7 | ModuleVersion = '1.1.54' 8 | 9 | # ID used to uniquely identify this module 10 | GUID = 'fba9035e-5d32-4a7f-ab91-5658c84e0668' 11 | 12 | # Author of this module 13 | Author = 'Pete Maan' 14 | 15 | # Company or vendor of this module 16 | # CompanyName = '' 17 | 18 | # Copyright statement for this module 19 | Copyright = '(c) 2018-2020 Pete Maan. All rights reserved.' 20 | 21 | # Description of the functionality provided by this module 22 | Description = 'Invoke CyberArk PARClient.exe Utility Commands with PowerShell' 23 | 24 | # Minimum version of the Windows PowerShell engine required by this module 25 | PowerShellVersion = '3.0' 26 | 27 | # Name of the Windows PowerShell host required by this module 28 | # PowerShellHostName = '' 29 | 30 | # Minimum version of the Windows PowerShell host required by this module 31 | # PowerShellHostVersion = '' 32 | 33 | # Minimum version of Microsoft .NET Framework required by this module 34 | # DotNetFrameworkVersion = '' 35 | 36 | # Minimum version of the common language runtime (CLR) required by this module 37 | # CLRVersion = '' 38 | 39 | # Processor architecture (None, X86, Amd64) required by this module 40 | # ProcessorArchitecture = '' 41 | 42 | # Modules that must be imported into the global environment prior to importing this module 43 | # RequiredModules = @() 44 | 45 | # Assemblies that must be loaded prior to importing this module 46 | # RequiredAssemblies = @() 47 | 48 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 49 | # ScriptsToProcess = @() 50 | 51 | # Type files (.ps1xml) to be loaded when importing this module 52 | #TypesToProcess = @() 53 | 54 | # Format files (.ps1xml) to be loaded when importing this module 55 | FormatsToProcess = @('VaultControl.Formats.ps1xml') 56 | 57 | # Functions to export from this module 58 | FunctionsToExport = @( 59 | 'Get-PARComponent', 60 | 'Get-PARComponentConfig', 61 | 'Get-PARComponentLog', 62 | 'Get-PARServer', 63 | 'Get-PARServerLog', 64 | 'Get-PARService', 65 | 'Restart-PARComponent', 66 | 'Restart-PARServer', 67 | 'Set-PARComponentConfig', 68 | 'Start-PARComponent', 69 | 'Stop-PARComponent', 70 | 'Set-PARConfiguration' 71 | ) 72 | 73 | #AliasesToExport = @() 74 | 75 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 76 | PrivateData = @{ 77 | 78 | PSData = @{ 79 | 80 | # Tags applied to this module. These help with module discovery in online galleries. 81 | Tags = @('CyberArk', 'PARClient', 'Security') 82 | 83 | # A URL to the license for this module. 84 | LicenseUri = 'https://github.com/pspete/VaultControl/blob/master/LICENSE.md' 85 | 86 | # A URL to the main website for this project. 87 | ProjectUri = 'https://github.com/pspete/VaultControl' 88 | 89 | # A URL to an icon representing this module. 90 | # IconUri = '' 91 | 92 | # ReleaseNotes of this module 93 | # ReleaseNotes = '' 94 | 95 | } # End of PSData hashtable 96 | 97 | } # End of PrivateData hashtable 98 | 99 | } 100 | -------------------------------------------------------------------------------- /VaultControl/VaultControl.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | 4 | .DESCRIPTION 5 | 6 | .EXAMPLE 7 | 8 | .INPUTS 9 | 10 | .OUTPUTS 11 | 12 | .NOTES 13 | 14 | .LINK 15 | 16 | #> 17 | [CmdletBinding()] 18 | param( 19 | 20 | [bool]$DotSourceModule = $false 21 | 22 | ) 23 | 24 | #Get function files 25 | Get-ChildItem $PSScriptRoot\ -Recurse -Include "*.ps1" | 26 | 27 | ForEach-Object { 28 | 29 | if ($DotSourceModule) { 30 | . $_.FullName 31 | } else { 32 | $ExecutionContext.InvokeCommand.InvokeScript( 33 | $false, 34 | ( 35 | [scriptblock]::Create( 36 | [io.file]::ReadAllText( 37 | $_.FullName, 38 | [Text.Encoding]::UTF8 39 | ) 40 | ) 41 | ), 42 | $null, 43 | $null 44 | ) 45 | 46 | } 47 | 48 | } 49 | 50 | #Read config and make available in script scope 51 | $ConfigFile = "$env:HOMEDRIVE$env:HomePath\PARConfiguration.xml" 52 | If(Test-Path $ConfigFile) { 53 | Write-Verbose "Importing Settings: $ConfigFile" 54 | $config = Import-Clixml -Path $ConfigFile 55 | Set-Variable -Name PAR -Value $config -Scope Script 56 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # version format 2 | version: 1.1.{build} 3 | 4 | environment: 5 | access_token: 6 | secure: bDZ9LJ84SWlGw/D3R/q3ADwDslfrLNZLMdH3ZRjdi5xwkGanmjf7DvgN+crc4BU/ 7 | psgallery_key: 8 | secure: FuPgJskczZMptxRgdUlBAy7OYmXBQl4zq86kXXSmBt6wKudnM2PK7W6cM7bj0te1 9 | coveralls_key: 10 | secure: lCe6CMSzOCxMfS6HrSP0Emt/0+ESY+ysqF6Y1PB4wh2PII2G7PtNARzFH+tRXwLs 11 | github_email: 12 | secure: x5ljenzXfYXkzpEu9eX7AQvb3AkFbiXG2NndMzw9Zc4= 13 | 14 | skip_tags: true 15 | 16 | skip_commits: 17 | files: 18 | - docs\* 19 | - .github\* 20 | - .vscode\* 21 | - README.md 22 | - LICENSE.md 23 | - CONTRIBUTING.md 24 | - CODE_OF_CONDUCT.md 25 | - ISSUE_TEMPLATE.md 26 | - PULL_REQUEST_TEMPLATE.md 27 | - appveyor.yml 28 | - CHANGELOG.md 29 | message: /update readme.*|update version.*|update appveyor.*/ 30 | 31 | only_commits: 32 | files: 33 | - build\ 34 | - VaultControl\ 35 | - Tests\ 36 | 37 | image: Visual Studio 2017 38 | 39 | install: 40 | - ps: . .\build\install.ps1 41 | - pwsh.exe -File .\build\install.ps1 42 | 43 | build_script: 44 | - ps: . .\build\build.ps1 45 | 46 | test_script: 47 | - ps: . .\build\test.ps1 48 | - pwsh.exe -File .\build\test.ps1 49 | 50 | deploy_script: 51 | - ps: . .\build\deploy-github.ps1 52 | - pwsh.exe -File .\build\deploy-psgallery.ps1 -------------------------------------------------------------------------------- /build/build.ps1: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # Header # 3 | #---------------------------------# 4 | Write-Host 'Build Information:' -ForegroundColor Yellow 5 | 6 | #Get current module version from manifest 7 | $ManifestPath = Join-Path "$pwd" $(Join-Path "$env:APPVEYOR_PROJECT_NAME" "$env:APPVEYOR_PROJECT_NAME.psd1") 8 | $CurrentVersion = (Import-PowerShellDataFile $ManifestPath).ModuleVersion 9 | 10 | #display module information 11 | Write-Host "ModuleName : $env:APPVEYOR_PROJECT_NAME" 12 | Write-Host "Build version : $env:APPVEYOR_BUILD_VERSION" 13 | Write-Host "Manifest version : $CurrentVersion" 14 | Write-Host "Author : $env:APPVEYOR_REPO_COMMIT_AUTHOR" 15 | Write-Host "Branch : $env:APPVEYOR_REPO_BRANCH" 16 | Write-Host "Build Folder : $env:APPVEYOR_BUILD_FOLDER" 17 | 18 | If ([System.Version]$($env:APPVEYOR_BUILD_VERSION) -le [System.Version]$CurrentVersion) { 19 | 20 | throw "Build Version Not Greater than Current Version" 21 | 22 | } 23 | Else { 24 | 25 | Try { 26 | 27 | #---------------------------------# 28 | # BuildScript # 29 | #---------------------------------# 30 | #---------------------------------# 31 | # Update module manifest # 32 | #---------------------------------# 33 | Write-Host "Updating Manifest Version to $env:APPVEYOR_BUILD_VERSION" -ForegroundColor Cyan 34 | 35 | #Replace version in manifest with build version from appveyor 36 | ((Get-Content $ManifestPath).replace("= '$($currentVersion)'", "= '$($env:APPVEYOR_BUILD_VERSION)'")) | Set-Content $ManifestPath -ErrorAction Stop 37 | 38 | <#-- Package Version Release --#> 39 | $Directory = New-Item -ItemType Directory -Path "Release\$($env:APPVEYOR_PROJECT_NAME)\$($env:APPVEYOR_BUILD_VERSION)" -Force -ErrorAction Stop 40 | $OutputArchive = "$($env:APPVEYOR_PROJECT_NAME)-v$($env:APPVEYOR_BUILD_VERSION).zip" 41 | 42 | $OutputArchive = "$($env:APPVEYOR_PROJECT_NAME)-v$($env:APPVEYOR_BUILD_VERSION).zip" 43 | $ReleaseSource = $(Resolve-Path .\$env:APPVEYOR_PROJECT_NAME) 44 | 45 | <#-- Create Release Folder --#> 46 | $Directory = New-Item -ItemType Directory -Path "..\Release\$($env:APPVEYOR_PROJECT_NAME)\$($env:APPVEYOR_BUILD_VERSION)" -Force -ErrorAction Stop 47 | 48 | <#-- Copy Module Files --#> 49 | Copy-Item -Path $ReleaseSource\* -Recurse -Destination $($Directory.Fullname) -Force -ErrorAction Stop 50 | 51 | 52 | If ((-not ($ENV:APPVEYOR_PULL_REQUEST_NUMBER)) -and (($ENV:APPVEYOR_REPO_BRANCH -eq 'master') -and ($ENV:APPVEYOR_BUILD_VERSION -ge "1.0.0"))) { 53 | 54 | If (($ENV:sig_key) -and ($ENV:PfxSecure)) { 55 | 56 | Write-Host "Signing Files" -ForegroundColor Cyan 57 | 58 | Try { 59 | $KeyPath = Join-Path $([System.Environment]::GetEnvironmentVariable("TEMP")) cert.pfx 60 | [IO.File]::WriteAllBytes($KeyPath, [Convert]::FromBase64String($($env:sig_key))) 61 | 62 | $SecurePW = ConvertTo-SecureString -String $($env:PfxSecure) -Force -AsPlainText 63 | $Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList "UserName", $SecurePW 64 | 65 | $Cert = Get-ChildItem -Path $KeyPath | Import-PfxCertificate -CertStoreLocation "Cert:\CurrentUser\My" -Password $Cred.Password 66 | 67 | $null = Get-ChildItem -Path "$($Directory.Fullname)\*.ps*" -Recurse | Set-AuthenticodeSignature -Certificate $Cert -TimestampServer 'http://timestamp.digicert.com' 68 | $null = New-FileCatalog -CatalogVersion 2 -CatalogFilePath "$($Directory.Fullname)\$($env:APPVEYOR_PROJECT_NAME).cat" -Path $($Directory.Fullname) 69 | $null = Set-AuthenticodeSignature -Certificate $Cert -TimestampServer 'http://timestamp.digicert.com' -FilePath "$($Directory.Fullname)\$($env:APPVEYOR_PROJECT_NAME).cat" 70 | } 71 | Catch { 72 | Throw $_ 73 | } 74 | Finally { 75 | 76 | Get-ChildItem -Path "Cert:\CurrentUser\My" -Recurse -CodeSigningCert | Remove-Item -Force 77 | Remove-Item -Path $KeyPath -Force 78 | Remove-Variable -Name SecurePW -Force 79 | Remove-Variable -Name Cred -Force 80 | 81 | } 82 | 83 | } 84 | 85 | } 86 | 87 | <#-- Create Package ---#> 88 | Compress-Archive $Directory -DestinationPath ..\$OutputArchive -ErrorAction Stop 89 | 90 | <#-- Release Artifact --#> 91 | Write-Host "Release Artifact : $OutputArchive" 92 | Push-AppveyorArtifact ..\$OutputArchive -FileName $OutputArchive -DeploymentName "$env:APPVEYOR_PROJECT_NAME-latest" 93 | 94 | } 95 | 96 | Catch { 97 | 98 | throw $_ 99 | 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /build/deploy-github.ps1: -------------------------------------------------------------------------------- 1 | <#--------------------------------- 2 | Update version number on GitHub to match build version 3 | ---------------------------------#> 4 | 5 | 6 | if (-not ($ENV:APPVEYOR_PULL_REQUEST_NUMBER)) { 7 | 8 | Write-Host "Deploy Process: GitHub Repository" -ForegroundColor Yellow 9 | 10 | <#---------------------------------#> 11 | <# If Not a PR #> 12 | <# Push psd1 file to ORIGIN Branch #> 13 | <#---------------------------------#> 14 | 15 | Try { 16 | 17 | Write-Host "Push Updated $($env:APPVEYOR_PROJECT_NAME).psd1 to GitHub..." -ForegroundColor Yellow 18 | 19 | git config --global core.safecrlf false 20 | git config --global credential.helper store 21 | Add-Content "$HOME\.git-credentials" "https://$($env:access_token):x-oauth-basic@github.com`n" 22 | git config --global user.email "$($env:github_email)" 23 | git config --global user.name "Pete Maan" 24 | 25 | git checkout -q $($ENV:APPVEYOR_REPO_BRANCH) 26 | 27 | git add $(Join-Path -Path (Join-Path -Path "$env:APPVEYOR_BUILD_FOLDER" -ChildPath "$env:APPVEYOR_PROJECT_NAME") -ChildPath "$env:APPVEYOR_PROJECT_NAME.psd1") 28 | 29 | git status 30 | 31 | git commit -s -m "Update Version: $($env:APPVEYOR_BUILD_VERSION)" 32 | 33 | git push --porcelain origin $($ENV:APPVEYOR_REPO_BRANCH) 34 | 35 | Write-Host "$($env:APPVEYOR_PROJECT_NAME) version $($env:APPVEYOR_BUILD_VERSION) pushed to GitHub." -ForegroundColor Cyan 36 | 37 | } 38 | 39 | Catch { 40 | 41 | Write-Host "Push to GitHub failed." -ForegroundColor Red 42 | throw $_ 43 | 44 | } 45 | 46 | Write-Host "Deploy Process: GitHub Release" -ForegroundColor Yellow 47 | 48 | If ($ENV:APPVEYOR_REPO_BRANCH -eq 'master') { 49 | 50 | <# Master Branch #> 51 | 52 | If ($env:APPVEYOR_BUILD_VERSION -ge "1.0.0") { 53 | 54 | <# Create New Release #> 55 | 56 | $token = $env:access_token 57 | $uploadFilePath = Resolve-Path "..\$($env:APPVEYOR_PROJECT_NAME)-v$($env:APPVEYOR_BUILD_VERSION).zip" 58 | $releaseName = "v$($env:APPVEYOR_BUILD_VERSION)" 59 | $repo = "pspete/$env:APPVEYOR_PROJECT_NAME" 60 | 61 | $headers = @{ 62 | "Authorization" = "token $token" 63 | "Content-type" = "application/json" 64 | } 65 | 66 | $body = @{ 67 | tag_name = $releaseName 68 | name = $releaseName 69 | body = "$($env:APPVEYOR_PROJECT_NAME) v$($env:APPVEYOR_BUILD_VERSION)" 70 | draft = $false 71 | prerelease = $false 72 | } 73 | 74 | Write-Host "Creating release $releaseName..." -NoNewline 75 | 76 | try { 77 | $json = (ConvertTo-Json $body) 78 | $release = Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/releases" -Headers $headers -Method POST -Body $json 79 | $uploadUrl = $release.upload_url.Replace("{?name,label}", "") + "?name=" + [IO.Path]::GetFileName($uploadFilePath) 80 | Write-Host "OK" -ForegroundColor Green 81 | 82 | Write-Host "Uploading asset $($env:APPVEYOR_PROJECT_NAME)-v$($env:APPVEYOR_BUILD_VERSION).zip..." -NoNewline 83 | 84 | $data = [System.IO.File]::ReadAllBytes($uploadFilePath) 85 | $wc = New-Object Net.WebClient 86 | $wc.Headers['Content-type'] = 'application/octet-stream' 87 | $wc.Headers['Authorization'] = "token $token" 88 | 89 | $null = $wc.UploadData($uploadUrl, "POST", $data) 90 | Write-Host "OK" -ForegroundColor Green 91 | } 92 | catch { 93 | 94 | Write-Host "GitHub Release Failed." -ForegroundColor Red 95 | throw $_ 96 | 97 | } 98 | 99 | } 100 | 101 | } 102 | 103 | Else { 104 | 105 | <# Not Master Branch #> 106 | Write-Host "$ENV:APPVEYOR_REPO_BRANCH Branch; No Release" -ForegroundColor Cyan 107 | exit; 108 | 109 | } 110 | 111 | } 112 | 113 | Else { 114 | 115 | Write-Host "Skipping Deploy Process: GitHub Repository" -ForegroundColor Yellow 116 | 117 | } -------------------------------------------------------------------------------- /build/deploy-psgallery.ps1: -------------------------------------------------------------------------------- 1 | <#--------------------------------- 2 | Auto-publish changes to master branch as a new module version in the PSGallery. 3 | - Only publish if build version is greater than 1.0 4 | - Skip Auto-publish with specific commit message of "Manual Deployment" 5 | ---------------------------------#> 6 | 7 | 8 | if (-not ($ENV:APPVEYOR_PULL_REQUEST_NUMBER)) { 9 | 10 | Write-Host "Deploy Process: PowerShell Gallery" -ForegroundColor Yellow 11 | 12 | <#---------------------------------#> 13 | <# If Not a PR #> 14 | <#---------------------------------#> 15 | If (($ENV:APPVEYOR_REPO_BRANCH -eq 'master') -and ($env:APPVEYOR_BUILD_VERSION -ge "1.0.0")) { 16 | 17 | <# Master Branch #> 18 | <# Version 1.0+ #> 19 | 20 | If ($ENV:APPVEYOR_REPO_COMMIT_MESSAGE -eq "Manual Deployment") { 21 | 22 | <# Manual Deploy to PSGallery #> 23 | Write-Host "Finished testing of branch: $env:APPVEYOR_REPO_BRANCH" -ForegroundColor Cyan 24 | Write-Host "Manual Deployment to PSGallery Required" -ForegroundColor Cyan 25 | Write-Host "Exiting" -ForegroundColor Cyan 26 | exit; 27 | 28 | } 29 | Else { 30 | 31 | <#---------------------------------# 32 | # Publish to PS Gallery # 33 | #----------------------------------#> 34 | 35 | $ModulePath = Resolve-Path "..\Release\$($env:APPVEYOR_PROJECT_NAME)\$($env:APPVEYOR_BUILD_VERSION)" 36 | 37 | Write-Host "Publish $($env:APPVEYOR_PROJECT_NAME) $($env:APPVEYOR_BUILD_VERSION) to Powershell Gallery......" -NoNewline 38 | 39 | Try { 40 | 41 | Publish-Module -Path $ModulePath -NuGetApiKey $($env:psgallery_key) -SkipAutomaticTags -Confirm:$false -ErrorAction Stop -Force 42 | 43 | Write-Host "OK" -ForegroundColor Green 44 | 45 | } 46 | Catch { 47 | 48 | Write-Host "Failed - $_." -ForegroundColor Red 49 | throw $_ 50 | 51 | } 52 | Finally { 53 | exit; 54 | } 55 | 56 | } 57 | 58 | } 59 | Else { 60 | 61 | <# No Deployment #> 62 | 63 | Write-Host "Finished testing: $($env:APPVEYOR_PROJECT_NAME) $env:APPVEYOR_REPO_BRANCH ($($env:APPVEYOR_BUILD_VERSION)) - Exiting" -ForegroundColor Cyan 64 | exit; 65 | 66 | } 67 | 68 | } 69 | Else { 70 | 71 | Write-Host "Skipping Deploy Process: PowerShell Gallery" -ForegroundColor Yellow 72 | 73 | } -------------------------------------------------------------------------------- /build/install.ps1: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # Header # 3 | #---------------------------------# 4 | Write-Host "Installing Required Modules:" -ForegroundColor Yellow 5 | 6 | $RequiredModules = @( 7 | "PowerShellGet" 8 | "Pester", 9 | "PSScriptAnalyzer", 10 | "coveralls", 11 | "PSCodeCovIo" 12 | ) 13 | 14 | #---------------------------------# 15 | # Install NuGet # 16 | #---------------------------------# 17 | if(-not $IsCoreCLR) { 18 | Write-Host "`tNuGet..." 19 | $pkg = Install-PackageProvider -Name NuGet -Confirm:$false -Force -ErrorAction Stop 20 | Write-Host "`t`tInstalled NuGet version '$($pkg.version)'" 21 | } 22 | #---------------------------------# 23 | # Install Required Modules # 24 | #---------------------------------# 25 | foreach ($Module in $RequiredModules) { 26 | 27 | Try { 28 | Write-Host "`tInstalling: $Module..." -NoNewline 29 | Install-Module -Name $Module -Repository PSGallery -Confirm:$false -Force -SkipPublisherCheck -ErrorAction Stop | Out-Null 30 | Write-Host " OK" -ForegroundColor Green 31 | }Catch { 32 | Write-Host "Error" -ForegroundColor Red 33 | throw $_ 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /build/test.ps1: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # Header # 3 | #---------------------------------# 4 | Write-Host "Testing: PSVersion $($PSVersionTable.PSVersion)" -ForegroundColor Yellow 5 | 6 | #---------------------------------# 7 | # Run Pester Tests # 8 | #---------------------------------# 9 | $files = Get-ChildItem $(Join-Path $ENV:APPVEYOR_BUILD_FOLDER $env:APPVEYOR_PROJECT_NAME) -Include *.ps1 -Recurse 10 | 11 | $res = Invoke-Pester -Path ".\Tests" -OutputFormat NUnitXml -OutputFile TestsResults.xml -CodeCoverage $files -PassThru -Show Summary, Failed 12 | 13 | Write-Host 'Uploading Test Results' 14 | $null = (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $(Resolve-Path .\TestsResults.xml)) 15 | 16 | Remove-Item -Path $(Resolve-Path .\TestsResults.xml) -Force 17 | 18 | if ($env:APPVEYOR_REPO_COMMIT_AUTHOR -eq "Pete Maan") { 19 | 20 | Write-Host 'Formating Code Coverage' 21 | $coverage = Format-Coverage -PesterResults $res -CoverallsApiToken $($env:coveralls_key) -BranchName $($env:APPVEYOR_REPO_BRANCH) 22 | 23 | $null = Export-CodeCovIoJson -CodeCoverage $res.CodeCoverage -RepoRoot $pwd -Path coverage.json 24 | 25 | Write-Host 'Publishing Code Coverage' 26 | $null = Publish-Coverage -Coverage $coverage 27 | 28 | $null = Invoke-WebRequest -Uri 'https://codecov.io/bash' -OutFile codecov.sh 29 | 30 | $null = bash codecov.sh -f coverage.json 31 | 32 | Remove-Item -Path $(Resolve-Path .\coverage.json) -Force 33 | Remove-Item -Path $(Resolve-Path .\codecov.sh) -Force 34 | 35 | } 36 | #---------------------------------# 37 | # Validate # 38 | #---------------------------------# 39 | if (($res.FailedCount -gt 0) -or ($res.PassedCount -eq 0)) { 40 | 41 | throw "$($res.FailedCount) tests failed." 42 | 43 | } 44 | else { 45 | 46 | Write-Host 'All tests passed' -ForegroundColor Green 47 | 48 | } --------------------------------------------------------------------------------