Tests/Integration/AuditPolicyResourceHelper.Integration.Tests.ps1
#requires -RunAsAdministrator # Get the root path of the resourse [String] $script:moduleRoot = Split-Path -Parent ( Split-Path -Parent $PSScriptRoot ) Import-Module -Name (Join-Path -Path $moduleRoot ` -ChildPath 'DSCResources\AuditPolicyResourceHelper\AuditPolicyResourceHelper.psm1' ) ` -Force #region Generate data <# The auditpol utility outputs the list of categories and subcategories in a couple of different ways. Using the /list flag only returns the categories without the associated audit setting, so it is easier to filter later on. #> $script:categories = @() $script:subcategories = @() auditpol /list /subcategory:* | Where-Object { $_ -notlike 'Category/Subcategory*' } | ForEach-Object ` { # The categories do not have any space in front of them, but the subcategories do. if ( $_ -notlike " *" ) { $categories += $_.Trim() } else { $subcategories += $_.trim() } } #endregion Describe 'Prerequisites' { # There are several dependencies for both Pester and AuditPolicyDsc that need to be validated. It "Should be running as admin" { # The tests need to run as admin to have access to the auditpol data ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` [Security.Principal.WindowsBuiltInRole] "Administrator") | Should Be $true } It "Should find auditpol.exe in System32" { # If the auditpol is not located on the system, the entire module will fail Test-Path "$env:SystemRoot\system32\auditpol.exe" | Should Be $true } } Describe 'auditpol.exe output' { # Verify the raw auditpol output format has not changed across different OS versions and types. It 'Should get auditpol default return with no parameters' { ( auditpol.exe )[0] | Should BeExactly 'Usage: AuditPol command [<sub-command><options>]' } It 'Should get CSV format with the /r switch' { ( auditpol.exe /get /subcategory:logon /r )[0] | Should BeExactly "Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting" } # Loop through the raw output of every category option to validate the auditpol /category subcommand foreach ( $category in $categories ) { Context "Category: $category" { $auditpolCategory = auditpol.exe /get /category:$category /r It 'Should return an empty string on line 1' { $auditpolCategory[1] | Should Be "" } It 'Should return the category contents on line 2' { # the auditpol /r output starts with the computer name on each entry $auditpolCategory[2] | Should Match "$env:ComputerName" } } } # Loop through the filtered output of every category option to validate the auditpol /category subcommand foreach ( $category in $categories ) { Context "Category: $category Filtered 'Select-String -Pattern `$env:ComputerName'" { # Reuse the same command as the raw output context, only this time filter out the entries. # This is to verify the row indexing is not broken in later formatting actions $auditpolCategory = auditpol.exe /get /category:$category /r | Select-String -Pattern $env:ComputerName $auditpolCategoryCount = ($auditpolCategory | Measure-Object).Count It 'Should return more than one item' { # The header row has been stripped, so there should be more than one category to # account for multiple subcategories $auditpolCategoryCount | Should BeGreaterThan 1 } # Loop through the subcategories returned by the current category that was queried for ( $i = 0; $i -lt $auditpolCategoryCount; $i++ ) { It "Should return a subcategory on line $i" { # Verify that each filtered row that is returned, is in the expected format $auditpolCategory[$i] | Should Match "$env:ComputerName,System," } } It 'Should return a null on the last line' { # With a zero base, the count of the subcategories should index to the end of the list $auditpolCategory[$auditpolCategoryCount] | Should BeNullOrEmpty } } } # Loop through the raw output of every subcategory to validate the auditpol /subcategory subcommand foreach ( $subcategory in $subcategories ) { Context "Subcategory: $subcategory" { $auditpolSubcategory = auditpol.exe /get /subcategory:$subcategory /r It 'Should return an empty string on line 1there should be more than one category to account for multiple subcategories' { # Verify the raw auditpol CSV header format has not changed across different OS versions and types. $auditpolSubcategory[1] | Should BeNullOrEmpty } It 'Should return the subcategory on line 2' { # Verify the raw auditpol CSV header format has not changed across different OS versions and types. $auditpolSubcategory[2] | Should Match "$env:ComputerName" } } } # Loop through the filtered output of every subcategory to validate the auditpol /subcategory subcommand foreach ( $subcategory in $subcategories ) { Context "Subcategory: $subcategory Filtered 'Select-String -Pattern `$env:ComputerName'" { # Reuse the same command as the raw output context, only this time filter out the entries. # This is to verify the row indexing is not broken in the formatting function $auditpolSubcategory = auditpol.exe /get /subcategory:$subcategory /r | Select-String -Pattern $env:ComputerName It 'Should return a single subcategory' { # Verify the raw auditpol CSV header format has not changed across different OS versions and types. ($auditpolSubcategory | Measure-Object).Count | Should Be 1 } It 'Should return the Subcategory on line 0' { # Verify that each filtered row that is returned is in the expected format $auditpolSubcategory[0] | Should Match "$env:ComputerName,System," } It 'Should return null on line 1' { # Verify the raw auditpol CSV header format has not changed across different OS versions and types. $auditpolSubcategory[1]| Should BeNullOrEmpty } } } } Describe "Function Invoke-Auditpol" { InModuleScope AuditPolicyResourceHelper { Context 'Subcategory and Option' { # These tests verify that the /r switch is passed to auditpol It 'Should return a CSV format when a single word subcategory is passed in' { ( Invoke-Auditpol -Command "Get" -SubCommand "Subcategory:Logoff" )[0] | Should match ".,." } It 'Should return a CSV format when a multi-word subcategory is passed in' { ( Invoke-Auditpol -Command "Get" -SubCommand "Subcategory:""Credential Validation""" )[0] | Should match ".,." } It 'Should return a CSV format when an option is passed in' { ( Invoke-Auditpol -Command "Get" -SubCommand "option:CrashOnAuditFail" )[0] | Should match ".,." } } Context 'Backup' { $script:path = ([system.IO.Path]::GetTempFileName()).Replace('tmp','csv') It 'Should be able to call Invoke-Audtipol with backup and not throw' { {$script:auditpolBackupReturn = Invoke-AuditPol -Command 'Backup' ` -SubCommand "file:$script:path"} | Should Not Throw } It 'Should not return anything when a backup is requested' { $script:auditpolBackupReturn | Should BeNullOrEmpty } It 'Should produce a valid CSV in a temp file when the backup switch is used' { (Get-Content -Path $script:path)[0] | Should BeExactly "Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value" } } Context 'Restore' { It 'Should be able to call Invoke-Audtipol with backup and not throw' { {$script:auditpolRestoreReturn = Invoke-AuditPol -Command 'Restore' ` -SubCommand "file:$script:path"} | Should Not Throw } It 'Should not return anything when a restore is requested' { $script:auditpolRestoreReturn | Should BeNullOrEmpty } } } } Describe 'Test-ValidSubcategory' { InModuleScope AuditPolicyResourceHelper { Context 'Invalid Input' { It 'Should not throw an exception' { { $script:testValidSubcategoryResult = Test-ValidSubcategory -Name 'Invalid' } | Should Not Throw } It 'Should return false when an invalid Subcategory is passed ' { $script:testValidSubcategoryResult | Should Be $false } } Context 'Valid Input' { It 'Should not throw an exception' { { $script:testValidSubcategoryResult = Test-ValidSubcategory -Name 'logon' } | Should Not Throw } It 'Should return true when a valid Subcategory is passed ' { $script:testValidSubcategoryResult | Should Be $true } } } } |