├── Commands └── Cmdlets │ ├── ClearRecycleBin.Tests.ps1 │ ├── ClearRecycleBinHelperFunctions.psm1 │ ├── Clipboard.Tests.ps1 │ ├── ClipboardHelperFunctions.psm1 │ ├── FormatHex.Tests.ps1 │ ├── HelperMethods.psm1 │ ├── MiscCmdletUpdates.Tests.ps1 │ ├── NewGuid.Tests.ps1 │ ├── NewTemporaryFile.Tests.ps1 │ ├── PSODataUtils.HelperMethods.psm1 │ ├── Pester.Commands.Cmdlets.NoNewlineParameter.Tests.ps1 │ ├── Pester.Commands.Cmdlets.StartProcessWaitPassThru.Tests.ps1 │ ├── Pester.ConvertString.Tests.ps1 │ ├── Pester.DelimitedText.Tests.ps1 │ ├── Pester.History.Tests.ps1 │ ├── Pester.Management.Copy.Item.Tests.ps1 │ ├── StringManipulationData │ └── ConvertString │ │ ├── incorrect-examples.csv │ │ └── replace-name-by-empty.csv │ ├── SymbolicLinksGenerator.psm1 │ ├── pester.commands.cmdlets.process.tests.ps1 │ ├── pester.core.job.tests.ps1 │ ├── pester.diagnostics.counter.tests.ps1 │ ├── pester.management.computersecurechannel.tests.ps1 │ ├── pester.utility.alias.tests.ps1 │ ├── pester.utility.clixml.tests.ps1 │ ├── pester.utility.command.tests.ps1 │ ├── pester.utility.formatdata.tests.ps1 │ ├── pester.utility.object.tests.ps1 │ ├── pester.utility.string.tests.ps1 │ └── pester.utility.xml.tests.ps1 ├── Contribution.md ├── LICENSE ├── README.md ├── Scripting ├── Classes │ ├── Classes.Completion.Tests.ps1 │ ├── MSFT_778492.psm1 │ ├── ProtectedAccess.Tests.ps1 │ ├── Scripting.Classes.Attributes.Tests.ps1 │ ├── Scripting.Classes.BasicParsing.Tests.ps1 │ ├── Scripting.Classes.Break.Tests.ps1 │ ├── Scripting.Classes.Exceptions.Tests.ps1 │ ├── Scripting.Classes.Modules.Tests.ps1 │ ├── scripting.classes.NestedModules.tests.ps1 │ ├── scripting.classes.inheritance.tests.ps1 │ ├── scripting.classes.miscops.tests.ps1 │ ├── scripting.classes.using.tests.ps1 │ ├── scripting.classes.using.variants.tests.ps1 │ └── scripting.enums.tests.ps1 ├── CompletionTestSupport.psm1 ├── LanguageTestSupport.psm1 └── LanguageandParser │ ├── BNotOperator.Tests.ps1 │ ├── Completion.Tests.ps1 │ ├── ExtensibleCompletion.Tests.ps1 │ ├── LanguageAndParser.TestFollowup.Tests.ps1 │ ├── MethodInvocation.Tests.ps1 │ ├── ParameterBinding.Tests.ps1 │ ├── Pester.Ast.Tests.ps1 │ ├── Pester.RedirectionOperator.Tests.ps1 │ ├── TypeAccelerator.Tests.ps1 │ ├── UsingAssembly.Tests.ps1 │ └── UsingNamespace.Tests.ps1 ├── Security ├── Pester.Acl.Tests.ps1 ├── Pester.Authenticode.Tests.ps1 ├── Pester.SuspiciousScriptBlockLogging.Tests.ps1 └── pester.security.credential.tests.ps1 ├── engine ├── EngineAPIs │ ├── Engine.Tests.ps1 │ ├── Pester.GetPowerShellAPI.Tests.ps1 │ ├── WMI.Tests.ps1 │ └── XmlAdapter.Tests.ps1 ├── ExtensibleTypeSystem │ ├── ETS.Tests.ps1 │ ├── Pester.FileVersionInfo.Tests.ps1 │ └── Pester.PSObject.Tests.ps1 ├── Other │ └── Pester.Engine.Other.InformationStream.Tests.ps1 └── Runspace │ └── Pester.Runspace.Tests.ps1 ├── provider └── Providers │ ├── Pester.Get-ChildItem.Depth.Tests.ps1 │ ├── Pester.Provider.Providers.tests.ps1 │ ├── Pester.Providers.DrivePersistence.Tests.ps1 │ └── pester.management.junction.tests.ps1 └── remoting └── Cmdlets └── NoReboot.tests.ps1 /Commands/Cmdlets/ClearRecycleBin.Tests.ps1: -------------------------------------------------------------------------------- 1 | # This is a Pester test suite to validate the Clear-RecycleBin cmdlet in the Microsoft.PowerShell.Management module. 2 | # 3 | # Copyright (c) Microsoft Corporation, 2015 4 | # 5 | # These tests are not portable as they required functions from the ClearRecycleBinHelperFunctions.psm1 module. 6 | # 7 | 8 | $currentDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path 9 | $helperModule = Join-Path $currentDirectory "ClearRecycleBinHelperFunctions.psm1" 10 | if (-not $helperModule) 11 | { 12 | throw "Helper module $helperModule is not available." 13 | } 14 | Import-Module $helperModule -Force 15 | 16 | if (-not (ShouldRun)) 17 | { 18 | write-verbose "Shell.Application namespace is not available, skipping tests..." 19 | return 20 | } 21 | 22 | # The number of test files to create and send to the recycle bin. 23 | $numberOfTestFiles = 10 24 | 25 | # Setup 26 | Setup 27 | 28 | <# 29 | Purpose: 30 | Verify that Clear-RecycleBin with no parameters clears the recycle bin. 31 | 32 | Action: 33 | Run Clear-RecycleBin with no parameters. 34 | 35 | Expected Result: 36 | All contents of the recycle bin are deleted. 37 | #> 38 | 39 | Describe "ClearRecycleBinWithNoParameters" { 40 | 41 | It "Clear-RecycleBin -Force" { 42 | TestCaseSetup -numberOfFiles $numberOfTestFiles 43 | $result = @{ 44 | InitialFileCount = GetRecycleBinFileCount 45 | FinalFileCount = $null 46 | } 47 | Clear-RecycleBin -Force 48 | $result.FinalFileCount = GetRecycleBinFileCount 49 | 50 | $result.InitialFileCount - $numberOfTestFiles | should be 0 51 | $result.FinalFileCount | should be 0 52 | } 53 | } 54 | 55 | 56 | <# 57 | Purpose: 58 | Verify that Clear-RecycleBin -DriveLetter parameter supports the following formats: C, C: and C:\. 59 | 60 | Action: 61 | Run Clear-RecycleBin -DriveLetter using various supported formats. 62 | 63 | Expected Result: 64 | All contents of the recycle bin for the default drive are deleted. 65 | #> 66 | 67 | $supportedFormats = @() 68 | $supportedFormats += $env:SystemDrive.Replace(":","") 69 | $supportedFormats += $env:SystemDrive 70 | $supportedFormats += ($env:SystemDrive + "\") 71 | Describe "ClearRecycleBinSupportedDriveLetterFormats" { 72 | 73 | foreach ($inputParam in $supportedFormats) 74 | { 75 | It "Clear-RecycleBin -DriveLetter $inputParam -Force" { 76 | TestCaseSetup -numberOfFiles $numberOfTestFiles 77 | $result = @{ 78 | InitialFileCount = GetRecycleBinFileCount 79 | FinalFileCount = $null 80 | } 81 | Clear-RecycleBin -Force -DriveLetter $inputParam 82 | $result.FinalFileCount = GetRecycleBinFileCount 83 | 84 | $result.InitialFileCount - $numberOfTestFiles | should be 0 85 | $result.FinalFileCount | should be 0 86 | } 87 | } 88 | } 89 | 90 | 91 | <# 92 | Purpose: 93 | Verify that Clear-RecycleBin -DriveLetter throws the correct exception for $null and empty. 94 | 95 | Action: 96 | Run Clear-RecycleBin -DriveLetter using $null and empty. 97 | 98 | Expected Result: 99 | The correct exception is thrown and the FullyQualifiedErrorId is ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ClearRecycleBinCommand. 100 | #> 101 | 102 | $invalidInputs = @($null, "") 103 | Describe "ClearRecycleBinHandlesNullAndEmptyInputs" { 104 | 105 | foreach ($inputParam in $invalidInputs) 106 | { 107 | It "Clear-RecycleBin -DriveLetter null or empty" { 108 | try 109 | { 110 | Clear-RecycleBin -Force -DriveLetter $inputParam -ErrorAction Stop 111 | throw "CodeExecuted" 112 | } 113 | catch 114 | { 115 | $_.FullyQualifiedErrorId | should be "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ClearRecycleBinCommand" 116 | } 117 | } 118 | } 119 | } 120 | 121 | 122 | <# 123 | Purpose: 124 | Verify that Clear-RecycleBin -DriveLetter throws the correct exception for a drive that does not exist. 125 | 126 | Action: 127 | Run Clear-RecycleBin -DriveLetter using an unknown drive. 128 | 129 | Expected Result: 130 | The correct exception is thrown and the FullyQualifiedErrorId is DriveNotFound,Microsoft.PowerShell.Commands.ClearRecycleBinCommand. 131 | #> 132 | 133 | # Get a drive letter between F and Y that is not being used for the drive name. 134 | $driveLetter = [char[]](70..89) | Where-Object {$_ -notin (Get-PSDrive).Name} | Select-Object -Last 1 135 | 136 | Describe "ClearRecycleBinThrowsDriveNotFoundForDrivesThatDoNotExist" { 137 | It "Clear-RecycleBin -Force -DriveLetter $driveLetter -ErrorAction Stop" { 138 | try 139 | { 140 | Clear-RecycleBin -Force -DriveLetter $driveLetter -ErrorAction Stop 141 | throw "CodeExecuted" 142 | } 143 | catch 144 | { 145 | $_.FullyQualifiedErrorId | should be "DriveNotFound,Microsoft.PowerShell.Commands.ClearRecycleBinCommand" 146 | } 147 | } 148 | } 149 | 150 | 151 | <# 152 | Purpose: 153 | Verify that Clear-RecycleBin -DriveLetter throws the correct exception for a drive name in the incorrect format. 154 | 155 | Action: 156 | Run Clear-RecycleBin -DriveLetter c:\\\. 157 | 158 | Expected Result: 159 | The correct exception is thrown and the FullyQualifiedErrorId is InvalidDriveNameFormat,Microsoft.PowerShell.Commands.ClearRecycleBinCommand. 160 | #> 161 | 162 | $driveName = ($env:SystemDrive + "\\\") 163 | Describe "ClearRecycleBinThrowsInvalidDriveNameFormatForInvalidDriveNames" { 164 | It "Clear-RecycleBin -Force -DriveLetter $driveName" { 165 | try 166 | { 167 | Clear-RecycleBin -Force -DriveLetter $driveName -ErrorAction Stop 168 | throw "CodeExecuted" 169 | } 170 | catch 171 | { 172 | $_.FullyQualifiedErrorId | should be "InvalidDriveNameFormat,Microsoft.PowerShell.Commands.ClearRecycleBinCommand" 173 | } 174 | } 175 | } 176 | 177 | <# 178 | Purpose: 179 | Verify that Clear-RecycleBin works using piping. 180 | 181 | Action: 182 | Run Get-Volume for the default drive, and pipe the output to Clear-RecycleBin. 183 | 184 | Expected Result: 185 | All contents of the recycle bin for the default drive are deleted. 186 | #> 187 | $driveName = $env:SystemDrive.Replace(":","") 188 | Describe "ClearRecycleBinSupportsPiping" { 189 | 190 | It "Get-Volume -DriveLetter $driveName | Clear-RecycleBin -Force" { 191 | TestCaseSetup -numberOfFiles $numberOfTestFiles 192 | $result = @{ 193 | InitialFileCount = GetRecycleBinFileCount 194 | FinalFileCount = $null 195 | } 196 | Get-Volume -DriveLetter $driveName | Clear-RecycleBin -Force 197 | $result.FinalFileCount = GetRecycleBinFileCount 198 | 199 | $result.InitialFileCount - $numberOfTestFiles | should be 0 200 | $result.FinalFileCount | should be 0 201 | } 202 | } 203 | 204 | # Clean up 205 | CleanUp 206 | 207 | -------------------------------------------------------------------------------- /Commands/Cmdlets/ClearRecycleBinHelperFunctions.psm1: -------------------------------------------------------------------------------- 1 | # This is a helper module for a Pester test suite to validate the Clear-RecycleBin cmdlet 2 | # in the Microsoft.PowerShell.Management module. 3 | # 4 | # Copyright (c) Microsoft Corporation, 2015 5 | # 6 | 7 | # Get the current directory, and create a folder to generate test files. 8 | $currentDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path 9 | 10 | # Returns the guid for the current system drive. 11 | # 12 | function GetDriveID 13 | { 14 | $defaultDrive = $env:SystemDrive.Replace(":", "") 15 | $driveID = $null 16 | try 17 | { 18 | $defaultVolume = Get-Volume -DriveLetter $defaultDrive -ErrorAction Stop 19 | $defaultVolume = $defaultVolume.Path.Replace("\\?\Volume", "") 20 | $driveID = $defaultVolume.Replace("\", "") 21 | } 22 | catch 23 | { 24 | Write-Verbose "Failed to get system drive Id. Error: $_" -Verbose 25 | } 26 | return $driveID 27 | } 28 | 29 | # By default this function returns false. 30 | # 31 | function ShouldRun 32 | { 33 | # If the Shell API is not available, skip the test suite. 34 | try 35 | { 36 | $shell = new-object -comobject "Shell.Application" 37 | } 38 | catch 39 | { 40 | # ignore the error and return false. 41 | return $false 42 | } 43 | 44 | if ($shell -eq $null) 45 | { 46 | return $false 47 | } 48 | 49 | # Check the registry to see if the user has disable sending files to the recycle bin. 50 | $systemDriveID = GetDriveID 51 | if ($systemDriveID -ne $null) 52 | { 53 | $registrySettingsPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\Volume\' 54 | $allDrives = @(Get-ChildItem $registrySettingsPath) 55 | if ($allDrives.Count -gt 0) 56 | { 57 | foreach ($drive in $allDrives) 58 | { 59 | if ($drive.PSChildName -match $systemDriveID) 60 | { 61 | # Save the original key value 62 | $keySettingPath = $registrySettingsPath + $drive.PSChildName 63 | $recybleBinKey = Get-ItemProperty -path $keySettingPath -Name NukeOnDelete 64 | if ($recybleBinKey.NukeOnDelete -eq 0) 65 | { 66 | return $true 67 | } 68 | } 69 | } 70 | } 71 | } 72 | return $false 73 | } 74 | 75 | function Setup 76 | { 77 | # Get the current directory, and create a folder to generate test files. 78 | $script:testFolderPath = join-path $currentDirectory "ClearRecycleBinTests" 79 | write-verbose "Test folder path: $testFolderPath" 80 | if (test-path $script:testFolderPath) 81 | { 82 | Remove-Item $script:testFolderPath -Recurse -Force -ea SilentlyContinue 83 | } 84 | New-Item $script:testFolderPath -ItemType Directory -Force|out-null 85 | 86 | # Script level variables for recycleBin manipulations. 87 | $script:shell = new-object -comobject "Shell.Application" 88 | $script:recycleBin = $script:shell.NameSpace(0xa) 89 | } 90 | 91 | function CleanUp 92 | { 93 | if (test-path $script:testFolderPath) 94 | { 95 | Remove-Item $script:testFolderPath -Recurse -Force -ea SilentlyContinue 96 | } 97 | } 98 | 99 | function TestCaseSetup 100 | { 101 | param 102 | ( 103 | [int]$numberOfFiles = 10 104 | ) 105 | 106 | # Script level variables for recycleBin manipulations. 107 | $script:shell = new-object -comobject "Shell.Application" 108 | $script:recycleBin = $script:shell.NameSpace(0xa) 109 | 110 | # Ensure that the recycle bin is empty. 111 | $script:recycleBin.Items() | Remove-Item -Force -Recurse -ea SilentlyContinue 112 | 113 | # Generate $numberOfFiles and send them to the RecycleBin. 114 | 1..$numberOfFiles | % { 115 | $filePath = Join-Path $script:testFolderPath ($_.ToString() + ".txt") 116 | Set-Content -Value $_ -Path $filePath 117 | $item = $script:shell.Namespace(0).ParseName("$filePath") 118 | $item.InvokeVerb("delete") 119 | } 120 | 121 | # Ensure that the RecycleBin is not empty. 122 | $results = @($script:recycleBin.Items()) 123 | if (-not ($results.Count -gt 0)) 124 | { 125 | throw "Failed to populate recycleBin with test files." 126 | } 127 | } 128 | 129 | function GetRecycleBinFileCount 130 | { 131 | return @($script:recycleBin.Items()).Count 132 | } 133 | -------------------------------------------------------------------------------- /Commands/Cmdlets/Clipboard.Tests.ps1: -------------------------------------------------------------------------------- 1 | # This is a Pester test suite to validate the Clipboard cmdlets in the Microsoft.PowerShell.Management module. 2 | # 3 | # Copyright (c) Microsoft Corporation, 2015 4 | # 5 | # These tests are not portable as they required functions from the ClipboardHelperFunctions.psm1 module. 6 | # 7 | 8 | $currentDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path 9 | $helperModule = Join-Path $currentDirectory "ClipboardHelperFunctions.psm1" 10 | $script:testFolderPath = join-path $env:TEMP "ClipboardTests" 11 | $script:rdpProcessOn = $false; 12 | 13 | if (-not $helperModule) 14 | { 15 | throw "Helper module $helperModule is not available." 16 | } 17 | Import-Module $helperModule -Force 18 | 19 | if (-not (ShouldRun)) 20 | { 21 | write-verbose "System.Windows.Clipborad namespace is not available, skipping tests..." 22 | return 23 | } 24 | 25 | # The number of test files to create for file copy. 26 | $numberOfTestFiles = 10 27 | 28 | # Setup 29 | Setup -numberOfFiles $numberOfTestFiles 30 | 31 | # If the test is running on the lab machine logged in from host, 32 | # the rdpclip.exe will share the clipboard content between host and lab machine. It needs to be temporary disabled. 33 | 34 | if ((Get-Process rdpclip -ErrorAction SilentlyContinue).count -ne 0) 35 | { 36 | Get-Process rdpclip | Stop-Process -force 37 | $rdpProcessOn = $true 38 | } 39 | 40 | <# 41 | Purpose: 42 | Verify that Get/Set-Clipboard works with text format. 43 | 44 | Action: 45 | Run set/Get Clipboard cmdltes with text input 46 | 47 | Expected Result: 48 | The Get-Clipboard should return what Set-Clipboard sets. 49 | #> 50 | 51 | Describe "ClipboardWorksWithTextFormats" { 52 | 53 | It "Get text content from clipboard" { 54 | $text = "Content is set to Clipboard." 55 | Set-Clipboard -Value $text 56 | Get-Clipboard | should be $text 57 | } 58 | 59 | It "Set Clipboard With Append swtich" { 60 | $text1 = "text1 set to Clipboard." 61 | $text2 = "text2 set to Clipboard." 62 | Set-Clipboard -Value $text1 63 | Set-Clipboard -Value $text2 -Append 64 | $result = New-Object -TypeName "System.Text.StringBuilder" 65 | $result.AppendLine($text1) 66 | $result.Append($text2) 67 | Get-Clipboard -Raw | should be $result.ToString() 68 | } 69 | 70 | It "Set Clipboard works with pipe line as Text." { 71 | $filePath = Join-Path $script:testFolderPath "1.txt" 72 | $content = Get-Content $filePath 73 | Get-Content $filePath | Set-Clipboard 74 | Get-Clipboard -Raw | should be $content 75 | } 76 | 77 | It "Set Clipboard works with multiple pipe line." { 78 | $content = "string1", "string2" 79 | $content | Set-Clipboard 80 | $result = Get-Clipboard 81 | $result.Count | should be 2 82 | $result[0] | should be "string1" 83 | $result[1] | should be "string2" 84 | } 85 | } 86 | 87 | 88 | <# 89 | Purpose: 90 | Verify that Get/Set-Clipboard works with file format. 91 | 92 | Action: 93 | Run set/Get Clipboard cmdltes with file format 94 | 95 | Expected Result: 96 | The Get-Clipboard should return what Set-Clipboard sets. 97 | #> 98 | 99 | Describe "ClipboardWorksWithFileFormats" { 100 | 101 | It "Get text content from clipboard contains file format" { 102 | $filePath = Join-Path $script:testFolderPath "1.txt" 103 | Set-Clipboard -Path $filePath 104 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 105 | (Get-Clipboard -Format FileDropList).fullname | should be $filePath 106 | } 107 | 108 | It "Set file format to Clipboard With Append swtich" { 109 | $filePath1 = Join-Path $script:testFolderPath "1.txt" 110 | $filePath2 = Join-Path $script:testFolderPath "2.txt" 111 | Set-Clipboard -Path $filePath1 112 | Set-Clipboard -Path $filePath2 -Append 113 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 114 | $result = Get-Clipboard -Format FileDropList -Raw 115 | $result.Contains($filePath1) | should be $true 116 | $result.Contains($filePath2) | should be $true 117 | } 118 | 119 | It "Set Clipboard works with file format" { 120 | $filePath = Join-Path $script:testFolderPath "1.txt" 121 | Set-Clipboard -Value "Test Value" 122 | [Windows.Clipboard]::ContainsText() | should be $true 123 | Set-Clipboard -Path $filePath 124 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 125 | } 126 | 127 | It "Set Clipboard works with wild card file name" { 128 | $filePath = Join-Path $script:testFolderPath "*" 129 | Set-Clipboard -Path $filePath 130 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 131 | $result = [Windows.Clipboard]::GetFileDropList() 132 | $result.Count | should be $numberOfTestFiles 133 | } 134 | 135 | It "Set Clipboard works pipeLine as file format" { 136 | Get-ChildItem $script:testFolderPath | Set-Clipboard 137 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 138 | $result = [Windows.Clipboard]::GetFileDropList() 139 | $result.Count | should be $numberOfTestFiles 140 | } 141 | 142 | It "Set Clipboard won't add duplicated file names" { 143 | Get-ChildItem $script:testFolderPath | Set-Clipboard 144 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 145 | $result = [Windows.Clipboard]::GetFileDropList() 146 | $result.Count | should be $numberOfTestFiles 147 | Get-ChildItem $script:testFolderPath | Set-Clipboard -Append 148 | $result = [Windows.Clipboard]::GetFileDropList() 149 | $result.Count | should be $numberOfTestFiles 150 | } 151 | 152 | It "Set Clipboard won't add non-existed file names" { 153 | $filePath = Join-Path $script:testFolderPath "invalidFile" 154 | $fullyQualifiedErrorId = "FailedToSetClipboard,Microsoft.PowerShell.Commands.SetClipboardCommand" 155 | $Error.Clear() 156 | try 157 | { 158 | Set-Clipboard -Path $filePath -ErrorAction Stop 159 | throw "Set-Clipboard doesn't throw expected exception" 160 | } 161 | catch 162 | { 163 | $_.FullyQualifiedErrorId | should be $fullyQualifiedErrorId 164 | 165 | } 166 | } 167 | 168 | It "Set Clipboard works with literal path file format" { 169 | $filePath = Join-Path $script:testFolderPath "[1].txt" 170 | Set-Content -Value "[1].txt" -Path $filePath 171 | Set-Clipboard -LiteralPath $filePath 172 | [Windows.Clipboard]::ContainsFileDropList() | should be $true 173 | $result = Get-Clipboard -Format FileDropList -Raw 174 | $result.Contains($filePath) | should be $true 175 | } 176 | } 177 | 178 | 179 | # Clean up 180 | CleanUp 181 | 182 | if ($rdpProcessOn) 183 | { 184 | Start-Process rdpclip -ErrorAction Ignore 185 | } 186 | 187 | -------------------------------------------------------------------------------- /Commands/Cmdlets/ClipboardHelperFunctions.psm1: -------------------------------------------------------------------------------- 1 | # This is a helper module for a Pester test suite to validate the Clipboard cmdlet 2 | # in the Microsoft.PowerShell.Management module. 3 | # 4 | # Copyright (c) Microsoft Corporation, 2015 5 | # 6 | 7 | function ShouldRun 8 | { 9 | # If the presentationCore is not available, skip the test suite. 10 | try 11 | { 12 | Add-Type -Assembly PresentationCore 13 | } 14 | catch 15 | { 16 | # ignore the error and return false. 17 | return $false 18 | } 19 | 20 | return $true 21 | } 22 | 23 | function Setup 24 | { 25 | param 26 | ( 27 | [int]$numberOfFiles = 10 28 | ) 29 | 30 | # Get the temp directory, and create a folder to generate test files. 31 | $script:testFolderPath = join-path $env:TEMP "ClipboardTests" 32 | write-verbose "Test folder path: $testFolderPath" 33 | if (test-path $script:testFolderPath) 34 | { 35 | Remove-Item $script:testFolderPath -Recurse -Force -ea SilentlyContinue 36 | } 37 | New-Item $script:testFolderPath -ItemType Directory -Force | out-null 38 | 39 | # Generate $numberOfFiles. 40 | 1..$numberOfFiles | % { 41 | $filePath = Join-Path $script:testFolderPath ($_.ToString() + ".txt") 42 | Set-Content -Value $_ -Path $filePath} 43 | 44 | } 45 | 46 | function CleanUp 47 | { 48 | if (test-path $script:testFolderPath) 49 | { 50 | Remove-Item $script:testFolderPath -Recurse -Force -ea SilentlyContinue 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Commands/Cmdlets/FormatHex.Tests.ps1: -------------------------------------------------------------------------------- 1 | # This is a Pester test suite to validate the Format-Hex cmdlet in the Microsoft.PowerShell.Utility module. 2 | # 3 | # Copyright (c) Microsoft Corporation, 2015 4 | # 5 | 6 | <# 7 | Purpose: 8 | Verify that Format-Hex display the Hexa decmial value for the input data. 9 | 10 | Action: 11 | Run Format-Fex. 12 | 13 | Expected Result: 14 | Hexa decimal equivalent of the input data is displayed. 15 | #> 16 | 17 | Describe "FormatHex" { 18 | 19 | New-Item TestDrive:\FormatHexDataDir -Type Directory -Force | Out-Null 20 | $inputFile = "TestDrive:\FormatHexDataDir\SourceFile-1.txt" 21 | $inputText = 'Hello World' 22 | Set-Content -Value $inputText -Path $inputFile 23 | 24 | # This test is to validate to pipeline support in Format-Hex cmdlet. 25 | It "ValidatePipelineSupport" { 26 | 27 | # InputObject Parameter set should get invoked and 28 | # the input data should be treated as string. 29 | $result = $inputText | Format-Hex 30 | $result | Should Not Be $null 31 | $result.GetType().Name | Should Be 'ByteCollection' 32 | $actualResult = $result.ToString() 33 | ($actualResult -match $inputText) | Should Be $true 34 | } 35 | 36 | # This test is to validate to pipeline support in Format-Hex cmdlet. 37 | It "ValidateByteArrayInputSupport" { 38 | 39 | # InputObject Parameter set should get invoked and 40 | # the input data should be treated as byte[]. 41 | $inputBytes = [System.Text.Encoding]::ASCII.GetBytes($inputText) 42 | 43 | $result = Format-Hex -InputObject $inputBytes 44 | $result | Should Not Be $null 45 | $result.GetType().Name | Should Be 'ByteCollection' 46 | $actualResult = $result.ToString() 47 | ($actualResult -match $inputText) | Should Be $true 48 | } 49 | 50 | # This test is to validate to input given through Path paramter set in Format-Hex cmdlet. 51 | It "ValidatePathParameterSet" { 52 | 53 | $result = Format-Hex -Path $inputFile 54 | $result | Should Not Be $null 55 | $result.GetType().Name | Should Be 'ByteCollection' 56 | $actualResult = $result.ToString() 57 | ($actualResult -match $inputText) | Should Be $true 58 | } 59 | 60 | # This test is to validate to Path paramter set is considered as default in Format-Hex cmdlet. 61 | It "ValidatePathAsDefaultParameterSet" { 62 | 63 | $result = Format-Hex $inputFile 64 | $result | Should Not Be $null 65 | $result.GetType().Name | Should Be 'ByteCollection' 66 | $actualResult = $result.ToString() 67 | ($actualResult -match $inputText) | Should Be $true 68 | } 69 | 70 | # This test is to validate to input given through LiteralPath paramter set in Format-Hex cmdlet. 71 | It "ValidateLiteralPathParameterSet" { 72 | 73 | $result = Format-Hex -LiteralPath $inputFile 74 | $result | Should Not Be $null 75 | $result.GetType().Name | Should Be 'ByteCollection' 76 | $actualResult = $result.ToString() 77 | ($actualResult -match $inputText) | Should Be $true 78 | } 79 | 80 | # This test is to validate to input given through pipeline. The input being piped from results of Get-hildItem 81 | It "ValidateFileInfoPipelineInput" { 82 | 83 | $result = Get-ChildItem $inputFile | Format-Hex 84 | $result | Should Not Be $null 85 | $result.GetType().Name | Should Be 'ByteCollection' 86 | $actualResult = $result.ToString() 87 | ($actualResult -match $inputText) | Should Be $true 88 | } 89 | 90 | # This test is to validate Encoding formats functionality of Format-Hex cmdlet. 91 | It "ValidateEncodingFormats" { 92 | 93 | $result = Format-Hex -InputObject $inputText -Encoding ASCII 94 | $result | Should Not Be $null 95 | $result.GetType().Name | Should Be 'ByteCollection' 96 | $actualResult = $result.ToString() 97 | ($actualResult -match $inputText) | Should Be $true 98 | } 99 | 100 | # This test is to validate the alias for Format-Hex cmdlet. 101 | It "ValidateCmdletAlias" { 102 | 103 | try 104 | { 105 | $result = Get-Command fhx -ErrorAction Stop 106 | $result | Should Not Be $null 107 | $result.CommandType | Should Not Be $null 108 | $result.CommandType.ToString() | Should Be "Alias" 109 | } 110 | catch 111 | { 112 | $_ | Should Be $null 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Commands/Cmdlets/MiscCmdletUpdates.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "GetDateFormatUpdates" { 2 | 3 | It "Verifies that FileDate format works" { 4 | $date = Get-Date 5 | $expectedFormat = "{0:yyyyMMdd}" -f $date 6 | $actualFormat = Get-Date -Date $date -Format FileDate 7 | 8 | $actualFormat | Should be $expectedFormat 9 | } 10 | 11 | It "Verifies that FileDateUniversal format works" { 12 | $date = (Get-Date).ToUniversalTime() 13 | $expectedFormat = "{0:yyyyMMddZ}" -f $date 14 | $actualFormat = Get-Date -Date $date -Format FileDateUniversal 15 | 16 | $actualFormat | Should be $expectedFormat 17 | } 18 | 19 | It "Verifies that FileDateTime format works" { 20 | $date = Get-Date 21 | $expectedFormat = "{0:yyyyMMddTHHmmssffff}" -f $date 22 | $actualFormat = Get-Date -Date $date -Format FileDateTime 23 | 24 | $actualFormat | Should be $expectedFormat 25 | } 26 | 27 | It "Verifies that FileDateTimeUniversal format works" { 28 | $date = (Get-Date).ToUniversalTime() 29 | $expectedFormat = "{0:yyyyMMddTHHmmssffffZ}" -f $date 30 | $actualFormat = Get-Date -Date $date -Format FileDateTimeUniversal 31 | 32 | $actualFormat | Should be $expectedFormat 33 | } 34 | 35 | } 36 | 37 | Describe "GetRandomMiscTests" { 38 | It "Shouldn't overflow when using max range" { 39 | 40 | $hadError = $false 41 | 42 | try 43 | { 44 | ## Don't actually need to validate 45 | Get-Random -Minimum ([Int32]::MinValue) -Maximum ([Int32]::MaxValue) -ErrorAction Stop 46 | } 47 | catch 48 | { 49 | $hadError = $true 50 | } 51 | 52 | $hadError | Should be $false 53 | } 54 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/NewGuid.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe -Tags "Unit" "New-Guid" { 2 | 3 | It "returns a new guid" { 4 | $guid = New-Guid 5 | $guid.GetType().FullName | Should Be "System.Guid" 6 | } 7 | 8 | It "should not be all zeros" { 9 | $guid = New-Guid 10 | $guid.ToString() | Should Not Be "00000000-0000-0000-0000-000000000000" 11 | } 12 | 13 | It "should return different guids with each call" { 14 | $guid1 = New-Guid 15 | $guid2 = New-Guid 16 | $guid1.ToString() | Should Not Be $guid2.ToString() 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Commands/Cmdlets/NewTemporaryFile.Tests.ps1: -------------------------------------------------------------------------------- 1 | # This is a Pester test suite to validate the New-TemporaryFile cmdlet in the Microsoft.PowerShell.Utility module. 2 | # 3 | # Copyright (c) Microsoft Corporation, 2015 4 | # 5 | 6 | <# 7 | Purpose: 8 | Verify that New-TemporaryFile creates a temporary file. 9 | 10 | Action: 11 | Run New-TemporaryFile. 12 | 13 | Expected Result: 14 | A FileInfo object for the temporary file is returned. 15 | #> 16 | 17 | Describe "NewTemporaryFile" { 18 | 19 | It "creates a new temporary file" { 20 | $tempFile = New-TemporaryFile 21 | 22 | Test-Path $tempFile | Should be $true 23 | $tempFile.GetType().Name | Should be "FileInfo" 24 | 25 | if(Test-Path $tempFile) 26 | { 27 | Remove-Item $tempFile -ErrorAction SilentlyContinue -Force 28 | } 29 | } 30 | 31 | It "with WhatIf does not create a file" { 32 | New-TemporaryFile -WhatIf | Should Be $null 33 | } 34 | 35 | It "has an OutputType of System.IO.FileInfo" { 36 | (Get-Command New-TemporaryFile).OutputType | Should Be "System.IO.FileInfo" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Commands/Cmdlets/Pester.Commands.Cmdlets.NoNewlineParameter.Tests.ps1: -------------------------------------------------------------------------------- 1 | # Tests related to TFS item 1370133 [PSUpgrade] Need -NoNewline parameter on Out-File, Add-Content and Set-Content 2 | # Connect request https://connect.microsoft.com/PowerShell/feedback/details/524739/need-nonewline-parameter-on-out-file-add-content-and-set-content 3 | 4 | Describe "Tests for -NoNewline parameter of Out-File, Add-Content and Set-Content" { 5 | 6 | It "NoNewline parameter works on Out-File" { 7 | $temp = New-TemporaryFile 8 | 1..5 | Out-File $temp.FullName -Encoding 'ASCII' -NoNewline 9 | (Get-Content $temp -Encoding Byte).Count | Should Be 5 10 | Remove-Item $temp -ErrorAction SilentlyContinue -Force 11 | } 12 | 13 | It "NoNewline parameter works on Set-Content" { 14 | $temp = New-TemporaryFile 15 | Set-Content -Path $temp.FullName -Value 'a','b','c' -Encoding 'ASCII' -NoNewline 16 | (Get-Content $temp -Encoding Byte).Count | Should Be 3 17 | Remove-Item $temp -ErrorAction SilentlyContinue -Force 18 | } 19 | 20 | It "NoNewline parameter works on Add-Content" { 21 | $temp = New-TemporaryFile 22 | 1..9 | %{Add-Content -Path $temp.FullName -Value $_ -Encoding 'ASCII' -NoNewline} 23 | (Get-Content $temp -Encoding Byte).Count | Should Be 9 24 | Remove-Item $temp -ErrorAction SilentlyContinue -Force 25 | } 26 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/Pester.Commands.Cmdlets.StartProcessWaitPassThru.Tests.ps1: -------------------------------------------------------------------------------- 1 | # Tests related to Bug 2817913 Start-Process -Wait sometimes doesn't wait 2 | # It seems when passing SafeHandle of the process to AssignProcessToJobObject, the handle gets corrupted sometimes. 3 | # The fix is to revert back to use raw handle (IntPtr) of the process for both FullCLR and CoreCLR. 4 | 5 | Describe "Tests for Start-Process -Wait -PassThru" -Tags "Innerloop", "BVT" { 6 | 7 | It "Process object returned from Start-Process -Wait -PassThru should have ExitCode to be 0" { 8 | $iterations = 5 9 | $errorCount = 0 10 | while ($iterations -gt 0) 11 | { 12 | $p = Start-Process cmd.exe -WindowStyle Hidden -ArgumentList "/C echo 1" -PassThru -Wait 13 | If ($p.ExitCode -eq $null -or $p.ExitCode -ne 0) { 14 | $errorCount ++ 15 | } 16 | $iterations -- 17 | } 18 | $errorCount | Should Be 0 19 | } 20 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/Pester.ConvertString.Tests.ps1: -------------------------------------------------------------------------------- 1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | $data = Join-Path $here "StringManipulationData\ConvertString" 3 | 4 | Describe "Convert-String test cases" { 5 | 6 | It "Changes first and last name with one Example" { 7 | 8 | $result = "Gustavo Soares" | Convert-String -Example "camilla araujo=araujo, c." 9 | $result | Should be "Soares, G." 10 | } 11 | 12 | It "Changes first and last name with one Example, and three inputs" { 13 | 14 | $result = "Lee Holmes", "Gustavo Soares", "Sumit Gulwani", "Vu Le" | 15 | Convert-String -Example "camilla araujo=araujo, c." 16 | 17 | $result[0] | Should be "Holmes, L." 18 | $result[1] | Should be "Soares, G." 19 | $result[2] | Should be "Gulwani, S." 20 | $result[3] | Should be "Le, V." 21 | } 22 | 23 | It "Changes first and last name with two Examples" { 24 | 25 | $examples = [PSCustomObject] @{ Before = 'camilla araujo'; After = 'araujo, c.' }, 26 | [PSCustomObject] @{ Before = 'lee holmes'; After = 'holmes, l.' } 27 | $result = "Gustavo Soares" | Convert-String -Example $examples 28 | 29 | $result | Should be "Soares, G." 30 | } 31 | 32 | It "Changes first and last name with one dictionary example" { 33 | $result = "Gustavo Soares" | Convert-String -Example @{ Before = "camilla araujo"; After = "araujo, c." } 34 | } 35 | 36 | It "Changes first and last name with two dictionary example" { 37 | $result = "Gustavo Soares" | Convert-String -Example @(@{ Before = "camilla araujo"; After = "araujo, c." },@{ Before = "vu le"; After = "le, v." }) 38 | } 39 | 40 | It "Check invalid text example" { 41 | { "Gustavo Soares" | Convert-String -Example "camilla araujo" } | Should Throw 42 | } 43 | 44 | It "Check invalid psobject examples" { 45 | $examples = Import-Csv $data\incorrect-examples.csv 46 | { "Gustavo Soares" | Convert-String -Example $examples } | Should Throw 47 | } 48 | 49 | It "Replace by empty" { 50 | $examples = Import-Csv $data\replace-name-by-empty.csv 51 | $result = "Gustavo Soares" | Convert-String -Example $examples 52 | $result.length -eq 0 | Should be true 53 | } 54 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/Pester.DelimitedText.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "DelimitedText" { 2 | 3 | It "verifies automatic property generation" { 4 | 5 | $result = "Hello 9", "Hello 10", "Hello 90" | ConvertFrom-String 6 | 7 | ## Verify first properties got extracted 8 | $result[0].P1 | Should be 'Hello' 9 | $result[1].P1 | Should be 'Hello' 10 | $result[2].P1 | Should be 'Hello' 11 | 12 | ## Verify second properties got extracted 13 | $result[0].P2 | Should be 9 14 | $result[1].P2 | Should be 10 15 | $result[2].P2 | Should be 90 16 | } 17 | 18 | It "verifies property overflow generation" { 19 | 20 | $result = "Hello 9" | ConvertFrom-String -PropertyNames A 21 | 22 | $result.A | Should be 'Hello' 23 | $result.P2 | Should be 9 24 | } 25 | 26 | It "verifies property renaming" { 27 | 28 | $result = "Hello 9" | ConvertFrom-String -PN B,C 29 | 30 | $result.B | Should be 'Hello' 31 | $result.C | Should be '9' 32 | } 33 | 34 | It "verifies property typing of numbers" { 35 | 36 | $result = "Hello 9" | ConvertFrom-String -Property B,C 37 | $result.C.GetType().FullName | Should be 'System.Byte' 38 | } 39 | 40 | It "verifies property typing of TimeSpan" { 41 | 42 | $result = "Hello 1:00" | ConvertFrom-String -Property B,C 43 | $result.C.GetType().FullName | Should be 'System.TimeSpan' 44 | } 45 | 46 | It "verifies property typing of DateTime" { 47 | 48 | $result = "Hello 1/1/2012" | ConvertFrom-String -Property B,C 49 | $result.C.GetType().FullName | Should be 'System.DateTime' 50 | } 51 | 52 | It "verifies property typing of Char" { 53 | 54 | $result = "Hello A" | ConvertFrom-String -Property B,C 55 | $result.C.GetType().FullName | Should be 'System.Char' 56 | } 57 | 58 | It "verifies empty strings don't turn into INTs" { 59 | 60 | $result = "Hello" | ConvertFrom-String -Delimiter 'l' 61 | $result.P2.GetType().FullName | Should be 'System.String' 62 | } 63 | 64 | It "verifies property typing of String" { 65 | 66 | $result = "Hello World" | ConvertFrom-String -Property B,C 67 | $result.C.GetType().FullName | Should be 'System.String' 68 | } 69 | 70 | It "verifies the ability to change the delimiter" { 71 | 72 | $result = "Hello-World" | ConvertFrom-String -Delimiter '-' 73 | $result.P1 | Should be 'Hello' 74 | $result.P2 | Should be 'World' 75 | } 76 | 77 | It "verifies that only matching text gets parsed" { 78 | 79 | $result = "Foo1","Hello1 World1","Hello-World" | ConvertFrom-String -Delimiter '-' 80 | $result.P1 | Should be 'Hello' 81 | $result.P2 | Should be 'World' 82 | @($result).Count | Should be 1 83 | } 84 | 85 | It "verifies that a good error message is returned from an invalid regular expression" { 86 | 87 | try 88 | { 89 | $result = "Hello World" | ConvertFrom-String -Delimiter '[' 90 | } 91 | catch 92 | { 93 | $errorRecord = $_ 94 | } 95 | 96 | $errorRecord.FullyQualifiedErrorId | Should be "InvalidRegularExpression,Microsoft.PowerShell.Commands.StringManipulation.ConvertFromStringCommand" 97 | } 98 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/Pester.History.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "History cmdlet test cases" { 2 | 3 | It "Tests Invoke-History on a cmdlet that generates output on all streams" { 4 | $streamSpammer = ' 5 | function StreamSpammer 6 | { 7 | [CmdletBinding()] 8 | param() 9 | 10 | Write-Debug "Debug" 11 | Write-Error "Error" 12 | Write-Information "Information" 13 | Write-Progress "Progress" 14 | Write-Verbose "Verbose" 15 | Write-Warning "Warning" 16 | "Output" 17 | } 18 | 19 | $informationPreference = "Continue" 20 | $debugPreference = "Continue" 21 | $verbosePreference = "Continue" 22 | ' 23 | 24 | $invocationSettings = New-Object System.Management.Automation.PSInvocationSettings 25 | $invocationSettings.AddToHistory = $true 26 | $ps = [PowerShell]::Create() 27 | $null = $ps.AddScript($streamSpammer).Invoke() 28 | $ps.Commands.Clear() 29 | $null = $ps.AddScript("StreamSpammer"); 30 | $null = $ps.Invoke($null, $invocationSettings) 31 | $ps.Commands.Clear() 32 | $null = $ps.AddScript("Invoke-History -id 1") 33 | $result = $ps.Invoke($null, $invocationSettings) 34 | $outputCount = $( 35 | $ps.Streams.Error; 36 | $ps.Streams.Progress; 37 | $ps.Streams.Verbose; 38 | $ps.Streams.Debug; 39 | $ps.Streams.Warning; 40 | $ps.Streams.Information).Count 41 | $ps.Dispose() 42 | 43 | ## Twice per stream - once for the original invocatgion, and once for the re-invocation 44 | $outputCount | Should be 12 45 | } 46 | 47 | It "Tests Invoke-History on a private command" { 48 | 49 | $invocationSettings = New-Object System.Management.Automation.PSInvocationSettings 50 | $invocationSettings.AddToHistory = $true 51 | $ps = [PowerShell]::Create() 52 | $null = $ps.AddScript("(Get-Command Get-Process).Visibility = 'Private'").Invoke() 53 | $ps.Commands.Clear() 54 | $null = $ps.AddScript("Get-Process -id $pid") 55 | $null = $ps.Invoke($null, $invocationSettings) 56 | $ps.Commands.Clear() 57 | $null = $ps.AddScript("Invoke-History -id 1") 58 | $result = $ps.Invoke($null, $invocationSettings) 59 | $errorResult = $ps.Streams.Error[0].FullyQualifiedErrorId 60 | $ps.Dispose() 61 | 62 | $errorResult | Should be CommandNotFoundException 63 | } 64 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/StringManipulationData/ConvertString/incorrect-examples.csv: -------------------------------------------------------------------------------- 1 | "before" 2 | "Camilla Araujo" 3 | "Yohanna Klafke" 4 | -------------------------------------------------------------------------------- /Commands/Cmdlets/StringManipulationData/ConvertString/replace-name-by-empty.csv: -------------------------------------------------------------------------------- 1 | "before","after" 2 | "Camilla Araujo","" 3 | "Yohanna Klafke","" 4 | -------------------------------------------------------------------------------- /Commands/Cmdlets/SymbolicLinksGenerator.psm1: -------------------------------------------------------------------------------- 1 | ParameterGenerator -name SymbolicLinkParameterValidationGenerator -definition { 2 | 3 | $returnObject = @() 4 | 5 | $targetValues = @("", $null, "$global:targetfile", "C:\NonExistentFile.txt", "HKLM:\Software") 6 | $pathValues = @("", $null, $(Join-Path $global:testDestinationRoot "ValidDestination.txt"), "Env:\APPDATA") 7 | $itemTypes = @("SymbolicLink", "Junction", "HardLink") 8 | 9 | foreach($target in $targetValues) 10 | { 11 | foreach($path in $pathValues) 12 | { 13 | foreach($type in $itemTypes) 14 | { 15 | if($path -eq $null) 16 | { 17 | $returnObject += New-Object PSObject -Property @{ Path = $path ; 18 | Target = $target; 19 | ItemType = $type; 20 | ExpectedError = "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.NewItemCommand" } 21 | } 22 | elseif(($path -eq "")) 23 | { 24 | $returnObject += New-Object PSObject -Property @{ Path = $path ; 25 | Target = $target; 26 | ItemType = $type; 27 | ExpectedError = "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.NewItemCommand" } 28 | } 29 | elseif($target -eq $null) 30 | { 31 | $returnObject += New-Object PSObject -Property @{ Path = $path ; 32 | Target = $target; 33 | ItemType = $type; 34 | ExpectedError = "ArgumentNull,Microsoft.PowerShell.Commands.NewItemCommand" } 35 | } 36 | elseif(($target -eq "")) 37 | { 38 | $returnObject += New-Object PSObject -Property @{ Path = $path ; 39 | Target = $target; 40 | ItemType = $type; 41 | ExpectedError = "ArgumentNull,Microsoft.PowerShell.Commands.NewItemCommand" } 42 | } 43 | elseif(($path -eq "C:\NonExistentFile.txt") -and ($Target -eq $(Join-Path $global:testDestinationRoot "ValidDestination.txt"))) 44 | { 45 | $returnObject += New-Object PSObject -Property @{ Path = $path ; 46 | Target = $target; 47 | ItemType = $type; 48 | ExpectedError = "System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.NewItemCommand" } 49 | } 50 | elseif($target -eq "HKLM:\Software") 51 | { 52 | $returnObject += New-Object PSObject -Property @{ Path = $path ; 53 | Target = $target; 54 | ItemType = $type; 55 | ExpectedError = "NotSupported,Microsoft.PowerShell.Commands.NewItemCommand" } 56 | } 57 | } 58 | } 59 | } 60 | 61 | $returnObject 62 | } 63 | 64 | ParameterGenerator -name SymbolicLinkValidParametersGenerator -definition { 65 | 66 | $returnObject = @() 67 | 68 | $destinationDirectory = join-path $global:testDestinationRoot "SymbolicDirectory" 69 | $destinationFile = join-path $global:testDestinationRoot "SymbolicFile.txt" 70 | 71 | $otherDrive = Get-OtherFileSystemDrive -path $global:targetfile 72 | $otherDriveDestination = Join-path $otherDrive "symbolicLink.txt" 73 | $returnObject += New-Object PSObject -Property @{ Target = $global:targetfile ; Path = $otherDriveDestination } 74 | 75 | 76 | $shareRoot = Get-ShareRoot 77 | $shareDestination = Join-Path $shareRoot "shareSymbolicLink.txt" 78 | $shareSource = Join-Path $shareRoot "targetfile.txt" 79 | $returnObject += New-Object PSObject -Property @{ Target = $global:targetfile ; Path = $shareDestination } 80 | $returnObject += New-Object PSObject -Property @{ Target = $shareSource ; Path = $shareDestination } 81 | $returnObject += New-Object PSObject -Property @{ Target = $shareSource ; Path = $destinationFile } 82 | 83 | ##On non English machine this will contain non-english characters. 84 | #$nonEnglishDestination = Join-Path $env:APPDATA "TODO" 85 | #$returnObject += New-Object PSObject -Property @{ Path = $shareSource ; LinkDestination = $nonEnglishDestination } 86 | 87 | $returnObject 88 | } 89 | 90 | function Get-OtherFileSystemDrive($path) 91 | { 92 | $currentDrive = [system.io.path]::GetPathRoot($path) 93 | $drives = Get-PSDrive -PSProvider FileSystem 94 | 95 | $selectedOtherDrive = $null 96 | 97 | $drives | %{ if( ($_.Root -ne $currentDrive) -and ($_.Used -gt 0)) { $selectedOtherDrive = $_.Root ; return $selectedOtherDrive} } 98 | } 99 | 100 | function Get-ShareRoot 101 | { 102 | $exists = Get-SmbShare -Name "LoopBackShare" -ErrorAction SilentlyContinue 103 | 104 | if(-not $exists) 105 | { 106 | "\\$env:COMPUTERNAME" + "\" + (New-SmbShare -Path $global:testDestinationRoot -Name "LoopBackShare" -FullAccess "$env:USERDNSDOMAIN\$env:USERNAME").Name 107 | } 108 | else 109 | { 110 | "\\$env:COMPUTERNAME\LoopBackShare" 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.commands.cmdlets.process.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Process cmdlets" { 2 | 3 | Context "Start Process" { 4 | BeforeAll { 5 | $username = "StartProcessTest" 6 | $password = "pass@word1" 7 | $computerName = $env:COMPUTERNAME 8 | 9 | ## Setup test user 10 | Start-Process -FilePath net.exe -ArgumentList ("user $username $password /add") -NoNewWindow -Wait 11 | 12 | ## Create credential for the user. 13 | $secureString = $password | ConvertTo-SecureString -AsPlainText -Force 14 | $credential = New-Object System.Management.Automation.PSCredential $username, $secureString 15 | } 16 | 17 | ## Test starts a command on powershell launched with a credential. Followup of bug Win8:545033 18 | 19 | It "can start process with credentials" { 20 | 21 | $output = "$env:temp\output.txt" 22 | ## Start a process with credential 23 | Start-Process powershell.exe -Credential $credential -ArgumentList ("-command whoami") -NoNewWindow -Wait -WorkingDirectory $env:SystemDrive -RedirectStandardOutput $output -LoadUserProfile 24 | 25 | ## Read the output of whoami 26 | $result = Get-Content $output 27 | $result | Should Be "$computerName\$username" 28 | } 29 | 30 | AfterAll { 31 | ## Remove test user 32 | Start-Process -FilePath net.exe -ArgumentList ("user $username /delete") -NoNewWindow -Wait 33 | Remove-Item $output -Force -ErrorAction SilentlyContinue 34 | 35 | $query = "select * from Win32_UserProfile where LocalPath LIKE '%$username%'" 36 | $userProfile = Get-CimInstance -Query $query 37 | 38 | if($userProfile) 39 | { 40 | ## Remove localpath 41 | Remove-Item -Recurse -Path ($userProfile.LocalPath) -ErrorAction SilentlyContinue -Force 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.core.job.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Job cmdlets" -Tags 'innerloop' { 2 | Context "Start-Job" { 3 | It "should be able to load by definitionName and type" { 4 | $jobname = "StartJobShouldBeAbleLoadByDefinitionNameAndType" 5 | try 6 | { 7 | $scheduledjob = Get-ScheduledJob -Name $jobname -ErrorAction SilentlyContinue 8 | 9 | if (!$scheduledjob) 10 | { 11 | $scheduledjob = Register-ScheduledJob -Name $jobname -ScriptBlock {echo $args[0]} -ArgumentList ($jobname) 12 | } 13 | 14 | $job = Start-Job -DefinitionName $jobname -Type "*ScheduledJob*" 15 | $actual = $job | Wait-Job | Receive-Job 16 | $actual | Should Be $jobname 17 | } 18 | finally 19 | { 20 | Remove-Job -Name $jobname -Force -ErrorAction SilentlyContinue 21 | Unregister-ScheduledJob -Name $jobname -Force -ErrorAction SilentlyContinue 22 | } 23 | } 24 | 25 | It "no recurse should not return result from child jobs" { 26 | $message = "StartJobNoRecurseShouldNotReturnTheResultsFromAnyChildJobs" 27 | try 28 | { 29 | $job = Start-Job {echo $args[0]} -ArgumentList ($message) 30 | $result = $job | Wait-Job | Receive-Job -NoRecurse 31 | $result | Should BeNullOrEmpty 32 | 33 | $result = $job.ChildJobs | Receive-Job 34 | $result | Should Be $message 35 | } 36 | finally 37 | { 38 | $job | Remove-Job -Force 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.diagnostics.counter.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Get-Counter" -Tags "innerloop" { 2 | It "should run for 5 iterations in continuous mode" { 3 | $result = [Powershell]::Create().AddScript('$a = 0; get-counter -Continuous | %{ $a++; if ($a -eq 5) {$a; break}}').Invoke() 4 | $result | Should Be 5 5 | } 6 | 7 | It "returns expected max count" { 8 | (get-counter -MaxSamples 5).Count | Should Be 5 9 | } 10 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.management.computersecurechannel.tests.ps1: -------------------------------------------------------------------------------- 1 | function ShouldRun($testCaseName) 2 | { 3 | # test-computersecurechannel only works if the test machine is on a domain 4 | if($env:PROCESSOR_ARCHITECTURE -eq "ARM") 5 | { 6 | return $false 7 | } 8 | return $true 9 | } 10 | 11 | if(ShouldRun) 12 | { 13 | Describe "Test-ComputerSecureChannel" -Tags "innerloop" { 14 | 15 | BeforeAll { 16 | $localHostNames = @( 17 | "localHost", 18 | ".", 19 | "::1", 20 | "127.0.0.1", 21 | $env:COMPUTERNAME, 22 | ($env:COMPUTERNAME + '.' + [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().DomainName) 23 | ) 24 | } 25 | 26 | It "works with localhost" { 27 | $localHostNames | % { Test-ComputerSecureChannel -Server $_ | Should Be $true } 28 | } 29 | 30 | It -pending "works with repair" { 31 | Test-ComputerSecureChannel -Repair | Should Be $true 32 | } 33 | 34 | It "throws error with invalid server name" { 35 | try 36 | { 37 | Test-ComputerSecureChannel -Server TestComputerSecureChannelFailsWithInvalidServerName 38 | } 39 | catch 40 | { 41 | $secureChannelError = $_ 42 | } 43 | 44 | $secureChannelError.FullyQualifiedErrorId | Should Be 'AddressResolutionException,Microsoft.PowerShell.Commands.TestComputerSecureChannelCommand' 45 | } 46 | 47 | It "throws error with null credential" { 48 | try 49 | { 50 | Test-ComputerSecureChannel -Credential 51 | } 52 | catch 53 | { 54 | $secureChannelError = $_ 55 | } 56 | 57 | $secureChannelError.FullyQualifiedErrorId | Should Be 'MissingArgument,Microsoft.PowerShell.Commands.TestComputerSecureChannelCommand' 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.alias.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Alias tests" -Tags "innerloop" { 2 | 3 | BeforeAll { 4 | $testPath = Join-Path testdrive:\ ("testAlias\[.test") 5 | New-Item -ItemType Directory -Path $testPath -Force | Out-Null 6 | 7 | class TestData 8 | { 9 | [string] $testName 10 | [string] $testFile 11 | [string] $expectedError 12 | 13 | TestData($name, $file, $error) 14 | { 15 | $this.testName = $name 16 | $this.testFile = $file 17 | $this.expectedError = $error 18 | } 19 | } 20 | } 21 | 22 | Context "Export-Alias literal path" { 23 | BeforeAll { 24 | $csvFile = Join-Path $testPath "alias.csv" 25 | $ps1File = Join-Path $testPath "alias.ps1" 26 | 27 | $testCases = @() 28 | $testCases += [TestData]::new("CSV", $csvFile, [NullString]::Value) 29 | $testCases += [TestData]::new("PS1", $ps1File, [NullString]::Value) 30 | $testCases += [TestData]::new("Empty string", "", "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ExportAliasCommand") 31 | $testCases += [TestData]::new("Null", [NullString]::Value, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportAliasCommand") 32 | $testCases += [TestData]::new("Non filesystem provider", 'cert:\alias.ps1', "ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ExportAliasCommand") 33 | } 34 | 35 | $testCases | % { 36 | 37 | It "for $($_.testName)" { 38 | 39 | $test = $_ 40 | try 41 | { 42 | Export-Alias -LiteralPath $test.testFile -ErrorAction SilentlyContinue 43 | } 44 | catch 45 | { 46 | $exportAliasError = $_ 47 | } 48 | 49 | if($test.expectedError -eq $null) 50 | { 51 | Test-Path -LiteralPath $test.testFile | Should Be $true 52 | } 53 | else 54 | { 55 | $exportAliasError.FullyqualifiedErrorId | Should Be $test.expectedError 56 | } 57 | } 58 | 59 | AfterEach { 60 | Remove-Item -LiteralPath $test.testFile -Force -ErrorAction SilentlyContinue 61 | } 62 | } 63 | 64 | It "when file exists with NoClobber" { 65 | Export-Alias -LiteralPath $csvFile 66 | 67 | try 68 | { 69 | Export-Alias -LiteralPath $csvFile -NoClobber 70 | } 71 | catch 72 | { 73 | $exportAliasError = $_ 74 | } 75 | 76 | $exportAliasError.FullyQualifiedErrorId | Should Be "NoClobber,Microsoft.PowerShell.Commands.ExportAliasCommand" 77 | } 78 | } 79 | 80 | Context "Export-All inside a literal path" { 81 | BeforeEach { 82 | Push-Location -LiteralPath $testPath 83 | } 84 | 85 | It "with a CSV file" { 86 | Export-Alias "alias.csv" 87 | Test-Path -LiteralPath (Join-Path $testPath "alias.csv") | Should Be $true 88 | } 89 | 90 | It "with NoClobber" { 91 | $path = Export-Alias alias.csv 92 | 93 | try 94 | { 95 | Export-Alias alias.csv -NoClobber 96 | } 97 | catch 98 | { 99 | $exportAliasError = $_ 100 | } 101 | 102 | $exportAliasError.FullyQualifiedErrorId | Should Be "NoClobber,Microsoft.PowerShell.Commands.ExportAliasCommand" 103 | } 104 | 105 | AfterEach { 106 | Pop-Location 107 | } 108 | } 109 | 110 | Context "Import-Alias literal path" { 111 | 112 | BeforeAll { 113 | $csvFile = Join-Path $testPath "alias.csv" 114 | $ps1File = Join-Path $testPath "alias.ps1" 115 | 116 | $testCases = @() 117 | $testCases += [TestData]::new("Empty string", "", "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ImportAliasCommand") 118 | $testCases += [TestData]::new("Null", [NullString]::Value, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ImportAliasCommand") 119 | $testCases += [TestData]::new("Non filesystem provider", 'cert:\alias.ps1', "NotSupported,Microsoft.PowerShell.Commands.ImportAliasCommand") 120 | } 121 | 122 | $testCases | % { 123 | 124 | It "for $($_.testName)" { 125 | $test = $_ 126 | 127 | try 128 | { 129 | Import-Alias -LiteralPath $test.testFile -ErrorAction SilentlyContinue 130 | } 131 | catch 132 | { 133 | $exportAliasError = $_ 134 | } 135 | 136 | $exportAliasError.FullyqualifiedErrorId | Should Be $test.expectedError 137 | } 138 | } 139 | 140 | It "can be done from a CSV file" { 141 | 142 | # alias file definition content 143 | $aliasDefinition = @' 144 | "myuh","update-help","","ReadOnly, AllScope" 145 | '@ 146 | 147 | $aliasFile = Join-Path $testPath "alias.csv" 148 | $aliasDefinition | Out-File -LiteralPath $aliasFile 149 | 150 | Import-Alias -LiteralPath $aliasFile 151 | 152 | # Verify that the alias was imported 153 | $definedAlias = Get-Alias myuh 154 | 155 | $definedAlias | Should Not Be $null 156 | $definedAlias.Name | Should Be "myuh" 157 | $definedAlias.Definition | Should Be "update-help" 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.clixml.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "CliXml test" -Tags "innerloop" { 2 | 3 | BeforeAll { 4 | $testFilePath = Join-Path "testdrive:\" "testCliXml" 5 | $subFilePath = Join-Path $testFilePath ".test" 6 | 7 | if(test-path $testFilePath) 8 | { 9 | Remove-Item $testFilePath -Force -Recurse 10 | } 11 | 12 | # Create the test File and push the location into specified path 13 | New-Item -Path $testFilePath -ItemType Directory | Out-Null 14 | New-Item -Path $subFilePath -ItemType Directory | Out-Null 15 | Push-Location $testFilePath 16 | 17 | class TestData 18 | { 19 | [string] $testName 20 | [object] $inputObject 21 | [string] $expectedError 22 | [string] $testFile 23 | 24 | TestData($name, $file, $inputObj, $error) 25 | { 26 | $this.testName = $name 27 | $this.inputObject = $inputObj 28 | $this.expectedError = $error 29 | $this.testFile = $file 30 | } 31 | } 32 | } 33 | 34 | AfterAll { 35 | Pop-Location 36 | } 37 | 38 | Context "Export-CliXml" { 39 | BeforeAll { 40 | $gpsList = Get-Process powershell 41 | $gps = $gpsList | Select-Object -First 1 42 | $filePath = Join-Path $subFilePath 'gps.xml' 43 | 44 | $testData = @() 45 | $testData += [TestData]::new("with path as Null", [NullString]::Value, $gps, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportClixmlCommand") 46 | $testData += [TestData]::new("with path as Empty string", "", $gps, "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ExportClixmlCommand") 47 | $testData += [TestData]::new("with path as non filesystem provider", "cert:\", $gps, "ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ExportClixmlCommand") 48 | } 49 | 50 | AfterEach { 51 | Remove-Item $filePath -Force -ErrorAction SilentlyContinue 52 | } 53 | 54 | $testData | % { 55 | 56 | It "$($_.testName)" { 57 | $test = $_ 58 | 59 | try 60 | { 61 | Export-Clixml -LiteralPath $test.testFile -InputObject $test.inputObject -Force 62 | } 63 | catch 64 | { 65 | $exportCliXmlError = $_ 66 | } 67 | 68 | $exportCliXmlError.FullyQualifiedErrorId | Should Be $test.expectedError 69 | } 70 | } 71 | 72 | It "can be created with literal path" { 73 | 74 | $filePath = Join-Path $subFilePath 'gps.xml' 75 | Export-Clixml -LiteralPath $filePath -InputObject ($gpsList | Select-Object -First 1) 76 | 77 | $filePath | Should Exist 78 | 79 | $fileContent = Get-Content $filePath 80 | $isExisted = $false 81 | 82 | foreach($item in $fileContent) 83 | { 84 | foreach($gpsItem in $gpsList) 85 | { 86 | $checkId = $gpsItem.Id 87 | if (($null -ne $(Select-String -InputObject $item -SimpleMatch $checkId)) -and ($null -ne $(Select-String -InputObject $item -SimpleMatch "Id"))) 88 | { 89 | $isExisted = $true 90 | break; 91 | } 92 | } 93 | } 94 | 95 | $isExisted | Should Be $true 96 | } 97 | 98 | It "can be created with literal path using pipeline" { 99 | 100 | 101 | $filePath = Join-Path $subFilePath 'gps.xml' 102 | ($gpsList | Select-Object -First 1) | Export-Clixml -LiteralPath $filePath 103 | 104 | $filePath | Should Exist 105 | 106 | $fileContent = Get-Content $filePath 107 | $isExisted = $false 108 | 109 | foreach($item in $fileContent) 110 | { 111 | foreach($gpsItem in $gpsList) 112 | { 113 | $checkId = $gpsItem.Id 114 | if (($null -ne $(Select-String -InputObject $item -SimpleMatch $checkId)) -and ($null -ne $(Select-String -InputObject $item -SimpleMatch "Id"))) 115 | { 116 | $isExisted = $true 117 | break; 118 | } 119 | } 120 | } 121 | 122 | $isExisted | Should Be $true 123 | } 124 | } 125 | 126 | Context "Import-CliXML" { 127 | BeforeAll { 128 | $gpsList = Get-Process powershell 129 | $gps = $gpsList | Select-Object -First 1 130 | $filePath = Join-Path $subFilePath 'gps.xml' 131 | 132 | $testData = @() 133 | $testData += [TestData]::new("with path as Null", [NullString]::Value, $null, "ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ImportClixmlCommand") 134 | $testData += [TestData]::new("with path as Empty string", "", $null, "ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ImportClixmlCommand") 135 | $testData += [TestData]::new("with path as non filesystem provider", "cert:\", $null, "ReadWriteFileNotFileSystemProvider,Microsoft.PowerShell.Commands.ImportClixmlCommand") 136 | } 137 | 138 | $testData | % { 139 | 140 | It "$($_.testName)" { 141 | $test = $_ 142 | 143 | try 144 | { 145 | Import-Clixml -LiteralPath $test.testFile 146 | } 147 | catch 148 | { 149 | $importCliXmlError = $_ 150 | } 151 | 152 | $importCliXmlError.FullyQualifiedErrorId | Should Be $test.expectedError 153 | } 154 | } 155 | 156 | It "can import from a literal path" { 157 | Export-Clixml -LiteralPath $filePath -InputObject $gps 158 | $filePath | Should Exist 159 | 160 | $fileContent = Get-Content $filePath 161 | $fileContent | Should Not Be $null 162 | 163 | $importedProcess = Import-Clixml $filePath 164 | $gps.ProcessName | Should Be $importedProcess.ProcessName 165 | $gps.Id | Should Be $importedProcess.Id 166 | } 167 | 168 | It "can import from a literal path using pipeline" { 169 | $gps | Export-Clixml -LiteralPath $filePath 170 | $filePath | Should Exist 171 | 172 | $fileContent = Get-Content $filePath 173 | $fileContent | Should Not Be $null 174 | 175 | $importedProcess = Import-Clixml $filePath 176 | $gps.ProcessName | Should Be $importedProcess.ProcessName 177 | $gps.Id | Should Be $importedProcess.Id 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.command.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Trace-Command" { 2 | 3 | Context "Listner options" { 4 | BeforeAll { 5 | $logFile = New-Item "TestDrive:\traceCommandLog.txt" -Force 6 | $actualLogFile = New-Item "TestDrive:\actualTraceCommandLog.txt" -Force 7 | } 8 | 9 | AfterEach { 10 | Remove-Item "TestDrive:\traceCommandLog.txt" -Force -ErrorAction SilentlyContinue 11 | Remove-Item "TestDrive:\actualTraceCommandLog.txt" -Force -ErrorAction SilentlyContinue 12 | } 13 | 14 | It "LogicalOperationStack works" { 15 | $keyword = "Trace_Command_ListenerOption_LogicalOperationStack_Foo" 16 | $stack = [System.Diagnostics.Trace]::CorrelationManager.LogicalOperationStack 17 | $stack.Push($keyword) 18 | 19 | Trace-Command -Name * -Expression {echo Foo} -ListenerOption LogicalOperationStack -FilePath $logfile 20 | 21 | $log = Get-Content $logfile | Where-Object {$_ -like "*LogicalOperationStack=$keyword*"} 22 | $log.Count | Should BeGreaterThan 0 23 | } 24 | 25 | It "Callstack works" { 26 | Trace-Command -Name * -Expression {echo Foo} -ListenerOption Callstack -FilePath $logfile 27 | $log = Get-Content $logfile | Where-Object {$_ -like "*Callstack= * System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)*"} 28 | $log.Count | Should BeGreaterThan 0 29 | } 30 | 31 | It "Datetime works" { 32 | $expectedDate = Trace-Command -Name * -Expression {Get-Date} -ListenerOption DateTime -FilePath $logfile 33 | $log = Get-Content $logfile | Where-Object {$_ -like "*DateTime=*"} 34 | $results = $log | ForEach-Object {[DateTime]::Parse($_.Split("=")[1])} 35 | 36 | ## allow a gap of 6 seconds. All traces should be finished within 6 seconds. 37 | $allowedGap = [timespan](60 * 1000 * 1000) 38 | $results | ForEach-Object { 39 | $actualGap = $_ - $expectedDate; 40 | if ($expectedDate -gt $_) 41 | { 42 | $actualGap = $expectedDate - $_; 43 | } 44 | 45 | $allowedGap | Should BeGreaterThan $actualGap 46 | } 47 | } 48 | 49 | It "None options has no effect" { 50 | Trace-Command -Name * -Expression {echo Foo} -ListenerOption None -FilePath $actualLogfile 51 | Trace-Command -name * -Expression {echo Foo} -FilePath $logfile 52 | 53 | Compare-Object (Get-Content $actualLogfile) (Get-Content $logfile) | Should BeNullOrEmpty 54 | } 55 | 56 | It "ThreadID works" { 57 | Trace-Command -Name * -Expression {echo Foo} -ListenerOption ThreadId -FilePath $logfile 58 | $log = Get-Content $logfile | Where-Object {$_ -like "*ThreadID=*"} 59 | $results = $log | ForEach-Object {$_.Split("=")[1]} 60 | 61 | $results | % { $_ | Should Be ([threading.thread]::CurrentThread.ManagedThreadId) } 62 | } 63 | 64 | It "Timestamp creates logs in ascending order" { 65 | Trace-Command -Name * -Expression {echo Foo} -ListenerOption Timestamp -FilePath $logfile 66 | $log = Get-Content $logfile | Where-Object {$_ -like "*Timestamp=*"} 67 | $results = $log | ForEach-Object {$_.Split("=")[1]} 68 | $sortedResults = $results | Sort-Object 69 | $sortedResults | Should Be $results 70 | } 71 | 72 | It "ProcessId logs current process Id" { 73 | Trace-Command -Name * -Expression {echo Foo} -ListenerOption ProcessId -FilePath $logfile 74 | $log = Get-Content $logfile | Where-Object {$_ -like "*ProcessID=*"} 75 | $results = $log | ForEach-Object {$_.Split("=")[1]} 76 | 77 | $results | ForEach-Object { $_ | Should Be $pid } 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.formatdata.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "FormatData" { 2 | 3 | Context "Export" { 4 | It "can export all types" { 5 | try 6 | { 7 | $expectAllFormat = Get-FormatData -typename * 8 | $expectAllFormat | Export-FormatData -path $env:temp\allformat.ps1xml -IncludeScriptBlock 9 | 10 | $sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() 11 | $sessionState.Formats.Clear() 12 | $sessionState.Types.Clear() 13 | 14 | $runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace($sessionState) 15 | $runspace.Open() 16 | 17 | $runspace.CreatePipeline("Update-FormatData -AppendPath $env:temp\allformat.ps1xml").Invoke() 18 | $actualAllFormat = $runspace.CreatePipeline("Get-FormatData -TypeName *").Invoke() 19 | 20 | $expectAllFormat.Count | Should Be $actualAllFormat.Count 21 | Compare-Object $expectAllFormat $actualAllFormat | Should Be $null 22 | $runspace.Close() 23 | } 24 | finally 25 | { 26 | Remove-Item -Path $env:temp\allformat.ps1xml -Force -ErrorAction SilentlyContinue 27 | } 28 | } 29 | 30 | It "works with literal path" { 31 | $filename = 'TestDrive:\[formats.ps1xml' 32 | Get-FormatData -TypeName * | Export-FormatData -LiteralPath $filename 33 | (Test-Path -LiteralPath $filename) | Should Be $true 34 | } 35 | 36 | It "should overwrite the destination file" { 37 | $filename = 'TestDrive:\ExportFormatDataWithForce.ps1xml' 38 | $unexpected = "SHOULD BE OVERWRITTEN" 39 | $unexpected | Out-File -FilePath $filename -Force 40 | $file = Get-Item $filename 41 | $file.IsReadOnly = $true 42 | Get-FormatData -TypeName * | Export-FormatData -Path $filename -Force 43 | 44 | $actual = @(Get-Content $filename)[0] 45 | $actual | Should Not Be $unexpected 46 | } 47 | 48 | It "should not overwrite the destination file with NoClobber" { 49 | $filename = "TestDrive:\ExportFormatDataWithNoClobber.ps1xml" 50 | Get-FormatData -TypeName * | Export-FormatData -LiteralPath $filename 51 | 52 | try 53 | { 54 | Get-FormatData -TypeName * | Export-FormatData -LiteralPath $filename -NoClobber 55 | } 56 | catch 57 | { 58 | $exportFormatError = $_ 59 | } 60 | 61 | $exportFormatError.FullyQualifiedErrorId | Should Be 'NoClobber,Microsoft.PowerShell.Commands.ExportFormatDataCommand' 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.object.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Object cmdlets" -Tags 'innerloop' { 2 | Context "Group-Object" { 3 | It "AsHashtable returns a hashtable" { 4 | $result = Get-Process | Group-Object -Property ProcessName -AsHashTable 5 | $result["powershell"].Count | Should BeGreaterThan 0 6 | } 7 | 8 | It "AsString returns a string" { 9 | $processes = Get-Process | Group-Object -Property ProcessName -AsHashTable -AsString 10 | $result = $processes.Keys | ForEach-Object {$_.GetType()} 11 | $result[0].Name | Should Be "String" 12 | } 13 | } 14 | 15 | Context "Tee-Object" { 16 | It "with literal path" { 17 | $path = "TestDrive:\[TeeObjectLiteralPathShouldWorkForSpecialFilename].txt" 18 | Write-Output "Test" | Tee-Object -LiteralPath $path | Tee-Object -Variable TeeObjectLiteralPathShouldWorkForSpecialFilename 19 | $TeeObjectLiteralPathShouldWorkForSpecialFilename | Should Be (Get-Content -LiteralPath $path) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.string.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "String cmdlets" -Tags 'innerloop' { 2 | Context "Select-String" { 3 | BeforeAll { 4 | $fileName = New-Item 'TestDrive:\selectStr[ingLi]teralPath.txt' 5 | "abc" | Out-File -LiteralPath $fileName.fullname 6 | "bcd" | Out-File -LiteralPath $fileName.fullname -Append 7 | "cde" | Out-File -LiteralPath $fileName.fullname -Append 8 | 9 | $fileNameWithDots = $fileName.FullName.Replace("\", "\.\") 10 | 11 | $tempFile = New-TemporaryFile 12 | "abc" | Out-File -LiteralPath $tempFile.fullname 13 | "bcd" | Out-File -LiteralPath $tempFile.fullname -Append 14 | "cde" | Out-File -LiteralPath $tempFile.fullname -Append 15 | $driveLetter = $tempFile.PSDrive.Name 16 | $fileNameAsNetworkPath = "\\localhost\$driveLetter`$" + $tempFile.FullName.SubString(2) 17 | 18 | Push-Location "$fileName\.." 19 | } 20 | 21 | AfterAll { 22 | Remove-Item $tempFile -Force -ErrorAction SilentlyContinue 23 | Pop-Location 24 | } 25 | 26 | It "LiteralPath with relative path" { 27 | (select-string -LiteralPath (Get-Item -LiteralPath $fileName).Name "b").count | Should Be 2 28 | } 29 | 30 | It "LiteralPath with absolute path" { 31 | (select-string -LiteralPath $fileName "b").count | Should Be 2 32 | } 33 | 34 | It "LiteralPath with dots in path" { 35 | (select-string -LiteralPath $fileNameWithDots "b").count | Should Be 2 36 | } 37 | 38 | It "Network path" { 39 | (select-string -LiteralPath $fileNameAsNetworkPath "b").count | Should Be 2 40 | } 41 | 42 | It "throws error for non filesystem providers" { 43 | select-string -literalPath cert:\currentuser\my "a" -ErrorAction SilentlyContinue -ErrorVariable selectStringError 44 | $selectStringError.FullyQualifiedErrorId | Should Be 'ProcessingFile,Microsoft.PowerShell.Commands.SelectStringCommand' 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Commands/Cmdlets/pester.utility.xml.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "XML cmdlets" { 2 | Context "Select-XML" { 3 | BeforeAll { 4 | $fileName = New-Item -Path 'TestDrive:\testSelectXml.xml' 5 | Push-Location "$fileName\.." 6 | "" | out-file -LiteralPath $fileName 7 | " " | out-file -LiteralPath $fileName -Append 8 | "" | out-file -LiteralPath $fileName -Append 9 | 10 | $fileNameWithDots = $fileName.FullName.Replace("\", "\.\") 11 | 12 | $driveLetter = [string]($fileName.FullName)[0] 13 | $fileNameAsNetworkPath = "\\localhost\$driveLetter`$" + $fileName.FullName.SubString(2) 14 | 15 | class TestData 16 | { 17 | [string] $testName 18 | [hashtable] $parameters 19 | 20 | TestData($name, $parameters) 21 | { 22 | $this.testName = $name 23 | $this.parameters = $parameters 24 | } 25 | } 26 | 27 | $testcases = @() 28 | $testcases += [TestData]::new('literalpath with relative paths', @{LiteralPath = $fileName.Name; XPath = 'Root'}) 29 | $testcases += [TestData]::new('literalpath with absolute paths', @{LiteralPath = $fileName.FullName; XPath = 'Root'}) 30 | $testcases += [TestData]::new('literalpath with path with dots', @{LiteralPath = $fileNameWithDots; XPath = 'Root'}) 31 | $testcases += [TestData]::new('literalpath with network path', @{LiteralPath = $fileNameAsNetworkPath; XPath = 'Root'}) 32 | $testcases += [TestData]::new('path with relative paths', @{Path = $fileName.Name; XPath = 'Root'}) 33 | $testcases += [TestData]::new('path with absolute paths', @{Path = $fileName.FullName; XPath = 'Root'}) 34 | $testcases += [TestData]::new('path with path with dots', @{Path = $fileNameWithDots; XPath = 'Root'}) 35 | $testcases += [TestData]::new('path with network path', @{Path = $fileNameAsNetworkPath; XPath = 'Root'}) 36 | } 37 | 38 | AfterAll { 39 | Remove-Item -LiteralPath $fileName -Force -ErrorAction SilentlyContinue 40 | Pop-Location 41 | } 42 | 43 | $testcases | % { 44 | 45 | $params = $_.parameters 46 | 47 | It $_.testName { 48 | @(Select-XML @params).Count | Should Be 1 49 | } 50 | } 51 | 52 | It "literalpath with non filesystem path" { 53 | Select-XML -literalPath cert:\currentuser\my "Root" -ErrorVariable selectXmlError -ErrorAction SilentlyContinue 54 | $selectXmlError.FullyQualifiedErrorId | Should Be 'ProcessingFile,Microsoft.PowerShell.Commands.SelectXmlCommand' 55 | } 56 | 57 | It "path with non filesystem path" { 58 | Select-XML -Path cert:\currentuser\my "Root" -ErrorVariable selectXmlError -ErrorAction SilentlyContinue 59 | $selectXmlError.FullyQualifiedErrorId | Should Be 'ProcessingFile,Microsoft.PowerShell.Commands.SelectXmlCommand' 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Contribution.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | We will be adding new tests over time, but we are currently not able to take pull requests, but we do want your input. 3 | If you find issues or other misbehavior, please create an [issue](https://github.com/PowerShell/PowerShell-Tests/issues) and we will review them to see how we can address it. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | 4 | Copyright (c) 2015 Microsoft Corporation. 5 | 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShell-Tests 2 | 3 | *NOTE* This repo has been superceded by [PowerShell/PowerShell](https://github.com/PowerShell/PowerShell/tree/master/test) and will be deleted by Sept 1st, 2017 4 | 5 | This project represents a selection of tests that the PowerShell team 6 | uses when testing PowerShell. More than 12 years of active 7 | development on PowerShell, we have created many different script based 8 | test frameworks. Early in 2015 we started the migration process of our 9 | internally created script based framework tests to the [Pester 10 | framework](https://github.com/pester/Pester) and this project represents 11 | the early fruits of that labor. Our plan is to continue to migrate our 12 | current tests and release them in this Project, with the aim of having all 13 | of our tests available in the OSS community using OSS test frameworks. 14 | 15 | We believe that by releasing these tests, our community can better understand 16 | how we test, use these as models to better understand PowerShell, and 17 | participate with us as we release future versions. 18 | 19 | Some of the tests have either been _Skipped_ or marked as _Pending_, we 20 | expect that these tests will be activated as product changes are made available 21 | in future releases. 22 | 23 | # Feedback 24 | This project will grow over time, but we are currently not able to take 25 | pull requests, but we _do_ want your input. If you find issues or other 26 | misbehavior, please create an issue and we will review them to see how we can 27 | address it. 28 | 29 | # Invoking the tests 30 | You can either clone the project, or download a ZIP. Once the tests have 31 | been placed on your system, you can invoke them as you invoke any other 32 | Pester test: 33 | ``` 34 | PS> Invoke-Pester 35 | ``` 36 | Because a number of our tests create local sessions, it is suggested (for 37 | now) that you run the tests in an elevated PowerShell session as non-admins, 38 | by default, will not have the appropriate permissions. 39 | -------------------------------------------------------------------------------- /Scripting/Classes/MSFT_778492.psm1: -------------------------------------------------------------------------------- 1 | 2 | $foo = 'MSFT_778492 script scope' 3 | 4 | class MSFT_778492 5 | { 6 | [string] F() 7 | { 8 | return $script:foo 9 | } 10 | } 11 | 12 | function Get-MSFT_778492 13 | { 14 | [MSFT_778492]::new() 15 | } 16 | -------------------------------------------------------------------------------- /Scripting/Classes/ProtectedAccess.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | Add-Type -WarningAction Ignore @' 3 | public class Base 4 | { 5 | private int data; 6 | 7 | protected Base() 8 | { 9 | data = 10; 10 | } 11 | 12 | protected Base(int i) 13 | { 14 | data = i; 15 | } 16 | 17 | protected int Field; 18 | protected int Property { get; set; } 19 | public int Property1 { get; protected set; } 20 | public int Property2 { protected get; set; } 21 | 22 | protected int Method() 23 | { 24 | return 32 + data; 25 | } 26 | protected int OverloadedMethod1(int i) 27 | { 28 | return 32 + i + data; 29 | } 30 | protected int OverloadedMethod1(string i) 31 | { 32 | return 1 + data; 33 | } 34 | public int OverloadedMethod2(int i) 35 | { 36 | return 32 + i + data; 37 | } 38 | protected int OverloadedMethod2(string i) 39 | { 40 | return 1 + data; 41 | } 42 | protected int OverloadedMethod3(int i) 43 | { 44 | return 32 + i + data; 45 | } 46 | public int OverloadedMethod3(string i) 47 | { 48 | return 1 + data; 49 | } 50 | } 51 | '@ 52 | 53 | $derived1,$derived2,$derived3 = Invoke-Expression @' 54 | class Derived : Base 55 | { 56 | Derived() : Base() {} 57 | Derived([int] $i) : Base($i) {} 58 | 59 | [int] TestPropertyAccess() 60 | { 61 | $this.Property = 1111 62 | return $this.Property 63 | } 64 | 65 | [int] TestPropertyAccess1() 66 | { 67 | $this.Property1 = 2111 68 | return $this.Property1 69 | } 70 | 71 | [int] TestPropertyAccess2() 72 | { 73 | $this.Property2 = 3111 74 | return $this.Property2 75 | } 76 | 77 | [int] TestDynamicPropertyAccess() 78 | { 79 | $p = 'Property' 80 | $this.$p = 1112 81 | return $this.$p 82 | } 83 | 84 | [int] TestFieldAccess() 85 | { 86 | $this.Field = 11 87 | return $this.Field 88 | } 89 | 90 | [int] TestDynamicFieldAccess() 91 | { 92 | $f = 'Field' 93 | $this.$f = 12 94 | return $this.$f 95 | } 96 | 97 | [int] TestMethodAccess() 98 | { 99 | return $this.Method() 100 | } 101 | 102 | [int] TestDynamicMethodAccess() 103 | { 104 | $m = 'Method' 105 | return $this.$m() 106 | } 107 | 108 | [int] TestOverloadedMethodAccess1a() 109 | { 110 | return $this.OverloadedMethod1(42) 111 | } 112 | [int] TestOverloadedMethodAccess1b() 113 | { 114 | return $this.OverloadedMethod1("abc") 115 | } 116 | [int] TestOverloadedMethodAccess2a() 117 | { 118 | return $this.OverloadedMethod2(42) 119 | } 120 | [int] TestOverloadedMethodAccess2b() 121 | { 122 | return $this.OverloadedMethod2("abc") 123 | } 124 | [int] TestOverloadedMethodAccess3a() 125 | { 126 | return $this.OverloadedMethod3(42) 127 | } 128 | [int] TestOverloadedMethodAccess3b() 129 | { 130 | return $this.OverloadedMethod3("abc") 131 | } 132 | } 133 | 134 | class Derived2 : Base {} 135 | 136 | [Derived]::new() 137 | [Derived]::new(20) 138 | [Derived2]::new() 139 | '@ 140 | 141 | Describe "Protected Member Access - w/ default ctor" -Tags "DRT" { 142 | It "Method Access" { $derived1.TestMethodAccess() | Should Be 42 } 143 | It "Dynamic Method Access" { $derived1.TestDynamicMethodAccess() | Should Be 42 } 144 | It "Field Access" { $derived1.TestFieldAccess() | Should Be 11 } 145 | It "Dynamic Field Access" { $derived1.TestDynamicFieldAccess() | Should Be 12 } 146 | It "Property Access - protected get/protected set" { $derived1.TestPropertyAccess() | Should Be 1111 } 147 | It "Property Access - public get/protected set " { $derived1.TestPropertyAccess1() | Should Be 2111 } 148 | It "Property Access - protected get/public set" { $derived1.TestPropertyAccess2() | Should Be 3111 } 149 | It "Dynamic Property Access" { $derived1.TestDynamicPropertyAccess() | Should Be 1112 } 150 | 151 | It "Method Access - overloaded 1a" { $derived1.TestOverloadedMethodAccess1a() | Should Be 84 } 152 | It "Method Access - overloaded 1b" { $derived1.TestOverloadedMethodAccess1b() | Should Be 11 } 153 | It "Method Access - overloaded 2a" { $derived1.TestOverloadedMethodAccess2a() | Should Be 84 } 154 | It "Method Access - overloaded 2b" { $derived1.TestOverloadedMethodAccess2b() | Should Be 11 } 155 | It "Method Access - overloaded 3a" { $derived1.TestOverloadedMethodAccess3a() | Should Be 84 } 156 | It "Method Access - overloaded 3b" { $derived1.TestOverloadedMethodAccess3b() | Should Be 11 } 157 | It "Implicit ctor calls protected ctor" { $derived3.OverloadedMethod2(42) | Should Be 84 } 158 | } 159 | 160 | Describe "Protected Member Access - w/ non-default ctor" -Tags "DRT" { 161 | It "Method Access" { $derived2.TestMethodAccess() | Should Be 52 } 162 | It "Dynamic Method Access" { $derived2.TestDynamicMethodAccess() | Should Be 52 } 163 | It "Field Access" { $derived2.TestFieldAccess() | Should Be 11 } 164 | It "Dynamic Field Access" { $derived2.TestDynamicFieldAccess() | Should Be 12 } 165 | It "Property Access - protected get/protected set" { $derived1.TestPropertyAccess() | Should Be 1111 } 166 | It "Property Access - public get/protected set " { $derived1.TestPropertyAccess1() | Should Be 2111 } 167 | It "Property Access - protected get/public set" { $derived1.TestPropertyAccess2() | Should Be 3111 } 168 | It "Dynamic Property Access" { $derived2.TestDynamicPropertyAccess() | Should Be 1112 } 169 | 170 | It "Method Access - overloaded 1a" { $derived2.TestOverloadedMethodAccess1a() | Should Be 94 } 171 | It "Method Access - overloaded 1b" { $derived2.TestOverloadedMethodAccess1b() | Should Be 21 } 172 | It "Method Access - overloaded 2a" { $derived2.TestOverloadedMethodAccess2a() | Should Be 94 } 173 | It "Method Access - overloaded 2b" { $derived2.TestOverloadedMethodAccess2b() | Should Be 21 } 174 | It "Method Access - overloaded 3a" { $derived2.TestOverloadedMethodAccess3a() | Should Be 94 } 175 | It "Method Access - overloaded 3b" { $derived2.TestOverloadedMethodAccess3b() | Should Be 21 } 176 | } 177 | 178 | Describe "Protected Member Access - members not visible outside class" -Tags "DRT" { 179 | Set-StrictMode -v 3 180 | It "Invalid protected field Get Access" { { $derived1.Field } | Should Throw } 181 | It "Invalid protected property Get Access" { { $derived1.Property } | Should Throw } 182 | It "Invalid protected field Set Access" { { $derived1.Field = 1 } | Should Throw } 183 | It "Invalid protected property Set Access" { { $derived1.Property = 1 } | Should Throw } 184 | 185 | It "Invalid protected constructor Access" { { [Base]::new() } | Should Throw } 186 | It "Invalid protected method Access" { { $derived1.Method() } | Should Throw } 187 | } 188 | 189 | -------------------------------------------------------------------------------- /Scripting/Classes/Scripting.Classes.Attributes.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe 'Attributes Test' -Tags "innerloop", "DRT" { 2 | 3 | BeforeAll { 4 | $dummyAttributesSource = @' 5 | using System.Management.Automation; 6 | namespace Dummy 7 | { 8 | public class DoubleStringTransformationAttribute : ArgumentTransformationAttribute 9 | { 10 | public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) 11 | { 12 | string arg = inputData as string; 13 | if (arg != null) 14 | { 15 | return arg + arg; 16 | } 17 | return inputData; 18 | } 19 | } 20 | 21 | public class AppendStringTransformationAttribute : ArgumentTransformationAttribute 22 | { 23 | public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) 24 | { 25 | string arg = inputData as string; 26 | if (arg != null) 27 | { 28 | return arg + "___"; 29 | } 30 | return inputData; 31 | } 32 | } 33 | 34 | public class DoubleInt : ArgumentTransformationAttribute 35 | { 36 | public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) 37 | { 38 | int? arg = inputData as int?; 39 | if (arg != null) 40 | { 41 | return arg + arg; 42 | } 43 | return inputData; 44 | } 45 | } 46 | } 47 | '@ 48 | Add-Type -TypeDefinition $dummyAttributesSource -ReferencedAssemblies "System.Management.Automation" 49 | } 50 | 51 | 52 | 53 | Context 'Property.Instance.ValidateSet.String' { 54 | class C1 { [ValidateSet("Present", "Absent")][string]$Ensure } 55 | # This call should not throw exception 56 | [C1]::new().Ensure = "Present" 57 | 58 | It 'Error when ValidateSet should be ExceptionWhenSetting' { 59 | try 60 | { 61 | [C1]::new().Ensure = "foo" 62 | throw "Exception expected" 63 | } 64 | catch 65 | { 66 | $_.FullyQualifiedErrorId | Should be 'ExceptionWhenSetting' 67 | } 68 | } 69 | } 70 | 71 | Context 'Property.Static.ValidateSet.String' { 72 | class C1 { static [ValidateSet("Present", "Absent")][string]$Ensure } 73 | # This call should not throw exception 74 | [C1]::Ensure = "Present" 75 | It 'Error when ValidateSet should be ExceptionWhenSetting'{ 76 | try { 77 | [C1]::Ensure = "foo" 78 | throw "Exception expected" 79 | } 80 | catch { 81 | $_.FullyQualifiedErrorId | Should be 'ExceptionWhenSetting' 82 | } 83 | } 84 | } 85 | 86 | Context 'Property.Instance.ValidateRange.Int' { 87 | class C1 { [ValidateRange(1, 10)][int]$f } 88 | # This call should not throw exception 89 | [C1]::new().f = 10 90 | [C1]::new().f = 1 91 | It 'Error when ValidateSet should be ExceptionWhenSetting'{ 92 | try { 93 | [C1]::new().f = 20 94 | throw "Exception expected" 95 | } 96 | catch { 97 | $_.FullyQualifiedErrorId | Should be 'ExceptionWhenSetting' 98 | } 99 | } 100 | } 101 | 102 | Context 'Property.Static.ValidateRange.Int' { 103 | class C1 { static [ValidateRange(1, 10)][int]$f } 104 | # This call should not throw exception 105 | [C1]::f = 5 106 | It 'Error when ValidateSet should be ExceptionWhenSetting'{ 107 | try { 108 | [C1]::f = 20 109 | throw "Exception expected" 110 | } 111 | catch { 112 | $_.FullyQualifiedErrorId | Should be 'ExceptionWhenSetting' 113 | } 114 | } 115 | } 116 | 117 | Context 'Property.Static.ValidateSet.ImplicitObject' { 118 | class C1 { static [ValidateSet("abc", 5)]$o } 119 | # This call should not throw exception 120 | [C1]::o = "abc" 121 | [C1]::o = 5 122 | It 'Error when ValidateSet should be ExceptionWhenSetting'{ 123 | try { 124 | [C1]::o = 1 125 | throw "Exception expected" 126 | } 127 | catch { 128 | $_.FullyQualifiedErrorId | Should be 'ExceptionWhenSetting' 129 | } 130 | } 131 | } 132 | 133 | # 134 | # We use [scriptblock]::Create() here to allow SuiteSetup add Dummy.Transformation type to 135 | # the scope. Otherwise, we will need to have all classes for attributes in parse time. 136 | # 137 | # Invoke() returns an array, we need first element of it. 138 | # 139 | 140 | Context 'Property.Instance.Transformation.ImplicitObject' { 141 | $c = [scriptblock]::Create('class C1 { [Dummy.DoubleStringTransformation()]$arg }; [C1]::new()').Invoke()[0] 142 | 143 | It 'Implicitly Transform to 100' { 144 | $c.arg = 100 145 | $c.arg | should be 100 146 | } 147 | It 'Implicitly Transform to foo' { 148 | $c.arg = "foo" 149 | $c.arg | should be "foofoo" 150 | } 151 | } 152 | 153 | Context 'Property.Instance.Transformation.String' { 154 | $c = [scriptblock]::Create('class C1 { [Dummy.DoubleStringTransformation()][string]$arg }; [C1]::new()').Invoke()[0] 155 | It 'set to foo' { 156 | $c.arg = "foo" 157 | $c.arg | should be "foofoo" 158 | } 159 | } 160 | 161 | Context Property.Instance.Transformation.Int { 162 | $c = [scriptblock]::Create('class C1 { [Dummy.DoubleInt()][int]$arg }; [C1]::new()').Invoke()[0] 163 | It 'arg should be 200' { 164 | $c.arg = 100 165 | $c.arg | should be 200 166 | } 167 | It 'Set to string should fail with ExceptionWhenSetting' { 168 | try { 169 | $c.arg = "abc" 170 | throw "Exception expected" 171 | } 172 | catch { 173 | $_.FullyQualifiedErrorId | Should be 'ExceptionWhenSetting' 174 | } 175 | } 176 | } 177 | 178 | Context Property.Instance.Transformation.Nullable { 179 | $c = [scriptblock]::Create('class C1 { [Nullable[int]][Dummy.DoubleStringTransformation()]$arg }; [C1]::new()').Invoke()[0] 180 | It 'arg should be 100' { 181 | $c.arg = 100 182 | $c.arg | should be 100 183 | } 184 | } 185 | 186 | Context Property.Instance.Transformation.Order { 187 | $c = [scriptblock]::Create('class C1 { [Dummy.DoubleStringTransformation()][Dummy.AppendStringTransformation()]$arg }; [C1]::new()').Invoke()[0] 188 | It 'arg should be 100' { 189 | $c.arg = 100 190 | $c.arg | should be 100 191 | } 192 | 193 | It 'arg should be foo___foo___g' { 194 | $c.arg = "foo" 195 | $c.arg | should be "foo___foo___" 196 | } 197 | } 198 | } 199 | 200 | Describe 'Type resolution with attributes' { 201 | # There is kind of a collision between names 202 | # System.Diagnostics.Tracing.EventSource 203 | # System.Diagnostics.Tracing.EventSourceAttribute 204 | # We need to make sure that we resolve type name to the right class at each usage 205 | Context 'Name collision' { 206 | 207 | It 'Resolve System.Diagnostics.Tracing.EventSource to Attribute and to Type in the different contexts' { 208 | [System.Diagnostics.Tracing.EventSource(Name = "MyPSEventSource")] 209 | class MyEventSource : System.Diagnostics.Tracing.EventSource 210 | { 211 | [void] OnEvent([string]$Message) {} 212 | } 213 | 214 | [MyEventSource]::new() | Should Not Be $null 215 | 216 | } 217 | } 218 | } -------------------------------------------------------------------------------- /Scripting/Classes/Scripting.Classes.Break.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe 'Break statements with classes' -Tags "DRT" { 2 | 3 | function Get-Errors([string]$sourceCode) { 4 | $tokens = $null 5 | $errors = $null 6 | $ast = [System.Management.Automation.Language.Parser]::ParseInput($sourceCode, [ref] $tokens, [ref] $errors) 7 | return $errors 8 | } 9 | 10 | Context 'break is inside a class method' { 11 | It 'reports parse error for break on non-existing label' { 12 | $errors = Get-Errors @' 13 | class A 14 | { 15 | static [int] foo() 16 | { 17 | while (1) { break some_label } 18 | return 1 19 | } 20 | } 21 | '@ 22 | $errors.Count | Should be 1 23 | $errors[0].ErrorId | Should be 'LabelNotFound' 24 | } 25 | 26 | It 'reports parse error for break outside of loop' { 27 | $errors = Get-Errors @' 28 | class A 29 | { 30 | static [int] foo() 31 | { 32 | break some_label 33 | return 1 34 | } 35 | } 36 | '@ 37 | $errors.Count | Should be 1 38 | $errors[0].ErrorId | Should be 'LabelNotFound' 39 | } 40 | 41 | It 'work fine, when break is legite' { 42 | class C 43 | { 44 | static [int] foo() 45 | { 46 | foreach ($i in 101..102) { 47 | break 48 | } 49 | return $i 50 | } 51 | } 52 | [C]::foo() | Should be 101 53 | } 54 | } 55 | 56 | Context 'continue inside a class method' { 57 | It 'reports parse error for continue on non-existing label' { 58 | $errors = Get-Errors @' 59 | class A 60 | { 61 | static [int] foo() 62 | { 63 | while (1) { continue some_label } 64 | return 1 65 | } 66 | } 67 | '@ 68 | $errors.Count | Should be 1 69 | $errors[0].ErrorId | Should be 'LabelNotFound' 70 | } 71 | } 72 | 73 | Context 'break is in called function' { 74 | It 'doesn''t terminate caller method' -Skip { 75 | 76 | function ImBreak() { 77 | break 78 | } 79 | 80 | class C 81 | { 82 | static [int] getInt() 83 | { 84 | ImBreak 85 | return 123 86 | } 87 | } 88 | 89 | $canary = $false 90 | try { 91 | [C]::getInt() | Should Be 123 92 | $canary = $true 93 | } finally { 94 | $canary | Should be $true 95 | } 96 | } 97 | 98 | It 'doesn''t allow goto outside of function with break' -Skip { 99 | 100 | function ImBreak() { 101 | break label1 102 | } 103 | 104 | class C 105 | { 106 | static [int] getInt() 107 | { 108 | $count = 123 109 | :label1 110 | foreach ($i in 0..3) { 111 | foreach ($i in 0..3) { 112 | ImBreak 113 | $count++ 114 | } 115 | } 116 | return $count 117 | } 118 | } 119 | 120 | $canary = $false 121 | try { 122 | [C]::getInt() | Should Be (123 + 4*4) 123 | $canary = $true 124 | } finally { 125 | $canary | Should be $true 126 | } 127 | } 128 | } 129 | 130 | Context 'no classes involved' { 131 | 132 | It 'doesn''t report parse error for non-existing label' { 133 | $errors = Get-Errors @' 134 | function foo() 135 | { 136 | while (1) { break some_label } 137 | while (1) { continue another_label } 138 | return 1 139 | } 140 | '@ 141 | $errors.Count | Should be 0 142 | } 143 | 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Scripting/Classes/Scripting.Classes.Exceptions.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe 'Exceptions flow for classes' -Tags "DRT" { 2 | 3 | $canaryHashtable = @{} 4 | 5 | $iss = [initialsessionstate]::CreateDefault() 6 | $iss.Variables.Add([System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('canaryHashtable', $canaryHashtable, $null)) 7 | $iss.Commands.Add([System.Management.Automation.Runspaces.SessionStateFunctionEntry]::new('Get-Canary', '$canaryHashtable')) 8 | $ps = [powershell]::Create($iss) 9 | 10 | BeforeEach { 11 | $canaryHashtable.Clear() 12 | $ps.Commands.Clear() 13 | } 14 | 15 | Context 'All calls are inside classes' { 16 | 17 | It 'does not execute statements after instance method with exception' { 18 | 19 | # Put try-catch outside to avoid try-catch logic altering analysis 20 | try { 21 | 22 | $ps.AddScript( @' 23 | class C 24 | { 25 | [void] m1() 26 | { 27 | $canaryHashtable = Get-Canary 28 | $canaryHashtable['canary'] = 42 29 | $this.ImThrow() 30 | $canaryHashtable['canary'] = 100 31 | } 32 | 33 | [void] ImThrow() 34 | { 35 | throw 'I told you' 36 | } 37 | } 38 | [C]::new().m1() 39 | '@).Invoke() 40 | 41 | } catch {} 42 | 43 | $canaryHashtable['canary'] | Should Be 42 44 | } 45 | 46 | It 'does not execute statements after static method with exception' { 47 | 48 | # Put try-catch outside to avoid try-catch logic altering analysis 49 | try { 50 | 51 | $ps.AddScript( @' 52 | class C 53 | { 54 | static [void] s1() 55 | { 56 | $canaryHashtable = Get-Canary 57 | $canaryHashtable['canary'] = 43 58 | [C]::ImThrow() 59 | $canaryHashtable['canary'] = 100 60 | } 61 | 62 | static [void] ImThrow() 63 | { 64 | 1 / 0 65 | } 66 | } 67 | [C]::s1() 68 | '@).Invoke() 69 | 70 | } catch {} 71 | 72 | $canaryHashtable['canary'] | Should Be 43 73 | } 74 | 75 | It 'does not execute statements after instance method with exception and deep stack' { 76 | 77 | # Put try-catch outside to avoid try-catch logic altering analysis 78 | try { 79 | 80 | $ps.AddScript( @' 81 | class C 82 | { 83 | [void] m1() 84 | { 85 | $canaryHashtable = Get-Canary 86 | $canaryHashtable['canary'] = 1 87 | $this.m2() 88 | $canaryHashtable['canary'] = -6101 89 | } 90 | 91 | [void] m2() 92 | { 93 | $canaryHashtable = Get-Canary 94 | $canaryHashtable['canary'] += 10 95 | $this.m3() 96 | $canaryHashtable['canary'] = -6102 97 | } 98 | 99 | [void] m3() 100 | { 101 | $canaryHashtable = Get-Canary 102 | $canaryHashtable['canary'] += 100 103 | $this.m4() 104 | $canaryHashtable['canary'] = -6103 105 | } 106 | 107 | [void] m4() 108 | { 109 | $canaryHashtable = Get-Canary 110 | $canaryHashtable['canary'] += 1000 111 | $this.ImThrow() 112 | $canaryHashtable['canary'] = -6104 113 | } 114 | 115 | [void] ImThrow() 116 | { 117 | $canaryHashtable = Get-Canary 118 | $canaryHashtable['canary'] += 10000 119 | 120 | 1 / 0 121 | } 122 | } 123 | [C]::new().m1() 124 | '@).Invoke() 125 | 126 | } catch {} 127 | 128 | $canaryHashtable['canary'] | Should Be 11111 129 | } 130 | } 131 | 132 | Context 'Class method call PS function' { 133 | 134 | $body = @' 135 | class C 136 | { 137 | [void] m1() 138 | { 139 | m2 140 | } 141 | 142 | static [void] s1() 143 | { 144 | s2 145 | } 146 | } 147 | 148 | 149 | function m2() 150 | { 151 | $canary = Get-Canary 152 | $canary['canaryM'] = 45 153 | ImThrow 154 | $canary['canaryM'] = 100 155 | } 156 | 157 | function s2() 158 | { 159 | $canary = Get-Canary 160 | $canary['canaryS'] = 46 161 | CallImThrow 162 | $canary['canaryS'] = 100 163 | } 164 | 165 | function CallImThrow() 166 | { 167 | ImThrow 168 | } 169 | 170 | function ImThrow() 171 | { 172 | 1 / 0 173 | } 174 | 175 | '@ 176 | 177 | It 'does not execute statements after function with exception called from instance method' { 178 | 179 | # Put try-catch outside to avoid try-catch logic altering analysis 180 | try { 181 | 182 | $ps.AddScript($body).Invoke() 183 | $ps.AddScript('$c = [C]::new(); $c.m1()').Invoke() 184 | 185 | } catch {} 186 | 187 | $canaryHashtable['canaryM'] | Should Be 45 188 | } 189 | 190 | It 'does not execute statements after function with exception called from static method' { 191 | 192 | # Put try-catch outside to avoid try-catch logic altering analysis 193 | try { 194 | 195 | $ps.AddScript($body).Invoke() 196 | $ps.AddScript('[C]::s1()').Invoke() 197 | 198 | } catch {} 199 | 200 | $canaryHashtable['canaryS'] | Should Be 46 201 | } 202 | 203 | } 204 | 205 | Context "No class is involved" { 206 | It "functions calls continue execution by default" { 207 | 208 | try { 209 | 210 | $ps.AddScript( @' 211 | 212 | $canaryHashtable = Get-Canary 213 | function foo() { 1 / 0; $canaryHashtable['canary'] += 10 } 214 | $canaryHashtable['canary'] = 1 215 | foo 216 | $canaryHashtable['canary'] += 100 217 | 218 | '@).Invoke() 219 | 220 | } catch {} 221 | 222 | $canaryHashtable['canary'] | Should Be 111 223 | } 224 | } 225 | } 226 | 227 | Describe "Exception error position" -Tags "DRT" { 228 | class MSFT_3090412 229 | { 230 | static f1() { [MSFT_3090412]::bar = 42 } 231 | static f2() { throw "an error in f2" } 232 | static f3() { "".Substring(0, 10) } 233 | static f4() { dir nosuchfile -ea Stop } 234 | } 235 | 236 | It "Setting a property that doesn't exist" { 237 | try { 238 | [MSFT_3090412]::f1() 239 | throw "f1 should have thrown" 240 | } catch { 241 | $_.InvocationInfo.Line | Should Match ([regex]::Escape('[MSFT_3090412]::bar = 42')) 242 | } 243 | } 244 | 245 | It "Throwing an exception" { 246 | try { 247 | [MSFT_3090412]::f2() 248 | throw "f2 should have thrown" 249 | } catch { 250 | $_.InvocationInfo.Line | Should Match ([regex]::Escape('throw "an error in f2"')) 251 | } 252 | } 253 | 254 | It "Calling a .Net method that throws" { 255 | try { 256 | [MSFT_3090412]::f3() 257 | throw "f3 should have thrown" 258 | } catch { 259 | $_.InvocationInfo.Line | Should Match ([regex]::Escape('"".Substring(0, 10)')) 260 | } 261 | } 262 | 263 | It "Terminating error" { 264 | try { 265 | [MSFT_3090412]::f4() 266 | throw "f4 should have thrown" 267 | } catch { 268 | $_.InvocationInfo.Line | Should Match ([regex]::Escape('dir nosuchfile -ea Stop')) 269 | } 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /Scripting/Classes/Scripting.Classes.Modules.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe 'PSModuleInfo.GetExportedTypeDefinitions()' { 2 | It "doesn't throw for any module" { 3 | $discard = Get-Module -ListAvailable | % { $_.GetExportedTypeDefinitions() } 4 | $true | Should Be $true # we only verify that we didn't throw. This line contains a dummy Should to make pester happy. 5 | } 6 | } 7 | 8 | Describe 'use of a module from two runspaces' { 9 | function New-TestModule { 10 | param( 11 | [string]$Name, 12 | [string]$Content 13 | ) 14 | 15 | mkdir -Force "TestDrive:\$Name" > $null 16 | $manifestParams = @{ 17 | Path = "TestDrive:\$Name\$Name.psd1" 18 | } 19 | 20 | if ($Content) { 21 | Set-Content -Path TestDrive:\$Name\$Name.psm1 -Value $Content 22 | $manifestParams['RootModule'] = "$Name.psm1" 23 | } 24 | 25 | New-ModuleManifest @manifestParams 26 | 27 | $resolvedTestDrivePath = Split-Path ((ls TestDrive:\)[0].FullName) 28 | if (-not ($env:PSModulePath -like "*$resolvedTestDrivePath*")) { 29 | $env:PSModulePath += ";$resolvedTestDrivePath" 30 | } 31 | } 32 | 33 | $originalPSModulePath = $env:PSModulePath 34 | try { 35 | 36 | New-TestModule -Name 'Random' -Content @' 37 | $script:random = Get-Random 38 | class RandomWrapper 39 | { 40 | [int] getRandom() 41 | { 42 | return $script:random 43 | } 44 | } 45 | '@ 46 | 47 | It -pending 'use different sessionStates for different modules' { 48 | $ps = 1..2 | % { $p = [powershell]::Create().AddScript(@' 49 | Import-Module Random 50 | '@) 51 | $p.Invoke() > $null 52 | $p 53 | } 54 | $res = 1..2 | % { 55 | 0..1 | % { 56 | $ps[$_].Commands.Clear() 57 | # The idea: instance created inside the context, in one runspace. 58 | # Method is called on instance in the different runspace, but it should know about the origin. 59 | $w = $ps[$_].AddScript('& (Get-Module Random) { [RandomWrapper]::new() }').Invoke()[0] 60 | $w.getRandom() 61 | } 62 | } 63 | 64 | $res.Count | Should Be 4 65 | $res[0] | Should Not Be $res[1] 66 | $res[0] | Should Be $res[2] 67 | $res[1] | Should Be $res[3] 68 | } 69 | 70 | } finally { 71 | $env:PSModulePath = $originalPSModulePath 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Scripting/Classes/scripting.classes.NestedModules.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe 'NestedModules' -Tags "DRT" { 2 | 3 | Import-Module $PSScriptRoot\..\LanguageTestSupport.psm1 4 | 5 | function New-TestModule { 6 | param( 7 | [string]$Name, 8 | [string]$Content, 9 | [string[]]$NestedContents 10 | ) 11 | 12 | mkdir -Force "TestDrive:\$Name" > $null 13 | $manifestParams = @{ 14 | Path = "TestDrive:\$Name\$Name.psd1" 15 | } 16 | 17 | if ($Content) { 18 | Set-Content -Path TestDrive:\$Name\$Name.psm1 -Value $Content 19 | $manifestParams['RootModule'] = "$Name.psm1" 20 | } 21 | 22 | if ($NestedContents) { 23 | $manifestParams['NestedModules'] = 1..$NestedContents.Count | % { 24 | $null = mkdir TestDrive:\$Name\Nested$_ 25 | $null = Set-Content -Path TestDrive:\$Name\Nested$_\Nested$_.psm1 -Value $NestedContents[$_ - 1] 26 | "Nested$_" 27 | } 28 | } 29 | 30 | New-ModuleManifest @manifestParams 31 | 32 | $resolvedTestDrivePath = Split-Path ((ls TestDrive:\)[0].FullName) 33 | if (-not ($env:PSModulePath -like "*$resolvedTestDrivePath*")) { 34 | $env:PSModulePath += ";$resolvedTestDrivePath" 35 | } 36 | } 37 | 38 | $originalPSModulePath = $env:PSModulePath 39 | 40 | try { 41 | 42 | 43 | # Create modules in TestDrive:\ 44 | New-TestModule -Name NoRoot -NestedContents @( 45 | 'class A { [string] foo() { return "A1"} }', 46 | 'class A { [string] foo() { return "A2"} }' 47 | ) 48 | 49 | New-TestModule -Name WithRoot -NestedContents @( 50 | 'class A { [string] foo() { return "A1"} }', 51 | 'class A { [string] foo() { return "A2"} }' 52 | ) -Content 'class A { [string] foo() { return "A0"} }' 53 | 54 | New-TestModule -Name ABC -NestedContents @( 55 | 'class A { [string] foo() { return "A"} }', 56 | 'class B { [string] foo() { return "B"} }' 57 | ) -Content 'class C { [string] foo() { return "C"} }' 58 | 59 | It 'Get-Module is able to find types' { 60 | $module = Get-Module NoRoot -ListAvailable 61 | $module.GetExportedTypeDefinitions().Count | Should Be 1 62 | 63 | $module = Get-Module WithRoot -ListAvailable 64 | $module.GetExportedTypeDefinitions().Count | Should Be 1 65 | 66 | $module = Get-Module ABC -ListAvailable 67 | $module.GetExportedTypeDefinitions().Count | Should Be 3 68 | } 69 | 70 | It 'Import-Module pick the right type' { 71 | $module = Import-Module ABC -PassThru 72 | $module.GetExportedTypeDefinitions().Count | Should Be 3 73 | $module = Import-Module ABC -PassThru -Force 74 | $module.GetExportedTypeDefinitions().Count | Should Be 3 75 | 76 | $module = Import-Module NoRoot -PassThru 77 | $module.GetExportedTypeDefinitions().Count | Should Be 1 78 | $module = Import-Module NoRoot -PassThru -Force 79 | $module.GetExportedTypeDefinitions().Count | Should Be 1 80 | [scriptblock]::Create(@' 81 | using module NoRoot 82 | [A]::new().foo() 83 | '@ 84 | ).Invoke() | Should Be A2 85 | 86 | $module = Import-Module WithRoot -PassThru 87 | $module.GetExportedTypeDefinitions().Count | Should Be 1 88 | $module = Import-Module WithRoot -PassThru -Force 89 | $module.GetExportedTypeDefinitions().Count | Should Be 1 90 | [scriptblock]::Create(@' 91 | using module WithRoot 92 | [A]::new().foo() 93 | '@ 94 | ).Invoke() | Should Be A0 95 | } 96 | 97 | Context 'execute type creation in the module context' { 98 | 99 | # let's define types to make it more fun 100 | class A { [string] foo() { return "local"} } 101 | class B { [string] foo() { return "local"} } 102 | class C { [string] foo() { return "local"} } 103 | 104 | # We need to think about it: should it work or not. 105 | # Currently, types are resolved in compile-time to the 'local' versions 106 | # So at runtime we don't call the module versions. 107 | It 'Can execute type creation in the module context with new()' -Skip { 108 | & (Get-Module ABC) { [C]::new().foo() } | Should Be C 109 | & (Get-Module NoRoot) { [A]::new().foo() } | Should Be A2 110 | & (Get-Module WithRoot) { [A]::new().foo() } | Should Be A0 111 | & (Get-Module ABC) { [A]::new().foo() } | Should Be A 112 | } 113 | 114 | It -pending 'Can execute type creation in the module context with New-Object' { 115 | & (Get-Module ABC) { (New-Object C).foo() } | Should Be C 116 | & (Get-Module NoRoot) { (New-Object A).foo() } | Should Be A2 117 | & (Get-Module WithRoot) { (New-Object A).foo() } | Should Be A0 118 | & (Get-Module ABC) { (New-Object A).foo() } | Should Be A 119 | } 120 | } 121 | 122 | } finally { 123 | $env:PSModulePath = $originalPSModulePath 124 | Get-Module @('ABC', 'NoRoot', 'WithRoot') | Remove-Module 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Scripting/Classes/scripting.classes.miscops.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe 'Misc Test' -Tags "innerloop", "DRT" { 2 | 3 | Context 'Where' { 4 | class C1 { 5 | [int[]] $Wheels = @(1,2,3); 6 | [string] Foo() { 7 | return (1..10).Where({ $PSItem -in $this.Wheels; }) -join ';' 8 | } 9 | 10 | [string] Bar() 11 | { 12 | return (1..10 | Where { $PSItem -in $this.Wheels; }) -join ';' 13 | } 14 | } 15 | It 'Invoke Where' { 16 | [C1]::new().Foo() | should be "1;2;3" 17 | } 18 | It 'Pipe to where' { 19 | [C1]::new().Bar() | should be "1;2;3" 20 | } 21 | } 22 | 23 | Context 'ForEach' { 24 | class C1 { 25 | [int[]] $Wheels = @(1,2,3); 26 | [string] Foo() { 27 | $ret="" 28 | Foreach($PSItem in $this.Wheels) { $ret +="$PSItem;"} 29 | return $ret 30 | } 31 | 32 | [string] Bar() 33 | { 34 | $ret = "" 35 | $this.Wheels | foreach { $ret += "$_;" } 36 | return $ret 37 | } 38 | } 39 | It 'Invoke Foreach' { 40 | [C1]::new().Foo() | should be "1;2;3;" 41 | } 42 | It 'Pipe to Foreach' { 43 | [C1]::new().Bar() | should be "1;2;3;" 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Scripting/Classes/scripting.classes.using.variants.tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("IgnoreScriptBlockCache", $true) 2 | try 3 | { 4 | . $PSScriptRoot\scripting.classes.using.tests.ps1 5 | } 6 | finally 7 | { 8 | [System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("IgnoreScriptBlockCache", $false) 9 | } 10 | -------------------------------------------------------------------------------- /Scripting/Classes/scripting.enums.tests.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Microsoft Corporation, 2015 3 | # 4 | 5 | Describe 'enums' -Tags "DRT" { 6 | 7 | Context 'basic enums' { 8 | enum E1 9 | { 10 | e0 11 | e1 12 | e2 13 | } 14 | 15 | It "has correct value 0" { [E1]::e0 | Should Be ([E1]0) } 16 | It "has correct value 1" { [E1]::e1 | Should Be ([E1]1) } 17 | It "has correct value 2" { [E1]::e2 | Should Be ([E1]2) } 18 | It "cast from string" { [E1]::e1 | Should Be 'e1' } 19 | It "cast to string" { 'e2' | Should Be ([E1]::e2) } 20 | } 21 | 22 | Context 'Basic enum with initial value' { 23 | enum E2 24 | { 25 | e0 26 | e1 = 5 27 | e2 28 | } 29 | 30 | It "has correct value 0" { [E2]::e0 | Should Be ([E2]0) } 31 | It "has correct value 5" { [E2]::e1 | Should Be ([E2]5) } 32 | It "has correct value 6" { [E2]::e2 | Should Be ([E2]6) } 33 | It "cast from string" { [E2]::e1 | Should Be 'e1' } 34 | It "cast to string" { 'e2' | Should Be ([E2]::e2) } 35 | } 36 | 37 | Context 'Basic enum with initial value expression' { 38 | enum E3 39 | { 40 | e0 41 | e1 = 5 42 | e2 = [int]::MaxValue 43 | e3 = 1 # This shouldn't be an error even though previous member was max int 44 | } 45 | 46 | It "has correct value 0" { [E3]::e0 | Should Be ([E3]0) } 47 | It "has correct value 5" { [E3]::e1 | Should Be ([E3]5) } 48 | It "has correct value [int]::MaxValue" { [E3]::e2 | Should Be ([E3]([int]::MaxValue)) } 49 | It "has correct value 1" { [E3]::e3 | Should Be ([E3]1) } 50 | It "cast from string" { [E3]::e2 | Should Be 'e2' } 51 | It "cast to string" { 'e3' | Should Be ([E3]::e3) } 52 | } 53 | 54 | Context 'Enum with complicated initial value' { 55 | enum E4 56 | { 57 | e0 = [E5]::e0 + 2 58 | } 59 | 60 | enum E5 61 | { 62 | e0 = [E6]::e0 + 2 63 | } 64 | 65 | enum E6 66 | { 67 | e0 = 38 68 | } 69 | 70 | It 'E4 has correct value' { [E4]::e0 | Should Be ([E4]42) } 71 | It 'E5 has correct value' { [E5]::e0 | Should Be ([E5]40) } 72 | It 'E6 has correct value' { [E6]::e0 | Should Be ([E6]38) } 73 | } 74 | } 75 | 76 | Describe 'Basic enum errors' -Tags "DRT" { 77 | 78 | Import-Module $PSScriptRoot\..\LanguageTestSupport.psm1 79 | 80 | AfterAll { 81 | Remove-Module LanguageTestSupport 82 | } 83 | 84 | ShouldBeParseError 'enum' MissingNameAfterKeyword 4 85 | ShouldBeParseError 'enum foo' MissingTypeBody 8 86 | ShouldBeParseError 'enum foo {' MissingEndCurlyBrace 10 87 | ShouldBeParseError 'enum foo { x = }' ExpectedValueExpression 14 88 | ShouldBeParseError 'enum foo { x =' ExpectedValueExpression,MissingEndCurlyBrace 14,14 89 | ShouldBeParseError 'enum foo {} enum foo {}' MemberAlreadyDefined 12 90 | ShouldBeParseError 'enum foo { x; x }' MemberAlreadyDefined 14 -SkipAndCheckRuntimeError 91 | ShouldBeParseError 'enum foo { X; x }' MemberAlreadyDefined 14 -SkipAndCheckRuntimeError 92 | ShouldBeParseError 'enum foo1 { x = [foo2]::x } enum foo2 { x = [foo1]::x }' CycleInEnumInitializers,CycleInEnumInitializers 0,28 -SkipAndCheckRuntimeError 93 | ShouldBeParseError 'enum foo { e = [int]::MaxValue; e2 }' EnumeratorValueTooLarge 33 -SkipAndCheckRuntimeError 94 | ShouldBeParseError 'enum foo { e = [int]::MaxValue + 1 }' EnumeratorValueTooLarge 15 -SkipAndCheckRuntimeError 95 | ShouldBeParseError 'enum foo { e = $foo }' EnumeratorValueMustBeConstant 15 -SkipAndCheckRuntimeError 96 | ShouldBeParseError 'enum foo { e = "hello" }' CannotConvertValue 15 -SkipAndCheckRuntimeError 97 | } 98 | -------------------------------------------------------------------------------- /Scripting/CompletionTestSupport.psm1: -------------------------------------------------------------------------------- 1 | 2 | class CompletionResult 3 | { 4 | [string]$CompletionText 5 | [string]$ListItemText 6 | [System.Management.Automation.CompletionResultType]$ResultType 7 | [string]$ToolTip 8 | [bool]$Found 9 | 10 | [bool] Equals($Other) 11 | { 12 | if ($Other -isnot [CompletionResult] -and 13 | $Other -isnot [System.Management.Automation.CompletionResult]) 14 | { 15 | return $false 16 | } 17 | 18 | # Comparison is intentionally fuzzy - CompletionText and ResultType must be specified 19 | # but the other properties don't need to match if they aren't specified 20 | 21 | if ($this.CompletionText -cne $Other.CompletionText -or 22 | $this.ResultType -ne $Other.ResultType) 23 | { 24 | return $false 25 | } 26 | 27 | if ($this.ListItemText -cne $Other.ListItemText -and 28 | ![string]::IsNullOrEmpty($this.ListItemText) -and ![string]::IsNullOrEmpty($Other.ListItemText)) 29 | { 30 | return $false 31 | } 32 | 33 | if ($this.ToolTip -cne $Other.ToolTip -and 34 | ![string]::IsNullOrEmpty($this.ToolTip) -and ![string]::IsNullOrEmpty($Other.ToolTip)) 35 | { 36 | return $false 37 | } 38 | 39 | return $true 40 | } 41 | } 42 | 43 | class CompletionTestCase 44 | { 45 | [string]$Description 46 | [CompletionResult[]]$ExpectedResults 47 | [string[]]$NotExpectedResults 48 | [hashtable]$TestInput 49 | } 50 | 51 | function Get-Completions 52 | { 53 | [CmdletBinding()] 54 | param([string]$InputScript, [int]$CursorColumn, $Options = $null) 55 | 56 | if (!$PSBoundParameters.ContainsKey('CursorColumn')) 57 | { 58 | $CursorColumn = $InputScript.IndexOf('<#CURSOR#>') 59 | if ($CursorColumn -lt 0) 60 | { 61 | $CursorColumn = $InputScript.Length 62 | } 63 | else 64 | { 65 | $InputScript = $InputScript -replace '<#CURSOR#>','' 66 | } 67 | } 68 | 69 | $results = [System.Management.Automation.CommandCompletion]::CompleteInput( 70 | <#inputScript#> $InputScript, 71 | <#cursorColumn#> $CursorColumn, 72 | <#options#> $Options) 73 | 74 | return $results 75 | } 76 | 77 | function Get-CompletionTestCaseData 78 | { 79 | param( 80 | [Parameter(ValueFromPipeline)] 81 | [hashtable[]]$Data) 82 | 83 | process 84 | { 85 | Write-Output ([CompletionTestCase[]]$Data) 86 | } 87 | } 88 | 89 | function Test-Completions 90 | { 91 | param( 92 | [Parameter(ValueFromPipeline)] 93 | [CompletionTestCase[]]$TestCases, 94 | [string] 95 | $Description) 96 | 97 | process 98 | { 99 | foreach ($test in $TestCases) 100 | { 101 | Describe $test.Description { 102 | $hash = $Test.TestInput 103 | $results = Get-Completions @hash 104 | 105 | foreach ($expected in $test.ExpectedResults) 106 | { 107 | foreach ($result in $results.CompletionMatches) 108 | { 109 | 110 | if ($expected.Equals($result)) 111 | { 112 | It "Checking for duplicates of: $($expected.CompletionText)" { 113 | # We should only find 1 of each expected result 114 | $expected.Found | Should Be $false 115 | } 116 | $expected.Found = $true 117 | } 118 | } 119 | } 120 | 121 | foreach ($expected in $test.ExpectedResults) 122 | { 123 | It "Checking for presence of expected result: $($expected.CompletionText)" { 124 | $expected.Found | Should Be $true 125 | } 126 | } 127 | 128 | foreach ($notExpected in $test.NotExpectedResults) 129 | { 130 | foreach ($result in $results.CompletionMatches) 131 | { 132 | It "Checking for results that should not be found: $notExpected" { 133 | $result.CompletionText -cne $notExpected | Should Be $true 134 | } 135 | } 136 | } 137 | 138 | } 139 | } 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /Scripting/LanguageTestSupport.psm1: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Run the new parser, return either errors or the ast 4 | # 5 | function Get-ParseResults 6 | { 7 | [CmdletBinding()] 8 | param( 9 | [Parameter(ValueFromPipeline=$True,Mandatory=$True)] 10 | [string]$src, 11 | [switch]$Ast 12 | ) 13 | 14 | $errors = $null 15 | $result = [System.Management.Automation.Language.Parser]::ParseInput($src, [ref]$null, [ref]$errors) 16 | if ($Ast) { $result } else { ,$errors } 17 | } 18 | 19 | # 20 | # Run script and return errors 21 | # 22 | function Get-RuntimeError 23 | { 24 | [CmdletBinding()] 25 | param( 26 | [Parameter(ValueFromPipeline=$True,Mandatory=$True)] 27 | [string]$src 28 | ) 29 | 30 | $errors = $null 31 | try 32 | { 33 | [scriptblock]::Create($src).Invoke() > $null 34 | } 35 | catch 36 | { 37 | return $_.Exception.InnerException.ErrorRecord 38 | } 39 | } 40 | 41 | function position_message 42 | { 43 | param($position) 44 | 45 | if ($position.Line.Length -lt $position.ColumnNumber) 46 | { 47 | $position.Line + " <<<<" 48 | } 49 | else 50 | { 51 | $position.Line.Insert($position.ColumnNumber, " <<<<") 52 | } 53 | } 54 | 55 | 56 | # 57 | # Run the new parser, check the errors against the expected errors 58 | # 59 | function Test-Error 60 | { 61 | [CmdletBinding()] 62 | param([string]$src, [string[]]$expectedErrors, [int[]]$expectedOffsets) 63 | 64 | Assert ($expectedErrors.Count -eq $expectedOffsets.Count) "Test case error" 65 | 66 | $errors = Get-ParseResults -Src $src 67 | 68 | 69 | if ($null -ne $errors) 70 | { 71 | Assert ($errors.Count -eq $expectedErrors.Count) "Expected $($expectedErrors.Count) errors, got $($errors.Count)" 72 | for ($i = 0; $i -lt $errors.Count; ++$i) 73 | { 74 | $err = $errors[$i] 75 | Assert ($expectedErrors[$i] -eq $err.ErrorId) ("Unexpected error: {0,-30}{1}" -f ("$($err.ErrorId):", 76 | (position_message $err.Extent.StartScriptPosition))) 77 | Assert ($expectedOffsets[$i] -eq $err.Extent.StartScriptPosition.Offset) ` 78 | "Expected position: $($expectedOffsets[$i]), got $($err.Extent.StartScriptPosition.Offset)" 79 | } 80 | } 81 | else 82 | { 83 | Assert $false "Expected errors but didn't receive any." 84 | } 85 | } 86 | 87 | # 88 | # Pester friendly version of Test-Error 89 | # 90 | function ShouldBeParseError 91 | { 92 | [CmdletBinding()] 93 | param( 94 | [string]$src, 95 | [string[]]$expectedErrors, 96 | [int[]]$expectedOffsets, 97 | # This is a temporary solution after moving type creation from parse time to runtime 98 | [switch]$SkipAndCheckRuntimeError 99 | ) 100 | 101 | Context "Parse error expected: <<$src>>" { 102 | # Test case error if this fails 103 | $expectedErrors.Count | Should Be $expectedOffsets.Count 104 | 105 | if ($SkipAndCheckRuntimeError) 106 | { 107 | It "error should happen at parse time, not at runtime" -Skip {} 108 | $errors = Get-RuntimeError -Src $src 109 | # for runtime errors we will only get the first one 110 | $expectedErrors = ,$expectedErrors[0] 111 | $expectedOffsets = ,$expectedOffsets[0] 112 | } 113 | else 114 | { 115 | $errors = Get-ParseResults -Src $src 116 | } 117 | 118 | It "Error count" { $errors.Count | Should Be $expectedErrors.Count } 119 | for ($i = 0; $i -lt $errors.Count; ++$i) 120 | { 121 | $err = $errors[$i] 122 | 123 | if ($SkipAndCheckRuntimeError) 124 | { 125 | $errorId = $err.FullyQualifiedErrorId 126 | } 127 | else 128 | { 129 | $errorId = $err.ErrorId 130 | } 131 | It "Error Id" { $errorId | Should Be $expectedErrors[$i] } 132 | It "Error position" -Pending:$SkipAndCheckRuntimeError { $err.Extent.StartScriptPosition.Offset | Should Be $expectedOffsets[$i] } 133 | } 134 | } 135 | } 136 | 137 | 138 | function Flatten-Ast 139 | { 140 | [CmdletBinding()] 141 | param([System.Management.Automation.Language.Ast] $ast) 142 | 143 | $ast 144 | $ast | gm -type property | ? { ($prop = $_.Name) -ne 'Parent' } | % { 145 | $ast.$prop | ? { $_ -is [System.Management.Automation.Language.Ast] } | % { Flatten-Ast $_ } 146 | } 147 | } 148 | 149 | function Test-ErrorStmt 150 | { 151 | param([string]$src, [string]$errorStmtExtent) 152 | 153 | $ast = Get-ParseResults $src -Ast 154 | $asts = @(Flatten-Ast $ast.EndBlock.Statements[0]) 155 | 156 | Assert ($asts[0] -is [System.Management.Automation.Language.ErrorStatementAst]) "Expected error statement" 157 | Assert ($asts.Count -eq $args.Count + 1) "Incorrect number of nested asts" 158 | Assert ($asts[0].Extent.Text -eq $errorStmtExtent) "Error statement expected <$errorStmtExtent>, got <$($asts[0].Extent.Text)>" 159 | for ($i = 0; $i -lt $args.Count; ++$i) 160 | { 161 | Assert ($asts[$i + 1].Extent.Text -eq $args[$i]) "Nested ast incorrect: <$($asts[$i+1].Extent.Text)>, expected <$($args[$i])>" 162 | } 163 | } 164 | 165 | function Test-Ast 166 | { 167 | param([string]$src) 168 | 169 | $ast = Get-ParseResults $src -Ast 170 | $asts = @(Flatten-Ast $ast) 171 | Assert ($asts.Count -eq $args.Count) "Incorrect number of nested asts, got $($asts.Count), expected $($args.Count)" 172 | for ($i = 0; $i -lt $args.Count; ++$i) 173 | { 174 | Assert ($asts[$i].Extent.Text -eq $args[$i]) "Nested ast incorrect: <$($asts[$i].Extent.Text)>, expected <$($args[$i])>" 175 | } 176 | } 177 | 178 | Export-ModuleMember -Function Test-Error, Test-ErrorStmt, Test-Ast, ShouldBeParseError, Get-ParseResults, Get-RuntimeError 179 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/BNotOperator.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | $baseTypes = @{ 4 | [SByte] = 'sbyte'; [Byte] = 'byte' 5 | [Int16] = 'short'; [UInt16] = 'ushort' 6 | [Int32] = 'int'; [UInt32] = 'uint' 7 | [Int64] = 'long'; [UInt64] = 'ulong' 8 | } 9 | 10 | $ns = [Guid]::NewGuid() -replace '-','' 11 | 12 | $typeDefinition = "namespace ns_$ns`n{" 13 | 14 | $enumTypeNames = foreach ($baseType in $baseTypes.Keys) 15 | { 16 | $baseTypeName = $baseTypes[$baseType] 17 | $typeDefinition += @" 18 | public enum E_$baseTypeName : $baseTypeName 19 | { 20 | Min = $($baseType::MinValue), 21 | MinPlus1 = $($baseType::MinValue + 1), 22 | MaxMinus1 = $($baseType::MaxValue - 1), 23 | Max = $($baseType::MaxValue) 24 | } 25 | "@ 26 | 27 | "ns_$ns.E_$baseTypeName" 28 | } 29 | 30 | $typeDefinition += "`n}" 31 | 32 | Write-Verbose $typeDefinition 33 | Add-Type $typeDefinition 34 | 35 | Describe "bnot on enums" -Tags "DRT" { 36 | foreach ($enumType in [type[]]$enumTypeNames) 37 | { 38 | Context $enumType.Name { 39 | It "max - 1" { 40 | $res = -bnot $enumType::MaxMinus1 41 | $res | Should Be $enumType::MinPlus1 42 | $res.GetType() | Should Be $enumType 43 | } 44 | 45 | It "min + 1" { 46 | $res = -bnot $enumType::MinPlus1 47 | $res | Should Be $enumType::MaxMinus1 48 | $res.GetType() | Should Be $enumType 49 | } 50 | 51 | It "Max" { 52 | $res = -bnot $enumType::Max 53 | $res | Should Be $enumType::Min 54 | $res.GetType() | Should Be $enumType 55 | } 56 | 57 | It "Min" { 58 | $res = -bnot $enumType::Min 59 | $res | Should Be $enumType::Max 60 | $res.GetType() | Should Be $enumType 61 | } 62 | } 63 | } 64 | } 65 | 66 | Describe "bnot on integral types" -Tags "DRT" { 67 | foreach ($baseType in $baseTypes.Keys) 68 | { 69 | Context $baseType.Name { 70 | 71 | $max = $baseType::MaxValue 72 | $maxMinus1 = $max - 1 73 | $min = $baseType::MinValue 74 | $minPlus1 = $min + 1 75 | 76 | if ([System.Runtime.InteropServices.Marshal]::SizeOf([type]$baseType) -lt 4) 77 | { 78 | $expectedResultType = [int] 79 | } 80 | else 81 | { 82 | $expectedResultType = $baseType 83 | } 84 | 85 | if ($baseType -eq [byte] -or $baseType -eq [uint16]) 86 | { 87 | # Because of type promotion rules, unsigned types smaller than int 88 | # don't quite follow the pattern of "flip all the bits", so our 89 | # tests are a little different. 90 | It "max - 1" { 91 | $res = -bnot $maxMinus1 92 | $res | Should Be (-bnot [int]$maxMinus1) 93 | $res.GetType() | Should Be $expectedResultType 94 | } 95 | 96 | It "min + 1" { 97 | $res = -bnot $minPlus1 98 | $res | Should Be (-bnot [int]$minPlus1) 99 | $res.GetType() | Should Be $expectedResultType 100 | } 101 | 102 | It "max" { 103 | $res = -bnot $max 104 | $res | Should Be (-bnot [int]$max) 105 | $res.GetType() | Should Be $expectedResultType 106 | } 107 | 108 | It "min" { 109 | $res = -bnot $min 110 | $res | Should Be (-bnot [int]$min) 111 | $res.GetType() | Should Be $expectedResultType 112 | } 113 | return 114 | } 115 | 116 | It "max - 1" { 117 | $res = -bnot $maxMinus1 118 | $res | Should Be $minPlus1 119 | $res.GetType() | Should Be $expectedResultType 120 | } 121 | 122 | It "min + 1" { 123 | $res = -bnot $minPlus1 124 | $res | Should Be $maxMinus1 125 | $res.GetType() | Should Be $expectedResultType 126 | } 127 | 128 | It "max" { 129 | $res = -bnot $max 130 | $res | Should Be $min 131 | $res.GetType() | Should Be $expectedResultType 132 | } 133 | 134 | It "min" { 135 | $res = -bnot $min 136 | $res | Should Be $max 137 | $res.GetType() | Should Be $expectedResultType 138 | } 139 | } 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/Completion.Tests.ps1: -------------------------------------------------------------------------------- 1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | Import-Module $here\..\CompletionTestSupport.psm1 -force 3 | 4 | # Convince the Pester Harness adapter that this is a pester test 5 | if ($false) { Describe; It } 6 | 7 | @{ 8 | Description = "Completion doesn't cause stack overflow" 9 | ExpectedResults = @( 10 | @{CompletionText = "BaseObject"; ResultType = "Property"} 11 | @{CompletionText = "Members"; ResultType = "Property"} 12 | @{CompletionText = "GetMetaObject("; ResultType = "Method"} 13 | @{CompletionText = "Equals("; ResultType = "Method"} 14 | @{CompletionText = "ToString("; ResultType = "Method"}) 15 | TestInput = @{inputScript = @' 16 | $dums = @() 17 | $dum = new-object PSObject 18 | $dum | add-member noteproperty Blah "blah" 19 | $dums += $dum 20 | foreach($dum in $dums) { 21 | $dum.<#CURSOR#> 22 | } 23 | '@ } 24 | } | Get-CompletionTestCaseData | Test-Completions 25 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/LanguageAndParser.TestFollowup.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | Describe "Clone array" { 3 | It "Cast in target expr" { 4 | (([int[]](42)).clone()) | Should Be 42 5 | (([int[]](1..5)).clone()).Length | Should Be 5 6 | (([int[]](1..5)).clone()).GetType() | Should Be ([int[]]) 7 | 8 | } 9 | It "Cast not in target expr" { 10 | $e = [int[]](42) 11 | $e.Clone() | Should Be 42 12 | $e = [int[]](1..5) 13 | $e.Clone().Length | Should Be 5 14 | $e.Clone().GetType() | Should Be ([int[]]) 15 | } 16 | } 17 | 18 | Describe "Set fields through PSMemberInfo" { 19 | Add-Type @" 20 | public struct AStruct { public string s; } 21 | "@ 22 | 23 | It "via cast" { 24 | ([AStruct]@{s = "abc" }).s | Should Be "abc" 25 | } 26 | It "via new-object" { 27 | (new-object AStruct -prop @{s="abc"}).s | Should Be "abc" 28 | } 29 | It "via PSObject" { 30 | $x = [AStruct]::new() 31 | $x.psobject.properties['s'].Value = 'abc' 32 | $x.s | Should Be "abc" 33 | } 34 | } 35 | 36 | Describe "MSFT:3309783" { 37 | # For a reliable test, we must run this in a new process because an earlier binding in this process 38 | # could mask the bug/fix. 39 | powershell -noprofile -command "[psobject] | % FullName" | Should Be System.Management.Automation.PSObject 40 | 41 | # For good measure, do the same thing in this process 42 | [psobject] | % FullName | Should Be System.Management.Automation.PSObject 43 | 44 | # Related - make sure we can still pipe objects derived from PSObject 45 | class MyPsObj : PSObject 46 | { 47 | MyPsObj($obj) : base($obj) { } 48 | [string] ToString() { 49 | # Don't change access via .psobject, that was also a bug. 50 | return "MyObj: " + $this.psobject.BaseObject 51 | } 52 | } 53 | 54 | [MyPsObj]::new("abc").psobject.ToString() | Should Be "MyObj: abc" 55 | [MyPsObj]::new("def") | Out-String | % Trim | Should Be "MyObj: def" 56 | } 57 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/MethodInvocation.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | Describe "Interface inheritance with remoting proxies" -Tags "P1", "RI" { 3 | $src = @" 4 | using System; 5 | using System.ServiceModel; 6 | 7 | namespace MSFT_716893 8 | { 9 | [ServiceContract] 10 | public interface IInterface1 11 | { 12 | [OperationContract]string BaseOperation(int i); 13 | } 14 | 15 | [ServiceContract] 16 | public interface IInterface2 : IInterface1 17 | { 18 | [OperationContract(Name="op1")]string Operation(string a); 19 | [OperationContract(Name="op2")]string Operation(string a, string b); 20 | } 21 | 22 | public class ServiceImplementation : IInterface2 23 | { 24 | public string Operation(string a) { return "1 - " + a; } 25 | public string Operation(string a, string b) { return "2 - " + a + " " + b; } 26 | public string BaseOperation(int i) { return "3 - " + i; } 27 | } 28 | 29 | public static class Service 30 | { 31 | static ServiceHost serviceHost; 32 | 33 | public static void Init() 34 | { 35 | Uri baseAddress = new Uri("http://localhost:8080/service"); 36 | serviceHost = new ServiceHost(typeof(ServiceImplementation), baseAddress); 37 | serviceHost.Open(); 38 | } 39 | 40 | public static IInterface1 GetProxy() 41 | { 42 | ChannelFactory factory = new ChannelFactory( 43 | serviceHost.Description.Endpoints[0].Binding, 44 | serviceHost.Description.Endpoints[0].Address); 45 | return factory.CreateChannel(); 46 | } 47 | 48 | public static void Close() 49 | { 50 | serviceHost.Close(); 51 | } 52 | } 53 | } 54 | "@ 55 | 56 | Add-Type -TypeDefinition $src -ReferencedAssemblies System.ServiceModel.dll 57 | 58 | BeforeEach { 59 | [MSFT_716893.Service]::Init() 60 | $proxy = [MSFT_716893.Service]::GetProxy() 61 | } 62 | 63 | AfterEach { 64 | [MSFT_716893.Service]::Close() 65 | } 66 | 67 | It "Direct invocation" { 68 | $proxy.Operation("a") | Should Be "1 - a" 69 | $proxy.Operation("a", "b") | Should Be "2 - a b" 70 | $proxy.BaseOperation(42) | Should Be "3 - 42" 71 | } 72 | 73 | It "Invocation via method constraints" { 74 | ([MSFT_716893.IInterface2]$proxy).Operation("c") | Should Be "1 - c" 75 | ([MSFT_716893.IInterface2]$proxy).Operation("d", "e") | Should Be "2 - d e" 76 | ([MSFT_716893.IInterface1]$proxy).BaseOperation(22) | Should Be "3 - 22" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/ParameterBinding.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | Describe 'Argument transformation attribute on optional argument with explicit $null' -Tags "P1", "RI" { 3 | $mod = Add-Type -PassThru -TypeDefinition @' 4 | using System; 5 | using System.Management.Automation; 6 | using System.Reflection; 7 | 8 | namespace MSFT_1407291 9 | { 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 11 | public class AddressTransformationAttribute : ArgumentTransformationAttribute 12 | { 13 | public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) 14 | { 15 | return (ulong) 42; 16 | } 17 | } 18 | 19 | [Cmdlet(VerbsLifecycle.Invoke, "CSharpCmdletTakesUInt64")] 20 | [OutputType(typeof(System.String))] 21 | public class Cmdlet1 : PSCmdlet 22 | { 23 | [Parameter(Mandatory = false)] 24 | [AddressTransformation] 25 | public ulong Address { get; set; } 26 | 27 | protected override void ProcessRecord() 28 | { 29 | WriteObject(Address); 30 | } 31 | } 32 | 33 | [Cmdlet(VerbsLifecycle.Invoke, "CSharpCmdletTakesObject")] 34 | [OutputType(typeof(System.String))] 35 | public class Cmdlet2 : PSCmdlet 36 | { 37 | [Parameter(Mandatory = false)] 38 | [AddressTransformation] 39 | public object Address { get; set; } 40 | 41 | protected override void ProcessRecord() 42 | { 43 | WriteObject(Address ?? "passed in null"); 44 | } 45 | } 46 | } 47 | '@ 48 | 49 | Import-Module $mod[0].Assembly 50 | 51 | function Invoke-ScriptFunctionTakesObject 52 | { 53 | param([MSFT_1407291.AddressTransformation()] 54 | [Parameter(Mandatory = $false)] 55 | [object]$Address = "passed in null") 56 | 57 | return $Address 58 | } 59 | 60 | function Invoke-ScriptFunctionTakesUInt64 61 | { 62 | param([MSFT_1407291.AddressTransformation()] 63 | [Parameter(Mandatory = $false)] 64 | [Uint64]$Address = 11) 65 | 66 | return $Address 67 | } 68 | 69 | 70 | Invoke-ScriptFunctionTakesObject | Should Be 42 71 | Invoke-ScriptFunctionTakesUInt64 | Should Be 42 72 | Invoke-CSharpCmdletTakesObject | Should Be "passed in null" 73 | Invoke-CSharpCmdletTakesUInt64 | Should Be 0 74 | 75 | Invoke-ScriptFunctionTakesObject -Address $null | Should Be 42 76 | Invoke-ScriptFunctionTakesUInt64 -Address $null | Should Be 42 77 | Invoke-CSharpCmdletTakesObject -Address $null | Should Be 42 78 | Invoke-CSharpCmdletTakesUInt64 -Address $null | Should Be 42 79 | } 80 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/Pester.Ast.Tests.ps1: -------------------------------------------------------------------------------- 1 | using Namespace System.Management.Automation.Language 2 | Describe "The SafeGetValue method on AST returns safe values" -Tags "DRT" { 3 | It "A hashtable is returned from a HashtableAst" { 4 | $HashtableAstType = [HashtableAst] 5 | $HtAst = { 6 | @{ one = 1 } 7 | }.ast.Find({$args[0] -is $HashtableAstType}, $true) 8 | $HtAst.SafeGetValue().GetType().Name | Should be Hashtable 9 | } 10 | It "An Array is returned from a LiteralArrayAst" { 11 | $ArrayAstType = [ArrayLiteralAst] 12 | $ArrayAst = { 13 | @( 1,2,3,4) 14 | }.ast.Find({$args[0] -is $ArrayAstType}, $true) 15 | $ArrayAst.SafeGetValue().GetType().Name | Should be "Object[]" 16 | } 17 | It "The proper error is returned when a variable is referenced" { 18 | $ast = { $a }.Ast.Find({$args[0] -is "VariableExpressionAst"},$true) 19 | try { 20 | $ast.SafeGetValue() | out-null 21 | Throw "Execution Succeeded" 22 | } 23 | catch { 24 | $_.FullyQualifiedErrorId | Should be "InvalidOperationException" 25 | $_.ToString() | Should Match '\$a' 26 | } 27 | } 28 | It "A ScriptBlock AST fails with the proper error" { 29 | try { 30 | { 1 }.Ast.SafeGetValue() 31 | Throw "Execution Succeeded" 32 | } 33 | catch { 34 | $_.FullyQualifiedErrorId | Should be "InvalidOperationException" 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/Pester.RedirectionOperator.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Redirection operator now supports encoding changes" { 2 | BeforeAll { 3 | $asciiString = "abc" 4 | $asciiCR = "`r`n" 5 | 6 | # If out-file -encoding happens to have a default, be sure to 7 | # save it away 8 | $SavedValue = $null 9 | $oldDefaultParameterValues = $psDefaultParameterValues 10 | $psDefaultParameterValues = @{} 11 | } 12 | AfterAll { 13 | # be sure to tidy up afterwards 14 | $psDefaultParameterValues = $oldDefaultParameterValues 15 | } 16 | BeforeEach { 17 | # start each test with a clean plate! 18 | $psdefaultParameterValues.Remove("out-file:encoding") 19 | } 20 | AfterEach { 21 | # end each test with a clean plate! 22 | $psdefaultParameterValues.Remove("out-file:encoding") 23 | } 24 | 25 | It "If encoding is unset, redirection should be Unicode" { 26 | $asciiString > TESTDRIVE:\file.txt 27 | $bytes = get-content -encoding byte TESTDRIVE:\file.txt 28 | # create the expected 29 | $BOM = [text.encoding]::unicode.GetPreamble() 30 | $TXT = [text.encoding]::unicode.GetBytes($asciiString) 31 | $CR = [text.encoding]::unicode.GetBytes($asciiCR) 32 | $expectedBytes = .{ $BOM; $TXT; $CR } 33 | $bytes.Count | should be $expectedBytes.count 34 | for($i = 0; $i -lt $bytes.count; $i++) { 35 | $bytes[$i] | Should be $expectedBytes[$i] 36 | } 37 | } 38 | 39 | # $availableEncodings = "unknown","string","unicode","bigendianunicode","utf8","utf7", "utf32","ascii","default","oem" 40 | $availableEncodings = (get-command out-file).Parameters["Encoding"].Attributes.ValidValues 41 | 42 | foreach($encoding in $availableEncodings) { 43 | # some of the encodings accepted by out-file aren't real, 44 | # and out-file has its own translation, so we'll 45 | # not do that logic here, but simply ignore those encodings 46 | # as they eventually are translated to "real" encoding 47 | $enc = [system.text.encoding]::$encoding 48 | if ( $enc ) 49 | { 50 | $msg = "Overriding encoding for out-file is respected for $encoding" 51 | $BOM = $enc.GetPreamble() 52 | $TXT = $enc.GetBytes($asciiString) 53 | $CR = $enc.GetBytes($asciiCR) 54 | $expectedBytes = .{ $BOM; $TXT; $CR } 55 | $psdefaultparameterValues["out-file:encoding"] = $encoding 56 | $asciiString > TESTDRIVE:/file.txt 57 | $observedBytes = Get-Content -encoding Byte TESTDRIVE:/file.txt 58 | # THE TEST 59 | It -pending $msg { 60 | $observedBytes.Count | Should be $expectedBytes.Count 61 | for($i = 0;$i -lt $observedBytes.Count; $i++) { 62 | $observedBytes[$i] | Should be $expectedBytes[$i] 63 | } 64 | } 65 | 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/TypeAccelerator.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | Describe "Type accelerators" -Tags "DRT" { 3 | $TypeAcceleratorsType = [psobject].Assembly.GetType("System.Management.Automation.TypeAccelerators") 4 | 5 | $TypeAccelerators = $TypeAcceleratorsType::Get 6 | $TypeAcceleratorsType::Add('msft_2174855', [int]) 7 | $TypeAcceleratorsType::Add('msft_2174855_rm', [int]) 8 | 9 | It "Basic type accelerator usage" { 10 | [msft_2174855] | Should Be ([int]) 11 | } 12 | 13 | It "Can query type accelerators" { 14 | $TypeAccelerators.Count -gt 82 | Should Be $true 15 | $TypeAccelerators['xml'] | Should Be ([System.Xml.XmlDocument]) 16 | $TypeAccelerators['AllowNull'] | Should Be ([System.Management.Automation.AllowNullAttribute]) 17 | } 18 | 19 | It "Can remove type accelerator" { 20 | $TypeAcceleratorsType::Get['msft_2174855_rm'] | Should Be ([int]) 21 | $TypeAcceleratorsType::Remove('msft_2174855_rm') 22 | $TypeAcceleratorsType::Get['msft_2174855_rm'] | Should Be $null 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/UsingAssembly.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | Describe "Using assembly" -Tags "DRT" { 3 | 4 | try 5 | { 6 | pushd $PSScriptRoot 7 | $guid = [Guid]::NewGuid() 8 | 9 | Add-Type -OutputAssembly $PSScriptRoot\UsingAssemblyTest$guid.dll -TypeDefinition @" 10 | public class ABC {} 11 | "@ 12 | 13 | It 'parse reports error on non-existing assembly by relative path' { 14 | $err = $null 15 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly foo.dll", [ref]$null, [ref]$err) 16 | 17 | $err.Count | Should Be 1 18 | $err[0].ErrorId | Should Be ErrorLoadingAssembly 19 | } 20 | 21 | It 'parse reports error on assembly with non-existing fully qualified name' { 22 | $err = $null 23 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly 'System.Management.Automation, Version=99.0.0.0'", [ref]$null, [ref]$err) 24 | 25 | $err.Count | Should Be 1 26 | $err[0].ErrorId | Should Be ErrorLoadingAssembly 27 | } 28 | 29 | It 'not allow UNC path' { 30 | $err = $null 31 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly \\networkshare\foo.dll", [ref]$null, [ref]$err) 32 | 33 | $err.Count | Should Be 1 34 | $err[0].ErrorId | Should Be CannotLoadAssemblyFromUncPath 35 | } 36 | 37 | It 'not allow http path' { 38 | $err = $null 39 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly http://microsoft.com/foo.dll", [ref]$null, [ref]$err) 40 | 41 | $err.Count | Should Be 1 42 | $err[0].ErrorId | Should Be CannotLoadAssemblyWithUriSchema 43 | } 44 | 45 | It "parse does not load the assembly" { 46 | $assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 47 | $assemblies -contains "UsingAssemblyTest$guid" | Should Be $false 48 | 49 | $err = $null 50 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly .\UsingAssemblyTest$guid.dll", [ref]$null, [ref]$err) 51 | 52 | $assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 53 | $assemblies -contains "UsingAssemblyTest$guid" | Should Be $false 54 | $err.Count | Should Be 0 55 | 56 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly '$PSScriptRoot\UsingAssemblyTest$guid.dll'", [ref]$null, [ref]$err) 57 | 58 | $assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 59 | $assemblies -contains "UsingAssemblyTest$guid" | Should Be $false 60 | $err.Count | Should Be 0 61 | 62 | $ast = [System.Management.Automation.Language.Parser]::ParseInput("using assembly `"$PSScriptRoot\UsingAssemblyTest$guid.dll`"", [ref]$null, [ref]$err) 63 | 64 | $assemblies = [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 65 | $assemblies -contains "UsingAssemblyTest$guid" | Should Be $false 66 | $err.Count | Should Be 0 67 | } 68 | 69 | It "reports runtime error about non-existing assembly with relative path" { 70 | $failed = $true 71 | try { 72 | [scriptblock]::Create("using assembly .\NonExistingAssembly.dll") 73 | $failed = $false 74 | } catch { 75 | $_.FullyQualifiedErrorId | Should be 'ParseException' 76 | $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should be 'ErrorLoadingAssembly' 77 | } 78 | $failed | Should be $true 79 | } 80 | #> 81 | It "Assembly loaded at runtime" { 82 | $assemblies = powershell -noprofile -command @" 83 | using assembly .\UsingAssemblyTest$guid.dll 84 | [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 85 | "@ 86 | $assemblies -contains "UsingAssemblyTest$guid" | Should Be $true 87 | 88 | $assemblies = powershell -noprofile -command @" 89 | using assembly $PSScriptRoot\UsingAssemblyTest$guid.dll 90 | [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 91 | "@ 92 | $assemblies -contains "UsingAssemblyTest$guid" | Should Be $true 93 | 94 | 95 | $assemblies = powershell -noprofile -command @" 96 | using assembly System.Drawing 97 | [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 98 | "@ 99 | $assemblies -contains "System.Drawing" | Should Be $true 100 | 101 | $assemblies = powershell -noprofile -command @" 102 | using assembly 'System.Drawing, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' 103 | [Appdomain]::CurrentDomain.GetAssemblies().GetName().Name 104 | "@ 105 | $assemblies -contains "System.Drawing" | Should Be $true 106 | } 107 | } 108 | finally 109 | { 110 | Remove-Item .\UsingAssemblyTest$guid.dll 111 | popd 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Scripting/LanguageandParser/UsingNamespace.Tests.ps1: -------------------------------------------------------------------------------- 1 | 2 | # There is an automatic 'using namespace system' which is 3 | # tested by this test, so don't uncomment the following: 4 | #using namespace System 5 | using namespace System.Threading 6 | using namespace System.Timers 7 | # Test parsing more than one using statement on one line 8 | using namespace System.Diagnostics; using namespace System.Runtime.CompilerServices 9 | using namespace System.Collections.Generic 10 | 11 | Import-Module $PSScriptRoot\..\LanguageTestSupport.psm1 12 | 13 | function ShouldBeErrorId 14 | { 15 | param([Parameter(ValueFromPipeline, Mandatory)] 16 | [ScriptBlock] 17 | $sb, 18 | 19 | [Parameter(Mandatory, Position=0)] 20 | [string] 21 | $FullyQualifiedErrorId) 22 | 23 | try 24 | { 25 | & $sb 26 | throw "Unexpected" 27 | } 28 | catch 29 | { 30 | $_.FullyQualifiedErrorId | Should Be $FullyQualifiedErrorId 31 | } 32 | } 33 | 34 | # Flags is System.FlagsAttribute 35 | # This tests our implicit 'using namespace System' 36 | # despite having other explicit using namespace statements. 37 | [Flags()] 38 | enum E1 39 | { 40 | E1 = 0x01 41 | E2 = 0x02 42 | E4 = 0x04 43 | } 44 | 45 | # Test attributes that won't be found w/o using, but w/o implicit Attribute suffix 46 | [CompilerGenerated()] 47 | class C1 48 | { 49 | [Thread][CompilerGenerated()]$Thread 50 | [Int32][CompilerGenerated()]$Int 51 | [ElapsedEventHandler][CompilerGenerated()]$EventHandler 52 | } 53 | 54 | # Test attributes that won't be found w/o using, but w/ implicit Attribute suffix 55 | [CompilerGeneratedAttribute()] 56 | class C2 57 | { 58 | [Thread][CompilerGeneratedAttribute()]$Thread 59 | [Int32][CompilerGeneratedAttribute()]$Int 60 | [ElapsedEventHandler][CompilerGeneratedAttribute()]$EventHandler 61 | } 62 | 63 | Describe "Using Namespace" -Tags "DRT" { 64 | It "Type literals w/ using namespace" { 65 | [Thread].FullName | Should Be System.Threading.Thread 66 | [Int32].FullName | Should Be System.Int32 67 | [ElapsedEventHandler].FullName | Should Be System.Timers.ElapsedEventHandler 68 | 69 | [C1].GetProperty("Thread").PropertyType.FullName | Should Be System.Threading.Thread 70 | [C1].GetProperty("Int").PropertyType.FullName | Should Be System.Int32 71 | [C1].GetProperty("EventHandler").PropertyType.FullName | Should Be System.Timers.ElapsedEventHandler 72 | } 73 | 74 | It "Covert string to Type w/ using namespace" { 75 | ("Thread" -as [Type]).FullName | Should Be System.Threading.Thread 76 | ("Int32" -as [Type]).FullName | Should Be System.Int32 77 | ("ElapsedEventHandler" -as [Type]).FullName | Should Be System.Timers.ElapsedEventHandler 78 | 79 | New-Object Int32 | Should Be 0 80 | New-Object CompilerGeneratedAttribute | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 81 | } 82 | 83 | It "Attributes w/ using namespace" { 84 | function foo 85 | { 86 | [DebuggerStepThrough()] 87 | param( 88 | [CompilerGeneratedAttribute()] 89 | $a, 90 | 91 | [CompilerGenerated()] 92 | $b 93 | ) 94 | 95 | "OK" 96 | } 97 | 98 | foo | Should Be OK 99 | $cmdInfo = gcm foo 100 | $cmdInfo.ScriptBlock.Attributes[0] | Should Be System.Diagnostics.DebuggerStepThroughAttribute 101 | $cmdInfo.Parameters['a'].Attributes[1] | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 102 | $cmdInfo.Parameters['b'].Attributes[1] | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 103 | 104 | [C1].GetProperty("Thread").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 105 | [C1].GetProperty("Int").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 106 | [C1].GetProperty("EventHandler").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 107 | 108 | [C2].GetProperty("Thread").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 109 | [C2].GetProperty("Int").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 110 | [C2].GetProperty("EventHandler").GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 111 | 112 | [C1].GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 113 | [C2].GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.Runtime.CompilerServices.CompilerGeneratedAttribute 114 | 115 | [E1].GetCustomAttributesData()[0].AttributeType.FullName | Should Be System.FlagsAttribute 116 | } 117 | 118 | It "Ambiguous type reference" { 119 | { [Timer] } | ShouldBeErrorId AmbiguousTypeReference 120 | } 121 | 122 | It "Parameters" { 123 | function foo([Thread]$t = $null) { 42 } 124 | 125 | foo | Should Be 42 126 | 127 | $mod = New-Module -Name UsingNamespaceModule -ScriptBlock { 128 | function Set-Thread([Thread]$t = $null) 129 | { 130 | 44 131 | } 132 | } 133 | Import-Module $mod 134 | Set-Thread | Should Be 44 135 | Remove-Module $mod 136 | } 137 | 138 | It "Generics" { 139 | function foo([List[string]]$l) 140 | { 141 | $l | Should Be "a string" 142 | } 143 | 144 | $l = [List[string]]::new() 145 | $l.Add("a string") 146 | foo $l 147 | } 148 | 149 | ShouldBeParseError "1; using namespace System" UsingMustBeAtStartOfScript 3 150 | ShouldBeParseError "using namespace Foo = System" UsingStatementNotSupported 0 151 | # TODO: add diagnostic (low pri) 152 | # ShouldBeParseError "using namespace System; using namespace System" UsingNamespaceAlreadySpecified 24 153 | } 154 | 155 | -------------------------------------------------------------------------------- /Security/Pester.Acl.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Tests for Get-Acl and Set-Acl" -Tags "innerloop" { 2 | 3 | It "Verifies that you can change the ACL of a file that you own, but don't have explicit access to" { 4 | 5 | $caughtError = $false 6 | 7 | try 8 | { 9 | $tempDirectory = Join-Path TestDrive: GetSetAclPrivilegeTest 10 | $null = New-Item -ItemType Directory $tempDirectory 11 | $acl = Get-Acl $tempDirectory 12 | $acl.SetSecurityDescriptorSddlForm("O:SYG:SYD:PAI") 13 | Set-Acl -AclObject $acl $tempDirectory -ErrorAction Stop 14 | 15 | $acl.SetSecurityDescriptorSddlForm("O:DUG:DUD:PAI(A;OICI;FA;;;DU)") 16 | Set-Acl -AclObject $acl $tempDirectory -ErrorAction Stop 17 | } 18 | catch 19 | { 20 | $caughtError = $true 21 | } 22 | 23 | $caughtError | Should be $false 24 | } 25 | 26 | It "invalid access policy throws an error" { 27 | $fileName = New-Item TestDrive:\newFile.txt -Force 28 | Get-Acl $fileName | Set-Acl $fileName -CentralAccessPolicy "SomeInvalidAccessPolicy" -ErrorAction SilentlyContinue -ErrorVariable setAclError 29 | $setAclError.FullyQualifiedErrorId | Should Be "SetAcl_CentralAccessPolicy,Microsoft.PowerShell.Commands.SetAclCommand" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Security/Pester.Authenticode.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Tests for authenticode cmdlets" { 2 | 3 | It "Verifies that we can retrieve catalog signatures from OS Binaries" { 4 | 5 | ## Only supported on Win8+ 6 | if([Version] (Get-WmiObject Win32_OperatingSystem).Version -lt ([Version] "6.2")) 7 | { 8 | return 9 | } 10 | 11 | $signature = Get-Command wmic | Get-Item | Get-AuthenticodeSignature 12 | $signature.IsOSBinary | Should be $true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Security/Pester.SuspiciousScriptBlockLogging.Tests.ps1: -------------------------------------------------------------------------------- 1 | function Test-SuspiciousScriptBlock 2 | { 3 | param( 4 | [ScriptBlock] $ScriptBlock, 5 | $Timeout = 30 6 | ) 7 | 8 | $mi = [ScriptBlock].GetMethod("CheckSuspiciousContent", [System.Reflection.BindingFlags] "InvokeMethod,Static,NonPublic") 9 | $results = $mi.Invoke($null, $ScriptBlock.Ast) 10 | 11 | if($results) { $true } 12 | else { $false } 13 | } 14 | 15 | Describe "Tests for suspicious script blocks being logged automatically" -Tags "OuterLoop" { 16 | 17 | It "Detects a bad type being used directly" { 18 | Test-SuspiciousScriptBlock { [System.Runtime.InteropServices.Marshal]::PtrToStringAuto } | Should be $true 19 | } 20 | 21 | It "Detects using a variable to access a static member" { 22 | 23 | Test-SuspiciousScriptBlock { $mshall::NumParamBytes } | Should be $true 24 | } 25 | 26 | It "Allows non-static access to a variable" { 27 | Test-SuspiciousScriptBlock -Timeout 3 { $mshall.NumParamBytes } | Should be $false 28 | } 29 | 30 | It "Detects casts to [Type]" { 31 | Test-SuspiciousScriptBlock { $mshall = [Type] ("System.Runtime.InteropService" + "s.Mars" + "hal") } | Should be $true 32 | } 33 | 34 | It "Allows casting to other object types" { 35 | Test-SuspiciousScriptBlock -Timeout 3 { $mshall = [String] ("System.Runtime.InteropService" + "s.Mars" + "hal") } | Should be $false 36 | } 37 | 38 | It "Detects access to [Type] members" { 39 | Test-SuspiciousScriptBlock { $mshall = [Type]::Equals("System.Runtime.InteropService" + "s.Mars" + "hal") } | Should be $true 40 | } 41 | 42 | It "Allows access to [Object] members" { 43 | Test-SuspiciousScriptBlock -Timeout 3 { $mshall = [Object]::Equals("System.Runtime.InteropService" + "s.Mars" + "hal") } | Should be $false 44 | } 45 | 46 | It "Detects type casting using -as" { 47 | Test-SuspiciousScriptBlock { $mshall = ("System.Runtime.InteropService" + "s.Mars" + "hal") -as [Type] } | Should be $true 48 | } 49 | 50 | It "Detects basic bad method invocation" { 51 | Test-SuspiciousScriptBlock { $foo.WriteProcessMemory() } | Should be $true 52 | } 53 | 54 | It "Detects indirect method invocation" { 55 | Test-SuspiciousScriptBlock { 56 | $foo = New-Object System.Object 57 | $method = "Write" + "ProcessMemory" 58 | $foo.$method() 59 | } | Should be $true 60 | } 61 | 62 | It "Detects PSObject method indirection" { 63 | Test-SuspiciousScriptBlock { 64 | $foo = New-Object System.Object 65 | $method = "Write" + "ProcessMemory" 66 | 67 | $foo.psobject.methods[$method].Invoke() 68 | } | Should be $true 69 | } 70 | 71 | It "Detects often-malicious methods" { 72 | Test-SuspiciousScriptBlock { 73 | $foo = New-Object System.Object 74 | [Object].GetMethods()[0].Invoke() 75 | } | Should be $true 76 | } 77 | 78 | It "Detects often-malicious methods" { 79 | Test-SuspiciousScriptBlock { 80 | $method = "Write" + "ProcessMemory" 81 | [Object].InvokeMember($method, $null) 82 | } | Should be $true 83 | } 84 | 85 | It "Detects AppDomain enumeration" { 86 | Test-SuspiciousScriptBlock { 87 | [AppDomain]::CurrentDomain.GetAssemblies()[0].GetTypes()[0].InvokeMember() 88 | } | Should be $true 89 | } 90 | 91 | It "Detects AppDomain enumeration" { 92 | Test-SuspiciousScriptBlock { 93 | [object].Assembly.GetTypes()[0].InvokeMember() 94 | } | Should be $true 95 | } 96 | } -------------------------------------------------------------------------------- /Security/pester.security.credential.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Get-Credential" -Tags "innerloop" { 2 | It "throws error on a long message" { 3 | Get-Credential -Message ('a'*2MB) -ErrorVariable credentialError -ErrorAction SilentlyContinue 4 | $credentialError.FullyQualifiedErrorId | Should be "CouldNotPromptForCredential,Microsoft.PowerShell.Commands.GetCredentialCommand" 5 | } 6 | } -------------------------------------------------------------------------------- /engine/EngineAPIs/WMI.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe -tags 'Innerloop', 'DRT' "COM ComplexMethodInvoke" { 2 | BeforeAll { 3 | $wmiclass=[WMICLass]"win32_processstartup" 4 | 5 | $ai = $wmiclass.createinstance() 6 | $ai.ShowWindow = 0 7 | $ai.X = 0 8 | $ai.Y = 0 9 | $wmiclass = [WMICLass]"win32_process" 10 | $pInfo = $wmiclass.Create("cmd.exe",[Environment]::CurrentDirectory,$ai) 11 | 12 | $tempId = $pInfo.ProcessId 13 | $result = get-WmiObject -query "select * from win32_process where processid=$tempId" 14 | } 15 | It "class name should be win32_process" { 16 | $wmiclass.Name | Should Be win32_Process 17 | } 18 | 19 | It "ProcessId should not be null" { 20 | $pInfo.ProcessId | Should Not BeNullOrEmpty 21 | } 22 | 23 | It "get-WmiObject -query can find process id" { 24 | $result.ProcessId | Should be $pInfo.ProcessId 25 | } 26 | 27 | AfterAll { 28 | $p= get-process -id $pInfo.ProcessId -ea SilentlyContinue 29 | if ( $null -ne $null) 30 | { 31 | $p.Kill() 32 | } 33 | } 34 | } 35 | 36 | Describe -tags 'Innerloop', 'DRT' "DateTimeConversions" { 37 | # WMI adapter testcase 38 | It "Conversion can round trip" { 39 | $wmiclass = [wmiclass]"win32_processstartup" 40 | $currentDate = [DateTime]::Now 41 | $dmtfDate = $wmiclass.ConvertFromDateTime($currentDate) 42 | $result = $wmiclass.ConvertToDateTime($dmtfDate) 43 | "$currentDate" | Should Be "$result" 44 | } 45 | } 46 | 47 | Describe -tags 'Innerloop', 'DRT' "GetMemberWMI" { 48 | # WMI adapter testcase 49 | BeforeAll { 50 | $processes = get-wmiobject win32_process 51 | $commandFromDotNet = New-Object wmisearcher -ArgumentList "select * from win32_process" 52 | $commandFromDotNetGet = $commandFromDotNet.get() 53 | $countMemberFromDotnet = ($commandFromDotNetGet | Get-Member).count 54 | $countMemberMemberTypeFromDotNet = ($commandFromDotNetGet | Get-Member -MemberType Properties).count 55 | } 56 | 57 | AfterAll { 58 | [System.GC]::Collect() 59 | [System.GC]::WaitForPendingFinalizers() 60 | } 61 | 62 | It "get-wmiobject win32_process should return at least 2 objects" { 63 | $processes.Count -gt 1 | Should Be $true 64 | } 65 | 66 | It "win32_process object returns correct number of members" { 67 | $members = $processes[0] | Get-Member 68 | $count = $members.Count 69 | $count | Should Be $countMemberFromDotnet 70 | } 71 | 72 | It "win32_process object returns correct number of properties" { 73 | $members = $processes[0] | Get-Member -membertype properties 74 | $members.Count | Should Be $countMemberMemberTypeFromDotNet 75 | } 76 | } 77 | Describe -tags 'Innerloop', 'DRT' "GetRelatedVariations" { 78 | # WMI adapter testcase 79 | 80 | BeforeAll { 81 | $wmiclass = [wmiclass]"win32_service" 82 | } 83 | 84 | It "win32_service should return atleast 1 related class" { 85 | $rClasses = $wmiclass.GetRelatedClasses() 86 | $rClasses.Count | Should Not Be 0 87 | } 88 | 89 | It "win32_service should return win32_wmisetting related class" { 90 | $rClasses = $wmiclass.GetRelatedClasses("Win32_WMISetting") 91 | $rClasses | Should Not BeNullOrEmpty 92 | } 93 | 94 | It "exception was thrown when calling GetRelationshipClasses(1,2,3,4,5)" { 95 | try { 96 | $wmiclass.GetRelationshipClasses(1,2,3,4,5) 97 | throw "Execution OK" 98 | } 99 | catch { 100 | $_.FullyQualifiedErrorId | should be "MethodCountCouldNotFindBest" 101 | } 102 | } 103 | } 104 | Describe -tags 'Innerloop', 'DRT' "GetWMIQuery" { 105 | # WMI adapter testcase 106 | It "Query returns at least one result" { 107 | $wmisearch1 = get-wmiobject -query 'Select * from Win32_process where Name="lsass.exe"' 108 | $wmisearch1 | Should Not BeNullOrEmpty 109 | } 110 | 111 | It "Associators of {win32_Service} should return 0 objects" { 112 | $wmisearch2 = get-wmiobject -query 'Associators of {win32_service}' 113 | $wmisearch2 | Should BeNullOrEmpty 114 | } 115 | } 116 | Describe -tags 'Innerloop', 'DRT' "GetWMIType" { 117 | # WMI adapter testcase 118 | 119 | It "GetType() on a [WMIClass] should return a ManagementClass" { 120 | $wmiclass = [wmiclass]"win32_process" 121 | $wmiclass.GetType() | Should be ([System.Management.ManagementClass]) 122 | } 123 | 124 | It "[wmi]'win32_process.handle=0' should return management object" { 125 | $wmiobj = [wmi]"win32_process.Handle=0" 126 | $wmiobj.getType() | Should Be ([system.management.managementobject]) 127 | } 128 | } 129 | Describe -tags 'Innerloop', 'DRT' "InParameters" { 130 | # Accessing InParameters of a Method should not throw exceptions. 131 | It "InParameters should not be null" { 132 | $wmiclass = [WMICLass]"win32_process" 133 | $method = @($wmiclass.Methods)[0] 134 | $parameters = $method.InParameters 135 | $parameters | Should Not BeNullOrEmpty 136 | } 137 | } 138 | Describe -tags 'Innerloop', 'DRT' "MethodInvokeStringNull" { 139 | # WMI adapter testcase 140 | # Refer Bug938036 : Invocation of WMI method with $null argument is problematic 141 | BeforeAll { 142 | $wmiclass = [WMIClass]"Win32_Process" 143 | $pInfo1 = $wmiclass.Create("ipconfig.exe",$null,$null) 144 | 145 | $mp=$wmiclass.psbase.GetMethodParameters("Create") 146 | $mp.CommandLine = "cmd.exe" 147 | $mp.CurrentDirectory = $null 148 | $mp.ProcessStartupInformation = $null 149 | $pInfo2=$wmiclass.psbase.InvokeMethod("Create",$mp,$null) 150 | } 151 | AfterAll { 152 | $p = get-process -id $pInfo1.ProcessId -ea silentlycontinue 153 | if ( $null -ne $p ) { $p.Kill() } 154 | $p = get-process -id $pInfo2.ProcessId -ea silentlycontinue 155 | if ( $null -ne $p ) { $p.Kill() } 156 | } 157 | 158 | It "WMI Create method call should succeed" { 159 | $pInfo1.ReturnValue | Should Be 0 160 | } 161 | 162 | It "ProcessId is not null" { 163 | $pInfo1.ProcessId | Should Not BeNullOrEmpty 164 | } 165 | 166 | It "Create method call should succeed" { 167 | $pInfo2.ReturnValue | Should Be 0 168 | } 169 | It "ProcessId is not null" { 170 | $pInfo2.ProcessId | Should Not BeNullOrEmpty 171 | } 172 | } 173 | Describe -tags 'Innerloop', 'DRT' "Searcher MethodInvokeWMI" { 174 | # WMI adapter testcase 175 | 176 | It "[WMISearcher] found process from id" { 177 | $searcher = [WMISearcher]"select * from win32_process where processid=$PID" 178 | $pInfo = $searcher.Get() 179 | @($pInfo).Count | should be 1 180 | } 181 | } 182 | 183 | Describe -tags 'Innerloop', 'DRT' "win8_238481" { 184 | # Win8: 238481:Name property does not work when pipelined from Get-WMIObject cmdlet. 185 | BeforeAll { 186 | $actual = @(get-WmiObject -list | select -first 1 | % { $_.name } ) 187 | $w32p = get-WmiObject -list win32_process 188 | } 189 | 190 | It "get-WmiObject -list | select -first 1 | % { $_.name } returns 1 result" { 191 | $actual.count | Should Be 1 192 | } 193 | 194 | It "AliasProperty Name is not working for win32_process ManagementClass" { 195 | $w32p.Name | Should be "win32_process" 196 | } 197 | 198 | It "Setting a new value for AliasProperty works" { 199 | $w32p.Name = "blah" 200 | $w32p.Name | Should Be "blah" 201 | } 202 | } 203 | 204 | Describe -tags 'Innerloop', 'DRT' "WMI" { 205 | # WMI adapter testcase 206 | It "retrieving single service should return 1 object" { 207 | $wmi = [WMI]"win32_service.Name='winmgmt'" 208 | @($wmi).Count | Should Be 1 209 | } 210 | } 211 | 212 | Describe -tags 'Innerloop', 'DRT' "WMIBaseObjectSetProperty" { 213 | # Setting property on a ManagementBaseObject object 214 | 215 | BeforeAll { 216 | $procClass=[WMICLass]"win32_processstartup" 217 | $ai = $procClass.createinstance() 218 | $ai.ShowWindow = 0 219 | $ai.X = 0 220 | $ai.Y = 0 221 | $wmiclass = [wmiclass]"win32_process" 222 | $wmiMethodParameters = $wmiclass.psbase.GetMethodParameters("Create") 223 | $wmiMethodParameters.CommandLine = "cmd.exe" 224 | $wmiMethodParameters.CurrentDirectory = "." 225 | $wmiMethodParameters.ProcessStartupInformation = $ai 226 | $pInfoCreate = $wmiclass.psbase.InvokeMethod("Create",$wmiMethodParameters,$null); 227 | $tempId = $pInfoCreate.ProcessId 228 | $pInfoObject = get-WmiObject -query "select * from win32_process where processid=$tempId" 229 | } 230 | AfterAll { 231 | $pInfoObject.Terminate() > $null 232 | } 233 | 234 | It "Win32_Process.PsBase.InvokeMethod() method returned null" { 235 | $pInfoCreate.ReturnValue | Should Be 0 236 | } 237 | It "ProcessId is set" { 238 | $pInfoCreate.ProcessId | Should Not BeNullOrEmpty 239 | } 240 | 241 | It "get-WmiObject -query found process via id" { 242 | $pInfoObject.ProcessId | should be $pInfoCreate.ProcessId 243 | } 244 | } 245 | Describe -tags 'Innerloop', 'DRT' "WMIClass" { 246 | # WMI adapter testcase 247 | It "Cast to improper WMIClass fails" { 248 | try { 249 | [WMIClass]"non-existent-class" 250 | throw "Execution OK" 251 | } catch { 252 | $_.FullyQualifiedErrorId | Should be "InvalidCastToWMIClass" 253 | } 254 | } 255 | } 256 | Describe -tags 'Innerloop', 'DRT' "WMIClassExceptions" { 257 | # WMI adapter testcase 258 | It "setting non-existent instance property throws" { 259 | $wmiclass = [wmiclass]"win32_processstartup" 260 | try { 261 | $wmiclass.X="10" 262 | throw "Execution OK" 263 | } catch { 264 | $_.FullyQualifiedErrorId | should be "ExceptionWhenSetting" 265 | } 266 | } 267 | } 268 | Describe -tags 'Innerloop', 'DRT' "WMIObjectExceptions" { 269 | # WMI adapter testcase 270 | 271 | It "Calling incorrect method from an instance throws correctly" { 272 | try { 273 | $wmiobject = [wmisearcher]"select * from win32_process" 274 | $wmiobject.Create("cmd.exe") 275 | Throw "Execution OK" 276 | } catch { 277 | $_.FullyQualifiedErrorId | should be "MethodNotFound" 278 | } 279 | } 280 | 281 | It "Invalid cast throws correctly" { 282 | try { 283 | $wmiobject=[wmi]'win32_process.Name="nonexistentprocess"' 284 | Throw "Execution OK" 285 | } catch { 286 | $_.FullyQualifiedErrorId | should be "InvalidCastToWMI" 287 | } 288 | } 289 | 290 | } 291 | Describe -tags 'Innerloop', 'P1' "WMISearcher" { 292 | # WMI adapter testcase 293 | BeforeAll { 294 | $wmiSearcher = [WMISearcher]"Select * from Win32_Process" 295 | $searchResult = $wmiSearcher.Get() 296 | $expected = get-process 297 | } 298 | It "process count should be approximately the same" { 299 | $diff = $expected.Count - $searchResult.Count 300 | [math]::Abs($diff) -lt 5 | should be $true 301 | } 302 | 303 | It "WMI search should return atleast one result" { 304 | $system = ([WMISearcher]'Select * from win32_process where Name="System"').Get() 305 | $system | Should Not BeNullOrEmpty 306 | } 307 | 308 | It "associators of win32_service should return 0 objects" { 309 | $wmisearcher = [WMISearcher]'Associators of {win32_service}' 310 | $wmisearcher.Get().Count | Should be 0 311 | } 312 | 313 | It "associators of WinMgmt should return at least 1 object." { 314 | # added a where to reduce time - it still finds associators 315 | $wmisearcher = [WMISearcher]'Associators of {win32_service="WinMgmt"} WHERE ResultClass=Win32_ComputerSystem' 316 | $wmisearcher.Get().Count | Should Not Be 0 317 | } 318 | 319 | } 320 | Describe -tags 'Innerloop', 'DRT' "WrongArguments" { 321 | # WMI adapter testcase 322 | BeforeAll { 323 | $wmiclass = [WMIClass]"win32_process" 324 | } 325 | It "WMIClass.Create() with 5 wrong arguments should throw" { 326 | try { 327 | $wmiclass.Create("cmd.exe",1,2,3,4,5) 328 | Throw "Execution OK" 329 | } catch { 330 | $_.FullyQualifiedErrorId | Should be "MethodCountCouldNotFindBest" 331 | } 332 | } 333 | 334 | It "Create() with wrong parameter type should throw" { 335 | try { 336 | $wmiclass.Create("cmd.exe",1,2) 337 | Throw "Execution OK" 338 | } catch { 339 | $_.FullyQualifiedErrorId | Should Be "CatchFromBaseAdapterMethodInvoke" 340 | } 341 | } 342 | 343 | It "Create() with wrong type should not create process" { 344 | $pInfo = $wmiclass.Create(1) 345 | $pInfo.ReturnValue | Should Not Be 0 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /engine/EngineAPIs/XmlAdapter.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe -tags 'Innerloop', 'DRT' "bug613651" { 2 | # Bug 613651: ParameterizedProperty 'Item' mask an XML Document 'Item' tag 3 | # 4 | # The bug would produce an error when get-member was called (The XML adapter would try 5 | # to add the "Item" parameterized property of the XmlElement to a dictionary that 6 | # already contains the "Item" adapted property) 7 | # 8 | It "The number of properties is incorrect" { 9 | $x = [xml] "12" 10 | $count = @(get-member -i $x.root -membertype property | measure).Count 11 | $count | Should Be 1 12 | } 13 | } 14 | Describe -tags 'Innerloop', 'DRT' "bug914412" { 15 | # Bug:914412: XML Adapter should support #cdata-section,#text sections 16 | BeforeAll { 17 | $cdata = 'some cdata content' 18 | $text = 'some text' 19 | $xmlContent = "$text" 20 | $xml = [xml]$xmlContent 21 | $xmlCdata = $xml.a."#cdata-section" 22 | $xmlText = $xml.a."#text" 23 | 24 | } 25 | Context "Getting values from Xml" { 26 | It "[xml] type accelerator gives proper type" { 27 | $xml.GetType() | Should Be ([System.Xml.XmlDocument]) 28 | } 29 | 30 | It "cdata has correct value" { 31 | $XmlCdata | should Be $cdata 32 | } 33 | It "text has correct value" { 34 | $xmlText | should Be $text 35 | } 36 | } 37 | 38 | Context "Setting new values for Xml Elements" { 39 | BeforeAll { 40 | $newCdata = 'new cdata content' 41 | $newText = 'new text' 42 | $xml.a."#cdata-section" = $newCdata 43 | $xml.a."#text" = $newText 44 | $newXmlCdata = $xml.a."#cdata-section" 45 | $newXmlText = $xml.a."#text" 46 | } 47 | It "text of element has correct value" { 48 | $newXmlText | Should be $newText 49 | } 50 | 51 | It "Expected: $newCdata Actual: $xmlCdata" { 52 | $newXmlCdata | should be $newCdata 53 | } 54 | } 55 | } 56 | Describe -tags 'Innerloop', 'P1' "win8_481571" { 57 | # Win8: 481571 Enforcing "PreserveWhitespace" breaks XML pretty printing 58 | It "[xml] preserves comments" { 59 | $content = "`r`n " 60 | $xml = [xml]$content 61 | $actual = $xml.a.b.("#comment") 62 | $actual | Should Be " comment " 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /engine/ExtensibleTypeSystem/ETS.Tests.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShell/PowerShell-Tests/40e562cdbd907f1aa98bec68d27af1d5374a338e/engine/ExtensibleTypeSystem/ETS.Tests.ps1 -------------------------------------------------------------------------------- /engine/ExtensibleTypeSystem/Pester.FileVersionInfo.Tests.ps1: -------------------------------------------------------------------------------- 1 | # Tests related to TFS item 1370183 [PSUpgrade] FileInfo (from Get-Item, et al) VersionInfo returns misleading binary version info 2 | # Connect request https://connect.microsoft.com/PowerShell/feedback/details/1027483/fileinfo-from-get-item-et-al-versioninfo-returns-misleading-binary-version-info 3 | 4 | Describe "Tests for new script properties of System.Diagnostics.FileVersionInfo" { 5 | 6 | It "FileVersionRaw should match 'File*Part' properties" { 7 | $hostFileVersion = Get-Process -Id $pid -FileVersionInfo 8 | $partsString = $hostFileVersion.FileMajorPart, $hostFileVersion.FileMinorPart, $hostFileVersion.FileBuildPart, $hostFileVersion.FilePrivatePart -join "." 9 | $hostFileVersion.FileVersionRaw -eq $partsString | Should Be $true 10 | } 11 | 12 | It "ProductVersionRaw should match 'Product*Part' properties" { 13 | $hostFileVersion = Get-Process -Id $pid -FileVersionInfo 14 | $partsString = $hostFileVersion.ProductMajorPart, $hostFileVersion.ProductMinorPart, $hostFileVersion.ProductBuildPart, $hostFileVersion.ProductPrivatePart -join "." 15 | $hostFileVersion.ProductVersionRaw -eq $partsString | Should Be $true 16 | } 17 | } -------------------------------------------------------------------------------- /engine/ExtensibleTypeSystem/Pester.PSObject.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Testing of PSObject behaviour" { 2 | 3 | It "Tests that PSObject.ToString() doesn't invoke script properties" { 4 | $env:Bug_2108520_Evaluated = "False" 5 | $x = New-Object PSObject 6 | $x | Add-Member ScriptProperty "Test" { $env:Bug_2108520_Evaluated = "True" } 7 | $x | Add-Member NoteProperty "Test2" 2 8 | $env:Bug_2108520_Evaluated | Should be "False" 9 | } 10 | } -------------------------------------------------------------------------------- /engine/Other/Pester.Engine.Other.InformationStream.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Validation for Information stream in PowerShell" { 2 | it "Supports Write-Information cmdlet and InformationVariable" { 3 | $process = Get-Process -id $pid 4 | Write-Information $process -Tags "Tag1","Tag2" -InformationVariable infoVar 5 | 6 | $infoVar.MessageData.Id | Should be $pid 7 | $infoVar.Tags[0] | Should be Tag1 8 | $infoVar.Tags[1] | Should be Tag2 9 | } 10 | 11 | it "Verifies InformationAction" { 12 | $output = Write-Information Test -Tags "Tag1","Tag2" *>&1 -InformationAction Ignore 13 | $output | Should be $null 14 | } 15 | 16 | it "Verifies InformationPreference" { 17 | $informationPreference = "Ignore" 18 | $output = Write-Information Test -Tags "Tag1","Tag2" *>&1 -InformationAction Ignore 19 | $output | Should be $null 20 | } 21 | 22 | it "Verifies Information stream redirection" { 23 | $process = Get-Process -id $pid 24 | $result = Write-Information $process -Tags "Tag1","Tag2" 6>&1 25 | 26 | $result.MessageData.Id | Should be $pid 27 | $result.Tags[0] | Should be Tag1 28 | $result.Tags[1] | Should be Tag2 29 | } 30 | 31 | it "Verifies Information stream on PowerShell object" { 32 | $ps = [PowerShell]::Create() 33 | $null = $ps.AddScript('$process = Get-Process -id $pid; $result = Write-Information $process -Tags "Tag1","Tag2"').Invoke() 34 | 35 | $result = $ps.Streams.Information[0] 36 | 37 | $result.MessageData.Id | Should be $pid 38 | $result.Tags[0] | Should be Tag1 39 | $result.Tags[1] | Should be Tag2 40 | } 41 | 42 | it "Verifies Information stream on jobs" { 43 | $j = Start-Job { Write-Information "FromJob" -Tags "Tag1","Tag2" } 44 | Wait-Job $j 45 | 46 | $result = $j.ChildJobs[0].Information[0] 47 | 48 | $result.MessageData | Should be "FromJob" 49 | $result.Tags[0] | Should be Tag1 50 | $result.Tags[1] | Should be Tag2 51 | } 52 | 53 | it "Verifies Information stream on workflow" { 54 | ## Test regular invocation 55 | workflow foo { Write-Information Bar } 56 | foo -InformationVariable bar 57 | $bar.MessageData | Should be "Bar" 58 | 59 | ## Test job invocation 60 | $j = foo -asjob 61 | Wait-Job $j 62 | $j.ChildJobs[0].Information.MessageData | Should be "Bar" 63 | 64 | ## Ensure that InformationAction works on workflow 65 | $result = foo -informationaction ignore *>&1 66 | $result | Should be $null 67 | } 68 | 69 | it "Verifies InformationVariable in workflow compilation" { 70 | workflow IVWorkflowTest { Write-Information Test -InformationVariable Test; $test } 71 | $result = IVWorkflowTest 72 | $result.MessageData | Should be "Test" 73 | } 74 | 75 | it "Verifies Information stream works over remoting" { 76 | icm localhost { Write-Information Test } -InformationVariable Test 77 | $test.MessageData | Should be "Test" 78 | } 79 | 80 | it "Verifies client-side stream redirection works over remoting" { 81 | 82 | $result = icm localhost { Write-Information Test 6>&1 } 83 | $result.MessageData | Should be "Test" 84 | } 85 | 86 | it "Verifies PowerShell-calling-PowerShell" { 87 | 88 | $result = powershell -noprofile { $pid; Write-Information Bar } *>&1 89 | $processPid = $result[0] 90 | $result[1].ProcessId | Should be $processPid 91 | } 92 | 93 | it "Verifies that host output can be redirected" { 94 | function spammer { [CmdletBinding()] param() Write-Host "Some host output" } 95 | spammer -InformationVariable spam 96 | $spam.MessageData.Message | Should be "Some host output" 97 | } 98 | } -------------------------------------------------------------------------------- /engine/Runspace/Pester.Runspace.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Runspace operations which" { 2 | # determine whether you're elevated and skip the remote test in that case 3 | BeforeAll { 4 | $windowsIdentity = [Security.Principal.WindowsIdentity]::GetCurrent() 5 | $windowsPrincipal = new-object Security.Principal.WindowsPrincipal $windowsIdentity 6 | if ($windowsPrincipal.IsInRole("Administrators") -eq 1) 7 | { 8 | $skip = $false 9 | $skipReason = "" 10 | } 11 | else 12 | { 13 | $skip = $true 14 | $skipReason = " (skipping because we're not an admin)" 15 | } 16 | } 17 | Context "Assign values to DefaultRunspace" { 18 | BeforeEach { 19 | $origRS = [runspace]::DefaultRunspace 20 | } 21 | # pester requires the original runspace to be available, so we assign 22 | # and then retrieve. We can't leave the DefaultRunspace 23 | # in a different state when we call our assertions because 24 | # pester needs the environment set up in that runspace 25 | It "Null can be assigned to DefaultRunspace" { 26 | [Runspace]::DefaultRunspace = $null 27 | $newRs = [runspace]::DefaultRunspace 28 | [Runspace]::DefaultRunspace = $origRS 29 | $newRs | Should BeNullOrEmpty 30 | } 31 | It "A LocalRunspace can be assigned to DefaultRunspace" { 32 | $nrs = [runspacefactory]::CreateRunspace() 33 | $nrs.Open() 34 | [runspace]::DefaultRunspace = $nrs 35 | $newRS = [runspace]::DefaultRunspace 36 | [Runspace]::DefaultRunspace = $origRS 37 | $newRS.Name |Should Not Be $origRS.Name 38 | 39 | } 40 | It -skip:$skip "A RemoteRunspace fails to be assigned to DefaultRunspace.${skipReason}" { 41 | try 42 | { 43 | $s = New-PSSession localhost 44 | [runspace]::DefaultRunspace = $s.Runspace 45 | throw "Execution OK" 46 | } 47 | catch 48 | { 49 | $_.FullyQualifiedErrorId | Should be ExceptionWhenSetting 50 | $_.Exception.InnerException.GetType().Name | 51 | Should Be InvalidOperationException 52 | } 53 | finally 54 | { 55 | if ( $s ) { $s | Remove-PSSession } 56 | } 57 | } 58 | } 59 | Context "Retrieve the RunspaceIsRemote property and validate" { 60 | It "The default runspace is not Remote" { 61 | [Runspace]::DefaultRunspace.RunspaceIsRemote | should be $false 62 | } 63 | It "A runspace created by runspacefactory without arguments is not Remote" { 64 | [RunspaceFactory]::CreateRunspace().RunspaceIsRemote | should be $false 65 | } 66 | It -skip:$skip "A Runspace created as part of new-pssession is Remote.${skipReason}" { 67 | try 68 | { 69 | $s = new-PsSession localhost 70 | $s.Runspace.RunspaceIsRemote | Should be $true 71 | } 72 | finally 73 | { 74 | if ( $s ) { $s | Remove-PsSession } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /provider/Providers/Pester.Get-ChildItem.Depth.Tests.ps1: -------------------------------------------------------------------------------- 1 | function CreateDirStructure 2 | { 3 | param( 4 | [string] $Dir, 5 | [int] $Width, 6 | [int] $Depth 7 | ) 8 | 9 | 1..$Width | % { 10 | $newDirPath = Join-Path $Dir ("Level"+$Depth+$_) 11 | $newFilePath = $newDirPath + ".txt" 12 | new-item -type directory -Path $newDirPath -Force | Out-Null 13 | Get-Date | Out-File $newFilePath 14 | if ($Depth -gt 0) { CreateDirStructure $newDirPath $Width ($Depth - 1) } 15 | } 16 | } 17 | 18 | #Pester.psm1 does not currently implement BeforeAll / AfterAll for suite setup/cleanup. 19 | $testDir = "$env:TEMP\GetChildItemDepthTests" 20 | CreateDirStructure $testDir 2 2 21 | 22 | <# Above produces this structure: 23 | $env:Temp\GetChildItemDepthTests\Level21 24 | $env:Temp\GetChildItemDepthTests\Level21.txt 25 | $env:Temp\GetChildItemDepthTests\Level21\Level11 26 | $env:Temp\GetChildItemDepthTests\Level21\Level11.txt 27 | $env:Temp\GetChildItemDepthTests\Level21\Level11\Level01 28 | $env:Temp\GetChildItemDepthTests\Level21\Level11\Level01.txt 29 | $env:Temp\GetChildItemDepthTests\Level21\Level11\Level02 30 | $env:Temp\GetChildItemDepthTests\Level21\Level11\Level02.txt 31 | $env:Temp\GetChildItemDepthTests\Level21\Level12 32 | $env:Temp\GetChildItemDepthTests\Level21\Level12.txt 33 | $env:Temp\GetChildItemDepthTests\Level21\Level12\Level01 34 | $env:Temp\GetChildItemDepthTests\Level21\Level12\Level01.txt 35 | $env:Temp\GetChildItemDepthTests\Level21\Level12\Level02 36 | $env:Temp\GetChildItemDepthTests\Level21\Level12\Level02.txt 37 | $env:Temp\GetChildItemDepthTests\Level22 38 | $env:Temp\GetChildItemDepthTests\Level22.txt 39 | $env:Temp\GetChildItemDepthTests\Level22\Level11 40 | $env:Temp\GetChildItemDepthTests\Level22\Level11.txt 41 | $env:Temp\GetChildItemDepthTests\Level22\Level11\Level01 42 | $env:Temp\GetChildItemDepthTests\Level22\Level11\Level01.txt 43 | $env:Temp\GetChildItemDepthTests\Level22\Level11\Level02 44 | $env:Temp\GetChildItemDepthTests\Level22\Level11\Level02.txt 45 | $env:Temp\GetChildItemDepthTests\Level22\Level12 46 | $env:Temp\GetChildItemDepthTests\Level22\Level12.txt 47 | $env:Temp\GetChildItemDepthTests\Level22\Level12\Level01 48 | $env:Temp\GetChildItemDepthTests\Level22\Level12\Level01.txt 49 | $env:Temp\GetChildItemDepthTests\Level22\Level12\Level02 50 | $env:Temp\GetChildItemDepthTests\Level22\Level12\Level02.txt 51 | #> 52 | 53 | Describe "Tests for Depth parameter of Get-ChildItem" { 54 | 55 | It "Depth 0 for items" { 56 | (Get-ChildItem $testDir -Recurse -Depth 0).Count -eq (Get-ChildItem $testDir).Count | Should Be $true 57 | } 58 | It "Depth 0 for names" { 59 | (Get-ChildItem $testDir -Recurse -Depth 0 -Name).Count -eq (Get-ChildItem $testDir -Name).Count | Should Be $true 60 | } 61 | It "FileSystemProvider limited recursion for items" { 62 | (Get-ChildItem $testDir -Recurse -Depth 1).Count | Should Be 12 63 | } 64 | It "FileSystemProvider limited recursion for names" { 65 | (Get-ChildItem $testDir -Recurse -Depth 1 -Name).Count | Should Be 12 66 | } 67 | It "RegistryProvider limited recursion for items" { 68 | $topLevelOnlyCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles").Count 69 | $depth1RecursionCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Recurse -Depth 1).Count 70 | $fullRecursionCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Recurse).Count 71 | ($depth1RecursionCount -gt $topLevelOnlyCount) -and ($depth1RecursionCount -lt $fullRecursionCount) | Should Be $true 72 | } 73 | It "RegistryProvider limited recursion for names" { 74 | $topLevelOnlyCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Name).Count 75 | $depth1RecursionCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Recurse -Depth 1 -Name).Count 76 | $fullRecursionCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Recurse -Name).Count 77 | ($depth1RecursionCount -gt $topLevelOnlyCount) -and ($depth1RecursionCount -lt $fullRecursionCount) | Should Be $true 78 | } 79 | It "Implicit recursion for FileSystemProvider" { 80 | (Get-ChildItem $testDir -Depth 1).Count -eq (Get-ChildItem -Recurse $testDir -Depth 1).Count | Should Be $true 81 | } 82 | It "Implicit recursion for RegistryProvider" { 83 | $explicitRecursionCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Recurse -Depth 0 -Name).Count 84 | $implicitRecursionCount = (Get-ChildItem "hklm:\SYSTEM\CurrentControlSet\Hardware Profiles" -Depth 0 -Name).Count 85 | $implicitRecursionCount | Should Be $explicitRecursionCount 86 | } 87 | } 88 | 89 | del $testDir -Recurse -Force 90 | -------------------------------------------------------------------------------- /provider/Providers/Pester.Providers.DrivePersistence.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Tests to check persistence of providers drives" { 2 | 3 | # test for bug 2784052 4 | It "Get-PSDrive should not remove custom drives" { 5 | $newDrives = Get-ChildItem function:[e-z]: -Name | ?{ !(Test-Path $_) } | select -First 7 6 | $newDriveLetters = $newDrives -replace ".$" 7 | $originalDriveCount = (Get-PSDrive).Count 8 | new-psdrive $newDriveLetters[0] -psp FileSystem -root 'c:\' 9 | new-psdrive $newDriveLetters[1] -psp Registry -root 'hkcu:\' 10 | new-psdrive $newDriveLetters[2] -psp Environment -root '' 11 | new-psdrive $newDriveLetters[3] -psp Function -root '' 12 | new-psdrive $newDriveLetters[4] -psp Certificate -root '\' 13 | new-psdrive $newDriveLetters[5] -psp Variable -root '' 14 | new-psdrive $newDriveLetters[6] -psp Alias -root '' 15 | 16 | # run Get-PSDrive several times to check for bug 2784052 (Fixing regression in CL#498641) 17 | # bug in 'if' condition in get-psdrive resulted in custom non-filesystem provider drives being removed when get-psdrive was called. 18 | 1..3 | % {Get-PSDrive} | Out-Null 19 | $newDriveCount = (Get-PSDrive).Count 20 | $newDriveCount | Should Be ($originalDriveCount + 7) 21 | $newDrives | %{ Test-Path $_ | Should Be $true } 22 | Remove-PSDrive $newDriveLetters 23 | } 24 | } -------------------------------------------------------------------------------- /provider/Providers/pester.management.junction.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Junctions" -Tags "P1", "Innerloop" { 2 | Context "Cyclic Junctions" { 3 | BeforeAll { 4 | $junctionTarget = (New-Item -Path "TestDrive:\JunctionTarget" -ItemType Directory -Force).FullName 5 | $null = New-Item -Path "TestDrive:\JunctionTarget\file.txt" 6 | $cyclicJunction = (New-Item -Path "TestDrive:\JunctionTarget\Cyclic" -target $junctionTarget -ItemType junction -Force).fullName 7 | } 8 | 9 | It "copy junction with force gets an error" { 10 | Copy-Item $cyclicJunction -Recurse -Destination "TestDrive:\CopyDestination" -force -ErrorAction SilentlyContinue -ErrorVariable copyErrorDirectory 11 | $copyErrorDirectory.FullyQualifiedErrorId | Should Be "CopyDirectoryInfoItemIOError,Microsoft.PowerShell.Commands.CopyItemCommand" 12 | } 13 | 14 | It "cannot be deleted without Force" { 15 | Remove-Item $cyclicJunction -Recurse -ErrorVariable cyclicDeleteError -ErrorAction SilentlyContinue 16 | $cyclicDeleteError.FullyQualifiedErrorId | Should Be "DirectoryNotEmpty,Microsoft.PowerShell.Commands.RemoveItemCommand" 17 | } 18 | 19 | It "can be deleted" { 20 | Remove-Item $cyclicJunction -Force -Recurse 21 | $cyclicJunction | Should Not Exist 22 | } 23 | } 24 | 25 | Context "Junction operations" { 26 | 27 | BeforeAll { 28 | $junctionTarget = (New-Item -Path "TestDrive:\JunctionTarget" -ItemType Directory -Force).FullName 29 | $null = New-Item -Path "TestDrive:\JunctionTarget\file.txt" 30 | $junction = (New-Item -Path "TestDrive:\JunctionDestination" -target $junctionTarget -ItemType junction -Force).fullName 31 | } 32 | 33 | It "target can be deleted" { 34 | Remove-Item $junctionTarget -Recurse -Force 35 | Get-ChildItem $junction -ErrorVariable targetDelete -ErrorAction SilentlyContinue 36 | $targetDelete.FullyQualifiedErrorId | Should Be "DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand" 37 | } 38 | 39 | AfterAll { 40 | Remove-Item $junction -Force -ErrorAction SilentlyContinue 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /remoting/Cmdlets/NoReboot.tests.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Tests for PowerShell Remoting Cmdlets with regards to WSMan No-Reboot feature 3 | # 2015 4 | # 5 | 6 | function Get-PluginDetails([string]$name = $(throw "Endpoint name not provided.")) 7 | { 8 | function Unescape-Xml($s) { 9 | if ($s) { 10 | $s = $s.Replace("<", "<"); 11 | $s = $s.Replace(">", ">"); 12 | $s = $s.Replace(""", '"'); 13 | $s = $s.Replace(""", '"'); 14 | $s = $s.Replace("'", "'"); 15 | $s = $s.Replace("&", "&"); 16 | } 17 | 18 | return $s; 19 | } 20 | 21 | $hashprovider = new-object system.collections.CaseInsensitiveHashCodeProvider 22 | $comparer=new-object system.collections.CaseInsensitiveComparer 23 | $h = new-object system.collections.hashtable([System.Collections.IHashCodeProvider]$hashprovider, [System.Collections.IComparer]$comparer) 24 | $wfendpoint = $false 25 | 26 | if (test-path wsman:\localhost\plugin\"$name") { 27 | function Get-Details([string]$path, [hashtable]$h) { 28 | foreach ($o in (get-childitem $path)) { 29 | if ($o.PSIsContainer) { 30 | Get-Details $o.PSPath $h 31 | } else { 32 | $h[$o.Name] = $o.Value 33 | } 34 | } 35 | } 36 | 37 | Get-Details wsman:\localhost\plugin\""$name"" $h 38 | 39 | $sddl = $h["Sddl"] 40 | if ($sddl) { 41 | $h.Remove("Sddl") 42 | $h["SecurityDescriptorSddl"] = $sddl 43 | } 44 | 45 | if ($h["PSSessionConfigurationTypeName"] -eq "Microsoft.PowerShell.Workflow.PSWorkflowSessionConfiguration") { 46 | import-module psworkflow -Scope local 47 | $wf = new-psworkflowexecutionoption 48 | 49 | foreach ($o in $wf.GetType().GetProperties()) { 50 | $h[$o.Name] = $o.GetValue($wf, $null) 51 | } 52 | } 53 | 54 | if (test-path wsman:\localhost\plugin\"$name"\InitializationParameters\SessionConfigurationData) { 55 | $xscd = [xml](Unescape-Xml (Unescape-Xml (get-item wsman:\localhost\plugin\"$name"\InitializationParameters\SessionConfigurationData).Value)) 56 | 57 | foreach ($o in $xscd.SessionConfigurationData.Param) { 58 | if ($o.Name -eq "PrivateData") { 59 | foreach($wf in $o.PrivateData.Param) { 60 | $h[$wf.Name] = $wf.Value 61 | } 62 | } else { 63 | $h[$o.Name] = $o.Value 64 | } 65 | } 66 | } 67 | } 68 | 69 | return $h 70 | } 71 | 72 | Describe "Remoting Cmdlets WinRM Noreboot Tests" { 73 | 74 | BeforeAll { 75 | $testName = 'abc' 76 | $checkRebootSession = $null 77 | $sc = 'SilentlyContinue' 78 | 79 | if ((Get-Service -Name 'WinRM').Status -ne 'Running'){ Start-Service -Name 'WinRM' } 80 | Unregister-PSSessionConfiguration -Name abc -Force -ErrorAction $sc 81 | 82 | function Restart-WinRM 83 | { 84 | # This removes all of the output to the screen 85 | Restart-Service -Name WinRM -Force -Confirm:$false 3>$null 86 | } 87 | 88 | } 89 | 90 | Context "Register-PSSessionConfiguration" { 91 | BeforeEach{ 92 | Restart-WinRM 93 | $checkRebootSession = New-PSSession -ComputerName localhost 94 | $checkRebootSession.State | Should be 'Opened' 95 | } 96 | 97 | AfterEach{ 98 | Remove-PSSession $checkRebootSession -Confirm:$false 99 | Unregister-PSSessionConfiguration -Name abc -Force -ErrorAction $sc 100 | } 101 | 102 | It "Registering without a reboot" { 103 | 104 | $checkRebootSession.State | Should be 'Opened' 105 | $c = Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 106 | $checkRebootSession.State | Should be 'Opened' 107 | 108 | $h = Get-PluginDetails $testName 109 | $h["Enabled"] | Should Be "True" 110 | } 111 | 112 | It "Registering without a reboot with -Force" { 113 | 114 | $checkRebootSession.State | Should be 'Opened' 115 | $c = Register-PSSessionConfiguration -Force -Name $testName -WarningAction $sc -WarningVariable $null 116 | $checkRebootSession.State | Should be 'Opened' 117 | 118 | $h = Get-PluginDetails $testName 119 | $h["Enabled"] | Should Be "True" 120 | } 121 | 122 | It "Error on re-register" { 123 | 124 | $checkRebootSession.State | Should be 'Opened' 125 | $c = Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 126 | $checkRebootSession.State | Should be 'Opened' 127 | 128 | #now should fail while still not rebooting 129 | { Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null } | Should Throw 130 | 131 | $checkRebootSession.State | Should be 'Opened' 132 | } 133 | 134 | It "Re-register with -Force should reboot and work" { 135 | 136 | # first instance of register does not require a reboot 137 | $checkRebootSession.State | Should be 'Opened' 138 | $c = Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null -Force 139 | $checkRebootSession.State | Should be 'Opened' 140 | 141 | Unregister-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 142 | 143 | # Now reboot of WinRM is required with -Force, the cmdlet should reboot WinRM for us 144 | { Register-PSSessionConfiguration -Name $testName -Force 3>$null } | Should not Throw 145 | 146 | $checkRebootSession.State | Should not be 'Opened' 147 | 148 | $newTestSession = New-PSSession -ComputerName localhost -ConfigurationName $testName 149 | $newTestSession.State | Should be 'Opened' 150 | Remove-PSSession $newTestSession -Confirm:$false 151 | } 152 | 153 | It "Re-register WITHOUT -Force should not reboot and session won't work" { 154 | 155 | # first instance of register does not require a reboot 156 | $checkRebootSession.State | Should be 'Opened' 157 | $c = Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 158 | $checkRebootSession.State | Should be 'Opened' 159 | 160 | Unregister-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 161 | 162 | # Now reboot of WinRM is required with -Force, the cmdlet should reboot WinRM for us 163 | { Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null } | Should not Throw 164 | 165 | $checkRebootSession.State | Should be 'Opened' 166 | 167 | { $newTestSession = New-PSSession -ComputerName localhost -ConfigurationName $testName -ErrorAction Stop } | Should Throw 168 | $newTestSession.State | Should not be 'Opened' 169 | } 170 | } 171 | 172 | Context "Unregister-PSSessionConfiguration" { 173 | BeforeEach{ 174 | Restart-WinRM 175 | $checkRebootSession = New-PSSession -ComputerName localhost 176 | $checkRebootSession.State | Should be 'Opened' 177 | } 178 | 179 | AfterEach{ 180 | Remove-PSSession $checkRebootSession -Confirm:$false 181 | Unregister-PSSessionConfiguration -Name abc -Force -ErrorAction $sc 182 | } 183 | 184 | It "Unregistering without a reboot" { 185 | 186 | Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 187 | 188 | $checkRebootSession.State | Should be 'Opened' 189 | Unregister-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 190 | $checkRebootSession.State | Should be 'Opened' 191 | } 192 | 193 | It "Unregistering without a reboot with -Force" { 194 | 195 | Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 196 | 197 | $checkRebootSession.State | Should be 'Opened' 198 | Unregister-PSSessionConfiguration -Force -Name $testName -WarningAction $sc -WarningVariable $null 199 | $checkRebootSession.State | Should be 'Opened' 200 | } 201 | 202 | It "Error on Unregistering a non-existing plugin" { 203 | 204 | $checkRebootSession.State | Should be 'Opened' 205 | { Unregister-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null -ErrorAction Stop } | Should Throw 206 | $checkRebootSession.State | Should be 'Opened' 207 | } 208 | } 209 | 210 | Context "Disable-PSSessionConfiguration" { 211 | BeforeEach{ 212 | Restart-WinRM 213 | $checkRebootSession = New-PSSession -ComputerName localhost 214 | $checkRebootSession.State | Should be 'Opened' 215 | } 216 | 217 | AfterEach{ 218 | Remove-PSSession $checkRebootSession -Confirm:$false 219 | Unregister-PSSessionConfiguration -Name abc -Force -ErrorAction $sc 220 | } 221 | 222 | It "Disabling without a reboot" { 223 | 224 | Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 225 | 226 | $checkRebootSession.State | Should be 'Opened' 227 | Disable-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 228 | $checkRebootSession.State | Should be 'Opened' 229 | 230 | $h = Get-PluginDetails $testName 231 | $h["Enabled"] | Should Be "False" 232 | } 233 | 234 | It "Disabling without a reboot with -Force" { 235 | 236 | Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 237 | 238 | $checkRebootSession.State | Should be 'Opened' 239 | Disable-PSSessionConfiguration -Force -Name $testName -WarningAction $sc -WarningVariable $null 240 | $checkRebootSession.State | Should be 'Opened' 241 | 242 | $h = Get-PluginDetails $testName 243 | $h["Enabled"] | Should Be "False" 244 | } 245 | } 246 | 247 | Context "Enable-PSSessionConfiguration" { 248 | BeforeEach{ 249 | Restart-WinRM 250 | $checkRebootSession = New-PSSession -ComputerName localhost 251 | $checkRebootSession.State | Should be 'Opened' 252 | } 253 | 254 | AfterEach{ 255 | Remove-PSSession $checkRebootSession -Confirm:$false 256 | Unregister-PSSessionConfiguration -Name abc -Force -ErrorAction $sc 257 | } 258 | 259 | It "Enabling without a reboot" { 260 | # Ensure session configuration commands work in strict mode 261 | Set-StrictMode -Version 5.0 262 | 263 | Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 264 | 265 | $checkRebootSession.State | Should be 'Opened' 266 | Enable-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 267 | $checkRebootSession.State | Should be 'Opened' 268 | 269 | $h = Get-PluginDetails $testName 270 | $h["Enabled"] | Should Be "True" 271 | } 272 | 273 | It "Enabling without a reboot with -Force" { 274 | # Ensure session configuration commands work in strict mode 275 | Set-StrictMode -Version 5.0 276 | 277 | Register-PSSessionConfiguration -Name $testName -WarningAction $sc -WarningVariable $null 278 | 279 | $checkRebootSession.State | Should be 'Opened' 280 | Enable-PSSessionConfiguration -Force -Name $testName -WarningAction $sc -WarningVariable $null 281 | $checkRebootSession.State | Should be 'Opened' 282 | 283 | $h = Get-PluginDetails $testName 284 | $h["Enabled"] | Should Be "True" 285 | } 286 | } 287 | } 288 | 289 | 290 | 291 | --------------------------------------------------------------------------------