├── .editorconfig ├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── Functions ├── CommonAliases.ps1 ├── CommonFunctions.ps1 ├── PSAppSetting │ └── Get-PSAppSetting.ps1 ├── PSConnectionString │ ├── Get-PSConnectionString.ps1 │ ├── Test-PSConnectionString.ps1 │ └── Test_ConnectionString.ps1 ├── PSUri │ ├── Get-PSEndpoint.ps1 │ ├── Get-PSUri.ps1 │ ├── Test-PSUri.ps1 │ └── Test_Uri.ps1 └── PSWebConfig │ ├── Get-PSWebConfig.ps1 │ ├── Get_ConfigFile.ps1 │ ├── Test-PSWebConfig.ps1 │ └── Unprotect-PSWebConfig.ps1 ├── LICENSE ├── PSWebConfig.format.ps1xml ├── PSWebConfig.psd1 ├── PSWebConfig.psm1 ├── README.md ├── Tests ├── Fixtures │ ├── web.config │ └── webrequests.csv ├── Import-LocalModule.ps1 ├── Module │ ├── Module.tests.ps1 │ └── ScriptAnalyzer.tests.ps1 ├── PSAppSetting │ └── Get-PSAppSetting.tests.ps1 ├── PSConnectionString │ ├── Get-PSConnectionString.tests.ps1 │ └── Test_ConnectionString.tests.ps1 ├── PSUri │ ├── Get-PSEndpoint.tests.ps1 │ ├── Get-PSUri.tests.ps1 │ └── Test_Uri.tests.ps1 └── PSWebConfig │ ├── Get-WebConfig.tests.ps1 │ └── Get_ConfigFile.tests.ps1 └── appveyor.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Default to all files 7 | [*] 8 | end_of_line = crlf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | # Powershell source files 13 | [*.{ps1,psm1,psd1}] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | [*.{xml,ps1xml,config,json}] 18 | indent_style = space 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | *.ps1 text 4 | *.psm1 text 5 | *.psd1 text 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode/ 2 | /build/ 3 | Test.xml 4 | vendor/packages/ 5 | *.sandbox.ps1 6 | TestsResults.xml 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 (Oct 4, 2015) 2 | - Initial version of `Get-PSWebConfig` and `Get-PSConnectionString` 3 | - Remote and local decryption of appSettings and connectionStrings WebConfig sections 4 | 5 | ## 1.1.0 (Feb 19, 2016) 6 | - Add `Test-PSConnectionString` cmdlet 7 | - Replace `-ComputerName` with `-PSSession` parameter for more flexible remote execution scenarios 8 | - Populating ComputerName property for all objects 9 | - Add PowerShell views for WebConfig, ConnectionString objects 10 | - Add warning for non-admin users for decrypt attemps 11 | 12 | ## 1.2.0 (Feb 20, 2016) 13 | - Add views for all `PSWebConfig` object-types 14 | 15 | ## 1.3.0 (Feb 25, 2016) 16 | - Automatic decryption of all configuration sections 17 | - Add `FileInfo` InputObject support 18 | - Set Path as the firts positinal parameter 19 | 20 | ## 1.4.0 (Feb 26, 2016) 21 | - Introduce `Get-PSEndpoint` and `Get-PSUri` to get URIs from config files 22 | - Change `FileName` output to `FileInfo` 23 | - Add `PSScriptAnalyzer` module for Pester tests 24 | - Fix code suggestions from `PSScriptAnalyzer` 25 | - Test if expected commands are exported too 26 | 27 | ## 1.5.0 (Feb 27, 2016) 28 | - Add `Test-PSUri` to test HTTP/HTTPS URIs 29 | - Add `Test-PSWebConfig` to fully test all URIs and Connectionstrings from complete configurations 30 | - Rename `PSAddress` to `PSUri` 31 | - Add `ReplaceRules` to Connectionstring test results 32 | - Add `PSWebConfig.TestResult` view for all tests 33 | 34 | ## 1.5.1 (Feb 28, 2016) 35 | - Regenerate module manifest for PSGallery 36 | 37 | ## 1.5.2 (Feb 28, 2016) 38 | - Refactor Pester tests and Fixtures 39 | - Reorganize functions into subfolders 40 | 41 | ## 1.6.0 (Jul 15, 2016) 42 | - Enable remote executions with resolving RunspaceIds without specifying -Session parameter 43 | - Add password-masking to Test-PSConnectionString 44 | - Test-PsWebConfig now support -IncludeAppsettings parameters 45 | - Better detailed -Verbose info from all cmdlets 46 | -------------------------------------------------------------------------------- /Functions/CommonAliases.ps1: -------------------------------------------------------------------------------- 1 | # IISAdministration and WebAdministration compatible aliases 2 | New-Alias -Name Test-WebConfigFile -Value Test-PSWebConfig -Scope Script 3 | 4 | # Common aliases for application config scenarios 5 | New-Alias -Name Get-PSAppConfig -Value Get-PSWebConfig -Scope Script 6 | New-Alias -Name Test-PSAppConfig -Value Test-PSWebConfig -Scope Script 7 | 8 | New-Alias -Name Decrypt-PSWebConfig -Value Unprotect-PSWebConfig -Scope Script 9 | -------------------------------------------------------------------------------- /Functions/CommonFunctions.ps1: -------------------------------------------------------------------------------- 1 | function Set_Type { 2 | param( 3 | [Parameter(ValueFromPipeline=$true)] 4 | [psobject[]]$InputObject, 5 | [string]$TypeName 6 | ) 7 | process { 8 | foreach ($object in $InputObject) { 9 | if ($TypeName) { 10 | $object.psobject.TypeNames.Insert(0, $TypeName) 11 | } 12 | $object 13 | } 14 | } 15 | } 16 | 17 | function Invoke-SessionCommand { 18 | [CmdletBinding()] 19 | param( 20 | [Parameter(Mandatory=$true)] 21 | [ScriptBlock]$ScriptBlock, 22 | 23 | [Parameter()] 24 | [Object[]]$ArgumentList, 25 | 26 | [Parameter()] 27 | [System.Management.Automation.Runspaces.PSSession]$Session 28 | ) 29 | 30 | if ($Session) { 31 | Write-Verbose "Executing remotely from '$($Session.ComputerName)'.." 32 | Invoke-Command -Session $Session -ArgumentList $ArgumentList -ScriptBlock $ScriptBlock | 33 | Add-Member -NotePropertyName Session -NotePropertyValue $Session -Force -PassThru 34 | } else { 35 | Write-Verbose 'Executig locally..' 36 | Invoke-Command -ArgumentList $ArgumentList -ScriptBlock $ScriptBlock 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Functions/PSAppSetting/Get-PSAppSetting.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns the appSettings from an or application/web config 4 | .DESCRIPTION 5 | The cmdlet takes an application/web configuration as an input and returns 6 | all applicationsettings from it. 7 | 8 | .PARAMETER ConfigXml 9 | Mandatory - Pipeline input for Configuration XML 10 | 11 | .EXAMPLE 12 | Get-PSWebConfig -Path 'C:\inetpub\wwwroot\myapp' | Get-PSAppSetting 13 | .EXAMPLE 14 | Get-WebSite mysite | Get-PSWebConfig | Get-PSAppSetting 15 | #> 16 | function Get-PSAppSetting { 17 | [CmdletBinding()] 18 | param( 19 | [Parameter(Mandatory=$true,ValueFromPipeLine=$true)] 20 | [psobject[]]$ConfigXml 21 | ) 22 | 23 | process { 24 | Write-Verbose "Executing Get-PSAppSetting" 25 | foreach ($config in $ConfigXml) { 26 | Write-Verbose "Processing configuration '$($config.ComputerName + " " + $config.File)'" 27 | if ($config -is [string]) { $config = [xml]$config } 28 | 29 | if ($config | Get-Member -Name configuration) { 30 | if ($config.configuration.appSettings.EncryptedData) { 31 | Write-Warning "appSettings section is encrypted. You may not see all relevant entries." 32 | Write-Warning "Execute this command as an administrator for automatic decryption." 33 | } 34 | 35 | foreach ($appSetting in $config.configuration.appSettings.add) { 36 | $appSetting | 37 | Add-Member -NotePropertyName Session -NotePropertyValue $config.Session -Force -PassThru | 38 | Add-Member -NotePropertyName ComputerName -NotePropertyValue $config.ComputerName -Force -PassThru | 39 | Add-Member -NotePropertyName File -NotePropertyValue $config.File -Force -PassThru | 40 | Add-Member -NotePropertyName SectionPath -NotePropertyValue "appSettings" -Force -PassThru | 41 | Set_Type -TypeName "PSWebConfig.AppSetting" 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Functions/PSConnectionString/Get-PSConnectionString.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns ConnectionStrings from an or application/web config 4 | .DESCRIPTION 5 | The cmdlet takes an application/web configuration as an input and returns 6 | the connectionstrings from it. 7 | 8 | If -IncludeAppSettings is specified it will try to match any ConnectionString from the 9 | appSettings sections too. 10 | .PARAMETER ConfigXml 11 | Mandatory - Pipeline input for Configuration XML 12 | .PARAMETER IncludeAppSettings 13 | Optional - Parameter to find any connectionStrings from application Settings 14 | 15 | .EXAMPLE 16 | Get-PSWebConfig -Path 'C:\inetpub\wwwroot\myapp' | Get-PSConnectionString 17 | .EXAMPLE 18 | Get-WebSite mysite | Get-PSWebConfig | Get-PSConnectionString 19 | .EXAMPLE 20 | Get-WebSite mysite | Get-PSWebConfig | Get-PSConnectionString -IncludeAppSettings 21 | #> 22 | function Get-PSConnectionString { 23 | [CmdletBinding()] 24 | param( 25 | [Parameter(Mandatory=$true,ValueFromPipeLine=$true)] 26 | [psobject[]]$ConfigXml, 27 | 28 | [switch]$IncludeAppSettings 29 | ) 30 | 31 | process { 32 | Write-Verbose "Executing Get-PSConnectionString" 33 | foreach ($config in $ConfigXml) { 34 | if ($config -is [string]) { $config = [xml]$config } 35 | 36 | if ($config | Get-Member -Name configuration) { 37 | Write-Verbose "Processing configuration '$($config.ComputerName + " " + $config.File)'" 38 | if ($config.configuration.connectionStrings.EncryptedData) { 39 | Write-Warning "ConnectionStrings section is encrypted. You may not see all relevant entries." 40 | Write-Warning "Execute this command as an administrator for automatic decryption." 41 | } 42 | 43 | foreach ($connectionString in $config.configuration.connectionStrings.add) { 44 | $connectionString | 45 | Add-Member -NotePropertyName Session -NotePropertyValue $config.Session -Force -PassThru | 46 | Add-Member -NotePropertyName ComputerName -NotePropertyValue $config.ComputerName -Force -PassThru | 47 | Add-Member -NotePropertyName File -NotePropertyValue $config.File -Force -PassThru | 48 | Add-Member -NotePropertyName SectionPath -NotePropertyValue "connectionStrings" -Force -PassThru | 49 | Set_Type -TypeName "PSWebConfig.ConnectionString" 50 | } 51 | 52 | if (-Not $IncludeAppSettings) { 53 | Write-Verbose "Appsettings are not included in ConnectionString processing." 54 | continue 55 | } 56 | 57 | Write-Verbose "Looking for ConnectionStrings in appsettings.." 58 | $config | Get-PSAppSetting | ForEach-Object { 59 | if ($_.value -match 'data source=') { 60 | $_ | 61 | Add-Member -MemberType AliasProperty -Name ConnectionString -Value value -Force -PassThru | 62 | Add-Member -MemberType AliasProperty -Name Name -Value key -Force -PassThru | 63 | Set_Type -TypeName "PSWebConfig.ConnectionString" 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Functions/PSConnectionString/Test-PSConnectionString.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Tests a ConnectionStrings from a local or remote machine 4 | .DESCRIPTION 5 | The cmdlet takes a ConnectionString as an input object or as a direct 6 | parameter then it tries to connect to the database. 7 | 8 | If Initial Catalog is specified, it queries the server for the specified 9 | database otherwise it checks whether it can access the tempdb. 10 | 11 | If a Session Property is passed via InputObject or directly with -Session 12 | parameter, the ConnectionString test will be executed against it. 13 | 14 | If -ReplaceRules hashtable is specified it will replace hash-keys with it's 15 | values in the ConnectionString to be tested. 16 | 17 | Passwords in the ConnectionString are masked by default, use -ShowPassword 18 | switch if you need to show passwords in test-results. 19 | 20 | .PARAMETER InputObject 21 | Mandatory - Pipeline input of PsConnectionString 22 | 23 | .PARAMETER ConnectionString 24 | Mandatory - Parameter to pass a ConnectionString as a string 25 | 26 | .PARAMETER ReplaceRules 27 | Optional - Hashtable that replaces hash-keys with it's values in the 28 | ConnectionString to be tested. 29 | 30 | .PARAMETER ShowPassword 31 | Optional - Switch to disable password masking for the test result. 32 | 33 | .PARAMETER Session 34 | Optional - PSSession to execute the test-against it. 35 | 36 | .EXAMPLE 37 | Test-PSConnectionString -ConnectionString 'Server=address;Database=db;User Id=uname;Password=***;' 38 | .EXAMPLE 39 | Get-WebSite mysite | Get-PSWebConfig | Get-PSConnectionString | Test-PSConnectionString 40 | #> 41 | function Test-PSConnectionString { 42 | [CmdletBinding(DefaultParameterSetName='InputObject')] 43 | param( 44 | [Parameter(ParameterSetName="InputObject",ValueFromPipeLine=$true)] 45 | [psobject[]]$InputObject, 46 | 47 | [Parameter(ParameterSetName="ConnectionString",ValueFromPipeLine=$true)] 48 | [string]$ConnectionString, 49 | 50 | [hashtable]$ReplaceRules, 51 | [System.Management.Automation.Runspaces.PSSession[]]$Session, 52 | 53 | [switch]$ShowPassword 54 | ) 55 | 56 | process { 57 | Write-Verbose "Executing Test-PSConnectionString" 58 | if ($ConnectionString) { 59 | $InputObject = New-Object -TypeName PsObject -Property @{ 60 | ConnectionString = $ConnectionString 61 | Session = $Session 62 | } 63 | } 64 | 65 | foreach ($entry in $InputObject) { 66 | if ($entry | Get-Member -Name ConnectionString) { 67 | 68 | $EntrySession = $entry.Session 69 | if ($Session) { $EntrySession = $Session } 70 | 71 | $ArgumentList = $entry.ConnectionString,$ReplaceRules,$ShowPassword 72 | if ($EntrySession) { 73 | Write-Verbose "Remote Test execution from '$($EntrySession.ComputerName)'" 74 | Invoke-Command ` 75 | -Session $EntrySession ` 76 | -ArgumentList $ArgumentList ` 77 | -ScriptBlock $Function:Test_ConnectionString | 78 | Add-Member -NotePropertyName Session -NotePropertyValue $EntrySession -Force -PassThru | 79 | Set_Type -TypeName 'PSWebConfig.TestResult' 80 | } else { 81 | Write-Verbose "Local Test execution" 82 | Invoke-Command ` 83 | -ArgumentList $ArgumentList ` 84 | -ScriptBlock $Function:Test_ConnectionString | 85 | Set_Type -TypeName 'PSWebConfig.TestResult' 86 | } 87 | } else { 88 | Write-Verbose "InputObject doesn't contain ConnectionString property" 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Functions/PSConnectionString/Test_ConnectionString.ps1: -------------------------------------------------------------------------------- 1 | function Test_ConnectionString { 2 | param( 3 | [Parameter(Mandatory, Position=0)] 4 | [string]$ConnectionString, 5 | 6 | [Parameter(Position=1)] 7 | [hashtable]$ReplaceRules, 8 | 9 | [Parameter(Position=2)] 10 | [bool]$ShowPassword=$false 11 | ) 12 | 13 | $result = New-Object PsObject -Property @{ 14 | ComputerName = [System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName 15 | TestType='SqlTest' 16 | Test=$ConnectionString 17 | Passed = $false 18 | Result = $null 19 | Status = $null 20 | 21 | ConnectionString=$ConnectionString 22 | ReplaceRules = $ReplaceRules 23 | SqlQuery= $null 24 | } 25 | 26 | try { 27 | # Transform ConnectionString 28 | if ($ReplaceRules) { 29 | $ReplaceRules.GetEnumerator() | ForEach-Object { 30 | $result.ConnectionString = $result.ConnectionString -replace $_.Key,$_.Value 31 | } 32 | } 33 | 34 | # Figure target database to check 35 | $DbToCheck = 'tempdb' 36 | $builder = New-Object System.Data.SqlClient.SqlConnectionStringBuilder $result.ConnectionString 37 | if ($builder.'Initial Catalog') { 38 | $DbToCheck = $builder.'Initial Catalog' 39 | } 40 | $result.SqlQuery="SELECT name FROM sysdatabases WHERE LOWER(name) = LOWER('$DbToCheck')" 41 | 42 | $SqlConnection = New-Object System.Data.SqlClient.SqlConnection -ErrorAction Stop 43 | $SqlConnection.ConnectionString = $result.ConnectionString 44 | $SqlConnection.Open() 45 | 46 | $SqlCmd = New-Object System.Data.SqlClient.SqlCommand 47 | $SqlCmd.CommandText = $result.SqlQuery 48 | $SqlCmd.Connection = $SqlConnection 49 | 50 | $result.Result = $SqlCmd.ExecuteScalar() 51 | $result.Status = "Passed: '$DbToCheck'" 52 | $result.Passed = $true 53 | } catch { 54 | $result.Result = $_ 55 | $result.Status = "Failed: '$DbToCheck'" 56 | $result.Passed = $false 57 | Write-Error $_ 58 | } finally { 59 | if ($SqlConnection) { $SqlConnection.Close() } 60 | } 61 | 62 | if (!$ShowPassword) { 63 | Write-Verbose "Masking password due to ShowPassword:false .." 64 | $maskRule = ';\s*password=(\S+)\s*(;|$)',';password=***;' 65 | $result.ConnectionString = $result.ConnectionString -ireplace $maskRule 66 | $result.Test = $result.Test -ireplace $maskRule 67 | } 68 | 69 | return $result 70 | } 71 | -------------------------------------------------------------------------------- /Functions/PSUri/Get-PSEndpoint.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns endpoint addresses from application or web configuration 4 | .DESCRIPTION 5 | It accepts configuration XMLs and returns \client endpoint addresses from 6 | system.serviceModel section. 7 | 8 | .PARAMETER ConfigXml 9 | Mandatory - Pipeline input for Configuration XML 10 | 11 | .EXAMPLE 12 | Get-PSWebConfig -Path 'C:\inetpub\wwwroot\myapp' | Get-PSEndpoint 13 | .EXAMPLE 14 | Get-WebSite mysite | Get-PSWebConfig | Get-PSEndpoint 15 | #> 16 | function Get-PSEndpoint { 17 | [CmdletBinding()] 18 | param( 19 | [Parameter(Mandatory=$true,ValueFromPipeLine=$true)] 20 | [psobject[]]$ConfigXml 21 | ) 22 | 23 | process { 24 | Write-Verbose "Executing Get-PSEndpoint" 25 | foreach ($config in $ConfigXml) { 26 | Write-Verbose "Processing configuration '$($config.ComputerName + " " + $config.File)'" 27 | if ($config | Get-Member -Name configuration) { 28 | foreach ($endpoint in $config.configuration.'system.serviceModel'.client.endpoint) { 29 | $endpoint | 30 | Add-Member -NotePropertyName Session -NotePropertyValue $config.Session -Force -PassThru | 31 | Add-Member -NotePropertyName ComputerName -NotePropertyValue $config.ComputerName -Force -PassThru | 32 | Add-Member -NotePropertyName File -NotePropertyValue $config.File -Force -PassThru | 33 | Add-Member -NotePropertyName SectionPath -NotePropertyValue 'system.serviceModel/client/endpoint' -Force -PassThru | 34 | Add-Member -MemberType AliasProperty -Name Uri -Value address -Force -PassThru | 35 | Set_Type -TypeName 'PSWebConfig.Uri' 36 | } 37 | } else { 38 | Write-Warning "Skipping invalid configuration: $config" 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Functions/PSUri/Get-PSUri.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns any URIs from application or web configuration. 4 | .DESCRIPTION 5 | It accepts configuration XMLs and returns any URIs found in appSettings and 6 | from client endpoint addresses. 7 | 8 | The cmdlet filters PSAppSettings for URIs and also returns PSEndpoint results. 9 | 10 | .PARAMETER ConfigXml 11 | Mandatory - Pipeline input for Configuration XML 12 | .PARAMETER IncludeAppSettings 13 | Optional - Switch to include http/s URIs from appsettings 14 | 15 | .EXAMPLE 16 | Get-PSWebConfig -Path 'C:\inetpub\wwwroot\myapp' | Get-PSUri 17 | .EXAMPLE 18 | Get-WebSite mysite | Get-PSWebConfig | Get-PSUri 19 | #> 20 | function Get-PSUri { 21 | [CmdletBinding()] 22 | param( 23 | [Parameter(Mandatory=$true,ValueFromPipeLine=$true)] 24 | [psobject[]]$ConfigXml, 25 | [switch]$IncludeAppSettings 26 | ) 27 | 28 | process { 29 | Write-Verbose "Executing Get-PSUri" 30 | 31 | Write-Verbose "Looking for service-endpoint addresses..." 32 | Get-PSEndpoint -ConfigXml $configXml 33 | 34 | if (-Not $IncludeAppSettings) { 35 | Write-Verbose "Appsettings are not included in URI processing." 36 | return 37 | } else { 38 | Write-Verbose "Looking for any http URLs from appSettings..." 39 | Get-PSAppSetting -ConfigXml $configXml | 40 | Where-Object value -imatch '^http[s]*:' | 41 | Add-Member -MemberType AliasProperty -Name name -Value key -Force -PassThru | 42 | Add-Member -MemberType AliasProperty -Name address -Value value -Force -PassThru | 43 | Add-Member -MemberType AliasProperty -Name Uri -Value value -Force -PassThru | 44 | Set_Type -TypeName 'PSWebConfig.Uri' 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Functions/PSUri/Test-PSUri.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Tests any HTTP/HTTPS URIs from a remote or local machine. 4 | 5 | .DESCRIPTION 6 | The cmdlet takes a URI as an input object or as a direct 7 | parameter then it tries to connect to it with Invoke-WebRequest with 8 | -UseBasicParsing switch and returns the result as a test object. 9 | 10 | You can specify a regular-expression for accepting various HTTP status 11 | codes with -AllowedStatusCodeRegexp parameter. 12 | 13 | Use -DisableSSLValidation switch to allow any HTTPs certificactes accepted 14 | for the tests. 15 | 16 | If a Session Property is passed via InputObject or directly with -Session 17 | parameter, the URI test will be executed against that. 18 | 19 | If -ReplaceRules hashtable is specified it will replace hash-keys with it's 20 | values in the URI to be tested. This could be useful, when you need to 21 | override the test Uri with dynamic values. 22 | 23 | .PARAMETER InputObject 24 | Mandatory - Pipeline input of PSUri 25 | 26 | .PARAMETER Uri 27 | Mandatory - Parameter to pass a URI as a string 28 | 29 | .PARAMETER AllowedStatusCodeRegexp 30 | Optional - Regxep string to set which HTTP Response Code should be accepted. 31 | 32 | .PARAMETER TimeOutSeconds 33 | Optional - TimeOut Seconds to be used for Invoke-WebRequest 34 | 35 | .PARAMETER DisableSSLValidation 36 | Optional - Switch to accept any SSL certificate for HTTPS URI tests. 37 | 38 | .PARAMETER ReplaceRules 39 | Optional - Hashtable that replaces hash-keys with it's values in the 40 | URI to be tested. 41 | 42 | .PARAMETER Session 43 | Optional - PSSession to execute the test-against it. 44 | 45 | .EXAMPLE 46 | Test-PSUri -Uri 'http://murati.hu' 47 | .EXAMPLE 48 | Get-WebSite mysite | Get-PSWebConfig | Get-PSUri | Test-PSUri 49 | #> 50 | function Test-PSUri { 51 | [CmdletBinding(DefaultParameterSetName='ByInputObject')] 52 | param( 53 | [Parameter(ParameterSetName="ByInputObject",ValueFromPipeLine=$true)] 54 | [psobject[]]$InputObject, 55 | 56 | [Parameter(ParameterSetName="ByUri",ValueFromPipeLine=$true)] 57 | [Parameter(Position=0)] 58 | [Alias('Address','Url')] 59 | [string[]]$Uri, 60 | 61 | [string]$AllowedStatusCodeRegexp = '^20[0-9]|^401|^403|^50[0-9]', 62 | 63 | [ValidateRange(0,3600)] 64 | [Int32]$TimeOutSeconds=5, 65 | 66 | [switch]$DisableSSLValidation, 67 | 68 | [hashtable]$ReplaceRules, 69 | 70 | [System.Management.Automation.Runspaces.PSSession[]]$Session 71 | ) 72 | 73 | process { 74 | Write-Verbose "Executing Test-PSUri" 75 | 76 | if ($Uri) { 77 | $InputObject = $Uri | Foreach-Object { 78 | New-Object -TypeName PsObject -Property @{ 79 | Uri = $_ 80 | Session = $Session 81 | } 82 | } 83 | } 84 | 85 | foreach ($entry in $InputObject) { 86 | if ($entry | Get-Member -Name Uri) { 87 | 88 | $EntrySession = $entry.Session 89 | if ($Session) { $EntrySession = $Session } 90 | 91 | $argumentList = $entry.Uri,$DisableSSLValidation,$AllowedStatusCodeRegexp,$TimeOutSeconds,$ReplaceRules 92 | 93 | if ($EntrySession) { 94 | Invoke-Command ` 95 | -Session $EntrySession ` 96 | -ArgumentList $argumentList ` 97 | -ScriptBlock $Function:Test_Uri | 98 | Add-Member -NotePropertyName Session -NotePropertyValue $EntrySession -Force -PassThru | 99 | Set_Type -TypeName 'PSWebConfig.TestResult' 100 | } else { 101 | Invoke-Command ` 102 | -ArgumentList $argumentList ` 103 | -ScriptBlock $Function:Test_Uri | 104 | Set_Type -TypeName 'PSWebConfig.TestResult' 105 | } 106 | } else { 107 | Write-Verbose "InputObject doesn't contain Uri property" 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Functions/PSUri/Test_Uri.ps1: -------------------------------------------------------------------------------- 1 | function Test_Uri { 2 | [CmdletBinding()] 3 | param( 4 | [string]$Uri, 5 | [bool]$DisableSSLValidation=$false, 6 | [string]$AllowedStatusCodeRegexp, 7 | [Int32]$TimeOutSeconds, 8 | [hashtable]$ReplaceRules 9 | ) 10 | 11 | $result = New-Object PsObject -Property @{ 12 | ComputerName = [System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName 13 | TestType='UriTest' 14 | Test=$Uri 15 | Passed = $false 16 | Result = $null 17 | Status = $null 18 | 19 | Uri=$Uri 20 | ReplaceRules = $ReplaceRules 21 | AllowedStatusRegexp = $AllowedStatusCodeRegexp 22 | DisableSSLValidation = $DisableSSLValidation 23 | TimeOutSeconds = $TimeOutSeconds 24 | } 25 | 26 | if ($DisableSSLValidation) { 27 | Write-Verbose "Disabling SSL Validation for Invoke-WebRequest" 28 | try { 29 | Add-Type @" 30 | using System.Net; 31 | using System.Security.Cryptography.X509Certificates; 32 | public class TrustAllCertsPolicy : ICertificatePolicy { 33 | public bool CheckValidationResult( 34 | ServicePoint srvPoint, X509Certificate certificate, 35 | WebRequest request, int certificateProblem) { 36 | return true; 37 | } 38 | } 39 | "@ 40 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 41 | } catch { 42 | Write-Error "Disabling SSL Validation failed." 43 | Write-Error $_ 44 | } 45 | } 46 | 47 | try { 48 | # Transform Uris 49 | if ($ReplaceRules) { 50 | $ReplaceRules.GetEnumerator() | ForEach-Object { 51 | $result.Uri = $result.Uri -replace $_.Key,$_.Value 52 | } 53 | } 54 | 55 | $result.Result = Invoke-WebRequest -UseBasicParsing -uri $result.Uri -TimeoutSec $result.TimeOutSeconds -ErrorAction Stop 56 | 57 | # Evaluate Response 58 | if ($result.Result) { 59 | $result.Status = $result.Result.StatusCode 60 | $result.Passed = ($result.Result.StatusCode -match $AllowedStatusCodeRegexp) 61 | } 62 | } catch { 63 | $result.Passed = $false 64 | $result.Status = $_ 65 | $result.Result = $_ 66 | Write-Error $_ 67 | } 68 | $result 69 | } 70 | -------------------------------------------------------------------------------- /Functions/PSWebConfig/Get-PSWebConfig.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns a decrypted configurations from websites or applications 4 | .DESCRIPTION 5 | The cmdlet finds the relevant web and app configs for the passed applications 6 | or websites and returns it in an XML/Text or File list format. 7 | 8 | It accepts either Path or an InputObject to discover the configuration files 9 | and if -Recurse is specified it discovers all sub-configuration too. 10 | 11 | Remote configurations can be fetched by setting -Session parameter. 12 | 13 | If the input object is received from a PSSession instance, it will try to 14 | use the session's InstanceId to fetch the configuration remotely. 15 | 16 | .PARAMETER InputObject 17 | Mandatory - Parameter to pass the Application or WebSite from pipeline 18 | .PARAMETER Path 19 | Mandatory - Parameter to pass the path for the target application 20 | .PARAMETER Recurse 21 | Optional - Switch to look for multiple web.config files in sub-folders for 22 | web applications 23 | .PARAMETER Session 24 | Optional - PSSession to execute configuration file lookup 25 | .PARAMETER AsXml 26 | Optional - Switch to return configuration as an unencypted and parsed 27 | XML object output (default behavior) 28 | .PARAMETER AsText 29 | Optional - Switch to return configfiles as unencrypted plain text output 30 | .PARAMETER AsFile 31 | Optional - Switch to return found configfile names as an output 32 | 33 | .EXAMPLE 34 | Get-PSWebConfig -Path 'c:\intepub\wwwroot\testapp\' 35 | .EXAMPLE 36 | $server1 = New-PSSession 'server1.local.domain' 37 | Get-PSWebConfig -Path 'c:\intepub\wwwroot\testapp\' -Session $server1 38 | .EXAMPLE 39 | Get-WebSite | Get-PSWebConfig -AsText -Recurse 40 | #> 41 | function Get-PSWebConfig { 42 | [CmdletBinding(DefaultParameterSetName="FromPipeLine")] 43 | param( 44 | [Parameter(ParameterSetName="FromPipeLine",Position=0)] 45 | [Parameter(ValueFromPipeLine=$true)] 46 | [psobject[]]$InputObject, 47 | 48 | [Parameter(ParameterSetName="FromPath",Position=0,Mandatory=$true)] 49 | [Alias('physicalPath')] 50 | [string]$Path, 51 | 52 | [Parameter(ParameterSetName="FromPath")] 53 | [Parameter(ParameterSetName="FromPipeLine")] 54 | [Parameter(ParameterSetName="AsFileInfo")] 55 | [switch]$AsFileInfo, 56 | 57 | [Parameter(ParameterSetName="FromPath")] 58 | [Parameter(ParameterSetName="FromPipeLine")] 59 | [Parameter(ParameterSetName="AsText")] 60 | [switch]$AsText, 61 | 62 | [Parameter(ParameterSetName="FromPath")] 63 | [Parameter(ParameterSetName="FromPipeLine")] 64 | [Parameter(ParameterSetName="AsXml")] 65 | [switch]$AsXml, 66 | 67 | [Parameter(ParameterSetName="FromPath")] 68 | [Parameter(ParameterSetName="FromPipeLine")] 69 | [Parameter(ParameterSetName="AsXml")] 70 | [switch]$Recurse, 71 | 72 | [System.Management.Automation.Runspaces.PSSession]$Session 73 | ) 74 | process { 75 | Write-Verbose "Executing Get-PSWebConfig" 76 | if (!$AsText -and !$AsFileInfo) { 77 | Write-Verbose "Defaulting output-format to XML object" 78 | $AsXml = $true 79 | } 80 | 81 | if ($Path) { 82 | Write-Verbose "Processing by Path" 83 | $InputObject = New-Object -TypeName PsObject -Property @{ 84 | physicalPath = $Path 85 | Session = $Session 86 | } 87 | } 88 | 89 | if ($InputObject) { 90 | Write-Verbose "Processing by InputObject" 91 | foreach ($entry in $InputObject) { 92 | # Setting Remote Session 93 | $EntrySession = $entry.Session 94 | if ($Session) { 95 | Write-Verbose "Overriding session from -Session Parameter" 96 | $EntrySession = $Session 97 | } 98 | elseif ($entry | Get-Member -Name RunspaceId) { 99 | Write-Verbose "Getting Session from RunspaceId '$($entry.RunspaceId)'" 100 | $EntrySession = Get-PSSession -InstanceId $entry.RunspaceId 101 | } 102 | 103 | if ($entry -is [System.IO.FileInfo] -or $entry.psobject.TypeNames -icontains 'Deserialized.System.IO.FileInfo') { 104 | Write-Verbose "Adding physicalPath alias for [System.IO.FileInfo] FullName" 105 | $entry = $entry | Add-Member -MemberType AliasProperty -Name physicalPath -Value FullName -PassThru 106 | } 107 | 108 | if ($entry | Get-Member -Name physicalPath) { 109 | if ($EntrySession) { 110 | Write-Verbose "Remote configuration fetch from '$($EntrySession.ComputerName + " " + $entry.physicalPath)'" 111 | $response = Invoke-Command ` 112 | -Session $EntrySession ` 113 | -ArgumentList @($entry.physicalPath, $AsFileInfo, $AsText, $Recurse) ` 114 | -ScriptBlock ${function:Get_ConfigFile} | 115 | Add-Member -NotePropertyName Session -NotePropertyValue $EntrySession -Force -PassThru 116 | } else { 117 | Write-Verbose "Local configuration fetch from '$($entry.physicalPath)'" 118 | $response = Invoke-Command ` 119 | -ArgumentList @($entry.physicalPath, $AsFileInfo, $AsText, $Recurse) ` 120 | -ScriptBlock ${function:Get_ConfigFile} 121 | } 122 | 123 | if ($AsXml) { 124 | $response | Set_Type -TypeName "PSWebConfig.WebConfig" 125 | } else { 126 | $response 127 | } 128 | } else { 129 | Write-Warning "Cannot get path from InputObject '$entry'" 130 | } 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Functions/PSWebConfig/Get_ConfigFile.ps1: -------------------------------------------------------------------------------- 1 | function Get_ConfigFile { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(Position=0)] 5 | [string]$Path, 6 | 7 | [Parameter(Position=1)] 8 | [bool]$AsFileInfo=$false, 9 | 10 | [Parameter(Position=2)] 11 | [bool]$AsText=$false, 12 | 13 | [Parameter(Position=3)] 14 | [bool]$Recurse=$false 15 | ) 16 | 17 | function Copy_WebConfig([string]$config) { 18 | if (-Not (Test-Path $config)) { 19 | Write-Warning "Could not find '$config'" 20 | return $null 21 | } 22 | 23 | # Copy the original file to temp for non-intrusive decryptions 24 | $tempFolder = [System.IO.Path]::GetTempPath() 25 | $appGuid = [guid]::NewGuid().Guid 26 | $tempAppFolder = Join-Path $tempFolder $appGuid 27 | $tempAppConfig = Join-Path $tempAppFolder 'web.config' 28 | 29 | Write-Verbose "Creating $tempAppFolder" 30 | mkdir $tempAppFolder -Force | Out-Null 31 | 32 | Write-Verbose "Copying $c to $tempAppFolder" 33 | Copy-Item -Path $config -Destination $tempAppFolder 34 | 35 | return $tempAppConfig 36 | } 37 | 38 | function Detect_AspNetRegIIS { 39 | $paths = @( 40 | "$($env:SystemRoot)\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe" 41 | "$($env:SystemRoot)\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe" 42 | ) 43 | foreach ($path in $paths) { 44 | if (Test-Path -Path $path) { 45 | Write-Verbose "$paths is found" 46 | return $path 47 | } 48 | } 49 | Write-Warning "Cannot find aspnet_regiis.exe in any known folders" 50 | return $null 51 | } 52 | 53 | function IsAdministrator { 54 | $user = [Security.Principal.WindowsIdentity]::GetCurrent(); 55 | (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) 56 | } 57 | 58 | function Decypt_WebConfig { 59 | param( 60 | [string]$folder, 61 | [string]$aspnet_regiis = $(Detect_AspNetRegIIS) 62 | ) 63 | 64 | $webConfigFile = Join-Path $folder 'web.config' 65 | if (Test-Path $webConfigFile) { 66 | $xmlContent = [xml](Get-Content $webConfigFile) 67 | if (-Not $xmlContent) { 68 | Write-Error "'$webConfigFile' is not a valid XML file." 69 | return 70 | } 71 | 72 | $alreadyWarned=$false 73 | $sections = $xmlContent.configuration | Get-Member -MemberType Property | Select-Object -ExpandProperty Name 74 | 75 | foreach ($s in $sections) { 76 | $encryptedSection = ($xmlContent -and ($xmlContent.configuration.$s.EncryptedData)) 77 | if ($encryptedSection -and $aspnet_regiis) { 78 | if (-Not $alreadyWarned -And -Not (IsAdministrator)) { 79 | Write-Warning "You are not in an Administrator context. You may not be able to decrypt configuration sections." 80 | $alreadyWarned = $true 81 | } 82 | 83 | $cryptArgs = "-pdf $s $folder" 84 | Write-Verbose "Decrypting > $aspnet_regiis $cryptArgs" 85 | Start-Process -FilePath $aspnet_regiis -ArgumentList $cryptArgs -WindowStyle Hidden -Wait 86 | } else { 87 | Write-Verbose "Skipping decryption of '$s' section" 88 | } 89 | } 90 | } 91 | } 92 | 93 | # Expand and Test Path 94 | $Path = [Environment]::ExpandEnvironmentVariables($Path) 95 | if ([String]::IsNullOrEmpty($Path) -or -Not (Test-Path $Path)) { 96 | Write-Verbose "Path '$Path' is not found." 97 | return 98 | } 99 | 100 | Write-Verbose "Looking for config files at '$Path'.." 101 | $configs = $() 102 | foreach ($f in @("web.config","*.exe.config")) { 103 | $found = $null 104 | $found = Get-ChildItem $Path -Filter $f -Recurse:$Recurse -ErrorAction SilentlyContinue 105 | if ($found) { $configs += @($found) } 106 | } 107 | $configs = $configs | Select-Object -Unique 108 | 109 | if ($AsFileInfo) { $configs } 110 | else { 111 | foreach ($c in ($configs | Select-Object -Unique)) { 112 | $content = $null 113 | Write-Verbose "File '$($c.FullName)'.." 114 | $isWebConfig = ($c.Name -eq 'web.config') 115 | 116 | if ($isWebConfig) { 117 | # Create a copy of web.config's and decrypt it 118 | $tempAppFolder = $null 119 | 120 | Write-Verbose "Cloning $($c.FullName) ..." 121 | $tempAppConfig = Copy_WebConfig -config $c.FullName 122 | $tempAppFolder = Split-Path $tempAppConfig -Parent 123 | 124 | if (Test-Path $tempAppConfig) { 125 | Decypt_WebConfig -folder $tempAppFolder 126 | 127 | Write-Verbose "Reading web.config content" 128 | $content = Get-Content $tempAppConfig | Out-String 129 | } 130 | 131 | Write-Verbose "Deleting $tempAppFolder" 132 | Remove-Item $tempAppFolder -Force -Recurse 133 | } else { 134 | # App.config 135 | Write-Verbose "Reading app config content" 136 | $content = Get-Content $c.FullName | Out-String 137 | } 138 | 139 | if (!$AsText) { 140 | $content = [xml]$content 141 | $content | Add-Member -NotePropertyName File -NotePropertyValue $c.FullName 142 | $content | Add-Member -NotePropertyName ComputerName -NotePropertyValue ([System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName) 143 | $content 144 | } 145 | else { $content } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Functions/PSWebConfig/Test-PSWebConfig.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Tests all URI and ConnectionStrings from web or application configuration. 4 | 5 | .DESCRIPTION 6 | The cmdlet fetches all ConnectionString and service endpoint URIs 7 | from a configuration xml and executes a test against them on a 8 | local or remote machine. 9 | 10 | If -IncludeAppSettings switch is defined, it will include any URI or 11 | ConnectionStrings to the tests. 12 | 13 | .PARAMETER InputObject 14 | Mandatory - Parameter to pass a PSWebConfig object 15 | 16 | .PARAMETER Session 17 | Optional - PSSession to execute configuration test 18 | 19 | .PARAMETER IncludeAppSettings 20 | Optional - Switch to include URIs and ConnectionStrings from appSettings 21 | sections 22 | 23 | .EXAMPLE 24 | Get-PSWebConfig -Path 'c:\intepub\wwwroot\testapp\' | Test-PSWebConfig 25 | 26 | .EXAMPLE 27 | Get-WebSite | Get-PSWebConfig -Recurse | Test-PSWebConfig 28 | #> 29 | function Test-PSWebConfig { 30 | [CmdletBinding(DefaultParameterSetName="FromPipeLine")] 31 | param( 32 | [Parameter( 33 | ParameterSetName="FromPipeLine", 34 | ValueFromPipeLine=$true, 35 | Position=0, 36 | Mandatory=$true)] 37 | [psobject[]]$ConfigXml, 38 | 39 | [switch]$IncludeAppSettings, 40 | [System.Management.Automation.Runspaces.PSSession]$Session 41 | ) 42 | process { 43 | Write-Verbose "Executing Test-PSWebConfig" 44 | 45 | if (-Not $ConfigXml.configuration) { 46 | Write-Verbose "InputObject is not a valid XML configuration, trying to get config XML." 47 | $ConfigXml = Get-PSWebConfig -InputObject $ConfigXml 48 | } 49 | 50 | Get-PSUri -ConfigXml $ConfigXml -IncludeAppSettings:$IncludeAppSettings | 51 | Test-PSUri -Session $Session 52 | 53 | Get-PSConnectionString -ConfigXml $ConfigXml -IncludeAppSettings:$IncludeAppSettings | 54 | Test-PSConnectionString -Session $Session 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Functions/PSWebConfig/Unprotect-PSWebConfig.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Decrypts and saves inplace a web.config file 4 | .DESCRIPTION 5 | Takes a Path or a WebAdministration object as an input, creates a 6 | backup of the original file and overrides the configuration with its 7 | decrypted version. 8 | 9 | The cmdlet prompts for clarification on the override, unless -Confirm 10 | is set to false. 11 | 12 | .PARAMETER InputObject 13 | Mandatory - Parameter to pass the Application or WebSite from pipeline 14 | .PARAMETER Path 15 | Mandatory - Parameter to pass the path for the target application 16 | .PARAMETER Recurse 17 | Optional - Switch to look for multiple web.config files in sub-folders for 18 | web applications 19 | .PARAMETER Confirm 20 | Optional - Boolean to disable override confirmation (default -Confirm:$true) 21 | .PARAMETER Session 22 | Optional - PSSession to execute the action 23 | 24 | .EXAMPLE 25 | Unprotect-PSWebConfig -Path 'c:\intepub\wwwroot\testapp\' 26 | .EXAMPLE 27 | $server1 = New-PSSession 'server1.local.domain' 28 | Unprotect-PSWebConfig -Path 'c:\intepub\wwwroot\testapp\' -Session $server1 29 | .EXAMPLE 30 | Get-WebSite | Unprotect-PSWebConfig 31 | #> 32 | 33 | function Unprotect-PSWebConfig { 34 | [CmdletBinding(DefaultParameterSetName="FromPipeLine")] 35 | param( 36 | [Parameter(ParameterSetName="FromPipeLine",Position=0)] 37 | [Parameter(ValueFromPipeLine=$true)] 38 | [psobject[]]$InputObject, 39 | 40 | [Parameter(ParameterSetName="FromPath",Position=0,Mandatory=$true)] 41 | [Alias('physicalPath')] 42 | [string]$Path, 43 | 44 | [switch]$Recurse, 45 | [bool]$Confirm=$true, 46 | 47 | [System.Management.Automation.Runspaces.PSSession]$Session 48 | ) 49 | process { 50 | Write-Verbose "Executing Unprotect-PSWebConfig" 51 | 52 | if ($Path) { 53 | Write-Verbose "Processing by Path" 54 | $InputObject = New-Object -TypeName PsObject -Property @{ 55 | physicalPath = $Path 56 | Session = $Session 57 | } 58 | } 59 | 60 | if ($InputObject) { 61 | Write-Verbose "Processing by InputObject" 62 | foreach ($entry in $InputObject) { 63 | # Setting Remote Session 64 | $EntrySession = $entry.Session 65 | if ($Session) { 66 | Write-Verbose "Overriding session from -Session Parameter" 67 | $EntrySession = $Session 68 | } 69 | elseif ($entry | Get-Member -Name RunspaceId) { 70 | Write-Verbose "Getting Session from RunspaceId '$($entry.RunspaceId)'" 71 | $EntrySession = Get-PSSession -InstanceId $entry.RunspaceId 72 | } 73 | 74 | Write-Verbose "Getting config files..." 75 | $configs = $entry | Get-PSWebConfig -AsFileInfo -Recurse:$Recurse -Session:$EntrySession 76 | 77 | foreach ($config in $configs) { 78 | $configFile = $config.FullName 79 | $backupFile = [string]::Join('.',@($configFile,((Get-Date -Format s) -replace ':','-'),'config')) 80 | $decryptedConfig = Get-PSWebConfig -AsText -Path $configFile -Session:$EntrySession 81 | 82 | $BackupAndOverride = { 83 | param( 84 | [string]$configFile, 85 | [string]$backupFile, 86 | [string]$decryptedConfig, 87 | [bool]$Confirm 88 | ) 89 | Write-Verbose "Creating backup to '$backupFile'.." 90 | Copy-Item -Path $configFile -Destination $backupFile -Force 91 | 92 | Write-Verbose "Overriding '$configFile' with decrypted content ..." 93 | Set-Content -Path $configFile -Value $decryptedConfig -Confirm:$Confirm 94 | } 95 | 96 | Invoke-SessionCommand -Session:$EntrySession -ArgumentList $configFile,$backupFile,$decryptedConfig,$Confirm -ScriptBlock $BackupAndOverride 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016, Akos Murati 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /PSWebConfig.format.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PSWebConfig.WebConfig 6 | 7 | PSWebConfig.WebConfig 8 | 9 | 10 | 11 | 12 | 13 | 14 | ComputerName 15 | 16 | 17 | File 18 | 19 | 20 | xml 21 | 22 | 23 | configuration 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | PSWebConfig.TestResult 33 | 34 | PSWebConfig.TestResult 35 | 36 | 37 | 38 | 39 | 40 | 41 | ComputerName 42 | 43 | 44 | TestType 45 | 46 | 47 | Test 48 | 49 | 50 | Passed 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | PSWebConfig.ConnectionString 60 | 61 | PSWebConfig.ConnectionString 62 | 63 | 64 | 65 | 66 | 67 | 68 | ComputerName 69 | 70 | 71 | File 72 | 73 | 74 | Name 75 | 76 | 77 | ConnectionString 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | PSWebConfig.AppSetting 87 | 88 | PSWebConfig.AppSetting 89 | 90 | 91 | 92 | 93 | 94 | 95 | ComputerName 96 | 97 | 98 | File 99 | 100 | 101 | Key 102 | 103 | 104 | Value 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | PSWebConfig.Uri 114 | 115 | PSWebConfig.Uri 116 | 117 | 118 | 119 | 120 | 121 | 122 | ComputerName 123 | 124 | 125 | File 126 | 127 | 128 | SectionPath 129 | 130 | 131 | name 132 | 133 | 134 | Uri 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /PSWebConfig.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for 'PSWebConfig' module 3 | # Created by: Akos Murati 4 | # Generated on: 02/28/2016 5 | # 6 | 7 | @{ 8 | 9 | # Script module or binary module file associated with this manifest. 10 | RootModule = 'PSWebConfig.psm1' 11 | 12 | # Version number of this module. 13 | ModuleVersion = '1.7.0.0' 14 | 15 | # ID used to uniquely identify this module 16 | GUID = '37abef2c-d883-46be-ce1a-53d16477d01d' 17 | 18 | # Author of this module 19 | Author = 'Akos Murati (akos@murati.hu)' 20 | 21 | # Company or vendor of this module 22 | CompanyName = 'murati.hu' 23 | 24 | # Copyright statement for this module 25 | Copyright = '(c) 2016 murati.hu . All rights reserved.' 26 | 27 | # Description of the functionality provided by this module 28 | Description = 'A PowerShell module for decrypting, inspecting and testing web.config and application config files in remote and local scenarios without the WebAdministration module.' 29 | 30 | # Minimum version of the Windows PowerShell engine required by this module 31 | # PowerShellVersion = '' 32 | 33 | # Name of the Windows PowerShell host required by this module 34 | # PowerShellHostName = '' 35 | 36 | # Minimum version of the Windows PowerShell host required by this module 37 | # PowerShellHostVersion = '' 38 | 39 | # Minimum version of Microsoft .NET Framework required by this module 40 | # DotNetFrameworkVersion = '' 41 | 42 | # Minimum version of the common language runtime (CLR) required by this module 43 | # CLRVersion = '' 44 | 45 | # Processor architecture (None, X86, Amd64) required by this module 46 | # ProcessorArchitecture = '' 47 | 48 | # Modules that must be imported into the global environment prior to importing this module 49 | # RequiredModules = @() 50 | 51 | # Assemblies that must be loaded prior to importing this module 52 | # RequiredAssemblies = @() 53 | 54 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 55 | # ScriptsToProcess = @() 56 | 57 | # Type files (.ps1xml) to be loaded when importing this module 58 | # TypesToProcess = @() 59 | 60 | # Format files (.ps1xml) to be loaded when importing this module 61 | # FormatsToProcess = @() 62 | 63 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 64 | # NestedModules = @() 65 | 66 | # Functions to export from this module 67 | FunctionsToExport = @( 68 | 'Get-PSWebConfig' 69 | 'Test-PSWebConfig' 70 | 71 | 'Get-PSAppSetting' 72 | 73 | 'Get-PSConnectionString' 74 | 'Test-PSConnectionString' 75 | 76 | 'Get-PSEndpoint' 77 | 'Get-PSUri' 78 | 'Test-PSUri' 79 | 80 | 'Unprotect-PSWebConfig' 81 | ) 82 | 83 | # Cmdlets to export from this module 84 | # CmdletsToExport = '*' 85 | 86 | # Variables to export from this module 87 | # VariablesToExport = '*' 88 | 89 | # Aliases to export from this module 90 | AliasesToExport = @( 91 | 'Get-PSAppConfig' 92 | 'Test-PSAppConfig' 93 | 'Test-WebConfigFile' 94 | 'Decrypt-PSWebConfig' 95 | ) 96 | 97 | # DSC resources to export from this module 98 | # DscResourcesToExport = @() 99 | 100 | # List of all modules packaged with this module 101 | # ModuleList = @() 102 | 103 | # List of all files packaged with this module 104 | # FileList = @() 105 | 106 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 107 | PrivateData = @{ 108 | 109 | PSData = @{ 110 | 111 | # Tags applied to this module. These help with module discovery in online galleries. 112 | Tags = @( 113 | 'web.config', 114 | 'app.config', 115 | 116 | 'decrypt', 117 | 'test', 118 | 'inspect', 119 | 'connectionString', 120 | 'appSetting', 121 | 'endpoint', 122 | 123 | 'IIS', 124 | 'aspnet_regiis', 125 | 'config', 126 | 'configuration', 127 | 'section', 128 | 'IISAdministration', 129 | 'WebAdministration' 130 | ) 131 | 132 | # A URL to the license for this module. 133 | LicenseUri = 'https://github.com/murati-hu/PSWebConfig/blob/master/LICENSE' 134 | 135 | # A URL to the main website for this project. 136 | ProjectUri = 'https://github.com/murati-hu/PSWebConfig' 137 | 138 | # A URL to an icon representing this module. 139 | # IconUri = '' 140 | 141 | # ReleaseNotes of this module 142 | # ReleaseNotes = '' 143 | 144 | } # End of PSData hashtable 145 | 146 | } # End of PrivateData hashtable 147 | 148 | # HelpInfo URI of this module 149 | HelpInfoURI = 'https://github.com/murati-hu/PSWebConfig' 150 | 151 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 152 | # DefaultCommandPrefix = '' 153 | 154 | } 155 | -------------------------------------------------------------------------------- /PSWebConfig.psm1: -------------------------------------------------------------------------------- 1 | Write-Verbose "PSWebConfig module" 2 | 3 | $functionFilter = Join-Path $PSScriptRoot "Functions\*.ps1" 4 | Get-ChildItem -Path $functionFilter -Recurse | Foreach-Object { 5 | Write-Verbose "Loading file $($_.Name).." 6 | . $_.FullName 7 | } 8 | 9 | Update-FormatData -PrependPath (Join-path $PSScriptRoot 'PSWebConfig.format.ps1xml') 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PSWebConfig PowerShell module 2 | ========================== 3 | 4 | [![Build status](https://ci.appveyor.com/api/projects/status/4tcovid4e04m1vdx?svg=true)](https://ci.appveyor.com/project/muratiakos/pswebconfig) 5 | 6 | PSWebConfig is a PowerShell module that provides an easy way to automatically decrypt, 7 | inspect and test web.config or any .NET based application configuration files both 8 | locally or remotely. 9 | 10 | ## Installation 11 | PSWebConfig is available via [PowerShell Gallery][PowerShellGallery] or [PsGet][psget], 12 | so you can simply install it with the following command: 13 | ```powershell 14 | Install-Module PSWebConfig 15 | 16 | # Or alternatevely you can install it with PsGet from this repository 17 | Install-Module -ModuleUrl https://github.com/murati-hu/PSWebConfig/archive/master.zip 18 | ``` 19 | Of course you can download and install the module manually too from 20 | [Downloads][download] 21 | 22 | ## Usage 23 | ```powershell 24 | Import-Module PSWebConfig 25 | ``` 26 | 27 | ## Examples 28 | ### View and decrypt a web.config 29 | `Get-PSWebConfig` cmdlet automatically fetches and decrypts any web.config 30 | file both locally and remotely without altering the actual config file on the 31 | target computer: 32 | ```powershell 33 | # Pipe any site into Get-PSWebConfig to show the decrypted config 34 | Get-Website | Get-PSWebConfig -AsText 35 | 36 | # You can use -Path attribute to find web.config files 37 | Get-PSWebConfig -Path C:\inetpub\wwwroot\ 38 | 39 | # If you wish to override the config with its decrypted version 40 | Get-Website | Decrypt-PSWebConfig -Confirm $false 41 | ``` 42 | ### Test config files 43 | `Test-PSWebConfig` function allows complete tests on all connectionStrings and 44 | Service addresses from a configuration both on local or remote computers. 45 | ```powershell 46 | # Pipe a config into Test-PSWebConfig 47 | Get-Website * | Test-PSWebConfig 48 | 49 | # Or use -Session to test it via remote PSSession 50 | $server1 = New-PSSession 'server1.local.domain' 51 | Get-PSWebConfig -Path C:\inetpub\wwwroot\ -Session $server1 | Test-PSWebConfig 52 | ``` 53 | 54 | ### Inspect ConnectionStrings 55 | ```powershell 56 | # Pipe Get-PSWebConfig into Get-PSConnectionString to get decrypted connectionstrings 57 | Get-Website * | Get-PSWebConfig | Get-PSConnectionString 58 | 59 | # You can also use -IncludeAppSettings to find connectionstrings from appSetting section 60 | Get-PSWebConfig -Path C:\inetpub\wwwroot\ | Get-PSConnectionString -IncludeAppSettings 61 | ``` 62 | 63 | ### Test ConnectionStrings 64 | `Test-PSConnectionString` cmdlet tries to initiate a SQL connection from a local or 65 | remote computer to test if there are any issue connection to a database. 66 | ```powershell 67 | # Pipe Get-PSConnectionString to Test-PSConnectionString 68 | Get-Website * | Get-PSWebConfig | Get-PSConnectionString -Inc | Test-PSConnectionString 69 | 70 | # You can also transform the connectionString with regex -ReplaceRules hashtable 71 | Test-PSConnectionString -Conn "Server=dbserver.local;Database=##TARGET_DB##" -ReplaceRules @{ '##TARGET_DB##'='myDb'} 72 | ``` 73 | 74 | ### Inspect appSettings 75 | ```powershell 76 | # Pipe Get-PSWebConfig into Get-PSAppSetting to get decrypted appSettings 77 | Get-Website * | Get-PSWebConfig | Get-PSAppSetting 78 | ``` 79 | 80 | ### Get service endpoints and URIs 81 | ```powershell 82 | # Pipe Get-PSWebConfig into Get-PSEndpoint to get decrypted webservice addresses 83 | Get-Website * | Get-PSWebConfig | Get-PSEndpoint 84 | 85 | # Or pipe Get-PSWebConfig into Get-PSUri to get URLs from appSettings too. 86 | Get-Website * | Get-PSWebConfig | Get-PSUri 87 | ``` 88 | 89 | Call `help` on any of the PSWebConfig cmdlets for more information and examples. 90 | 91 | ## Documentation 92 | Cmdlets and functions for PSWebConfig have their own help PowerShell help, which 93 | you can read with `help `. 94 | 95 | ## Versioning 96 | PSWebConfig aims to adhere to [Semantic Versioning 2.0.0][semver]. 97 | 98 | ## Issues 99 | In case of any issues, raise an [issue ticket][issues] in this repository and/or 100 | feel free to contribute to this project if you have a possible fix for it. 101 | 102 | ## Development 103 | * Source hosted at [Github.com][repo] 104 | * Report issues/questions/feature requests on [Github Issues][issues] 105 | 106 | Pull requests are very welcome! Make sure your patches are well tested. 107 | Ideally create a topic branch for every separate change you make. For 108 | example: 109 | 110 | 1. Fork the [repo][repo] 111 | 2. Create your feature branch (`git checkout -b my-new-feature`) 112 | 3. Commit your changes (`git commit -am 'Added some feature'`) 113 | 4. Push to the branch (`git push origin my-new-feature`) 114 | 5. Create new Pull Request 115 | 116 | ## Authors 117 | Created and maintained by [Akos Murati][muratiakos] (). 118 | 119 | ## License 120 | Apache License, Version 2.0 (see [LICENSE][LICENSE]) 121 | 122 | [repo]: https://github.com/murati-hu/PsWebConfig 123 | [issues]: https://github.com/murati-hu/PsWebConfig/issues 124 | [muratiakos]: http://murati.hu 125 | [license]: LICENSE 126 | [semver]: http://semver.org/ 127 | [psget]: http://psget.net/ 128 | [PowerShellGallery]: https://www.powershellgallery.com/packages/PSWebConfig 129 | [download]: https://github.com/murati-hu/PSWebConfig/archive/master.zip 130 | -------------------------------------------------------------------------------- /Tests/Fixtures/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Tests/Fixtures/webrequests.csv: -------------------------------------------------------------------------------- 1 | uri,statuscodes,shouldpass 2 | wrongurl,,0 3 | http://murati.hu,,1 4 | http://bing.com,^999$,0 5 | -------------------------------------------------------------------------------- /Tests/Import-LocalModule.ps1: -------------------------------------------------------------------------------- 1 | # Load module from the local filesystem, instead from the ModulePath 2 | Remove-Module PSWebConfig -Force -ErrorAction SilentlyContinue 3 | Import-Module (Split-Path $PSScriptRoot -Parent) 4 | 5 | $script:FunctionPath = Resolve-Path (Join-Path $PSScriptRoot '../Functions') 6 | $script:FixturePath = Resolve-Path (Join-Path $PSScriptRoot 'Fixtures') 7 | -------------------------------------------------------------------------------- /Tests/Module/Module.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $moduleName = 'PSWebConfig' 4 | $exportedCommands = (Get-Command -Module $moduleName) 5 | $expectedCommands = @( 6 | 'Get-PSWebConfig' 7 | 'Get-PSAppConfig' 8 | 9 | 'Decrypt-PSWebConfig' 10 | 'Unprotect-PSWebConfig' 11 | 12 | 'Test-PSWebConfig' 13 | 'Test-WebConfigFile' 14 | 'Test-PSAppConfig' 15 | 16 | 'Get-PSAppSetting' 17 | 18 | 'Get-PSConnectionString' 19 | 'Test-PSConnectionString' 20 | 21 | 'Get-PSEndpoint' 22 | 'Get-PSUri' 23 | 'Test-PSUri' 24 | ) 25 | 26 | Describe "$moduleName Module" { 27 | It "Should be loaded" { 28 | Get-Module $moduleName | Should Not BeNullOrEmpty 29 | } 30 | } 31 | 32 | Describe 'Exported commands' { 33 | # Test if the exported command is expected 34 | Foreach ($command in $exportedCommands) 35 | { 36 | Context $command { 37 | It 'Should be an expected command' { 38 | $expectedCommands -contains $command.Name | Should Be $true 39 | } 40 | 41 | It 'Should have proper help' { 42 | $help = Get-Help $command.Name 43 | $help.description | Should Not BeNullOrEmpty 44 | $help.Synopsis | Should Not BeNullOrEmpty 45 | $help.examples | Should Not BeNullOrEmpty 46 | } 47 | } 48 | } 49 | } 50 | 51 | Describe 'Expected commands' { 52 | # Test if the expected command is exported 53 | Foreach ($command in $expectedCommands) 54 | { 55 | Context $command { 56 | It 'Should be an exported command' { 57 | $exportedCommands.Name -contains $command | Should Be $true 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Tests/Module/ScriptAnalyzer.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $scriptSources = Get-ChildItem -Path $script:FunctionPath -Filter '*.ps1' -Recurse 4 | $scriptAnalyzer = Get-Module PSScriptAnalyzer -ListAvailable 5 | 6 | if (-Not $scriptAnalyzer) { 7 | Write-Verbose "PSScriptAnalyzer module is not available." 8 | return 9 | } 10 | 11 | Describe "Script Source analysis" { 12 | Import-Module PSScriptAnalyzer 13 | 14 | $scriptSources | ForEach-Object { 15 | Context "Source $($_.Name)" { 16 | $results = Invoke-ScriptAnalyzer -Path $_.FullName -ErrorVariable $errors 17 | 18 | it "should have no errors" { 19 | $errors | Should BeNullOrEmpty 20 | } 21 | 22 | it "should not have warnings" { 23 | $results | 24 | Where-Object Severity -eq "Warning" | 25 | Should BeNullOrEmpty 26 | } 27 | 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/PSAppSetting/Get-PSAppSetting.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | $webConfigFile = Join-Path $script:FixturePath 'web.config' 6 | 7 | Describe 'Get-PSAppSetting' { 8 | Context 'Local web.config' { 9 | $config = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 10 | $appSettings = $config | Get-PSAppSetting -Verbose:$isVerbose 11 | 12 | It 'should return all AppSettings' { 13 | $appSettings | Should Not BeNullOrEmpty 14 | $appSettings.Count | Should Be 5 15 | $appSettings | Foreach-Object { 16 | $_.psobject.TypeNames -contains 'PSWebConfig.AppSetting' | Should Be $true 17 | $_.SectionPath | Should Be 'appSettings' 18 | $_.key | Should Not BeNullOrEmpty 19 | $_.value | Should Not BeNullOrEmpty 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/PSConnectionString/Get-PSConnectionString.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | $webConfigFile = Join-Path $script:FixturePath 'web.config' 6 | 7 | Describe "Get-PSConnectionString" { 8 | Context "Local web.config connectionStrings section" { 9 | $config = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 10 | 11 | It "should return only connectionStrings by default" { 12 | $connStrs = $config | Get-PSConnectionString -Verbose:$isVerbose 13 | $connStrs | Should Not BeNullOrEmpty 14 | $connStrs.GetType().Name | Should Be "XmlElement" 15 | $connStrs.psobject.TypeNames -contains 'PSWebConfig.ConnectionString' | Should Be $true 16 | 17 | $connStrs.name | Should Be 'login' 18 | $connStrs.SectionPath | Should Be 'connectionStrings' 19 | $connStrs.connectionstring | Should Not BeNullOrEmpty 20 | } 21 | 22 | It "should return connectionStrings with -IncludeAppSettings" { 23 | $connStrs = $config | Get-PSConnectionString -IncludeAppSettings -Verbose:$isVerbose 24 | $connStrs | Should Not BeNullOrEmpty 25 | $connStrs.Count | Should Be 2 26 | $connStrs | Foreach-Object { 27 | $_.psobject.TypeNames -contains 'PSWebConfig.ConnectionString' | Should Be $true 28 | @('login','AppConfigSqlConnectionString') -contains $_.name | Should Be $true 29 | @('connectionStrings','appSettings') -contains $_.SectionPath | Should Be $true 30 | $_.connectionstring | Should Not BeNullOrEmpty 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tests/PSConnectionString/Test_ConnectionString.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | Describe "Test_ConnectionString helper function" { 6 | # Function to test 7 | . (Join-Path $script:FunctionPath 'PSConnectionString/Test_ConnectionString.ps1') 8 | 9 | @{ 10 | Invalid='IvServer=localhost;IvDatabase=##DB##;Connection Timeout=1' 11 | NonExisting="Server=localhost;Database=##DB##ThatShouldNotExist;User Id=uname;Password=4bCd;Connection Timeout=1;" 12 | NonExistingWithPasswordEnd="Server=localhost;Database=##DB##ThatShouldNotExist;User Id=uname;Connection Timeout=1;Password=4bCd" 13 | }.GetEnumerator() | 14 | ForEach-Object { 15 | context "$($_.Key) SqlConnectionString" { 16 | $failingConnectionString=$_.Value 17 | 18 | It "Should have failed test result properties" { 19 | $result = Test_ConnectionString -ConnectionString $failingConnectionString -Verbose:$isVerbose -ShowPassword $true -EA 0 20 | $result | Should Not BeNullOrEmpty 21 | $result.ComputerName | Should Be ([System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName) 22 | $result.TestType | Should Be 'SqlTest' 23 | $result.Test | Should Be $failingConnectionString 24 | $result.ConnectionString | Should Be $failingConnectionString 25 | $result.Passed | Should Be $false 26 | $result.Result | Should Not BeNullOrEmpty 27 | $result.Status | Should Match 'Failed' 28 | } 29 | 30 | It "Should replace ConnectionString with ReplaceRules" { 31 | $replacedFailingConnectionString=$failingConnectionString -replace '##DB##','DB_SUBST' 32 | $replaceRule = @{'##DB##'='DB_SUBST'} 33 | $result = Test_ConnectionString -ConnectionString $failingConnectionString -ReplaceRules $replaceRule -Verbose:$isVerbose -ShowPassword $true -EA 0 34 | 35 | $result.Test | Should Be $failingConnectionString 36 | $result.ConnectionString | Should Be $replacedFailingConnectionString 37 | } 38 | 39 | if ($failingConnectionString -imatch "Password=") { 40 | It "Should replace replace Password= field to ***" { 41 | $result = Test_ConnectionString -ConnectionString $failingConnectionString -Verbose:$isVerbose -EA 0 42 | 43 | $result.Test | Should Match 'Password=\*\*\*' 44 | $result.ConnectionString | Should Match 'Password=\*\*\*' 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tests/PSUri/Get-PSEndpoint.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | $webConfigFile = Join-Path $script:FixturePath 'web.config' 6 | 7 | Describe "Get-PSEndpoint" { 8 | Context "Local web.config" { 9 | $config = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 10 | $endpoints = $config | Get-PSEndpoint -Verbose:$isVerbose 11 | 12 | It "should return all client endpoints as an address" { 13 | $endpoints | Should Not BeNullOrEmpty 14 | $endpoints.Count | Should Be 2 15 | $endpoints | Foreach-Object { 16 | $_.psobject.TypeNames -contains 'PSWebConfig.Uri' | Should Be $true 17 | $_.SectionPath | Should Be 'system.serviceModel/client/endpoint' 18 | $_.name | Should Not BeNullOrEmpty 19 | $_.address | Should Not BeNullOrEmpty 20 | $_.Uri | Should Not BeNullOrEmpty 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/PSUri/Get-PSUri.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | $webConfigFile = Join-Path $script:FixturePath 'web.config' 6 | 7 | Describe 'Get-PSUri' { 8 | Context 'Local web.config' { 9 | $config = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 10 | $addresses = $config | Get-PSUri -Verbose:$isVerbose -IncludeAppsettings 11 | $endpoints = (Get-PSEndpoint -ConfigXml $config -Verbose:$isVerbose) 12 | 13 | It 'should return all addresses with -IncludeAppsettings' { 14 | $addresses | Should Not BeNullOrEmpty 15 | $addresses.Count | Should Be (2+2) # appSetting + endpoints 16 | $addresses | Foreach-Object { 17 | $_.psobject.TypeNames -contains 'PSWebConfig.Uri' | Should Be $true 18 | $_.SectionPath | Should Match '^system.serviceModel/client/endpoint$|^appSettings$' 19 | $_.name | Should Not BeNullOrEmpty 20 | $_.address | Should Not BeNullOrEmpty 21 | $_.Uri | Should Match '^http[s]*:' 22 | } 23 | } 24 | 25 | It 'should contain all service endpoints' { 26 | $addresses | Should Not BeNullOrEmpty 27 | foreach ($e in $endpoints) { 28 | $addresses -contains $e | Should Be $true 29 | } 30 | } 31 | 32 | It 'should be the same as Get-PSEndpoint without -IncludeAppsettings' { 33 | $addressesWithouAppSettings = $config | Get-PSUri -Verbose:$isVerbose 34 | $addressesWithouAppSettings | Should Not BeNullOrEmpty 35 | $addressesWithouAppSettings | Should Be $endpoints 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Tests/PSUri/Test_Uri.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | Describe "Test_Uri helper function" { 6 | # Function to test 7 | . (Join-Path $script:FunctionPath 'PSUri/Test_Uri.ps1') 8 | 9 | Context "Testing multiple URIs and StatusCodes" { 10 | $uriTests = Import-Csv -LiteralPath (Join-Path $script:FixturePath 'webrequests.csv') -Delimiter ',' 11 | 12 | foreach ($uriTest in $uriTests) { 13 | $verb = 'fail' 14 | if ($uriTest.shouldpass -eq 1) { $verb = 'pass'} 15 | 16 | It "'$($uriTest.uri)' should $verb if statuscode matches '$($uriTest.statuscodes)'" { 17 | $result = $null 18 | if ($uriTest.statuscodes) { 19 | $result = Test_Uri -Uri $uriTest.uri -AllowedStatusCodeRegexp $uriTest.statuscodes -ErrorAction SilentlyContinue -Verbose:$isVerbose 20 | } else { 21 | $result = Test_Uri -Uri $uriTest.uri -ErrorAction SilentlyContinue -Verbose:$isVerbose 22 | } 23 | 24 | $result | Should Not BeNullOrEmpty 25 | $result.ComputerName | Should Be ([System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName) 26 | $result.TestType | Should Be 'UriTest' 27 | $result.Test | Should Be $UriTest.uri 28 | $result.Uri | Should Be $UriTest.uri 29 | $result.Passed | Should Be ($uriTest.shouldpass -eq 1) 30 | $result.Result | Should Not BeNullOrEmpty 31 | $result.Status | Should Not BeNullOrEmpty 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/PSWebConfig/Get-WebConfig.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | $webConfigFile = Join-Path $script:FixturePath 'web.config' 6 | 7 | $webConfigSections = @( 8 | "appSettings" 9 | "connectionStrings" 10 | ) 11 | 12 | $testInput = New-Object -TypeName PsObject -Property @{ 13 | physicalPath = $webConfigFile 14 | } 15 | 16 | Describe "Web.config file test" { 17 | It "Test-file Should exists" { 18 | $webConfigFile | Should Exist 19 | } 20 | 21 | $xml = [xml](Get-Content $webConfigFile) 22 | It "Should be a valid XMLDocument" { 23 | $xml.GetType().Name | Should Be "XmlDocument" 24 | } 25 | 26 | foreach($section in $webConfigSections) { 27 | It "Should have '$section' configuration section" { 28 | $xml.configuration.$section | Should Not BeNullOrEmpty 29 | } 30 | } 31 | } 32 | 33 | Describe "Get-PSWebConfig" { 34 | Context "Parameters input" { 35 | It "should accept -Path" { 36 | Get-PSWebConfig -Path $webConfigFile -AsXml -Verbose:$isVerbose | 37 | Select-Object -ExpandProperty File | 38 | Should Be $webConfigFile 39 | } 40 | 41 | It "should accept Path at 0 position" { 42 | Get-PSWebConfig $webConfigFile -AsXml -Verbose:$isVerbose | 43 | Select-Object -ExpandProperty File | 44 | Should Be $webConfigFile 45 | } 46 | 47 | It "should accept -InputObject" { 48 | Get-PSWebConfig -InputObject $testInput -AsXml -Verbose:$isVerbose | 49 | Select-Object -ExpandProperty File | 50 | Should Be $testInput.physicalPath 51 | } 52 | } 53 | Context "Pipeline input" { 54 | It "should accept testInputObject" { 55 | $testInput | 56 | Get-PSWebConfig -AsXml -Verbose:$isVerbose | 57 | Select-Object -ExpandProperty File | 58 | Should Be $testInput.physicalPath 59 | } 60 | 61 | It "should accept FileInfo" { 62 | Get-Item $webConfigFile | 63 | Get-PSWebConfig -AsXml -Verbose:$isVerbose | 64 | Select-Object -ExpandProperty File | 65 | Should Be $testInput.physicalPath 66 | } 67 | } 68 | } 69 | Describe "Get-PSWebConfig" { 70 | Context "Invalid Paths" { 71 | It "Should not return anything" { 72 | Get-PSWebConfig -Path 'clearly:\invalid\path\to_fail' -Verbose:$isVerbose | 73 | Should BeNullOrEmpty 74 | } 75 | } 76 | 77 | Context "Default XML output" { 78 | It "should return the XML object by default" { 79 | $defaultConfig = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 80 | $defaultConfig | Should Not BeNullOrEmpty 81 | $defaultConfig.GetType().Name | Should Be 'XmlDocument' 82 | #$defaultConfig.OuterXml | Set-Content ./default.txt -Enc UTF8 83 | 84 | $xmlConfig = Get-PSWebConfig -Path $webConfigFile -AsXml -Verbose:$isVerbose 85 | $xmlConfig | Should Not BeNullOrEmpty 86 | $xmlConfig.GetType().Name | Should Be 'XmlDocument' 87 | #$xmlConfig.OuterXml | Set-Content ./xml.txt -Enc UTF8 88 | 89 | $defaultConfig.OuterXml | Should Be $xmlConfig.OuterXml 90 | } 91 | 92 | It "should have PSWebConfig.WebConfig additional type" { 93 | $config = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 94 | $config | Should Not BeNullOrEmpty 95 | $config.psobject.TypeNames -contains 'PsWebConfig.WebConfig' | Should Be $true 96 | } 97 | 98 | It "Should be a valid XML Configuration" { 99 | $config = Get-PSWebConfig -Path $webConfigFile -Verbose:$isVerbose 100 | $config.GetType().Name | Should Be 'XmlDocument' 101 | $config.configuration | Should Not BeNullOrEmpty 102 | $config.configuration.GetType().Name | Should Be 'XmlElement' 103 | } 104 | } 105 | 106 | Context "AsFileInfo output" { 107 | It "should match the source File" { 108 | $config = Get-PSWebConfig -Path $webConfigFile -AsFileInfo -Verbose:$isVerbose 109 | $config | Should Not BeNullOrEmpty 110 | $config | Should Be $webConfigFile 111 | $config.GetType().Name | Should Be 'FileInfo' 112 | } 113 | 114 | It "should find web.config in folders" { 115 | $config = Get-PSWebConfig -Path $script:FixturePath -AsFileInfo -Verbose:$isVerbose 116 | $config | Should Not BeNullOrEmpty 117 | $config.FullName | Should Be $webConfigFile 118 | } 119 | } 120 | 121 | Context "Unencrypted text output" { 122 | It "should be the same XML string as the source file" { 123 | $config = Get-PSWebConfig -Path $webConfigFile -AsText -Verbose:$isVerbose 124 | $config | Should Not BeNullOrEmpty 125 | $config.GetType().Name | Should Be 'String' 126 | 127 | $rawConfig = Get-Content -Path $webConfigFile 128 | 129 | #Convert both String to XML to strip unnessary whitespaces 130 | ([xml]$config).OuterXml | Should Be ([xml]$rawConfig).OuterXml 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Tests/PSWebConfig/Get_ConfigFile.tests.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot '../Import-LocalModule.ps1') 2 | 3 | $isVerbose=($VerbosePreference -eq 'Continue') 4 | 5 | Describe "Get_ConfigFile helper" { 6 | # Function to test 7 | . (Join-Path $script:FunctionPath 'PSWebConfig/Get_ConfigFile.ps1') 8 | $webConfigFile = Join-Path $script:FixturePath 'web.config' 9 | 10 | It "Should be able to find web.config files recursively" { 11 | $files = Get_ConfigFile -Path $script:FixturePath -AsFileInfo:$true -Recurse:$true -Verbose:$isVerbose 12 | $files | Should Not BeNullOrEmpty 13 | $files.GetType().Name | Should Be 'FileInfo' 14 | } 15 | 16 | It "Should be able to return XML content" { 17 | $xml = Get_ConfigFile -Path $webConfigFile -Verbose:$isVerbose 18 | $xml | Should Not BeNullOrEmpty 19 | $xml.configuration.GetType().Name | Should Be 'XmlElement' 20 | $xml.File | Should Be $webConfigFile 21 | $xml.ComputerName | Should Be ([System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName) 22 | } 23 | 24 | It "Should be able to read the file content" { 25 | $content = Get_ConfigFile -Path $webConfigFile -AsText:$true -Verbose:$isVerbose 26 | $content | Should Not BeNullOrEmpty 27 | $content.GetType().Name | Should Be 'String' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | install: 2 | - cinst pester 3 | 4 | build: false 5 | 6 | test_script: 7 | - ps: $res = Invoke-Pester -Path ".\Tests" -OutputFormat NUnitXml -OutputFile TestsResults.xml -PassThru 8 | - ps: (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestsResults.xml)) 9 | - ps: if ($res.FailedCount -gt 0) { throw "$($res.FailedCount) tests failed."} 10 | --------------------------------------------------------------------------------