. $PSScriptRoot\..\..\Load-PesterModules.ps1 $here = Split-Path -Parent $MyInvocation.MyCommand.Path $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.tests\.', '.' $functionPath = Join-Path -Path $here -ChildPath $sut Write-Host "Overriding SUT: $functionPath" Import-Module $functionPath -Force $moduleForMock = "" # We need to use their stupid [Amazon.EC2.Model.Tag], so we have to import their module. Import-Module AWSPowerShell Mock -CommandName Get-LogLeadName -ModuleName $moduleForMock -MockWith { return 'Get-TerminatedComputersReport.tests' } Mock -CommandName Write-Progress -ModuleName $moduleForMock -MockWith {} Mock -CommandName Import-Module -ModuleName $moduleForMock -MockWith {} Mock -CommandName Get-Date -ModuleName $moduleForMock -MockWith {return ([datetime]::Now)} Mock -CommandName Write-Error -ModuleName $moduleForMock -MockWith {} Mock -CommandName Test-IsTeamCityProcess -ModuleName $moduleForMock -MockWith { return $false } $credential = ([pscredential]::new("test",("test1" | ConvertTo-SecureString -AsPlainText -Force))) Describe "Get-TerminatedComputersReport" { Context "When a parameter value is not valid or missing" { It "Throws an exception if Credential parameter is blank" { { Get-TerminatedComputersReport -Credential -Domain fh.local } | Should -Throw } It "Throws an exception if Domain parameter is blank" { { Get-TerminatedComputersReport -Credential $credential -Domain } | Should -Throw } It "Throws an exception if OU is not provided a value" { { Get-TerminatedComputersReport -OU } | Should -Throw } It "Throws an exception if NumberOfDays is not provided a value" { { Get-TerminatedComputersReport -NumberOfDays } | Should -Throw } It "Throws an exception if NumberOfDays is outside of the valid range" { { Get-TerminatedComputersReport -NumberOfDays 366 } | Should -Throw } } Context "Error Handling"{ It "Writes an error if AWSPowerShell cannot be loaded" { Mock -CommandName Get-Module -ModuleName $moduleForMock -MockWith {[pscustomobject]@{"Name" = "NotAWSPowerShell"}} Mock -CommandName Import-Module -ModuleName $moduleForMock -MockWith { throw "Module not found."} Get-TerminatedComputersReport -CheckAWS Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -ModuleName $moduleForMock -Scope It -ParameterFilter { $Message -like "*Unable to load the AWSPowerShell module*"} } It "Writes an error if DNS for the domain cannot be resolved" { Mock -CommandName Resolve-DnsName -ModuleName $moduleForMock -MockWith { throw "It's always DNS."} Get-TerminatedComputersReport -Credential $credential -Domain fh.local Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -ModuleName $moduleForMock -Scope It -ParameterFilter { $Message -like "*Error when resolving DNS for*"} } It "Writes an error if bad credentials are supplied" { Mock -CommandName Resolve-DnsName -ModuleName $moduleForMock -MockWith { return [pscustomobject]@{"IPAddress"="10.0.0.1"} } Mock -CommandName Test-Connection -ModuleName $moduleForMock -MockWith { return [pscustomobject]@{"Address"="10.0.0.1";"ResponseTime" = 25} } Mock -CommandName Get-ADComputer -ModuleName $moduleForMock -MockWith { throw [System.Security.Authentication.AuthenticationException]::new("The server has rejected the client credentials.") } Get-TerminatedComputersReport -Credential $credential -Domain fh.local Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -ModuleName $moduleForMock -Scope It -ParameterFilter { $Message -like "*Unable to connect to the target domain, invalid credentials*"} } It "Writes an error if unable to retrieve AD Computer objects" { Mock -CommandName Resolve-DnsName -ModuleName $moduleForMock -MockWith { return [pscustomobject]@{"IPAddress"="10.0.0.1"} } Mock -CommandName Test-Connection -ModuleName $moduleForMock -MockWith { return [pscustomobject]@{"Address"="10.0.0.1";"ResponseTime" = 25} } Mock -CommandName Get-ADComputer -ModuleName $moduleForMock -MockWith { throw "Something bad happened"} Get-TerminatedComputersReport -Credential $credential -Domain fh.local Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -ModuleName $moduleForMock -Scope It -ParameterFilter { $Message -like "*Unable to retrieve Computer objects from AD*"} } It "Writes an error if unable to retrieve EC2 instances from us-east-1" { Mock -CommandName Get-Module -ModuleName $moduleForMock -MockWith {[pscustomobject]@{"Name" = "AWSPowerShell"}} Mock -CommandName Get-ADComputer -ModuleName $moduleForMock -MockWith {} Mock -CommandName Get-EC2Instance -ModuleName $moduleForMock -ParameterFilter { $Region -eq "us-east-1"} -MockWith {throw "Error getting EC2 in us-east-1"} Get-TerminatedComputersReport -CheckAWS Assert-MockCalled -CommandName Write-Error -Times 4 -Exactly -ModuleName $moduleForMock -Scope It -ParameterFilter { $Message -like "*An error occurred while retrieving EC2 instances in us-east-1*"} } It "Writes an error if unable to retrieve EC2 instances from us-west-2"{ Mock -CommandName Get-Module -ModuleName $moduleForMock -MockWith {[pscustomobject]@{"Name" = "AWSPowerShell"}} Mock -CommandName Get-ADComputer -ModuleName $moduleForMock -MockWith {} Mock -CommandName Get-EC2Instance -ModuleName $moduleForMock -ParameterFilter { $Region -eq "us-east-1"} -MockWith {} Mock -CommandName Get-EC2Instance -ModuleName $moduleForMock -ParameterFilter { $Region -eq "us-west-2"} -MockWith {throw "Error getting EC2 in us-west-2"} Get-TerminatedComputersReport -CheckAWS Assert-MockCalled -CommandName Get-EC2Instance -Times 5 -Exactly -ModuleName $moduleForMock -Scope It Assert-MockCalled -CommandName Write-Error -Times 1 -Exactly -ModuleName $moduleForMock -Scope It -ParameterFilter { $Message -like "*An error occurred while retrieving EC2 instances in us-west-2*"} } } Context "Returns results" { $testDate = Get-Date It "Returns results without comparing to AWS" { Mock -CommandName Get-ADComputer -ModuleName $moduleForMock -MockWith { return ( [pscustomobject]@{ "Name" = "TestComputerName" "Enabled" = $true "IPv4Address" = "10.0.0.2" "lastLogonDate" = $testDate "PasswordLastSet" = $testDate "SID" = "The-Sloth" } ) } $adOnlyTest = Get-TerminatedComputersReport $expected = [pscustomobject]@{ "ADName" = "TestComputerName" "IsEnabled" = $true "ADIPv4Address" = "10.0.0.2" "LastLogon" = $testDate "PasswordLastSet" = $testDate "SID" = "The-Sloth" "TerminationConfidence" = [byte](($testDate) -lt ($testDate).AddDays(-90)) } (($adOnlyTest).ADName -eq ($expected).ADName) | Should -BeTrue (($adOnlyTest).IsEnabled -eq ($expected).IsEnabled) | Should -BeTrue (($adOnlyTest).ADIPv4Address -eq ($expected).ADIPv4Address) | Should -BeTrue (($adOnlyTest).LastLogon -eq ($expected).LastLogon) | Should -BeTrue (($adOnlyTest).PasswordLastSet -eq ($expected).PasswordLastSet) | Should -BeTrue (($adOnlyTest).SID -eq ($expected).SID) | Should -BeTrue (($adOnlyTest).TerminationConfidence -eq ($expected).TerminationConfidence) | Should -BeTrue } It "Returns results comparing to AWS" { Mock -CommandName Get-Module -ModuleName $moduleForMock -MockWith {[pscustomobject]@{"Name" = "AWSPowerShell"}} $script:mockCalled = 0 $getEC2InstanceMock = { $script:mockCalled++ if($script:mockCalled -eq 1){ # This is a hot mess, but we are trying to replicate the blackmagic that AWS has created when returning these objects return ( @{"Instances"=[pscustomobject]@{ "InstanceId" = "i-AmTheSloth" "PrivateIPAddress" = "10.0.0.2" "tags" = @([Amazon.EC2.Model.Tag]::new("alk:hostname","TestComputerName"),[Amazon.EC2.Model.Tag]::new("alk:designation","1000")) } } ) } else { return $null } } Mock -CommandName Get-ADComputer -ModuleName $moduleForMock -MockWith { return ( [pscustomobject]@{ "Name" = "TestComputerName" "Enabled" = $true "IPv4Address" = "10.0.0.2" "lastLogonDate" = $testDate "PasswordLastSet" = $testDate "SID" = "The-Sloth" } ) } Mock -CommandName Get-EC2Instance -ModuleName $moduleForMock -MockWith $getEC2InstanceMock $awsTest = Get-TerminatedComputersReport -CheckAWS $expected = [pscustomobject]@{ "ADName" = "TestComputerName" "IsEnabled" = $true "ADIPv4Address" = "10.0.0.2" "LastLogon" = $testDate "PasswordLastSet" = $testDate "SID" = "The-Sloth" "InstanceIdByIP" = "i-AmTheSloth" "InstanceIdByName" = "i-AmTheSloth" "DoesInstanceMatch" = $true "Designation" = "1000" "TerminationConfidence" = 0 } (($awsTest).ADName -eq ($expected).ADName) | Should -BeTrue (($awsTest).IsEnabled -eq ($expected).IsEnabled) | Should -BeTrue (($awsTest).ADIPv4Address -eq ($expected).ADIPv4Address) | Should -BeTrue (($awsTest).LastLogon -eq ($expected).LastLogon) | Should -BeTrue (($awsTest).PasswordLastSet -eq ($expected).PasswordLastSet) | Should -BeTrue (($awsTest).SID -eq ($expected).SID) | Should -BeTrue (($awsTest).InstanceIdByIP -eq ($expected).InstanceIdByIP) | Should -BeTrue (($awsTest).InstanceIdByName -eq ($expected).InstanceIdByName) | Should -BeTrue (($awsTest).DoesInstanceMatch -eq ($expected).DoesInstanceMatch) | Should -BeTrue (($awsTest).Designation -eq ($expected).Designation) | Should -BeTrue (($awsTest).TerminationConfidence -eq ($expected).TerminationConfidence) | Should -BeTrue } } }