From 11600e52bd016e32f6c45ff6ddd4f57b69409de2 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 15:37:33 -0500 Subject: [PATCH 01/53] Updated formatting, added caching for appveyor --- PSDPA/Classes/AccessToken.ps1 | 8 +- PSDPA/Classes/Annotation.ps1 | 2 +- PSDPA/Classes/Monitor.ps1 | 6 +- PSDPA/Private/Get-DpaAccessToken.ps1 | 5 +- PSDPA/Private/Invoke-DpaRequest.ps1 | 8 +- PSDPA/Public/Add-DpaAnnotation.ps1 | 11 +-- PSDPA/Public/Get-DpaAnnotation.ps1 | 5 +- PSDPA/Public/Get-DpaConfig.ps1 | 8 +- PSDPA/Public/Get-DpaLicense.ps1 | 8 +- PSDPA/Public/Get-DpaMonitor.ps1 | 11 +-- PSDPA/Public/Get-DpaMonitorLicense.ps1 | 9 +- PSDPA/Public/New-DpaMonitor.ps1 | 8 +- PSDPA/Public/Remove-DpaAnnotation.ps1 | 3 +- PSDPA/Public/Set-DpaConfig.ps1 | 2 +- PSDPA/Public/Start-DpaMonitor.ps1 | 6 +- PSDPA/Public/Stop-DpaMonitor.ps1 | 6 +- Tests/PSDPA.Tests.ps1 | 129 ++++++++++++++++++++++++- appveyor.yml | 9 ++ 18 files changed, 180 insertions(+), 64 deletions(-) diff --git a/PSDPA/Classes/AccessToken.ps1 b/PSDPA/Classes/AccessToken.ps1 index 366c7d1..1795251 100644 --- a/PSDPA/Classes/AccessToken.ps1 +++ b/PSDPA/Classes/AccessToken.ps1 @@ -23,8 +23,8 @@ class AccessToken { [bool] IsValid() { return ` - (Get-Date) -lt $this.Expiration -and - $null -ne $this.AccessToken -and - $null -ne $this.TokenType + (Get-Date) -lt $this.Expiration -and + $null -ne $this.AccessToken -and + $null -ne $this.TokenType } -} +} \ No newline at end of file diff --git a/PSDPA/Classes/Annotation.ps1 b/PSDPA/Classes/Annotation.ps1 index aa7e1ab..8541347 100644 --- a/PSDPA/Classes/Annotation.ps1 +++ b/PSDPA/Classes/Annotation.ps1 @@ -30,4 +30,4 @@ class Annotation { $this.Description = $Json.description $this.Time = $Json.time } -} +} \ No newline at end of file diff --git a/PSDPA/Classes/Monitor.ps1 b/PSDPA/Classes/Monitor.ps1 index 18803be..a7d5ca6 100644 --- a/PSDPA/Classes/Monitor.ps1 +++ b/PSDPA/Classes/Monitor.ps1 @@ -74,11 +74,11 @@ class MonitorFactory { static [Monitor[]] $Monitors static [Object] getByType ([Object] $O) { - return [MonitorFactory]::Monitors.Where({$_ -is $O}) + return [MonitorFactory]::Monitors.Where( {$_ -is $O}) } static [Object] getByName ([String] $Name) { - return [MonitorFactory]::Monitors.Where({$_.Name -eq $Name}) + return [MonitorFactory]::Monitors.Where( {$_.Name -eq $Name}) } [Monitor] New ([PSCustomObject] $Json) { @@ -86,4 +86,4 @@ class MonitorFactory { return (New-Object -TypeName "$type" -ArgumentList $Json) } -} +} \ No newline at end of file diff --git a/PSDPA/Private/Get-DpaAccessToken.ps1 b/PSDPA/Private/Get-DpaAccessToken.ps1 index e890bdc..5e75e86 100644 --- a/PSDPA/Private/Get-DpaAccessToken.ps1 +++ b/PSDPA/Private/Get-DpaAccessToken.ps1 @@ -7,7 +7,7 @@ function Get-DpaAccessToken { $refreshToken = (Get-DpaConfig -Name 'refreshtoken').Value $request = @{ - grant_type = 'refresh_token' + grant_type = 'refresh_token' refresh_token = $refreshToken } @@ -18,8 +18,7 @@ function Get-DpaAccessToken { Set-PSFConfig -Module 'psdpa' -Name 'accesstoken' -Value $accessToken $PSDefaultParameterValues['Invoke-DpaRequest:AccessToken'] = $accessToken return $accessToken - } - catch { + } catch { Stop-PSFFunction -Message "Could not obtain access token" -ErrorRecord $_ -EnableException $EnableException } } \ No newline at end of file diff --git a/PSDPA/Private/Invoke-DpaRequest.ps1 b/PSDPA/Private/Invoke-DpaRequest.ps1 index 57e6d04..ccc3e6b 100644 --- a/PSDPA/Private/Invoke-DpaRequest.ps1 +++ b/PSDPA/Private/Invoke-DpaRequest.ps1 @@ -27,8 +27,8 @@ function Invoke-DpaRequest { } $headers = @{ - 'Accept' = 'application/json' - 'Content-Type' = 'application/json;charset=UTF-8' + 'Accept' = 'application/json' + 'Content-Type' = 'application/json;charset=UTF-8' 'Authorization' = $AccessToken.ToAuthorizationHeader() } @@ -48,9 +48,9 @@ function Invoke-DpaRequest { } $params = @{ - 'Uri' = $uri + 'Uri' = $uri 'Headers' = $headers - 'Method' = $Method + 'Method' = $Method } if ($PSBoundParameters.ContainsKey('Request')) { $params['Body'] = $Request | ConvertTo-Json diff --git a/PSDPA/Public/Add-DpaAnnotation.ps1 b/PSDPA/Public/Add-DpaAnnotation.ps1 index ffe050c..4cc6824 100644 --- a/PSDPA/Public/Add-DpaAnnotation.ps1 +++ b/PSDPA/Public/Add-DpaAnnotation.ps1 @@ -92,8 +92,7 @@ function Add-DpaAnnotation { begin { if ($PSCmdlet.ParameterSetName -eq 'ByName') { $Monitor = Get-DpaMonitor -MonitorName $MonitorName - } - elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { + } elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { $Monitor = Get-DpaMonitor -DatabaseId $DatabaseId } } @@ -103,14 +102,14 @@ function Add-DpaAnnotation { $endpoint = "/databases/$($monitorObject.DatabaseId)/annotations" $request = @{ - 'title' = $Title + 'title' = $Title 'description' = $Description - 'createdBy' = $CreatedBy - 'time' = $Time.ToString("yyyy-MM-ddTHH\:mm\:sszzz") + 'createdBy' = $CreatedBy + 'time' = $Time.ToString("yyyy-MM-ddTHH\:mm\:sszzz") } $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Post' -Request $request New-Object -TypeName 'Annotation' -ArgumentList $response.data } } -} +} \ No newline at end of file diff --git a/PSDPA/Public/Get-DpaAnnotation.ps1 b/PSDPA/Public/Get-DpaAnnotation.ps1 index 4888e62..ee65ad5 100644 --- a/PSDPA/Public/Get-DpaAnnotation.ps1 +++ b/PSDPA/Public/Get-DpaAnnotation.ps1 @@ -80,8 +80,7 @@ function Get-DpaAnnotation { begin { if ($PSCmdlet.ParameterSetName -eq 'ByName') { $Monitor = Get-DpaMonitor -MonitorName $MonitorName - } - elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { + } elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { $Monitor = Get-DpaMonitor -DatabaseId $DatabaseId } } @@ -92,7 +91,7 @@ function Get-DpaAnnotation { $parameters = @{ 'startTime' = $StartTime.ToString("yyyy-MM-ddTHH\:mm\:ss.fffzzz") - 'endTime' = $EndTime.ToString("yyyy-MM-ddTHH\:mm\:ss.fffzzz") + 'endTime' = $EndTime.ToString("yyyy-MM-ddTHH\:mm\:ss.fffzzz") } $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Get' -Parameters $parameters diff --git a/PSDPA/Public/Get-DpaConfig.ps1 b/PSDPA/Public/Get-DpaConfig.ps1 index 3b33f17..79fc4bb 100644 --- a/PSDPA/Public/Get-DpaConfig.ps1 +++ b/PSDPA/Public/Get-DpaConfig.ps1 @@ -36,10 +36,10 @@ function Get-DpaConfig { $Name = $Name.ToLower() $results = [PSFramework.Configuration.ConfigurationHost]::Configurations.Values | Where-Object { - ($_.Name -like $Name) -and - ($_.Module -like $Module) -and - ((-not $_.Hidden) -or ($Force)) - } | Sort-Object Module, Name + ($_.Name -like $Name) -and + ($_.Module -like $Module) -and + ((-not $_.Hidden) -or ($Force)) + } | Sort-Object Module, Name $results | Select-Object Name, Value, Description } \ No newline at end of file diff --git a/PSDPA/Public/Get-DpaLicense.ps1 b/PSDPA/Public/Get-DpaLicense.ps1 index ffee5fb..f5ed995 100644 --- a/PSDPA/Public/Get-DpaLicense.ps1 +++ b/PSDPA/Public/Get-DpaLicense.ps1 @@ -60,11 +60,11 @@ function Get-DpaLicense { foreach ($license in $response) { [PSCustomObject] @{ - Product = $license.licenseProduct - Category = $license.licenseCategory + Product = $license.licenseProduct + Category = $license.licenseCategory Available = [int] $license.licensesAvailable - Consumed = [int] $license.licensesConsumed - Total = [int] $license.licensesAvailable + [int] $license.licensesConsumed + Consumed = [int] $license.licensesConsumed + Total = [int] $license.licensesAvailable + [int] $license.licensesConsumed } } } \ No newline at end of file diff --git a/PSDPA/Public/Get-DpaMonitor.ps1 b/PSDPA/Public/Get-DpaMonitor.ps1 index 2b7bc47..b6c94a3 100644 --- a/PSDPA/Public/Get-DpaMonitor.ps1 +++ b/PSDPA/Public/Get-DpaMonitor.ps1 @@ -52,8 +52,7 @@ function Get-DpaMonitor { if ($PSBoundParameters.ContainsKey('DatabaseId') -and $DatabaseId.Count -eq 1) { Write-PSFMessage -Level Verbose -Message 'Getting a single monitor' $endpoint = "/databases/$DatabaseId/monitor-information" - } - else { + } else { Write-PSFMessage -Level Verbose -Message 'Getting all monitors' $endpoint = '/databases/monitor-information' } @@ -61,8 +60,7 @@ function Get-DpaMonitor { try { $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Get' $monitors = $response.data - } - catch { + } catch { if ($_.Exception.Response.StatusCode.value__ -eq 422) { return $null } @@ -72,8 +70,7 @@ function Get-DpaMonitor { if ($PSBoundParameters.ContainsKey('DatabaseId') -and $DatabaseId -is [array]) { $monitors = $monitors | Where-Object { $_.dbid -in $DatabaseId } - } - elseif ($PSCmdlet.ParameterSetName -eq 'ByName') { + } elseif ($PSCmdlet.ParameterSetName -eq 'ByName') { $monitors = $monitors | Where-Object { $_.name -in $MonitorName } } @@ -81,4 +78,4 @@ function Get-DpaMonitor { foreach ($monitor in $monitors) { $monitorFactory.New($monitor) } -} +} \ No newline at end of file diff --git a/PSDPA/Public/Get-DpaMonitorLicense.ps1 b/PSDPA/Public/Get-DpaMonitorLicense.ps1 index 778f01b..ff20460 100644 --- a/PSDPA/Public/Get-DpaMonitorLicense.ps1 +++ b/PSDPA/Public/Get-DpaMonitorLicense.ps1 @@ -60,8 +60,7 @@ function Get-DpaMonitorLicense { begin { if ($PSCmdlet.ParameterSetName -eq 'ByName') { $Monitor = Get-DpaMonitor -MonitorName $MonitorName - } - elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { + } elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { $Monitor = Get-DpaMonitor -DatabaseId $DatabaseId } } @@ -72,9 +71,9 @@ function Get-DpaMonitorLicense { $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Get' [PSCustomObject] @{ - ServerName = $response.data.serverName - OverLicensed = $response.data.overLicensed - VmLicenseProduct = $response.data.vmLicenseProduct + ServerName = $response.data.serverName + OverLicensed = $response.data.overLicensed + VmLicenseProduct = $response.data.vmLicenseProduct PerformanceLicenseProduct = $response.data.performanceLicenseProduct } } diff --git a/PSDPA/Public/New-DpaMonitor.ps1 b/PSDPA/Public/New-DpaMonitor.ps1 index 51f5d95..441568b 100644 --- a/PSDPA/Public/New-DpaMonitor.ps1 +++ b/PSDPA/Public/New-DpaMonitor.ps1 @@ -58,7 +58,7 @@ function Add-DpaMonitor { } $request = @{ - serverName = $ServerName + serverName = $ServerName databaseType = $DatabaseType.ToUpper() } @@ -97,8 +97,7 @@ function Add-DpaMonitor { if ($PSBoundParameters.ContainsKey('MonitoringCredential') -and $DatabaseType -ne 'Db2') { $request['monitoringUser'] = $MonitoringCredential.UserName $request['monitoringUserPassword'] = $MonitoringCredential.GetNetworkCredential().Password - } - else { + } else { $request['monitoringUser'] = $Credential.UserName $request['monitoringUserPassword'] = $Credential.GetNetworkCredential().Password } @@ -106,8 +105,7 @@ function Add-DpaMonitor { try { $response = Invoke-DpaRequest -Endpoint '/databases/register-monitor' -Request $request -Method 'POST' - } - catch { + } catch { Stop-PSFFunction -Message "Could not register monitor" -ErrorRecord $_ return } diff --git a/PSDPA/Public/Remove-DpaAnnotation.ps1 b/PSDPA/Public/Remove-DpaAnnotation.ps1 index 588abca..0b10169 100644 --- a/PSDPA/Public/Remove-DpaAnnotation.ps1 +++ b/PSDPA/Public/Remove-DpaAnnotation.ps1 @@ -40,8 +40,7 @@ function Remove-DpaAnnotation { $endpoint = "databases/$($annotationObject.DatabaseId)/annotations/$($annotationObject.AnnotationId)" try { $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Delete' - } - catch { + } catch { Stop-PSFFunction -Message "Could not remove annotation" -EnableException:$EnableException -ErrorRecord $_ } } diff --git a/PSDPA/Public/Set-DpaConfig.ps1 b/PSDPA/Public/Set-DpaConfig.ps1 index 6dabab8..2defb95 100644 --- a/PSDPA/Public/Set-DpaConfig.ps1 +++ b/PSDPA/Public/Set-DpaConfig.ps1 @@ -22,4 +22,4 @@ function Set-DpaConfig { Get-DpaConfig -Name $name } -} +} \ No newline at end of file diff --git a/PSDPA/Public/Start-DpaMonitor.ps1 b/PSDPA/Public/Start-DpaMonitor.ps1 index b58dc65..310a84c 100644 --- a/PSDPA/Public/Start-DpaMonitor.ps1 +++ b/PSDPA/Public/Start-DpaMonitor.ps1 @@ -56,8 +56,7 @@ function Start-DpaMonitor { begin { if ($PSCmdlet.ParameterSetName -eq 'ByName') { $Monitor = Get-DpaMonitor -MonitorName $MonitorName - } - elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { + } elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { $Monitor = Get-DpaMonitor -DatabaseId $DatabaseId } @@ -70,8 +69,7 @@ function Start-DpaMonitor { foreach ($monitorObject in $Monitor) { try { $response = Invoke-DpaRequest -Endpoint "/databases/$($monitorObject.Dbid)/monitor-status" -Method 'PUT' -Request $request - } - catch { + } catch { Stop-PSFFunction -Message "Could not start the monitor" -EnableException:$EnableException -ErrorRecord $_ -Target $monitorObject.Name } } diff --git a/PSDPA/Public/Stop-DpaMonitor.ps1 b/PSDPA/Public/Stop-DpaMonitor.ps1 index 63e4c7f..c86ffe9 100644 --- a/PSDPA/Public/Stop-DpaMonitor.ps1 +++ b/PSDPA/Public/Stop-DpaMonitor.ps1 @@ -55,8 +55,7 @@ function Stop-DpaMonitor { begin { if ($PSCmdlet.ParameterSetName -eq 'ByName') { $Monitor = Get-DpaMonitor -MonitorName $MonitorName - } - elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { + } elseif ($PSCmdlet.ParameterSetName -eq 'ByDatabaseId') { $Monitor = Get-DpaMonitor -DatabaseId $DatabaseId } @@ -70,8 +69,7 @@ function Stop-DpaMonitor { if ($PSCmdlet.ShouldProcess($monitor.Name, 'Stop Monitor')) { try { $response = Invoke-DpaRequest -Endpoint "/databases/$($monitorObject.Dbid)/monitor-status" -Method 'PUT' -Request $request - } - catch { + } catch { Stop-PSFFunction -Message "Could not stop the monitor" -ErrorRecord $_ -Target $monitorObject.Name } } diff --git a/Tests/PSDPA.Tests.ps1 b/Tests/PSDPA.Tests.ps1 index 0ecdc25..805d9fb 100644 --- a/Tests/PSDPA.Tests.ps1 +++ b/Tests/PSDPA.Tests.ps1 @@ -1,8 +1,129 @@ . $PSScriptRoot\Shared.ps1 +$Path = Split-Path -Parent $MyInvocation.MyCommand.Path +$ModulePath = (Get-Item $Path).Parent.FullName + '\' + $ModuleName -Describe "Module Manifest Tests PS$PSVersion" { - It 'Passes Test-ModuleManifest' { - Test-ModuleManifest -Path $ENV:BHPSModuleManifest - $? | Should Be $true +function Split-ArrayInParts($array, [int]$parts) { + #splits an array in "equal" parts + $size = $array.Length / $parts + $counter = [pscustomobject] @{ Value = 0 } + $groups = $array | Group-Object -Property { [math]::Floor($counter.Value++ / $size) } + $rtn = @() + foreach ($g in $groups) { + $rtn += , @($g.Group) + } + $rtn +} + +Describe "$ModuleName style" -Tag 'Compliance' { + <# + Ensures common formatting standards are applied: + - OTSB style, courtesy of PSSA's Invoke-Formatter, is what dbatools uses + - UTF8 without BOM is what is going to be used in PS Core, so we adopt this standard for dbatools + #> + $AllFiles = Get-ChildItem -Path $ModulePath -File -Recurse -Filter '*.ps*1' + $AllFunctionFiles = Get-ChildItem -Path "$ModulePath\Public", "$ModulePath\Private", "$ModulePath\Classes" -Filter '*.ps*1' + Context "formatting" { + $maxConcurrentJobs = $env:NUMBER_OF_PROCESSORS + $whatever = Split-ArrayInParts -array $AllFunctionFiles -parts $maxConcurrentJobs + $jobs = @() + foreach ($piece in $whatever) { + $jobs += Start-Job -ScriptBlock { + foreach ($p in $Args) { + $content = Get-Content -Path $p.FullName -Raw -Encoding UTF8 + $result = Invoke-Formatter -ScriptDefinition $content -Settings CodeFormattingOTBS + if ($result -ne $content) { + $p + } + } + } -ArgumentList $piece + } + $null = $jobs | Wait-Job #-Timeout 120 + $results = $jobs | Receive-Job + + foreach ($f in $results) { + It "$f is adopting OTSB formatting style. Please run Invoke-DbatoolsFormatter against the failing file and commit the changes." { + 1 | Should -Be 0 + } + } + } + + Context "BOM" { + foreach ($f in $AllFiles) { + [byte[]]$byteContent = Get-Content -Path $f.FullName -Encoding Byte -ReadCount 4 -TotalCount 4 + if ( $byteContent[0] -eq 0xef -and $byteContent[1] -eq 0xbb -and $byteContent[2] -eq 0xbf ) { + It "$f has no BOM in it" { + "utf8bom" | Should -Be "utf8" + } + } + } + } + + Context "indentation" { + foreach ($f in $AllFiles) { + $LeadingTabs = Select-String -Path $f -Pattern '^[\t]+' + if ($LeadingTabs.Count -gt 0) { + It "$f is not indented with tabs (line(s) $($LeadingTabs.LineNumber -join ','))" { + $LeadingTabs.Count | Should -Be 0 + } + } + $TrailingSpaces = Select-String -Path $f -Pattern '([^ \t\r\n])[ \t]+$' + if ($TrailingSpaces.Count -gt 0) { + It "$f has no trailing spaces (line(s) $($TrailingSpaces.LineNumber -join ','))" { + $TrailingSpaces.Count | Should -Be 0 + } + } + } + } +} + +Describe "$ModuleName style" -Tag 'Compliance' { + <# + Ensures avoiding already discovered pitfalls + #> + $AllPublicFunctions = Get-ChildItem -Path "$ModulePath\Public" -Filter '*.ps*1' + + Context "NoCompatibleTLS" { + # .NET defaults clash with recent TLS hardening (e.g. no TLS 1.2 by default) + foreach ($f in $AllPublicFunctions) { + $NotAllowed = Select-String -Path $f -Pattern 'Invoke-WebRequest | New-Object System.Net.WebClient|\.DownloadFile' + if ($NotAllowed.Count -gt 0) { + It "$f should instead use Invoke-TlsWebRequest, see #4250" { + $NotAllowed.Count | Should -Be 0 + } + } + } + } + +} + + +Describe "$ModuleName ScriptAnalyzerErrors" -Tag 'Compliance' { + $ScriptAnalyzerErrors = @() + $ScriptAnalyzerErrors += Invoke-ScriptAnalyzer -Path "$ModulePath\Public" -Severity Error + $ScriptAnalyzerErrors += Invoke-ScriptAnalyzer -Path "$ModulePath\Private" -Severity Error + Context "Errors" { + if ($ScriptAnalyzerErrors.Count -gt 0) { + foreach ($err in $ScriptAnalyzerErrors) { + It "$($err.scriptName) has Error(s) : $($err.RuleName)" { + $err.Message | Should -Be $null + } + } + } + } +} + +Describe "$ModuleName Tests missing" -Tag 'Tests' { + $functions = Get-ChildItem .\Public\ -Recurse -Include *.ps1 + Context "Every function should have tests" { + foreach ($f in $functions) { + It "$($f.basename) has a tests.ps1 file" { + Test-Path "Tests\$($f.basename).Tests.ps1" | Should Be $true + } + If (Test-Path "Tests\$($f.basename).Tests.ps1") { + It "$($f.basename) has validate parameters unit test" { + "Tests\$($f.basename).Tests.ps1" | should FileContentMatch 'Context "Validate parameters"' + } + } + } } } \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index c54f8a3..62125de 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,15 @@ environment: os: WMF 5 +cache: + - C:\Program Files\WindowsPowerShell\Modules\PSScriptAnalyzer -> Build\build.requirements.psd1 + - C:\Program Files\WindowsPowerShell\Modules\Pester -> Build\build.requirements.psd1 + - C:\Program Files\WindowsPowerShell\Modules\PSCodeCovIo -> Build\build.requirements.psd1 + - C:\Program Files\WindowsPowerShell\Modules\PSFramework -> Build\build.requirements.psd1 + - C:\Program Files\WindowsPowerShell\Modules\BuildHelpers -> Build\build.requirements.psd1 + - C:\Program Files\WindowsPowerShell\Modules\PSDeploy -> Build\build.requirements.psd1 + - C:\Program Files\WindowsPowerShell\Modules\psake -> Build\build.requirements.psd1 + # Skip on updates to the readme. # We can force this by adding [skip ci] or [ci skip] anywhere in commit message skip_commits: From c4f47af125679e36a0d5dbf281835f041edf7997 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 15:41:44 -0500 Subject: [PATCH 02/53] Requiring newer version of PSScriptAnalyzer so we get Invoke-Formatter --- Build/build.requirements.psd1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/build.requirements.psd1 b/Build/build.requirements.psd1 index 2b501a6..5477f45 100644 --- a/Build/build.requirements.psd1 +++ b/Build/build.requirements.psd1 @@ -8,6 +8,7 @@ } } + 'PSScriptAnalyzer' = '1.17.1' 'psake' = '4.7.0' 'PSDeploy' = '0.2.5' 'BuildHelpers' = '1.1.1' From 1d5f8e788d0a264ed5fde89aba5856e49a44a10e Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 15:52:35 -0500 Subject: [PATCH 03/53] Fixing analyzer tests and stubbing in some test files --- Invoke-DpaFormatter.ps1 | 88 ++++++++++++++++++++++++++++++++++ Tests/Get-DpaConfig.Tests.ps1 | 0 Tests/New-DpaMonitor.Tests.ps1 | 0 Tests/PSDPA.Tests.ps1 | 11 ++++- Tests/Set-DpaConfig.Tests.ps1 | 0 5 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 Invoke-DpaFormatter.ps1 create mode 100644 Tests/Get-DpaConfig.Tests.ps1 create mode 100644 Tests/New-DpaMonitor.Tests.ps1 create mode 100644 Tests/Set-DpaConfig.Tests.ps1 diff --git a/Invoke-DpaFormatter.ps1 b/Invoke-DpaFormatter.ps1 new file mode 100644 index 0000000..6214aba --- /dev/null +++ b/Invoke-DpaFormatter.ps1 @@ -0,0 +1,88 @@ +function Invoke-DpaFormatter { + <# + .SYNOPSIS + Helps formatting function files to dbatools' standards + + .DESCRIPTION + Uses PSSA's Invoke-Formatter to format the target files and saves it without the BOM. + + .PARAMETER Path + The path to the ps1 file that needs to be formatted + + .PARAMETER EnableException + By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. + This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. + Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. + + .NOTES + Tags: Formatting + Author: Simone Bizzotto + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Invoke-DbatoolsFormatter + + .EXAMPLE + PS C:\> Invoke-DbatoolsFormatter -Path C:\dbatools\functions\Get-DbaDatabase.ps1 + + Reformats C:\dbatools\functions\Get-DbaDatabase.ps1 to dbatools' standards + + #> + [CmdletBinding()] + param ( + [parameter(Mandatory, ValueFromPipeline)] + [object[]]$Path, + [switch]$EnableException + ) + begin { + $HasInvokeFormatter = $null -ne (Get-Command Invoke-Formatter -ErrorAction SilentlyContinue).Version + if (!($HasInvokeFormatter)) { + Stop-Function -Message "You need a recent version of PSScriptAnalyzer installed" + } + $CBHRex = [regex]'(?smi)\s+<#[^#]*#>' + $CBHStartRex = [regex]'(?[ ]+)<#' + $CBHEndRex = [regex]'(?[ ]*)#>' + } + process { + foreach ($p in $Path) { + try { + $realPath = (Resolve-Path -Path $p -ErrorAction Stop).Path + } catch { + Stop-Function -Message "Cannot find or resolve $p" -Continue + } + + $content = Get-Content -Path $realPath -Raw -Encoding UTF8 + #strip ending empty lines + $content = $content -replace "(?s)`r`n\s*$" + try { + $content = Invoke-Formatter -ScriptDefinition $content -Settings CodeFormattingOTBS -ErrorAction Stop + } catch { + Write-Message -Level Warning "Unable to format $p" + } + #match the ending indentation of CBH with the starting one, see #4373 + $CBH = $CBHRex.Match($content).Value + if ($CBH) { + #get starting spaces + $startSpaces = $CBHStartRex.Match($CBH).Groups['spaces'] + if ($startSpaces) { + #get end + $newCBH = $CBHEndRex.Replace($CBH, "$startSpaces#>") + if ($newCBH) { + #replace the CBH + $content = $content.Replace($CBH, $newCBH) + } + } + } + $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False + $realContent = @() + #trim whitespace lines + foreach ($line in $content.Split("`n")) { + $realContent += $line.TrimEnd() + } + [System.IO.File]::WriteAllText($realPath, ($realContent -Join "`r`n"), $Utf8NoBomEncoding) + } + } +} \ No newline at end of file diff --git a/Tests/Get-DpaConfig.Tests.ps1 b/Tests/Get-DpaConfig.Tests.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/Tests/New-DpaMonitor.Tests.ps1 b/Tests/New-DpaMonitor.Tests.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/Tests/PSDPA.Tests.ps1 b/Tests/PSDPA.Tests.ps1 index 805d9fb..2ec676f 100644 --- a/Tests/PSDPA.Tests.ps1 +++ b/Tests/PSDPA.Tests.ps1 @@ -1,6 +1,11 @@ . $PSScriptRoot\Shared.ps1 $Path = Split-Path -Parent $MyInvocation.MyCommand.Path -$ModulePath = (Get-Item $Path).Parent.FullName + '\' + $ModuleName +if ($ENV:BHProjectPath) { + $ModulePath = Join-Path $ENV:BHProjectPath $ModuleName +} else { + $ModulePath = (Get-Item $Path).Parent.FullName + '\' + $ModuleName +} +Write-Host "ModulePath: $ModulePath" function Split-ArrayInParts($array, [int]$parts) { #splits an array in "equal" parts @@ -113,17 +118,19 @@ Describe "$ModuleName ScriptAnalyzerErrors" -Tag 'Compliance' { } Describe "$ModuleName Tests missing" -Tag 'Tests' { - $functions = Get-ChildItem .\Public\ -Recurse -Include *.ps1 + $functions = Get-ChildItem (Join-Path -Path $ModulePath -ChildPath 'Public') -Recurse -Include *.ps1 Context "Every function should have tests" { foreach ($f in $functions) { It "$($f.basename) has a tests.ps1 file" { Test-Path "Tests\$($f.basename).Tests.ps1" | Should Be $true } + <# If (Test-Path "Tests\$($f.basename).Tests.ps1") { It "$($f.basename) has validate parameters unit test" { "Tests\$($f.basename).Tests.ps1" | should FileContentMatch 'Context "Validate parameters"' } } + #> } } } \ No newline at end of file diff --git a/Tests/Set-DpaConfig.Tests.ps1 b/Tests/Set-DpaConfig.Tests.ps1 new file mode 100644 index 0000000..e69de29 From 4c7e5554bad0f10f37d9027ee4358ca25ea1b2ff Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 16:01:01 -0500 Subject: [PATCH 04/53] Updating caching location for modules --- appveyor.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 62125de..b8ea902 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,13 +10,13 @@ environment: os: WMF 5 cache: - - C:\Program Files\WindowsPowerShell\Modules\PSScriptAnalyzer -> Build\build.requirements.psd1 - - C:\Program Files\WindowsPowerShell\Modules\Pester -> Build\build.requirements.psd1 - - C:\Program Files\WindowsPowerShell\Modules\PSCodeCovIo -> Build\build.requirements.psd1 - - C:\Program Files\WindowsPowerShell\Modules\PSFramework -> Build\build.requirements.psd1 - - C:\Program Files\WindowsPowerShell\Modules\BuildHelpers -> Build\build.requirements.psd1 - - C:\Program Files\WindowsPowerShell\Modules\PSDeploy -> Build\build.requirements.psd1 - - C:\Program Files\WindowsPowerShell\Modules\psake -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSScriptAnalyzer -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\Pester -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSCodeCovIo -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSFramework -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\BuildHelpers -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSDeploy -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\psake -> Build\build.requirements.psd1 # Skip on updates to the readme. # We can force this by adding [skip ci] or [ci skip] anywhere in commit message From 51d325c2f997264150d3b5e2a29c0d63cfdcdfdd Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 16:07:21 -0500 Subject: [PATCH 05/53] Hopefully getting rid of warning in build --- Build/build.requirements.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/build.requirements.psd1 b/Build/build.requirements.psd1 index 5477f45..b9c1117 100644 --- a/Build/build.requirements.psd1 +++ b/Build/build.requirements.psd1 @@ -4,7 +4,7 @@ Target = '$ENV:USERPROFILE\Documents\WindowsPowerShell\Modules' AddToPath = $True Parameters = @{ - Force = $True + #Force = $True } } From b1d5f05d2f0a1f6d8091348107c44e8be350d200 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 16:11:34 -0500 Subject: [PATCH 06/53] Switch to Get-NextNugetPackageVersion --- Build/psake.ps1 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 4249002..ff8f22f 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -75,16 +75,13 @@ Task Build -Depends Test { Set-ModuleFunctions # Bump the module version if we didn't already - Try - { - $GalleryVersion = Get-NextPSGalleryVersion -Name $env:BHProjectName -ErrorAction Stop - $GithubVersion = Get-MetaData -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -ErrorAction Stop + try { + [version]$GalleryVersion = Get-NextNugetPackageVersion -Name $env:BHProjectName -ErrorAction Stop + [version]$GithubVersion = Get-MetaData -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -ErrorAction Stop if($GalleryVersion -ge $GithubVersion) { Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $GalleryVersion -ErrorAction stop } - } - Catch - { + } catch { "Failed to update version for '$env:BHProjectName': $_.`nContinuing with existing version" } } From 653951677c627b619c62b2e8508366c8c027f76d Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Wed, 13 Feb 2019 18:22:56 -0500 Subject: [PATCH 07/53] Update README.md Adding PSGallery version shield --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1ef446..3e5319d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ goal of the module is to provide complete PowerShell coverage for the API. | Branch | Status | |:--- |:--- | -| Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) | +| Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSDPA.svg?style=flat&label=PSGallery)](https://www.powershellgallery.com/packages/PSDPA) | Development |[![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) | ## Instructions From 3ebb0d13c7e2bbc0a0a36cfce4ab452812cb4e3a Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 11:27:55 -0500 Subject: [PATCH 08/53] Update README.md Added Codacy badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e5319d..77e41f7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ goal of the module is to provide complete PowerShell coverage for the API. | Branch | Status | |:--- |:--- | | Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSDPA.svg?style=flat&label=PSGallery)](https://www.powershellgallery.com/packages/PSDPA) -| Development |[![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) | +| Development |[![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c303d5eae85a4840908206a4a1bcf92d)](https://www.codacy.com/app/awickham10/psdpa?utm_source=github.com&utm_medium=referral&utm_content=awickham10/psdpa&utm_campaign=Badge_Grade) | ## Instructions ``` powershell From 87261f9e76f3be95e689cf20921c7d6cdcba6547 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 11:40:38 -0500 Subject: [PATCH 09/53] Added ShouldProcess support to state changing functions --- PSDPA/Public/Set-DpaConfig.ps1 | 20 +++++++++++--------- PSDPA/Public/Start-DpaMonitor.ps1 | 12 +++++++----- PSDPA/Public/Stop-DpaMonitor.ps1 | 2 +- Tests/PSDPA.Tests.ps1 | 1 - 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/PSDPA/Public/Set-DpaConfig.ps1 b/PSDPA/Public/Set-DpaConfig.ps1 index 2defb95..7612141 100644 --- a/PSDPA/Public/Set-DpaConfig.ps1 +++ b/PSDPA/Public/Set-DpaConfig.ps1 @@ -1,5 +1,5 @@ function Set-DpaConfig { - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess)] param ( [Parameter()] $BaseUri, @@ -9,17 +9,19 @@ function Set-DpaConfig { ) process { - foreach ($parameter in $PSBoundParameters.GetEnumerator()) { - $name = $parameter.Key.ToLower() + if ($PSCmdlet.ShouldProcess('Updated Config')) { + foreach ($parameter in $PSBoundParameters.GetEnumerator()) { + $name = $parameter.Key.ToLower() - Set-PSFConfig -Module psdpa -Name $name -Value $parameter.Value - Register-PSFConfig -FullName psdpa.$name -EnableException -WarningAction SilentlyContinue + Set-PSFConfig -Module psdpa -Name $name -Value $parameter.Value + Register-PSFConfig -FullName psdpa.$name -EnableException -WarningAction SilentlyContinue - if ($name -eq 'refreshtoken') { - Set-Variable -Scope 1 -Name PSDefaultParameterValues -Value @{ 'PSDPA:AccessToken' = $value } + if ($name -eq 'refreshtoken') { + Set-Variable -Scope 1 -Name PSDefaultParameterValues -Value @{ 'PSDPA:AccessToken' = $value } + } } - } - Get-DpaConfig -Name $name + Get-DpaConfig -Name $name + } } } \ No newline at end of file diff --git a/PSDPA/Public/Start-DpaMonitor.ps1 b/PSDPA/Public/Start-DpaMonitor.ps1 index 310a84c..1b86c55 100644 --- a/PSDPA/Public/Start-DpaMonitor.ps1 +++ b/PSDPA/Public/Start-DpaMonitor.ps1 @@ -37,7 +37,7 @@ License: MIT https://opensource.org/licenses/MIT #> function Start-DpaMonitor { - [CmdletBinding(DefaultParameterSetName = 'ByName')] + [CmdletBinding(DefaultParameterSetName = 'ByName', SupportsShouldProcess)] param ( [Parameter(ParameterSetName = 'ByDatabaseId', Mandatory)] [int[]] $DatabaseId, @@ -67,10 +67,12 @@ function Start-DpaMonitor { process { foreach ($monitorObject in $Monitor) { - try { - $response = Invoke-DpaRequest -Endpoint "/databases/$($monitorObject.Dbid)/monitor-status" -Method 'PUT' -Request $request - } catch { - Stop-PSFFunction -Message "Could not start the monitor" -EnableException:$EnableException -ErrorRecord $_ -Target $monitorObject.Name + if ($PSCmdlet.ShouldProcess($monitor.Name, 'Start Monitor')) { + try { + $response = Invoke-DpaRequest -Endpoint "/databases/$($monitorObject.Dbid)/monitor-status" -Method 'PUT' -Request $request + } catch { + Stop-PSFFunction -Message "Could not start the monitor" -EnableException:$EnableException -ErrorRecord $_ -Target $monitorObject.Name + } } } } diff --git a/PSDPA/Public/Stop-DpaMonitor.ps1 b/PSDPA/Public/Stop-DpaMonitor.ps1 index c86ffe9..b22a5e0 100644 --- a/PSDPA/Public/Stop-DpaMonitor.ps1 +++ b/PSDPA/Public/Stop-DpaMonitor.ps1 @@ -37,7 +37,7 @@ License: MIT https://opensource.org/licenses/MIT #> function Stop-DpaMonitor { - [CmdletBinding(DefaultParameterSetName = 'ByName')] + [CmdletBinding(DefaultParameterSetName = 'ByName', SupportsShouldProcess)] param ( [Parameter(ParameterSetName = 'ByDatabaseId', Mandatory)] [int[]] $DatabaseId, diff --git a/Tests/PSDPA.Tests.ps1 b/Tests/PSDPA.Tests.ps1 index 2ec676f..13370d7 100644 --- a/Tests/PSDPA.Tests.ps1 +++ b/Tests/PSDPA.Tests.ps1 @@ -5,7 +5,6 @@ if ($ENV:BHProjectPath) { } else { $ModulePath = (Get-Item $Path).Parent.FullName + '\' + $ModuleName } -Write-Host "ModulePath: $ModulePath" function Split-ArrayInParts($array, [int]$parts) { #splits an array in "equal" parts From 6cb2a7ac0e328693e98ebdfc82af64d3f614d362 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 11:42:42 -0500 Subject: [PATCH 10/53] Remove Write-Host --- Build/deploy.psdeploy.ps1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Build/deploy.psdeploy.ps1 b/Build/deploy.psdeploy.ps1 index 4469664..51fcda4 100644 --- a/Build/deploy.psdeploy.ps1 +++ b/Build/deploy.psdeploy.ps1 @@ -38,10 +38,9 @@ if( else { "Skipping deployment: To deploy, ensure that...`n" + - "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + - "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + - "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" | - Write-Host + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + + "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" } # Publish to AppVeyor if we're in AppVeyor From 86d9b695da1756f30d3531c686daf9af5f32e2ae Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 11:57:09 -0500 Subject: [PATCH 11/53] Updated readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 77e41f7..e4dee62 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ PSDPA is an open source PowerShell module for the Solarwinds DPA REST API. The goal of the module is to provide complete PowerShell coverage for the API. -| Branch | Status | -|:--- |:--- | -| Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSDPA.svg?style=flat&label=PSGallery)](https://www.powershellgallery.com/packages/PSDPA) -| Development |[![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c303d5eae85a4840908206a4a1bcf92d)](https://www.codacy.com/app/awickham10/psdpa?utm_source=github.com&utm_medium=referral&utm_content=awickham10/psdpa&utm_campaign=Badge_Grade) | +Branch | Status +--- | --- +Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSDPA.svg?style=flat&label=PSGallery)](https://www.powershellgallery.com/packages/PSDPA) +Development | [![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c303d5eae85a4840908206a4a1bcf92d)](https://www.codacy.com/app/awickham10/psdpa?utm_source=github.com&utm_medium=referral&utm_content=awickham10/psdpa&utm_campaign=Badge_Grade) ## Instructions ``` powershell From 8ec3edfaa52797f594a3fba5a36fdc9486ac66f3 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 12:07:50 -0500 Subject: [PATCH 12/53] Changing Write-Host to Write-PSFMessage --- Build/deploy.psdeploy.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/deploy.psdeploy.ps1 b/Build/deploy.psdeploy.ps1 index 51fcda4..f3ee0f0 100644 --- a/Build/deploy.psdeploy.ps1 +++ b/Build/deploy.psdeploy.ps1 @@ -37,7 +37,7 @@ if( } else { - "Skipping deployment: To deploy, ensure that...`n" + + Write-PSFMessage -Level 'Output' -Message "Skipping deployment: To deploy, ensure that...`n" + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" From 3eec667bde62bf1c3690482704a44bfdfbaa2462 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 12:14:02 -0500 Subject: [PATCH 13/53] Fixing write message --- Build/deploy.psdeploy.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Build/deploy.psdeploy.ps1 b/Build/deploy.psdeploy.ps1 index f3ee0f0..4d84a1d 100644 --- a/Build/deploy.psdeploy.ps1 +++ b/Build/deploy.psdeploy.ps1 @@ -37,10 +37,10 @@ if( } else { - Write-PSFMessage -Level 'Output' -Message "Skipping deployment: To deploy, ensure that...`n" + + Write-PSFMessage -Level 'Output' -Message ("Skipping deployment: To deploy, ensure that...`n" + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + - "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" + "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)") } # Publish to AppVeyor if we're in AppVeyor From 513b60ee387473772108a8b2036f496a4a095bb4 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 12:38:57 -0500 Subject: [PATCH 14/53] Adding should process support to Remove-DpaAnnotation --- PSDPA/Public/Remove-DpaAnnotation.ps1 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/PSDPA/Public/Remove-DpaAnnotation.ps1 b/PSDPA/Public/Remove-DpaAnnotation.ps1 index 0b10169..809bd3b 100644 --- a/PSDPA/Public/Remove-DpaAnnotation.ps1 +++ b/PSDPA/Public/Remove-DpaAnnotation.ps1 @@ -27,7 +27,7 @@ License: MIT https://opensource.org/licenses/MIT #> function Remove-DpaAnnotation { - [CmdletBinding(DefaultParameterSetName = 'ById')] + [CmdletBinding(DefaultParameterSetName = 'ById', SupportsShouldProcess)] param ( [Parameter(ParameterSetName = 'ByObject', ValueFromPipeline)] [Annotation[]] $Annotation, @@ -37,11 +37,13 @@ function Remove-DpaAnnotation { ) foreach ($annotationObject in $Annotation) { - $endpoint = "databases/$($annotationObject.DatabaseId)/annotations/$($annotationObject.AnnotationId)" - try { - $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Delete' - } catch { - Stop-PSFFunction -Message "Could not remove annotation" -EnableException:$EnableException -ErrorRecord $_ + if ($PSCmdlet.ShouldProcess($annotationObject.Title, 'Remove Annotation')) { + $endpoint = "databases/$($annotationObject.DatabaseId)/annotations/$($annotationObject.AnnotationId)" + try { + $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Delete' + } catch { + Stop-PSFFunction -Message "Could not remove annotation" -EnableException:$EnableException -ErrorRecord $_ + } } } } \ No newline at end of file From 3b45ff4875b081b7e4d9c77cda1ac92f42b57319 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 12:40:47 -0500 Subject: [PATCH 15/53] Updating readme --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e4dee62..937230c 100644 --- a/README.md +++ b/README.md @@ -27,22 +27,22 @@ Get-DpaMonitor ## Functions ### Configuration -* Set-DpaConfig - Complete -* Get-DpaConfig - Complete +* Set-DpaConfig - Complete +* Get-DpaConfig - Complete ### Monitor -* Get-DpaMonitor - Complete -* Start-DpaMonitor - Complete -* Stop-DpaMonitor - Complete -* Set-DpaMonitorPassword - Not Implemented -* Add-DpaMonitor - Not Implemented +* Get-DpaMonitor - Complete +* Start-DpaMonitor - Complete +* Stop-DpaMonitor - Complete +* Set-DpaMonitorPassword - Not Implemented +* Add-DpaMonitor - Not Implemented ### Licensing -* Get-DpaLicense - Complete -* Get-DpaMonitorLicense - Complete -* Set-DpaLicense - Not Implemented +* Get-DpaLicense - Complete +* Get-DpaMonitorLicense - Complete +* Set-DpaLicense - Not Implemented ### Annotations -* Get-DpaAnnotation - Complete -* Add-DpaAnnotation - Test Coverage Needed -* Remove-DpaAnnotation - Complete +* Get-DpaAnnotation - Complete +* Add-DpaAnnotation - Test Coverage Needed +* Remove-DpaAnnotation - Complete From 4f24b0a9937bdd2606ccf8be20ad1688c4315882 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 13:25:17 -0500 Subject: [PATCH 16/53] Updated readme --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 937230c..d8b8672 100644 --- a/README.md +++ b/README.md @@ -27,22 +27,22 @@ Get-DpaMonitor ## Functions ### Configuration -* Set-DpaConfig - Complete -* Get-DpaConfig - Complete + * Set-DpaConfig - Complete + * Get-DpaConfig - Complete ### Monitor -* Get-DpaMonitor - Complete -* Start-DpaMonitor - Complete -* Stop-DpaMonitor - Complete -* Set-DpaMonitorPassword - Not Implemented -* Add-DpaMonitor - Not Implemented + * Get-DpaMonitor - Complete + * Start-DpaMonitor - Complete + * Stop-DpaMonitor - Complete + * Set-DpaMonitorPassword - Not Implemented + * Add-DpaMonitor - Not Implemented ### Licensing -* Get-DpaLicense - Complete -* Get-DpaMonitorLicense - Complete -* Set-DpaLicense - Not Implemented + * Get-DpaLicense - Complete + * Get-DpaMonitorLicense - Complete + * Set-DpaLicense - Not Implemented ### Annotations -* Get-DpaAnnotation - Complete -* Add-DpaAnnotation - Test Coverage Needed -* Remove-DpaAnnotation - Complete + * Get-DpaAnnotation - Complete + * Add-DpaAnnotation - Test Coverage Needed + * Remove-DpaAnnotation - Complete From 6f6488af1c1c1505cc6ab5a1775e94ec2b3beb93 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Fri, 15 Feb 2019 13:45:19 -0500 Subject: [PATCH 17/53] Updated readme --- README.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d8b8672..319fd4e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ # PSDPA Solarwinds DPA PowerShell Module (Unofficial) + PSDPA is an open source PowerShell module for the Solarwinds DPA REST API. The goal of the module is to provide complete PowerShell coverage for the API. -Branch | Status ---- | --- -Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSDPA.svg?style=flat&label=PSGallery)](https://www.powershellgallery.com/packages/PSDPA) -Development | [![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c303d5eae85a4840908206a4a1bcf92d)](https://www.codacy.com/app/awickham10/psdpa?utm_source=github.com&utm_medium=referral&utm_content=awickham10/psdpa&utm_campaign=Badge_Grade) +| Branch | Status | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Master | [![Master Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/master?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/master) [![Master Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/master/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![PSGallery Version](https://img.shields.io/powershellgallery/v/PSDPA.svg?style=flat&label=PSGallery)](https://www.powershellgallery.com/packages/PSDPA) | +| Development | [![Development Build Status](https://ci.appveyor.com/api/projects/status/i165eqibj5cvger3/branch/development?svg=true)](https://ci.appveyor.com/project/awickham10/psdpa/branch/development) [![Development Code Coverage](https://codecov.io/gh/awickham10/psdpa/branch/development/graph/badge.svg)](https://codecov.io/gh/awickham10/psdpa) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c303d5eae85a4840908206a4a1bcf92d)](https://www.codacy.com/app/awickham10/psdpa?utm_source=github.com&utm_medium=referral&utm_content=awickham10/psdpa&utm_campaign=Badge_Grade) | ## Instructions -``` powershell + +```powershell # Install the PSDPA module from the gallery Install-Module PSDPA @@ -26,23 +28,28 @@ Get-DpaMonitor ``` ## Functions + ### Configuration - * Set-DpaConfig - Complete - * Get-DpaConfig - Complete + +- Set-DpaConfig - Complete +- Get-DpaConfig - Complete ### Monitor - * Get-DpaMonitor - Complete - * Start-DpaMonitor - Complete - * Stop-DpaMonitor - Complete - * Set-DpaMonitorPassword - Not Implemented - * Add-DpaMonitor - Not Implemented + +- Get-DpaMonitor - Complete +- Start-DpaMonitor - Complete +- Stop-DpaMonitor - Complete +- Set-DpaMonitorPassword - Not Implemented +- Add-DpaMonitor - Not Implemented ### Licensing - * Get-DpaLicense - Complete - * Get-DpaMonitorLicense - Complete - * Set-DpaLicense - Not Implemented + +- Get-DpaLicense - Complete +- Get-DpaMonitorLicense - Complete +- Set-DpaLicense - Not Implemented ### Annotations - * Get-DpaAnnotation - Complete - * Add-DpaAnnotation - Test Coverage Needed - * Remove-DpaAnnotation - Complete + +- Get-DpaAnnotation - Complete +- Add-DpaAnnotation - Test Coverage Needed +- Remove-DpaAnnotation - Complete From 93fda6eaf7fa53834a25fb7d41f5911f22b3f0b7 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 13:24:00 -0400 Subject: [PATCH 18/53] Added help for Set-DpaConfig --- PSDPA/Public/Set-DpaConfig.ps1 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/PSDPA/Public/Set-DpaConfig.ps1 b/PSDPA/Public/Set-DpaConfig.ps1 index 7612141..aee4496 100644 --- a/PSDPA/Public/Set-DpaConfig.ps1 +++ b/PSDPA/Public/Set-DpaConfig.ps1 @@ -1,3 +1,26 @@ +<# + +.SYNOPSIS +Sets configuration options for PSDPA. + +.PARAMETER BaseUri +The base URI for the DPA API. + +.PARAMETER RefreshToken +The refresh token for the DPA API. + +.EXAMPLE +Set-DpaConfig -BaseUri 'http://yourserver:8123/iwc/api' -RefreshToken 'yourrefreshtoken' + +Sets the Base URI and Refresh Token for the DPA API. + +.NOTES +Author: Andrew Wickham ( @awickham ) + +Copyright: (C) Andrew Wickham, andrew@awickham.com +License: MIT https://opensource.org/licenses/MIT + +#> function Set-DpaConfig { [CmdletBinding(SupportsShouldProcess)] param ( From 26eec307e4e51a6127e59ffe363594e5ae99f5bb Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 14:20:43 -0400 Subject: [PATCH 19/53] Include request body in verbose messages --- PSDPA/Private/Invoke-DpaRequest.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/PSDPA/Private/Invoke-DpaRequest.ps1 b/PSDPA/Private/Invoke-DpaRequest.ps1 index ccc3e6b..d082738 100644 --- a/PSDPA/Private/Invoke-DpaRequest.ps1 +++ b/PSDPA/Private/Invoke-DpaRequest.ps1 @@ -54,6 +54,7 @@ function Invoke-DpaRequest { } if ($PSBoundParameters.ContainsKey('Request')) { $params['Body'] = $Request | ConvertTo-Json + Write-Verbose $params['Body'] } Invoke-RestMethod @params From f0a7a0cccdac600a6215352bbc2af09e550104c0 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 14:21:09 -0400 Subject: [PATCH 20/53] Add AzureSQLDatabaseMonitor class --- PSDPA/Classes/Monitor.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PSDPA/Classes/Monitor.ps1 b/PSDPA/Classes/Monitor.ps1 index a7d5ca6..a661bfc 100644 --- a/PSDPA/Classes/Monitor.ps1 +++ b/PSDPA/Classes/Monitor.ps1 @@ -70,6 +70,10 @@ class SqlServerMonitor : Monitor { } } +class AzureSQLDatabaseMonitor : Monitor { + AzureSQLDatabaseMonitor ([PSCustomObject] $Json) : base ($Json) {} +} + class MonitorFactory { static [Monitor[]] $Monitors From 329acba46052a37ee22c203c721befad7437fe71 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 14:21:35 -0400 Subject: [PATCH 21/53] Add Database parameter for Azure SQL DB support --- PSDPA/Public/New-DpaMonitor.ps1 | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/PSDPA/Public/New-DpaMonitor.ps1 b/PSDPA/Public/New-DpaMonitor.ps1 index 441568b..e082eb3 100644 --- a/PSDPA/Public/New-DpaMonitor.ps1 +++ b/PSDPA/Public/New-DpaMonitor.ps1 @@ -1,4 +1,4 @@ -function Add-DpaMonitor { +function New-DpaMonitor { [CmdletBinding()] param ( [Parameter(Mandatory)] @@ -11,6 +11,9 @@ function Add-DpaMonitor { [ValidateSet('AzureSQLDB', 'Db2', 'MySQL', 'Oracle', 'SQLServer', 'Sybase')] $DatabaseType, + [Parameter()] + $Database, + [Parameter()] $DisplayName, @@ -29,6 +32,9 @@ function Add-DpaMonitor { [Parameter(Mandatory)] [PSCredential] $Credential, + [Parameter()] + [switch] $CreateMonitoringUser, + [Parameter()] [PSCredential] $MonitoringCredential, @@ -93,6 +99,16 @@ function Add-DpaMonitor { $request['sysAdminUser'] = $Credential.UserName $request['sysAdminPassword'] = $Credential.GetNetworkCredential().Password + if ($CreateMonitoringUser) { + $request['monitoringUserIsNew'] = $true + } else { + $request['monitoringUserIsNew'] = $false + } + + if ($PSBoundParameters.ContainsKey('Database')) { + $request['database'] = $Database + } + if ($DatabaseType -ne 'Db2') { if ($PSBoundParameters.ContainsKey('MonitoringCredential') -and $DatabaseType -ne 'Db2') { $request['monitoringUser'] = $MonitoringCredential.UserName @@ -106,7 +122,12 @@ function Add-DpaMonitor { try { $response = Invoke-DpaRequest -Endpoint '/databases/register-monitor' -Request $request -Method 'POST' } catch { - Stop-PSFFunction -Message "Could not register monitor" -ErrorRecord $_ + $responseStream = $_.Exception.Response.GetResponseStream() + $streamReader = New-Object System.IO.StreamReader $responseStream + + $response = $streamReader.ReadToEnd() | ConvertFrom-Json + + Stop-PSFFunction -Message $response.messages[0].reason -ErrorRecord $_ return } From 8ee19b9e735beac0d257ccbe2fde55a9be76affb Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 14:28:02 -0400 Subject: [PATCH 22/53] Force Invoke-DpaRequest to get a new access token if it's no longer valid --- PSDPA/Private/Invoke-DpaRequest.ps1 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/PSDPA/Private/Invoke-DpaRequest.ps1 b/PSDPA/Private/Invoke-DpaRequest.ps1 index d082738..8ceed11 100644 --- a/PSDPA/Private/Invoke-DpaRequest.ps1 +++ b/PSDPA/Private/Invoke-DpaRequest.ps1 @@ -17,15 +17,10 @@ function Invoke-DpaRequest { $Parameters ) - if (-not $PSBoundParameters.ContainsKey('AccessToken')) { + if (-not $PSBoundParameters.ContainsKey('AccessToken') -or -not $AccessToken.IsValid()) { $AccessToken = Get-DpaAccessToken } - if (-not $AccessToken.IsValid()) { - Stop-PSFFunction -Message "You do not have a valid access token" - return - } - $headers = @{ 'Accept' = 'application/json' 'Content-Type' = 'application/json;charset=UTF-8' From 3390d981a55e1c658d7bb1a2fccb47452cda41b3 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:22:38 -0400 Subject: [PATCH 23/53] Added Add-DpaAnnotation integration tests --- PSDPA/Public/Add-DpaAnnotation.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/PSDPA/Public/Add-DpaAnnotation.ps1 b/PSDPA/Public/Add-DpaAnnotation.ps1 index 4cc6824..7c4df17 100644 --- a/PSDPA/Public/Add-DpaAnnotation.ps1 +++ b/PSDPA/Public/Add-DpaAnnotation.ps1 @@ -99,6 +99,7 @@ function Add-DpaAnnotation { process { foreach ($monitorObject in $Monitor) { + Write-PSFMessage -Level Verbose -Message "Adding annotation to Database ID $($monitorObject.DatabaseId)" $endpoint = "/databases/$($monitorObject.DatabaseId)/annotations" $request = @{ @@ -109,7 +110,12 @@ function Add-DpaAnnotation { } $response = Invoke-DpaRequest -Endpoint $endpoint -Method 'Post' -Request $request - New-Object -TypeName 'Annotation' -ArgumentList $response.data + + try { + New-Object -TypeName 'Annotation' -ArgumentList $monitorObject, $response.data + } catch { + Stop-PSFFunction -Level Critical -Message 'Could not create annotation from API response' -ErrorRecord $_ -EnableException:$EnableException + } } } } \ No newline at end of file From 99effb015bb9839264df4dedf55960d224dee4bc Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:22:50 -0400 Subject: [PATCH 24/53] Added Add-DpaAnnotation tests --- Tests/Add-DpaAnnotation.Tests.ps1 | 75 +++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/Tests/Add-DpaAnnotation.Tests.ps1 b/Tests/Add-DpaAnnotation.Tests.ps1 index 02416b8..d75f343 100644 --- a/Tests/Add-DpaAnnotation.Tests.ps1 +++ b/Tests/Add-DpaAnnotation.Tests.ps1 @@ -15,17 +15,84 @@ Describe "$CommandName Unit Tests" -Tag 'Unit' { param ( $Name , $Mandatory = $true ) $command | Should -HaveParameter $Name -Mandatory:$Mandatory } + } +} - It 'should default Time to the current time' { +Describe "$CommandName Integration Tests" -Tag 'Integration' { + Context 'Azure SQL DB' { + BeforeAll { + # set the start time and remove ticks since DPA doesn't support them + $contextStartTime = Get-Date + $contextStartTime = $contextStartTime.AddTicks(-($contextStartTime.Ticks % [TimeSpan]::TicksPerSecond)); + + # get our test monitor + $monitor = Get-DpaMonitor -MonitorName 'PSDPATESTDB01@PSDPATEST01' + + # default annotation parameters to use for tests + $annotationParams = @{ + Monitor = $monitor + Title = 'Testing API' + Description = 'This is a test of Add-DpaAnnotation' + CreatedBy = 'Test User' + Time = $contextStartTime + } + } + + BeforeEach { + $script:annotation = $null + } + + It 'should add an annotation' { + { $script:annotation = Add-DpaAnnotation @annotationParams -EnableException } | Should -Not -Throw + + foreach ($annotationParam in $annotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $annotationParams[$annotationParam] + } + + $annotation.Type | Should -Be 'API' + } + It 'should add an annotation when piping a monitor' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Monitor') + + { $script:annotation = $monitor | Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } + + $annotation.DatabaseId | Should -BeExactly $monitor.DatabaseId + $annotation.Type | Should -Be 'API' } It 'should default CreatedBy to the current user' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('CreatedBy') + + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } + + $annotation.CreatedBy | Should -Be $env:USERNAME } - } -} -Describe "$CommandName Integration Tests" -Tag 'Integration' { + It 'should default Time to the current time' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Time') + + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } + + # give ourselves a 10 minute swing on time just in case server times vary + $currentTime = Get-Date + $annotation.Time | Should -BeGreaterThan $currentTime.AddMinutes(-5) + $annotation.Time | Should -BeLessThan $currentTime.AddMinutes(5) + } + } } \ No newline at end of file From a91dd8e152bb0c07f0d1203c8ab2514f6365864d Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:23:11 -0400 Subject: [PATCH 25/53] Database should only be used when using AzureSQLDB or Db2 --- PSDPA/Public/New-DpaMonitor.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSDPA/Public/New-DpaMonitor.ps1 b/PSDPA/Public/New-DpaMonitor.ps1 index e082eb3..95ea008 100644 --- a/PSDPA/Public/New-DpaMonitor.ps1 +++ b/PSDPA/Public/New-DpaMonitor.ps1 @@ -105,7 +105,7 @@ function New-DpaMonitor { $request['monitoringUserIsNew'] = $false } - if ($PSBoundParameters.ContainsKey('Database')) { + if ($PSBoundParameters.ContainsKey('Database') -and $DatabaseType -in @('AzureSQLDB', 'Db2')) { $request['database'] = $Database } From abcd056e3b60c31faea17d6fac94461b6ace19bc Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:23:22 -0400 Subject: [PATCH 26/53] Adding some verbosity --- PSDPA/Private/Get-DpaAccessToken.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PSDPA/Private/Get-DpaAccessToken.ps1 b/PSDPA/Private/Get-DpaAccessToken.ps1 index 5e75e86..24f9190 100644 --- a/PSDPA/Private/Get-DpaAccessToken.ps1 +++ b/PSDPA/Private/Get-DpaAccessToken.ps1 @@ -12,11 +12,14 @@ function Get-DpaAccessToken { } try { + Write-PSFMessage -Level 'Verbose' -Message 'Getting an access token' + $response = Invoke-RestMethod -Uri $authTokenUri -Method 'POST' -Body $request $accessToken = New-Object -TypeName 'AccessToken' -ArgumentList $response Set-PSFConfig -Module 'psdpa' -Name 'accesstoken' -Value $accessToken $PSDefaultParameterValues['Invoke-DpaRequest:AccessToken'] = $accessToken + return $accessToken } catch { Stop-PSFFunction -Message "Could not obtain access token" -ErrorRecord $_ -EnableException $EnableException From 64c77262293c317eab891a86e50fed266fbb9323 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:30:02 -0400 Subject: [PATCH 27/53] Modifying some test scaffolding to support local configurations --- Tests/Constants.ps1 | 6 ++++-- Tests/Shared.ps1 | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Tests/Constants.ps1 b/Tests/Constants.ps1 index 98ba528..7605805 100644 --- a/Tests/Constants.ps1 +++ b/Tests/Constants.ps1 @@ -1,6 +1,8 @@ -$localConstants = Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -ChildPath 'Constants.Local.ps1' +Write-PSFMessage -Level Verbose -Message 'Loading constants from Constants.ps1' + +$localConstants = Join-Path -Path (Split-Path -Path $ConstantsFile -Parent) -ChildPath 'Constants.Local.ps1' if (Test-Path -Path $localConstants) { - .\$localConstants + . $localConstants return } diff --git a/Tests/Shared.ps1 b/Tests/Shared.ps1 index db1c19d..cf3c0a9 100644 --- a/Tests/Shared.ps1 +++ b/Tests/Shared.ps1 @@ -6,7 +6,8 @@ if(-not $ENV:BHProjectPath) $PSVersion = $PSVersionTable.PSVersion.Major $ModuleName = $ENV:BHProjectName -. (Join-Path -Path $PSScriptRoot -ChildPath 'Constants.ps1') +$ConstantsFile = Join-Path -Path $PSScriptRoot -ChildPath 'Constants.ps1' +. $ConstantsFile Remove-Module $ENV:BHProjectName -ErrorAction SilentlyContinue Import-Module (Join-Path $ENV:BHProjectPath $ModuleName) -Force \ No newline at end of file From 82a4ac3a218ac7c459d558f23588198365de4cb7 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:30:23 -0400 Subject: [PATCH 28/53] Ignore Constants.Local.ps1 from git --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..100c540 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Tests/Constants.Local.ps1 From 77900e73bf0b95ee28101dc761bb37fc34a97da2 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:36:48 -0400 Subject: [PATCH 29/53] Stubbing in to allow PSDPA to actually run --- Tests/Constants.ps1 | 12 ++++++++++-- appveyor.yml | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Tests/Constants.ps1 b/Tests/Constants.ps1 index 7605805..b5facf3 100644 --- a/Tests/Constants.ps1 +++ b/Tests/Constants.ps1 @@ -6,5 +6,13 @@ if (Test-Path -Path $localConstants) { return } -Set-PSFConfig -Module 'PSDPA' -Name 'baseuri' -Value 'https://myfakedpaserver:8124/iwc/api' -Set-PSFConfig -Module 'PSDPA' -Name 'refreshtoken' -Value 'thisismyrefreshtoken' \ No newline at end of file +if (-not $ENV:PSDPA_URI) { + Stop-PSFFunction -Message "Environment variable PSDPA_URI is not set" -EnableException +} + +if (-not $ENV:PSDPA_TOKEN) { + Stop-PSFFunction -Message "Environment variable PSDPA_TOKEN is not set" -EnableException +} + +Set-PSFConfig -Module 'PSDPA' -Name 'baseuri' -Value $ENV:PSDPA_URI +Set-PSFConfig -Module 'PSDPA' -Name 'refreshtoken' -Value $ENV:PSDPA_TOKEN \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index b8ea902..2f11683 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,6 +6,10 @@ environment: secure: 76Y+lNAkDCWwiO9jWmihZBlOKPD2rtU3b+dd5Fpkz34WtXFqTKDQFp30IA60Cj3e CODECOV_TOKEN: secure: xn88TAvqQYjOWy5VnVNLLDNIeYi75NcrDMZdcEoAFPpW91KcdPSwk4NnvUxLI9hG + PSDPA_BASEURI: + secure: /Ah4/9vQOkXmMZdB8SrlHqueDF5uMC/ME3pc8jgl7qqiR1rpG+W3mjyeR+FbxOPh + PSDPA_TOKEN: + secure: kTA548nZiwq71GIiCau5wvSPTVNn9dVfaHC//NuCKo2fljzkpL+niUwjfOVvVIbDPf8zOxznxspn1GrEkm27Dg8XGHyd9XfD8leyiKTp0gavhNLVkrVzG1/Zqj6eyFO7IKVGYB4hs7nJJasuAFxVtBjcR9UZdFEbw8d/Z06YqQo= os: WMF 5 From 8e36f4537d0fe60cd9b86a79b903e5e80ded6137 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:39:00 -0400 Subject: [PATCH 30/53] =?UTF-8?q?EnableException=20is=20a=20bool,=20not=20?= =?UTF-8?q?a=20switch=20=F0=9F=A4=A6=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tests/Constants.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Constants.ps1 b/Tests/Constants.ps1 index b5facf3..257b672 100644 --- a/Tests/Constants.ps1 +++ b/Tests/Constants.ps1 @@ -7,11 +7,11 @@ if (Test-Path -Path $localConstants) { } if (-not $ENV:PSDPA_URI) { - Stop-PSFFunction -Message "Environment variable PSDPA_URI is not set" -EnableException + Stop-PSFFunction -Message "Environment variable PSDPA_URI is not set" -EnableException $true } if (-not $ENV:PSDPA_TOKEN) { - Stop-PSFFunction -Message "Environment variable PSDPA_TOKEN is not set" -EnableException + Stop-PSFFunction -Message "Environment variable PSDPA_TOKEN is not set" -EnableException $true } Set-PSFConfig -Module 'PSDPA' -Name 'baseuri' -Value $ENV:PSDPA_URI From 441bdfc6b68cb6fc5c3b3f2d0a2daa285aadcceb Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 15:40:57 -0400 Subject: [PATCH 31/53] =?UTF-8?q?PSDPA=5FBASEURI,=20not=20PSDPA=5FURI...?= =?UTF-8?q?=20=F0=9F=A4=A6=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tests/Constants.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Constants.ps1 b/Tests/Constants.ps1 index 257b672..beaf345 100644 --- a/Tests/Constants.ps1 +++ b/Tests/Constants.ps1 @@ -6,13 +6,13 @@ if (Test-Path -Path $localConstants) { return } -if (-not $ENV:PSDPA_URI) { - Stop-PSFFunction -Message "Environment variable PSDPA_URI is not set" -EnableException $true +if (-not $ENV:PSDPA_BASEURI) { + Stop-PSFFunction -Message "Environment variable PSDPA_BASEURI is not set" -EnableException $true } if (-not $ENV:PSDPA_TOKEN) { Stop-PSFFunction -Message "Environment variable PSDPA_TOKEN is not set" -EnableException $true } -Set-PSFConfig -Module 'PSDPA' -Name 'baseuri' -Value $ENV:PSDPA_URI +Set-PSFConfig -Module 'PSDPA' -Name 'baseuri' -Value $ENV:PSDPA_BASEURI Set-PSFConfig -Module 'PSDPA' -Name 'refreshtoken' -Value $ENV:PSDPA_TOKEN \ No newline at end of file From 980b4c48ad005899685eb92f0fa4874361c4be6d Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 17:02:41 -0400 Subject: [PATCH 32/53] Add in debug config --- appveyor.debug.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 appveyor.debug.yml diff --git a/appveyor.debug.yml b/appveyor.debug.yml new file mode 100644 index 0000000..6396464 --- /dev/null +++ b/appveyor.debug.yml @@ -0,0 +1,33 @@ +image: Visual Studio 2017 + +#Publish to PowerShell Gallery with this key +environment: + NugetApiKey: + secure: 76Y+lNAkDCWwiO9jWmihZBlOKPD2rtU3b+dd5Fpkz34WtXFqTKDQFp30IA60Cj3e + CODECOV_TOKEN: + secure: xn88TAvqQYjOWy5VnVNLLDNIeYi75NcrDMZdcEoAFPpW91KcdPSwk4NnvUxLI9hG + PSDPA_BASEURI: + secure: /Ah4/9vQOkXmMZdB8SrlHqueDF5uMC/ME3pc8jgl7qqiR1rpG+W3mjyeR+FbxOPh + PSDPA_TOKEN: + secure: kTA548nZiwq71GIiCau5wvSPTVNn9dVfaHC//NuCKo2fljzkpL+niUwjfOVvVIbDPf8zOxznxspn1GrEkm27Dg8XGHyd9XfD8leyiKTp0gavhNLVkrVzG1/Zqj6eyFO7IKVGYB4hs7nJJasuAFxVtBjcR9UZdFEbw8d/Z06YqQo= + +cache: + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSScriptAnalyzer -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\Pester -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSCodeCovIo -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSFramework -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\BuildHelpers -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSDeploy -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\psake -> Build\build.requirements.psd1 + +# Skip on updates to the readme. +# We can force this by adding [skip ci] or [ci skip] anywhere in commit message +skip_commits: + message: /updated readme.*|update readme.*s/ + +build: false + +#Kick off the CI/CD pipeline +test_script: + - ps: $VerbosePreference = 'Continue' + - ps: . .\build\Start-Build.ps1 -Task Deploy \ No newline at end of file From 686f4dd8235c5a348d021463220ca16bc86a344b Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 17:11:52 -0400 Subject: [PATCH 33/53] Add help and remove some initially unnecessary parameters --- PSDPA/Public/New-DpaMonitor.ps1 | 78 +++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/PSDPA/Public/New-DpaMonitor.ps1 b/PSDPA/Public/New-DpaMonitor.ps1 index 95ea008..193bd98 100644 --- a/PSDPA/Public/New-DpaMonitor.ps1 +++ b/PSDPA/Public/New-DpaMonitor.ps1 @@ -1,10 +1,64 @@ +<# + +.SYNOPSIS +Adds a monitor to DPA. + +.DESCRIPTION +Adds a database server to DPA to be monitored. + +.PARAMETER ServerName +Server (Name or IP). + +.PARAMETER Port +Port number. + +.PARAMETER DatabaseType +Type of database server. + +.PARAMETER Database +Name of the database to connect to (Azure SQL DB or Db2 only). + +.PARAMETER DisplayName +Name to display in DPA. + +.PARAMETER AmazonRDS +Indicates whether or not the server is an Amazon RDS server. + +.PARAMETER Credential +Credential to use to connect to the server to setup DPA objects. + +.PARAMETER CreateMonitoringUser +Indicates whether or not to create the monitoring user, or if it has already been created. + +.PARAMETER MonitoringCredential +Credential DPA will use to monitor the server with. + +.PARAMETER EnableException +Replaces user friendly yellow warnings with bloody red exceptions of doom! Use +this if you want the function to throw terminating errors you want to catch. + +.EXAMPLE +$sysadminCredential = Get-Credential +$monitoringCredential = Get-Credential + +New-DpaMonitor -ServerName 'mytestserver.database.windows.net' -Port 1433 -DatabaseType 'AzureSQLDB' -DisplayName 'mytestserver' -Database 'mytestdatabase' -Credential $sysadminCredential -MonitoringCredential $monitoringCredential -CreateMonitoringUser + +Registers an Azure SQL DB for monitoring and creates the monitoring credential. + +.NOTES +Author: Andrew Wickham ( @awickham ) + +Copyright: (C) Andrew Wickham, andrew@awickham.com +License: MIT https://opensource.org/licenses/MIT + +#> function New-DpaMonitor { [CmdletBinding()] param ( [Parameter(Mandatory)] $ServerName, - [Parameter()] + [Parameter(Mandatory)] $Port, [Parameter(Mandatory)] @@ -20,15 +74,6 @@ function New-DpaMonitor { [Parameter()] [switch] $AmazonRDS, - [Parameter()] - [string] $RepositoryTableSpace, - - [Parameter()] - [string] $JdbcUrlProperties, - - [Parameter()] - [string] $ConnectionProperties, - [Parameter(Mandatory)] [PSCredential] $Credential, @@ -38,6 +83,7 @@ function New-DpaMonitor { [Parameter()] [PSCredential] $MonitoringCredential, + [Parameter()] [switch] $EnableException ) @@ -76,18 +122,6 @@ function New-DpaMonitor { $request['amazonRds'] = $AmazonRDS } - if ($PSBoundParameters.ContainsKey('RepositoryTableSpace')) { - $request['repositoryTableSpace'] = $RepositoryTableSpace - } - - if ($PSBoundParameters.ContainsKey('JdbcUrlProperties')) { - $request['jdbcUrlProperties'] = $JdbcUrlProperties - } - - if ($PSBoundParameters.ContainsKey('ConnectionProperties')) { - $request['connectionProperties'] = $ConnectionProperties - } - if ($DatabaseType -eq 'SQLServer') { $isDomainUser = $Credential.GetNetworkCredential().Domain -ne '' if ($isDomainUser) { From c222ce0e7341924772ef054b1f86011c670f62ec Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 18:58:46 -0400 Subject: [PATCH 34/53] Updated README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 319fd4e..2dae7b7 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Get-DpaMonitor - Start-DpaMonitor - Complete - Stop-DpaMonitor - Complete - Set-DpaMonitorPassword - Not Implemented -- Add-DpaMonitor - Not Implemented +- New-DpaMonitor - Test Coverage Needed ### Licensing @@ -51,5 +51,5 @@ Get-DpaMonitor ### Annotations - Get-DpaAnnotation - Complete -- Add-DpaAnnotation - Test Coverage Needed +- Add-DpaAnnotation - Complete - Remove-DpaAnnotation - Complete From 7e15171b31d622af6d141d780e839c5dd61da7bd Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 19:50:27 -0400 Subject: [PATCH 35/53] Adding automation to start/stop DPA test VM --- Build/build.requirements.psd1 | 1 + Build/psake.ps1 | 35 ++++++++++++++++++++++++++++++++++ Tools/Get-AppVeyorBuildIPs.ps1 | 18 +++++++++++++++++ appveyor.yml | 16 ++++++---------- 4 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 Tools/Get-AppVeyorBuildIPs.ps1 diff --git a/Build/build.requirements.psd1 b/Build/build.requirements.psd1 index b9c1117..8c7fe10 100644 --- a/Build/build.requirements.psd1 +++ b/Build/build.requirements.psd1 @@ -15,4 +15,5 @@ 'Pester' = '4.6.0' 'PSFramework' = '0.10.31.176' 'PSCodeCovIo' = '1.0.1' + 'Az' = '1.0.0' } \ No newline at end of file diff --git a/Build/psake.ps1 b/Build/psake.ps1 index ff8f22f..d188a58 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -31,6 +31,32 @@ Task Init { } Task Test -Depends Init { + $lines + "`n`tSTATUS: Starting DPA VM" + + if (-not $ENV:PSDPA_AZ) { + Stop-PSFFunction -Message "Environment variable PSDPA_AZ is not set" -EnableException $true + } + + try { + $azCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList $ENV:PSDPA_AZ_APP, $ENV:PSDPA_AZ + $azAccount = Connect-AzAccount -Tenant $ENV:PSDPA_AZ_TENANT -Credential $azCredential -ServicePrincipal + + $dpaVm = Get-AzVM -ResourceGroupName 'PSDPA' -Name 'dpa' -Status + $dpaVmStatus = $dpaVm.Statuses | Where-Object { $_.Code -like 'PowerState/*' } + + if ($dpaVmStatus.DisplayStatus -ne 'VM running') { + "Starting DPA VM" + $dpaVm | Start-AzVM + } else { + "DPA VM is already running" + } + } catch { + Stop-PSFFunction -Message "Could not start Azure DPA VM" -ErrorRecord $_ -EnableException $true + } + $lines + "`n" + $lines "`n`tSTATUS: Testing with PowerShell $PSVersion" @@ -66,6 +92,15 @@ Task Test -Depends Init { Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" } "`n" + + $lines + "`n`tSTATUS: Stopping DPA VM" + + try { + $dpaVm | Stop-AzVM + } catch { + Stop-PSFFunction -Message "Could not stop Azure DPA VM" -ErrorRecord $_ -EnableException $true + } } Task Build -Depends Test { diff --git a/Tools/Get-AppVeyorBuildIPs.ps1 b/Tools/Get-AppVeyorBuildIPs.ps1 new file mode 100644 index 0000000..872f386 --- /dev/null +++ b/Tools/Get-AppVeyorBuildIPs.ps1 @@ -0,0 +1,18 @@ +# modified from https://community.spiceworks.com/scripts/show/2327-what-is-my-ip-get-whatismyip +param ( + [Parameter()] + [switch] $EnableException +) + +try { + $webRequest = Invoke-WebRequest -Uri 'https://www.appveyor.com/docs/build-environment/#ip-addresses' -ErrorAction Stop -UseBasicParsing + + $matches = $webRequest.Content | Select-String -Pattern "\b(?:\d{1,3}\.){3}\d{1,3}\b" -AllMatches + if ($matches) { + $matches.Matches.Value + } else { + Stop-PSFFunction -Message 'Unable to locate any IPs' -EnableException:$EnableException + } +} catch { + Stop-PSFFunction -Message 'Unable to process AppVeyor docs' -ErrorRecord $_ -EnableException:$EnableException +} \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 2f11683..0853103 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# See http://www.appveyor.com/docs/appveyor-yml for many more options +image: Visual Studio 2017 #Publish to PowerShell Gallery with this key environment: @@ -10,17 +10,13 @@ environment: secure: /Ah4/9vQOkXmMZdB8SrlHqueDF5uMC/ME3pc8jgl7qqiR1rpG+W3mjyeR+FbxOPh PSDPA_TOKEN: secure: kTA548nZiwq71GIiCau5wvSPTVNn9dVfaHC//NuCKo2fljzkpL+niUwjfOVvVIbDPf8zOxznxspn1GrEkm27Dg8XGHyd9XfD8leyiKTp0gavhNLVkrVzG1/Zqj6eyFO7IKVGYB4hs7nJJasuAFxVtBjcR9UZdFEbw8d/Z06YqQo= - -os: WMF 5 + PSDPA_AZ: + secure: 3vZUMa+iGf9aqcTolqBjG+tkPnbe3HIzVMBVJkW4dVTqi8t36MmPeXuMcKefJsXe + PSDPA_AZ_TENANT: 1e220ef3-d984-4f20-9bc7-a54afa8ec2af + PSDPA_AZ_APP: 66fb92de-ce0b-48cd-8839-d70991013dd8 cache: - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSScriptAnalyzer -> Build\build.requirements.psd1 - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\Pester -> Build\build.requirements.psd1 - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSCodeCovIo -> Build\build.requirements.psd1 - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSFramework -> Build\build.requirements.psd1 - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\BuildHelpers -> Build\build.requirements.psd1 - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\PSDeploy -> Build\build.requirements.psd1 - - C:\Users\appveyor\Documents\WindowsPowerShell\Modules\psake -> Build\build.requirements.psd1 + - C:\Users\appveyor\Documents\WindowsPowerShell\Modules -> Build\build.requirements.psd1 # Skip on updates to the readme. # We can force this by adding [skip ci] or [ci skip] anywhere in commit message From ab1a176c3bef014c4762c2a8a9d44ccd2bc11973 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 19:53:35 -0400 Subject: [PATCH 36/53] Troubleshooting --- Build/psake.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index d188a58..58d24a8 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -38,8 +38,12 @@ Task Test -Depends Init { Stop-PSFFunction -Message "Environment variable PSDPA_AZ is not set" -EnableException $true } + if (-not $ENV:PSDPA_AZ_APP) { + Stop-PSFFunction -Message "Environment variable PSDPA_AZ_APP is not set" -EnableException $true + } + try { - $azCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList $ENV:PSDPA_AZ_APP, $ENV:PSDPA_AZ + $azCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList @($ENV:PSDPA_AZ_APP, $ENV:PSDPA_AZ) $azAccount = Connect-AzAccount -Tenant $ENV:PSDPA_AZ_TENANT -Credential $azCredential -ServicePrincipal $dpaVm = Get-AzVM -ResourceGroupName 'PSDPA' -Name 'dpa' -Status From c431ca871200b17fc9b7357f2d4b5e06c49794eb Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 19:57:01 -0400 Subject: [PATCH 37/53] =?UTF-8?q?=F0=9F=A4=B7=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Build/psake.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 58d24a8..ec00d1c 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -43,8 +43,9 @@ Task Test -Depends Init { } try { - $azCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList @($ENV:PSDPA_AZ_APP, $ENV:PSDPA_AZ) - $azAccount = Connect-AzAccount -Tenant $ENV:PSDPA_AZ_TENANT -Credential $azCredential -ServicePrincipal + $azPassword = ConvertTo-SecureString -String $ENV:PSDPA_AZ -AsPlainText -Force + $azCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList @($ENV:PSDPA_AZ_APP, $azPassword) + $null = Connect-AzAccount -Tenant $ENV:PSDPA_AZ_TENANT -Credential $azCredential -ServicePrincipal $dpaVm = Get-AzVM -ResourceGroupName 'PSDPA' -Name 'dpa' -Status $dpaVmStatus = $dpaVm.Statuses | Where-Object { $_.Code -like 'PowerState/*' } From 758087151abf4b75aae2ff77c682bb0cd557e7cd Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:00:06 -0400 Subject: [PATCH 38/53] No confirm and force for stopping VM --- Build/psake.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index ec00d1c..1dd83fc 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -102,7 +102,7 @@ Task Test -Depends Init { "`n`tSTATUS: Stopping DPA VM" try { - $dpaVm | Stop-AzVM + $dpaVm | Stop-AzVM -Confirm:$false -Force } catch { Stop-PSFFunction -Message "Could not stop Azure DPA VM" -ErrorRecord $_ -EnableException $true } From a7f0132e810f9d21b01de7eafd21faed1fa14114 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:04:37 -0400 Subject: [PATCH 39/53] No colon needed --- PSDPA/Public/Add-DpaAnnotation.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSDPA/Public/Add-DpaAnnotation.ps1 b/PSDPA/Public/Add-DpaAnnotation.ps1 index 7c4df17..53705a2 100644 --- a/PSDPA/Public/Add-DpaAnnotation.ps1 +++ b/PSDPA/Public/Add-DpaAnnotation.ps1 @@ -114,7 +114,7 @@ function Add-DpaAnnotation { try { New-Object -TypeName 'Annotation' -ArgumentList $monitorObject, $response.data } catch { - Stop-PSFFunction -Level Critical -Message 'Could not create annotation from API response' -ErrorRecord $_ -EnableException:$EnableException + Stop-PSFFunction -Level Critical -Message 'Could not create annotation from API response' -ErrorRecord $_ -EnableException $EnableException } } } From e842f26e8b482a026f1d2182524da4c99d152b22 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:10:05 -0400 Subject: [PATCH 40/53] Additional test coverage --- Tests/Add-DpaAnnotation.Tests.ps1 | 43 ++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Tests/Add-DpaAnnotation.Tests.ps1 b/Tests/Add-DpaAnnotation.Tests.ps1 index d75f343..0ca96fa 100644 --- a/Tests/Add-DpaAnnotation.Tests.ps1 +++ b/Tests/Add-DpaAnnotation.Tests.ps1 @@ -42,7 +42,7 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { $script:annotation = $null } - It 'should add an annotation' { + It 'should add an annotation when using -Monitor' { { $script:annotation = Add-DpaAnnotation @annotationParams -EnableException } | Should -Not -Throw foreach ($annotationParam in $annotationParams.Keys) { @@ -52,6 +52,34 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { $annotation.Type | Should -Be 'API' } + It 'should add an annotation when using -DatabaseId' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Monitor') + $thisAnnotationParams['DatabaseId'] = $monitor.DatabaseId + + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } + + $annotation.Type | Should -Be 'API' + } + + It 'should add an annotation when using -MonitorName' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Monitor') + $thisAnnotationParams['MonitorName'] = $monitor.DisplayName + + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } + + $annotation.Type | Should -Be 'API' + } + It 'should add an annotation when piping a monitor' { $thisAnnotationParams = $annotationParams.Clone() $thisAnnotationParams.Remove('Monitor') @@ -94,5 +122,18 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { $annotation.Time | Should -BeGreaterThan $currentTime.AddMinutes(-5) $annotation.Time | Should -BeLessThan $currentTime.AddMinutes(5) } + + It 'should gracefully fail when DPA gives a mangled response' { + Mock -CommandName 'Invoke-DpaRequest' -MockWith { + return @{ + 'Id' = 100 + 'Fake' = $true + } + } + + Assert-MockCalled -CommandName 'Invoke-DpaRequest' -Times 1 -ParameterFilter { $Endpoint -eq "/databases/$($monitor.DatabaseId)/annotations" } + + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Throw 'Could not create annotation from API response' + } } } \ No newline at end of file From b1c4722ffb0731c431fc87771c794de9069e05b9 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:24:24 -0400 Subject: [PATCH 41/53] Added waiting for DPA before testing --- Build/psake.ps1 | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 1dd83fc..975cf9d 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -30,6 +30,41 @@ Task Init { "`n" } +function Wait-DpaAvailable { + # modified from https://web.archive.org/web/20150405035615/http://poshcode.org/85 + + param( + [string] $Server, + [int] $Port, + [int] $TimeoutMilliseconds = 3000 + ) + + $ErrorActionPreference = 'SilentlyContinue' + + $tcpClient = Mew-Object System.Net.Sockets.TcpClient + $iar = $tcpClient.BeginConnect($Server, $Port, $null, $null) + $wait = $iar.AsyncWaitHandle.WaitOne($timeout, $false) + + if(!$wait) { + $tcpClient.Close() + + return $false + } else { + $error.Clear() + $null = $tcpClient.EndConnect($iar) + if(!$?) { + $failed = $true + } + $tcpClient.Close() + } + + if($failed) { + return $false + } else { + return $true + } +} + Task Test -Depends Init { $lines "`n`tSTATUS: Starting DPA VM" @@ -52,7 +87,12 @@ Task Test -Depends Init { if ($dpaVmStatus.DisplayStatus -ne 'VM running') { "Starting DPA VM" - $dpaVm | Start-AzVM + $azStart = $dpaVm | Start-AzVM + + "Waiting up to 10 minutes for DPA to start" + if (-not (Wait-DpaAvailable -Server '13.67.213.239' -Port 8123 -TimeoutMilliseconds 600000)) { + Stop-PSFFunction -Message "DPA VM failed to start in a timely fashion" -EnableException $true + } } else { "DPA VM is already running" } From e4d784d9a2dc0bb39a110184f85ec1522831ddea Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:28:49 -0400 Subject: [PATCH 42/53] New not Mew - this isn't pokemon --- Build/psake.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 975cf9d..eb65cdb 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -41,7 +41,7 @@ function Wait-DpaAvailable { $ErrorActionPreference = 'SilentlyContinue' - $tcpClient = Mew-Object System.Net.Sockets.TcpClient + $tcpClient = New-Object System.Net.Sockets.TcpClient $iar = $tcpClient.BeginConnect($Server, $Port, $null, $null) $wait = $iar.AsyncWaitHandle.WaitOne($timeout, $false) From d190888667d25b76f4cabcec94d1b9208fc5f7fa Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:38:20 -0400 Subject: [PATCH 43/53] Trying different method of waiting on DPA to become available --- Build/psake.ps1 | 44 ++++++-------------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index eb65cdb..aace85e 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -30,41 +30,6 @@ Task Init { "`n" } -function Wait-DpaAvailable { - # modified from https://web.archive.org/web/20150405035615/http://poshcode.org/85 - - param( - [string] $Server, - [int] $Port, - [int] $TimeoutMilliseconds = 3000 - ) - - $ErrorActionPreference = 'SilentlyContinue' - - $tcpClient = New-Object System.Net.Sockets.TcpClient - $iar = $tcpClient.BeginConnect($Server, $Port, $null, $null) - $wait = $iar.AsyncWaitHandle.WaitOne($timeout, $false) - - if(!$wait) { - $tcpClient.Close() - - return $false - } else { - $error.Clear() - $null = $tcpClient.EndConnect($iar) - if(!$?) { - $failed = $true - } - $tcpClient.Close() - } - - if($failed) { - return $false - } else { - return $true - } -} - Task Test -Depends Init { $lines "`n`tSTATUS: Starting DPA VM" @@ -90,9 +55,12 @@ Task Test -Depends Init { $azStart = $dpaVm | Start-AzVM "Waiting up to 10 minutes for DPA to start" - if (-not (Wait-DpaAvailable -Server '13.67.213.239' -Port 8123 -TimeoutMilliseconds 600000)) { - Stop-PSFFunction -Message "DPA VM failed to start in a timely fashion" -EnableException $true - } + $maxCycles = 60 + $cycles = 0 + do { + Start-Sleep -Seconds 10 + $cycles++ + } until (Test-NetConnection '13.67.213.239' -Port 8123 | Where-Object { $_.TcpTestSucceeded } -or $cycles++ -ge $maxCycles ) } else { "DPA VM is already running" } From 57ad3dd2b67d7a7a49951f3aac2df8b95abaaa1e Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:53:10 -0400 Subject: [PATCH 44/53] C'mon --- Build/psake.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index aace85e..d45fcb0 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -60,7 +60,7 @@ Task Test -Depends Init { do { Start-Sleep -Seconds 10 $cycles++ - } until (Test-NetConnection '13.67.213.239' -Port 8123 | Where-Object { $_.TcpTestSucceeded } -or $cycles++ -ge $maxCycles ) + } until ((Test-NetConnection '13.67.213.239' -Port 8123 | Where-Object { $_.TcpTestSucceeded }) -or $cycles++ -ge $maxCycles ) } else { "DPA VM is already running" } From d9058832a6a08eb11c6ec35d5816d9590c0aa540 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 20:59:37 -0400 Subject: [PATCH 45/53] Moving test to module scope so mocking can be performed and changing DisplayName to Name to resolve null error --- Tests/Add-DpaAnnotation.Tests.ps1 | 164 +++++++++++++++--------------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/Tests/Add-DpaAnnotation.Tests.ps1 b/Tests/Add-DpaAnnotation.Tests.ps1 index 0ca96fa..6e5cf47 100644 --- a/Tests/Add-DpaAnnotation.Tests.ps1 +++ b/Tests/Add-DpaAnnotation.Tests.ps1 @@ -19,121 +19,123 @@ Describe "$CommandName Unit Tests" -Tag 'Unit' { } Describe "$CommandName Integration Tests" -Tag 'Integration' { - Context 'Azure SQL DB' { - BeforeAll { - # set the start time and remove ticks since DPA doesn't support them - $contextStartTime = Get-Date - $contextStartTime = $contextStartTime.AddTicks(-($contextStartTime.Ticks % [TimeSpan]::TicksPerSecond)); - - # get our test monitor - $monitor = Get-DpaMonitor -MonitorName 'PSDPATESTDB01@PSDPATEST01' - - # default annotation parameters to use for tests - $annotationParams = @{ - Monitor = $monitor - Title = 'Testing API' - Description = 'This is a test of Add-DpaAnnotation' - CreatedBy = 'Test User' - Time = $contextStartTime + InModuleScope -ModuleName 'PSDPA' { + Context 'Azure SQL DB' { + BeforeAll { + # set the start time and remove ticks since DPA doesn't support them + $contextStartTime = Get-Date + $contextStartTime = $contextStartTime.AddTicks(-($contextStartTime.Ticks % [TimeSpan]::TicksPerSecond)); + + # get our test monitor + $monitor = Get-DpaMonitor -MonitorName 'PSDPATESTDB01@PSDPATEST01' + + # default annotation parameters to use for tests + $annotationParams = @{ + Monitor = $monitor + Title = 'Testing API' + Description = 'This is a test of Add-DpaAnnotation' + CreatedBy = 'Test User' + Time = $contextStartTime + } } - } - BeforeEach { - $script:annotation = $null - } + BeforeEach { + $script:annotation = $null + } + + It 'should add an annotation when using -Monitor' { + { $script:annotation = Add-DpaAnnotation @annotationParams -EnableException } | Should -Not -Throw - It 'should add an annotation when using -Monitor' { - { $script:annotation = Add-DpaAnnotation @annotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $annotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $annotationParams[$annotationParam] + } - foreach ($annotationParam in $annotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $annotationParams[$annotationParam] + $annotation.Type | Should -Be 'API' } - $annotation.Type | Should -Be 'API' - } + It 'should add an annotation when using -DatabaseId' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Monitor') + $thisAnnotationParams['DatabaseId'] = $monitor.DatabaseId - It 'should add an annotation when using -DatabaseId' { - $thisAnnotationParams = $annotationParams.Clone() - $thisAnnotationParams.Remove('Monitor') - $thisAnnotationParams['DatabaseId'] = $monitor.DatabaseId + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw - { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } - foreach ($annotationParam in $thisAnnotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + $annotation.Type | Should -Be 'API' } - $annotation.Type | Should -Be 'API' - } + It 'should add an annotation when using -MonitorName' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Monitor') + $thisAnnotationParams['MonitorName'] = $monitor.Name - It 'should add an annotation when using -MonitorName' { - $thisAnnotationParams = $annotationParams.Clone() - $thisAnnotationParams.Remove('Monitor') - $thisAnnotationParams['MonitorName'] = $monitor.DisplayName + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw - { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } - foreach ($annotationParam in $thisAnnotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + $annotation.Type | Should -Be 'API' } - $annotation.Type | Should -Be 'API' - } + It 'should add an annotation when piping a monitor' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Monitor') - It 'should add an annotation when piping a monitor' { - $thisAnnotationParams = $annotationParams.Clone() - $thisAnnotationParams.Remove('Monitor') + { $script:annotation = $monitor | Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw - { $script:annotation = $monitor | Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } - foreach ($annotationParam in $thisAnnotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + $annotation.DatabaseId | Should -BeExactly $monitor.DatabaseId + $annotation.Type | Should -Be 'API' } - $annotation.DatabaseId | Should -BeExactly $monitor.DatabaseId - $annotation.Type | Should -Be 'API' - } + It 'should default CreatedBy to the current user' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('CreatedBy') - It 'should default CreatedBy to the current user' { - $thisAnnotationParams = $annotationParams.Clone() - $thisAnnotationParams.Remove('CreatedBy') + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw - { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } - foreach ($annotationParam in $thisAnnotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + $annotation.CreatedBy | Should -Be $env:USERNAME } - $annotation.CreatedBy | Should -Be $env:USERNAME - } + It 'should default Time to the current time' { + $thisAnnotationParams = $annotationParams.Clone() + $thisAnnotationParams.Remove('Time') - It 'should default Time to the current time' { - $thisAnnotationParams = $annotationParams.Clone() - $thisAnnotationParams.Remove('Time') + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw - { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw + foreach ($annotationParam in $thisAnnotationParams.Keys) { + $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + } - foreach ($annotationParam in $thisAnnotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] + # give ourselves a 10 minute swing on time just in case server times vary + $currentTime = Get-Date + $annotation.Time | Should -BeGreaterThan $currentTime.AddMinutes(-5) + $annotation.Time | Should -BeLessThan $currentTime.AddMinutes(5) } - # give ourselves a 10 minute swing on time just in case server times vary - $currentTime = Get-Date - $annotation.Time | Should -BeGreaterThan $currentTime.AddMinutes(-5) - $annotation.Time | Should -BeLessThan $currentTime.AddMinutes(5) - } - - It 'should gracefully fail when DPA gives a mangled response' { - Mock -CommandName 'Invoke-DpaRequest' -MockWith { - return @{ - 'Id' = 100 - 'Fake' = $true + It 'should gracefully fail when DPA gives a mangled response' { + Mock -CommandName 'Invoke-DpaRequest' -MockWith { + return @{ + 'Id' = 100 + 'Fake' = $true + } } - } - Assert-MockCalled -CommandName 'Invoke-DpaRequest' -Times 1 -ParameterFilter { $Endpoint -eq "/databases/$($monitor.DatabaseId)/annotations" } + Assert-MockCalled -CommandName 'Invoke-DpaRequest' -Times 1 -ParameterFilter { $Endpoint -eq "/databases/$($monitor.DatabaseId)/annotations" } - { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Throw 'Could not create annotation from API response' + { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Throw 'Could not create annotation from API response' + } } } } \ No newline at end of file From 6ba62260cd10e2a4f5ec10b7ea9ea18d83097c62 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 21:03:23 -0400 Subject: [PATCH 46/53] Moar test changes --- Build/psake.ps1 | 13 +++++++------ Tests/Add-DpaAnnotation.Tests.ps1 | 18 +----------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index d45fcb0..01cbbdc 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -98,6 +98,13 @@ Task Test -Depends Init { } Remove-Item "$ProjectRoot\$TestFile" -Force -ErrorAction SilentlyContinue + + try { + $dpaVm | Stop-AzVM -Confirm:$false -Force + } catch { + Stop-PSFFunction -Message "Could not stop Azure DPA VM" -ErrorRecord $_ -EnableException $true + } + # Failed tests? # Need to tell psake or it will proceed to the deployment. Danger! if($TestResults.FailedCount -gt 0) @@ -108,12 +115,6 @@ Task Test -Depends Init { $lines "`n`tSTATUS: Stopping DPA VM" - - try { - $dpaVm | Stop-AzVM -Confirm:$false -Force - } catch { - Stop-PSFFunction -Message "Could not stop Azure DPA VM" -ErrorRecord $_ -EnableException $true - } } Task Build -Depends Test { diff --git a/Tests/Add-DpaAnnotation.Tests.ps1 b/Tests/Add-DpaAnnotation.Tests.ps1 index 6e5cf47..77a9d24 100644 --- a/Tests/Add-DpaAnnotation.Tests.ps1 +++ b/Tests/Add-DpaAnnotation.Tests.ps1 @@ -74,10 +74,7 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Not -Throw - foreach ($annotationParam in $thisAnnotationParams.Keys) { - $annotation.$annotationParam | Should -BeExactly $thisAnnotationParams[$annotationParam] - } - + $annotation.DatabaseId | Should -BeExactly $monitor.DatabaseId $annotation.Type | Should -Be 'API' } @@ -123,19 +120,6 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { $annotation.Time | Should -BeGreaterThan $currentTime.AddMinutes(-5) $annotation.Time | Should -BeLessThan $currentTime.AddMinutes(5) } - - It 'should gracefully fail when DPA gives a mangled response' { - Mock -CommandName 'Invoke-DpaRequest' -MockWith { - return @{ - 'Id' = 100 - 'Fake' = $true - } - } - - Assert-MockCalled -CommandName 'Invoke-DpaRequest' -Times 1 -ParameterFilter { $Endpoint -eq "/databases/$($monitor.DatabaseId)/annotations" } - - { $script:annotation = Add-DpaAnnotation @thisAnnotationParams -EnableException } | Should -Throw 'Could not create annotation from API response' - } } } } \ No newline at end of file From 8c7bcc8724df8edaf24e2687a948e4f69e0ceb4c Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 21:05:41 -0400 Subject: [PATCH 47/53] Hide some warnings from Get-DpaMonitor tests --- Tests/Get-DpaMonitor.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Get-DpaMonitor.Tests.ps1 b/Tests/Get-DpaMonitor.Tests.ps1 index a5f35e8..809a17d 100644 --- a/Tests/Get-DpaMonitor.Tests.ps1 +++ b/Tests/Get-DpaMonitor.Tests.ps1 @@ -73,13 +73,13 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { } It 'should return an empty resultset when a monitor is not found' { - Get-DpaMonitor -DatabaseId 0 | Should -HaveCount 0 + Get-DpaMonitor -DatabaseId 0 -WarningAction 'SilentlyContinue' | Should -HaveCount 0 Assert-MockCalled -CommandName 'Invoke-RestMethod' -Times 1 } It 'should not throw an exception when monitor is not found and -EnableException is not used' { - { Get-DpaMonitor -DatabaseId 0 } | Should -Not -Throw 'Not Found' + { Get-DpaMonitor -DatabaseId 0 -WarningAction 'SilentlyContinue' } | Should -Not -Throw 'Not Found' Assert-MockCalled -CommandName 'Invoke-RestMethod' -Times 1 } From 2ddf46d5ec79511545c0275ff6a10cd3af3eb186 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 21:10:14 -0400 Subject: [PATCH 48/53] Hide error/warnings from test connection --- Build/psake.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 01cbbdc..a3d28bd 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -60,7 +60,7 @@ Task Test -Depends Init { do { Start-Sleep -Seconds 10 $cycles++ - } until ((Test-NetConnection '13.67.213.239' -Port 8123 | Where-Object { $_.TcpTestSucceeded }) -or $cycles++ -ge $maxCycles ) + } until ((Test-NetConnection '13.67.213.239' -Port 8123 -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue' | Where-Object { $_.TcpTestSucceeded }) -or $cycles++ -ge $maxCycles ) } else { "DPA VM is already running" } From db6eee0878242c4af11e216a846b9b013a01ba9e Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 21:13:23 -0400 Subject: [PATCH 49/53] Tidying up --- Build/psake.ps1 | 2 ++ Tests/Add-DpaAnnotation.Tests.ps1 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index a3d28bd..68fbc48 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -61,6 +61,8 @@ Task Test -Depends Init { Start-Sleep -Seconds 10 $cycles++ } until ((Test-NetConnection '13.67.213.239' -Port 8123 -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue' | Where-Object { $_.TcpTestSucceeded }) -or $cycles++ -ge $maxCycles ) + + Start-Sleep -Seconds 60 } else { "DPA VM is already running" } diff --git a/Tests/Add-DpaAnnotation.Tests.ps1 b/Tests/Add-DpaAnnotation.Tests.ps1 index 77a9d24..679bd7c 100644 --- a/Tests/Add-DpaAnnotation.Tests.ps1 +++ b/Tests/Add-DpaAnnotation.Tests.ps1 @@ -27,7 +27,7 @@ Describe "$CommandName Integration Tests" -Tag 'Integration' { $contextStartTime = $contextStartTime.AddTicks(-($contextStartTime.Ticks % [TimeSpan]::TicksPerSecond)); # get our test monitor - $monitor = Get-DpaMonitor -MonitorName 'PSDPATESTDB01@PSDPATEST01' + $monitor = Get-DpaMonitor -MonitorName 'PSDPATESTDB01@PSDPATEST01' -EnableException # default annotation parameters to use for tests $annotationParams = @{ From b7230e9d0862c314dcf54a4f6181a526538496dd Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 21:53:53 -0400 Subject: [PATCH 50/53] wait longer --- Build/psake.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 68fbc48..d924365 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -62,7 +62,7 @@ Task Test -Depends Init { $cycles++ } until ((Test-NetConnection '13.67.213.239' -Port 8123 -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue' | Where-Object { $_.TcpTestSucceeded }) -or $cycles++ -ge $maxCycles ) - Start-Sleep -Seconds 60 + Start-Sleep -Seconds 180 } else { "DPA VM is already running" } From 9445ca64ed5e855960750fb96d307375b9779b4f Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 22:08:33 -0400 Subject: [PATCH 51/53] Updated README !deploy --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2dae7b7..d4af1eb 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ Set-DpaConfig -BaseUri 'https://yourdpaserver:8124/iwc/api' -RefreshToken 'yourp # Get listing of monitors Get-DpaMonitor + +# Add an annotation to all monitors +Get-DpaMonitor | Add-DpaAnnotation -Title 'Patching' -Description 'Quarterly patching' ``` ## Functions From dbcaa47736fd7df9065c4b815cd08e7cf86f7780 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 22:19:51 -0400 Subject: [PATCH 52/53] !deploy From b0367dd42909f16f9702be1b621efe26c4b37b1d Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Mon, 25 Mar 2019 22:22:57 -0400 Subject: [PATCH 53/53] !deploy