diff --git a/MyTasks.psm1 b/MyTasks.psm1 index 82979eb..1ba37fe 100644 --- a/MyTasks.psm1 +++ b/MyTasks.psm1 @@ -32,7 +32,6 @@ Register-ArgumentCompleter -CommandName $cmd -ParameterName Name -ScriptBlock { [xml]$In = Get-Content -Path $MyTaskPath -Encoding UTF8 - #$in.objects.object.childnodes.where( {$_.Name -eq 'Name'}).'#text' foreach ($obj in $in.Objects.object) { $obj.Property | ForEach-Object -Begin {$propHash = [ordered]@{}} -Process { $propHash.Add($_.name, $_.'#text') diff --git a/MyTasksFunctions.ps1 b/MyTasksFunctions.ps1 index edd168b..d5f9393 100644 --- a/MyTasksFunctions.ps1 +++ b/MyTasksFunctions.ps1 @@ -114,7 +114,7 @@ Function _ImportTasks { } #_ImportTasks -#exported functions +# region exported functions Function New-MyTask { [cmdletbinding(SupportsShouldProcess, DefaultParameterSetName = "Date")] @@ -637,7 +637,7 @@ Function Get-MyTask { "ID" { Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Retrieving Task by ID: $ID" #$results = $tasks.where( {$_.id -eq $ID}) - $results = $tasks.where({$_.id -match "^($($id -join '|'))$" }) + $results = $tasks.where( {$_.id -match "^($($id -join '|'))$" }) } #id "All" { @@ -1141,6 +1141,7 @@ Function Save-MyTask { [string]$pb = ($PSBoundParameters | Format-Table -AutoSize | Out-String).TrimEnd() Write-Verbose "[$((Get-Date).TimeofDay) EGIN ] PSBoundparameters: `n$($pb.split("`n").Foreach({"$("`t"*4)$_"}) | Out-String) `n" Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Using parameter set $($PSCmdlet.ParameterSetName)" + } Process { @@ -1355,9 +1356,10 @@ table { width:95%;margin-left:5px; margin-bottom:20px;} } Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Validating Requirements" if ((Get-Module PSScheduledJob) -And (($PSVersionTable.Platform -eq 'Win32NT') -OR ($PSVersionTable.PSEdition -eq 'Desktop'))) { + Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Creating a Daily job trigger for $($Time.TimeofDay)" $trigger = New-JobTrigger -Daily -At $Time - + $opt = New-ScheduledJobOption -RunElevated -RequireNetwork Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Registering the scheduled job" if ($AsHtml) { @@ -1372,7 +1374,7 @@ table { width:95%;margin-left:5px; margin-bottom:20px;} MaxResultCount = 5 ScheduledJobOption = $opt Credential = $TaskCredential - } + } $regParams | Out-String | Write-Verbose Register-ScheduledJob @regParams } @@ -1434,44 +1436,44 @@ Function Get-EmailReminder { Process { Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting scheduled job myTasksEmail" if ((Get-Module PSScheduledJob) -And (($PSVersionTable.Platform -eq 'Win32NT') -OR ($PSVersionTable.PSEdition -eq 'Desktop'))) { - $t = Get-ScheduledJob myTasksEmail + $t = Get-ScheduledJob myTasksEmail - $hash = $t.InvocationInfo.Parameters[0].where( {$_.name -eq "argumentlist"}).value + $hash = $t.InvocationInfo.Parameters[0].where( {$_.name -eq "argumentlist"}).value - Try { - #get the last run - Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting last job run" - $last = Get-Job -name $t.name -Newest 1 -ErrorAction stop - } - Catch { - $last = [PSCustomObject]@{ - PSEndTime = "11/30/1999" -as [datetime] - State = "The task has not yet run" + Try { + #get the last run + Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting last job run" + $last = Get-Job -name $t.name -Newest 1 -ErrorAction stop + } + Catch { + $last = [PSCustomObject]@{ + PSEndTime = "11/30/1999" -as [datetime] + State = "The task has not yet run" + } + } + [pscustomobject]@{ + Task = $t.Name + Frequency = $t.JobTriggers.Frequency + At = $t.JobTriggers.at.TimeOfDay + To = $hash.To + From = $hash.From + MailServer = $hash.SMTPServer + Port = $hash.Port + UseSSL = $hash.UseSSL + AsHTML = $hash.BodyAsHTML + LastRun = $last.PSEndTime + LastState = $last.State + Started = $last.psBeginTime + Ended = $last.psEndTime + Result = $last.output + Enabled = $t.Enabled + Errors = $last.Errors + Warnings = $last.warnings } } - [pscustomobject]@{ - Task = $t.Name - Frequency = $t.JobTriggers.Frequency - At = $t.JobTriggers.at.TimeOfDay - To = $hash.To - From = $hash.From - MailServer = $hash.SMTPServer - Port = $hash.Port - UseSSL = $hash.UseSSL - AsHTML = $hash.BodyAsHTML - LastRun = $last.PSEndTime - LastState = $last.State - Started = $last.psBeginTime - Ended = $last.psEndTime - Result = $last.output - Enabled = $t.Enabled - Errors = $last.Errors - Warnings = $last.warnings + else { + Write-Warning "This command requires the PSScheduledJob module on a Windows platform." } - } - else { - Write-Warning "This command requires the PSScheduledJob module on a Windows platform." - } } #process End { @@ -1483,7 +1485,7 @@ Function Get-EmailReminder { Function Set-MyTaskPath { [cmdletbinding(SupportsShouldProcess)] - [OutputType("None",[System.Management.Automation.PSVariable])] + [OutputType("None", [System.Management.Automation.PSVariable])] Param( [Parameter(Mandatory, HelpMessage = "Enter the path to your new myTaskPath directory")] [ValidateScript( {Test-Path $_})] @@ -1509,4 +1511,5 @@ Function Set-MyTaskPath { } } #close Set-MyTaskPath +#endregion diff --git a/Tests/MyTasks.module.tests.ps1 b/Tests/MyTasks.module.tests.ps1 new file mode 100644 index 0000000..1613851 --- /dev/null +++ b/Tests/MyTasks.module.tests.ps1 @@ -0,0 +1,182 @@ +if (Get-Module -Name MyTasks) { + Remove-Module -Name MyTasks +} + +Import-Module -Name "$PSScriptRoot\..\Mytasks.psd1" -Force + +Describe 'MyTasks' { + + $Module = Get-Module -Name MyTasks + It 'should have 15 functions' { + $Module.ExportedFunctions.count | Should -Be 15 + } + + It 'should have 8 aliases command' { + $Module.ExportedAliases.Count | Should -Be 8 + } + + It 'should not export any variables' { + $Module.ExportedVariables.Count | Should -Be 0 + } + + $modvariables = @( + @{Variable = 'myTaskArchivePath'} + @{Variable = 'myTaskCategory'} + @{Variable = 'mytaskhome'} + @{Variable = 'mytaskPath'} + ) + + It 'should define a global variable called ' -TestCases $modVariables { + param ($Variable) + {Get-Variable -Name $variable -Scope global} | Should -Not -Throw + } + It 'should have a formatting xml file' { + $Module.ExportedFormatFiles.Count | Should -Be 1 + } + + It 'should have an about help topic' { + {Get-Help about_mytasks} | Should -Not -Throw + } + + It 'requires PowerShell 5.0' { + $Module.PowerShellVersion | Should -Be '5.0' + } +} #describe my module + +Describe "Functions" { + + $cmds = @( + @{Name = 'Disable-EmailReminder'} + @{Name = 'Enable-EmailReminder'} + @{Name = 'Get-EmailReminder'} + @{Name = 'New-MyTask'} + @{Name = 'Set-MyTask'} + @{Name = 'Save-MyTask'} + @{Name = 'Remove-MyTask'} + @{Name = 'Complete-MyTask'} + @{Name = 'Show-MyTask'} + @{Name = 'Get-MyTask'} + @{Name = 'Add-MyTaskCategory'} + @{Name = 'Get-MyTaskCategory'} + @{Name = 'Remove-MyTaskCategory'} + @{Name = 'Backup-MyTaskFile'} + @{Name = 'Set-MyTaskPath'} + ) + + It " has external help defined with at least one example" -TestCases $cmds { + param($Name) + $help = Get-Help $Name + $help.Description | Should -Not -BeNullOrEmpty + $help.Examples | Should -Not -BeNullOrEmpty + } + + Context 'Enable-EmailReminder' { + $cmd = Get-Command -Name Enable-EmailReminder + $params = "TO", "TASKCREDENTIAL" + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + } + + Context 'New-MyTask' { + $cmd = Get-Command -Name New-MyTask + $params = "NAME", "CATEGORY" + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + $params = 'NAME'.'DUEDATE'.'DESCRIPTION'.'CATEGORY' + Foreach ($item in $params) { + It "should have a $item parameter that accepts pipeline input by name" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).ValueFromPipelineByPropertyName | Should -be $True + } + } + } + Context 'Set-MyTask' { + $cmd = Get-Command -Name Set-MyTask + $params = "NAME" + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + + $params = "NAME" + Foreach ($item in $params) { + It "should have a $item parameter that accepts pipeline input by name" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).ValueFromPipelineByPropertyName | Should -be $True + } + } + } + Context 'Save-MyTask' { + $cmd = Get-Command -Name Save-MyTask + $params = "TASK" + Foreach ($item in $params) { + It "should have a $item parameter that accepts pipeline input by value" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).ValueFromPipeline| Should -be $True + } + } + } + Context 'Remove-MyTask' { + $cmd = Get-Command -Name Remove-MyTask + $params = "NAME", 'INPUTOBJECT' + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + } + Context 'Complete-MyTask' { + $cmd = Get-Command -Name Complete-MyTask + $params = "NAME", 'ID' + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + } + + Context 'Add-MyTaskCategory' { + $cmd = Get-Command -Name Add-MyTaskCategory + $params = "CATEGORY" + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + Foreach ($item in $params) { + It "should have a $item parameter that accepts pipeline input by value" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).ValueFromPipeline| Should -be $True + } + } + } + + Context 'Remove-MyTaskCategory' { + $cmd = Get-Command -Name Remove-MyTaskCategory + $params = "CATEGORY" + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + Foreach ($item in $params) { + It "should have a $item parameter that accepts pipeline input by value" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).ValueFromPipeline| Should -be $True + } + } + } + + Context 'Set-MyTaskPath' { + $cmd = Get-Command -Name Set-MyTaskPath + $params = "PATH" + Foreach ($item in $params) { + It "should have a mandatory $item parameter" { + ($cmd.parameters["$item"].Attributes).where( {$_.typeid.name -match 'parameterAttribute'}).Mandatory | Should -be $True + } + } + } + +} #describe functions \ No newline at end of file diff --git a/Tests/MyTasks.tests.ps1 b/Tests/MyTasks.tests.ps1 index f991ee8..87aedbe 100644 --- a/Tests/MyTasks.tests.ps1 +++ b/Tests/MyTasks.tests.ps1 @@ -7,34 +7,8 @@ Import-Module -Name "$PSScriptRoot\..\Mytasks.psd1" -Force InModuleScope MyTasks { - Describe 'The Module' { - - $Module = Get-Module -Name MyTasks - It 'should have 15 functions' { - $Module.ExportedFunctions.count | Should -Be 15 - } - - It 'should have 8 aliases command' { - $Module.ExportedAliases.Count | Should -Be 8 - } - - It 'should not export any variables' { - $Module.ExportedVariables.Count | Should -Be 0 - } - - It 'should have a formatting xml file' { - $Module.ExportedFormatFiles.Count | Should -Be 1 - } - - It 'requires PowerShell 5.0' { - $Module.PowerShellVersion | Should -Be '5.0' - } - } #describe my module - - Describe 'Categories' { BeforeAll { - #$myTaskCategory = "TestDrive:\myTaskCategory.txt" Set-MyTaskPath 'TestDrive:' } @@ -89,17 +63,7 @@ InModuleScope MyTasks { $Due = (Get-Date).AddDays(30).Date - Set-MyTaskPath 'TestDrive:' - - <# - need absolute path for XML files - new-Item -Name Documents -ItemType Directory -path TestDrive: - $home = $TestDrive - $mytaskhome = Join-Path $home -childpath Documents - $mytaskPath = Join-Path $home\Documents -child "myTasks.xml" - $myTaskArchivePath = Join-Path -Path $home\Documents -ChildPath "myTasksArchive.xml" - $myTaskCategory = Join-Path -path $home\Documents -childpath "myTaskCategory.txt" - #> + Set-MyTaskPath -path 'TestDrive:' Add-MyTaskCategory -Category Work, Personal, Other, Training, Testing @@ -165,7 +129,7 @@ InModuleScope MyTasks { {Show-MyTask | Get-Member -ErrorAction Stop} | Should -Throw } - It "should complete a task' { + It 'should complete a task' { {Complete-Mytask -Name Test1 -ErrorAction Stop} | Should -Not -Throw (Get-MyTask -Completed | Measure-Object).Count | Should -Be 1 } @@ -175,16 +139,15 @@ InModuleScope MyTasks { } Context 'Archive' { - - $SavePath = $TestDrive | Join-Path -ChildPath "Archive.xml" + It 'should complete and archive a task' { {Complete-Mytask -Name Test2 -Archive -ErrorAction Stop} | Should -Not -Throw (Get-MyTask -All | Where-Object {-not $_.Completed}).Count | Should -Be 3 } - It 'should archive or save a task' { - Get-MyTask -Completed | Save-MyTask -Path $SavePath - $SavePath | Should -Exist + It "should archive or save a task" { + Get-MyTask -Completed | Save-MyTask + $myTaskArchivePath | Should -Exist Get-MyTask -Name Test1 -WarningAction SilentlyContinue | Should -BeNull (Get-MyTask -All).Count | Should -Be 3 } @@ -205,19 +168,17 @@ InModuleScope MyTasks { It 'should backup the task file' { {Backup-MyTaskFile -ErrorAction Stop} | Should -Not -Throw - #dir TestDrive: -Recurse | out-string | write-host 'TestDrive:\MyTasks_Backup_*.xml' | Should -Exist } } } #describe my tasks - Describe 'Set-MyTaskPath (TaskVariables)' { + Describe 'Set-MyTaskPath' -Tag variables { + BeforeAll { - $NewFolder = $TestDrive | - Join-Path -ChildPath MyTasks | - New-Item -Path $New -ItemType Directory - + $NewFolder = New-Item -path $TestDrive -name MyTasks -ItemType Directory Set-MyTaskPath -Path $NewFolder.Fullname + $target = $NewFolder.FullName.Replace("\", "\\") } $VariableTests = @( @@ -227,9 +188,9 @@ InModuleScope MyTasks { @{ Variable = 'mytaskPath' } ) - It 'should update $' -TestCases $VariableTests { + It "should update " -TestCases $VariableTests { param($Variable) - Get-Variable $Variable -ValueOnly | Should -Match $NewFolder.Fullname + Get-Variable $Variable -ValueOnly | Should -Match "^$target" } } #describe task variables @@ -241,30 +202,29 @@ InModuleScope MyTasks { #> Mock Register-ScheduledJob { 1 } -Verifiable Mock Unregister-ScheduledJob {} -Verifiable - Mock Get-ScheduledJob { } -ParameterFilter {$Name -eq "myTasksEmail"} - Mock Get-ScheduledJob { $True } -ParameterFilter {$Name -eq "myTasksEmail"} Mock Get-ScheduledJob { $False } -ParameterFilter {$Name -eq "myTasksEmail"} - + #create a credential $Password = ConvertTo-SecureString -String "Password" -AsPlainText -Force $Credential = [PSCredential]::new("localhost\me", $Password) - + It 'should require a standard email address' { - {Enable-EmailReminder -To foo@company.com -TaskCredential $Credential }| Should -Not -Throw + {Enable-EmailReminder -To foo@company.com -TaskCredential $Credential } | Should -Not -Throw {Enable-EmailReminder -To foo -TaskCredential $Credential} | Should -Throw } - - It 'should fail if a job already exists' { - $Reminders = Enable-EmailReminder -To foo@company.com -TaskCredential $Credential -WarningAction SilentlyContinue - $Reminders.Count | Should -Be 0 - } - + It 'should register a scheduled job' { $Reminders = Enable-EmailReminder -To foo@company.com -TaskCredential $Credential $Reminders.Count | Should -Be 1 Assert-MockCalled Register-ScheduledJob } + It 'should fail if a job already exists' { + Mock Get-ScheduledJob { $True } -ParameterFilter {$Name -eq "myTasksEmail"} + $Reminders = Enable-EmailReminder -To foo@company.com -TaskCredential $Credential -WarningAction SilentlyContinue + $reminders | out-string | write-host -ForegroundColor cyan + $Reminders.Count | Should -Be 0 + } It 'should get a job result' { Mock Get-ScheduledJob { @@ -303,7 +263,7 @@ InModuleScope MyTasks { Assert-MockCalled Get-ScheduledJob Assert-MockCalled Get-Job - #$r | out-string | write-host -ForegroundColor CYAN + $Reminder | Should -BeOfType PSCustomobject $Reminder.Task | Should -Be "myTasksEmail" $Reminder.LastState | Should -Be "Completed" @@ -317,4 +277,5 @@ InModuleScope MyTasks { Assert-MockCalled Unregister-ScheduledJob } } #describe email settings -} #in module + +} #in module scope