├── .gitignore ├── Build.ps1 ├── CHANGELOG.md ├── LICENSE ├── Private ├── Expand-PoshspecTestExpression.ps1 ├── Get-PoshspecParam.ps1 ├── Invoke-PoshspecExpression.ps1 ├── SearchAd.ps1 ├── Test-RunAsAdmin.ps1 └── UserRightsAssignment.ps1 ├── Public ├── AppPool.ps1 ├── AuditPolicy.ps1 ├── CimObject.ps1 ├── DnsHost.ps1 ├── File.ps1 ├── Firewall.ps1 ├── Folder.ps1 ├── Hotfix.ps1 ├── Http.ps1 ├── Interface.ps1 ├── LocalGroup.ps1 ├── LocalUser.ps1 ├── Package.ps1 ├── Registry.ps1 ├── SecurityOption.ps1 ├── SecurityOptionData.psd1 ├── ServerFeature.ps1 ├── Service.ps1 ├── Share.ps1 ├── SoftwareProduct.ps1 ├── TcpPort.ps1 ├── UserRightsAssignment.ps1 ├── Volume.ps1 └── WebSite.ps1 ├── README.md ├── Tests └── poshspec.Tests.ps1 ├── en-US └── about_poshspec.help.txt ├── exampleoutput.png ├── poshspec.psd1 ├── poshspec.psm1 └── poshspecdemo.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | # Don't checkin this output dir 2 | Release/ 3 | 4 | .vscode/ 5 | .swp/ -------------------------------------------------------------------------------- /Build.ps1: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # PREVIEW VERSION OF PSAKE SCRIPT FOR MODULE BUILD & PUBLISH TO THE PSGALLERY 3 | ############################################################################## 4 | # 5 | # We are hoping to add support for publishing modules to the PowerShell gallery 6 | # and private repositories in a future release of this extension. This is an 7 | # early look at the approach we are considering which is to supply a 8 | # PSake-based script that will: 9 | # 10 | # 1. Create a directory from which to publish your module. 11 | # 2. Copy the appropriate module files to that directory excluding items like 12 | # the .vscode directory, Pester tests, etc. These are configurable in Build.ps1. 13 | # 3. Verify all existing Pester tests pass. 14 | # 4. Publish the module to the desired repository (defaulting to the PSGallery). 15 | # 16 | # Requirements: PSake. If you don't have this module installed use the following 17 | # command to install it: 18 | # 19 | # PS C:\> Install-Module PSake -Scope CurrentUser 20 | # 21 | ############################################################################## 22 | # This is a PSake script that supports the following tasks: 23 | # clean, build, test and publish. The default task is build. 24 | # 25 | # The publish task uses the Publish-Module command to publish 26 | # to either the PowerShell Gallery (the default) or you can change 27 | # the $Repository property to the name of an alternate repository. 28 | # 29 | # The test task invokes Pester to run any Pester tests in your 30 | # workspace folder. Name your test scripts .Tests.ps1 31 | # and Pester will find and run the tests contained in the files. 32 | # 33 | # You can run this build script directly using the invoke-psake 34 | # command which will execute the build task. This task "builds" 35 | # a temporary folder from which the module can be published. 36 | # 37 | # PS C:\> invoke-psake build.ps1 38 | # 39 | # You can run your Pester tests (if any) by running the following command. 40 | # 41 | # PS C:\> invoke-psake build.ps1 -taskList test 42 | # 43 | # You can execute the publish task with the following command. Note that 44 | # the publish task will run the test task first. The Pester tests must pass 45 | # before the publish task will run. The first time you run the publish 46 | # command, you will be prompted to enter your PowerShell Gallery NuGetApiKey. 47 | # After entering the key, it is encrypted and stored so you will not have to 48 | # enter it again. 49 | # 50 | # PS C:\> invoke-psake build.ps1 -taskList publish 51 | # 52 | # You can verify the stored and encrypted NuGetApiKey by running the following 53 | # command. This will display your NuGetApiKey in plain text! 54 | # 55 | # PS C:\> invoke-psake build.ps1 -taskList showKey 56 | # 57 | # You can store a new NuGetApiKey with this command. You can leave off 58 | # the -properties parameter and you'll be prompted for the key. 59 | # 60 | # PS C:\> invoke-psake build.ps1 -taskList storeKey -properties @{NuGetApiKey='test123'} 61 | # 62 | 63 | ############################################################################### 64 | # Customize these properties for your module. 65 | ############################################################################### 66 | Properties { 67 | $ManifestPath = (Get-Item $PSScriptRoot\*.psd1)[0] 68 | # The name of your module should match the basename of the PSD1 file. 69 | $ModuleName = $ManifestPath.BaseName 70 | 71 | # Path to the release notes file. Set to $null if the release notes reside in the manifest file. 72 | $ReleaseNotesPath = "$PSScriptRoot\CHANGELOG.md" 73 | 74 | # The directory used to publish the module from. If you are using Git, the 75 | # $PublishDir should be ignored if it is under the workspace directory. 76 | $PublishDir = "$PSScriptRoot\Release\$ModuleName" 77 | 78 | # The following items will not be copied to the $PublishDir. 79 | # Add items that should not be published with the module. 80 | $Exclude = @( 81 | 'Release', 82 | 'Tests', 83 | '.git*', 84 | '.vscode', 85 | '*.png', 86 | 'poshspecdemo.ps1', 87 | (Split-Path $PSCommandPath -Leaf) 88 | ) 89 | 90 | # Name of the repository you wish to publish to. Default repo is the PSGallery. 91 | $PublishRepository = 'PSGallery' 92 | 93 | # Your NuGet API key for the PSGallery. Leave it as $null and the first time 94 | # you publish you will be prompted to enter your API key. The build will 95 | # store the key encrypted in a file, so that on subsequent publishes you 96 | # will no longer be prompted for the API key. 97 | $NuGetApiKey = $null 98 | $EncryptedApiKeyPath = "$env:LOCALAPPDATA\vscode-powershell\PSGalleryApiKey.clixml" 99 | } 100 | 101 | ############################################################################### 102 | # Customize these tasks for performing operations before and/or after publish. 103 | ############################################################################### 104 | Task PrePublish { 105 | } 106 | 107 | Task PostPublish { 108 | } 109 | 110 | ############################################################################### 111 | # Core task implementations - this possibly "could" ship as part of the 112 | # vscode-powershell extension and then get dot sourced into this file. 113 | ############################################################################### 114 | Task default -depends Build 115 | 116 | Task Publish -depends Test, PrePublish, PublishImpl, PostPublish { 117 | } 118 | 119 | Task PublishImpl -depends Test -requiredVariables PublishDir, EncryptedApiKeyPath { 120 | $NuGetApiKey = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath 121 | 122 | $publishParams = @{ 123 | Path = $PublishDir 124 | NuGetApiKey = $NuGetApiKey 125 | } 126 | 127 | if ($PublishRepository) { 128 | $publishParams['Repository'] = $PublishRepository 129 | } 130 | 131 | # Consider not using -ReleaseNotes parameter when Update-ModuleManifest has been fixed. 132 | if ($ReleaseNotesPath) { 133 | $publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath) 134 | } 135 | 136 | "Calling Publish-Module..." 137 | Publish-Module @publishParams 138 | } 139 | 140 | Task Test -depends Build { 141 | Import-Module Pester 142 | Invoke-Pester $PSScriptRoot 143 | } 144 | 145 | Task Build -depends Clean -requiredVariables PublishDir, Exclude, ModuleName { 146 | if ((Get-Command -Name Step-ModuleVersion -ErrorAction SilentlyContinue).Source) 147 | { 148 | Step-ModuleVersion -Path $ManifestPath 149 | } 150 | else 151 | { 152 | Write-Warning "'Step-ModuleVersion' command is not available." 153 | } 154 | 155 | Copy-Item $PSScriptRoot\* -Destination $PublishDir -Recurse -Exclude $Exclude 156 | 157 | # Get contents of the ReleaseNotes file and update the copied module manifest file 158 | # with the release notes. 159 | # DO NOT USE UNTIL UPDATE-MODULEMANIFEST IS FIXED - HORRIBLY BROKEN RIGHT NOW. 160 | # if ($ReleaseNotesPath) { 161 | # $releaseNotes = @(Get-Content $ReleaseNotesPath) 162 | # Update-ModuleManifest -Path $PublishDir\${ModuleName}.psd1 -ReleaseNotes $releaseNotes 163 | # } 164 | } 165 | 166 | Task Clean -depends Init -requiredVariables PublishDir { 167 | # Sanity check the dir we are about to "clean". If $PublishDir were to 168 | # inadvertently get set to $null, the Remove-Item commmand removes the 169 | # contents of \*. That's a bad day. Ask me how I know? :-( 170 | if ($PublishDir.Contains($PSScriptRoot)) { 171 | Remove-Item $PublishDir\* -Recurse -Force 172 | } 173 | } 174 | 175 | Task Init -requiredVariables PublishDir { 176 | if (!(Test-Path $PublishDir)) { 177 | $null = New-Item $PublishDir -ItemType Directory 178 | } 179 | } 180 | 181 | Task StoreKey -requiredVariables EncryptedApiKeyPath { 182 | if (Test-Path $EncryptedApiKeyPath) { 183 | Remove-Item $EncryptedApiKeyPath 184 | } 185 | 186 | $null = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath 187 | "The NuGetApiKey has been stored in $EncryptedApiKeyPath" 188 | } 189 | 190 | Task ShowKey -requiredVariables EncryptedApiKeyPath { 191 | $NuGetApiKey = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath 192 | "The stored NuGetApiKey is: $NuGetApiKey" 193 | } 194 | 195 | Task ? -description 'Lists the available tasks' { 196 | "Available tasks:" 197 | $psake.context.Peek().tasks.Keys | Sort 198 | } 199 | 200 | ############################################################################### 201 | # Helper functions 202 | ############################################################################### 203 | function Get-NuGetApiKey($NuGetApiKey, $EncryptedApiKeyPath) { 204 | $storedKey = $null 205 | if (!$NuGetApiKey) { 206 | if (Test-Path $EncryptedApiKeyPath) { 207 | $storedKey = Import-Clixml $EncryptedApiKeyPath | ConvertTo-SecureString 208 | $cred = New-Object -TypeName PSCredential -ArgumentList 'kh',$storedKey 209 | $NuGetApiKey = $cred.GetNetworkCredential().Password 210 | Write-Verbose "Retrieved encrypted NuGetApiKey from $EncryptedApiKeyPath" 211 | } 212 | else { 213 | $cred = Get-Credential -Message "Enter your NuGet API Key in the password field (or nothing, this isn't used yet in the preview)" -UserName "user" 214 | $apiKeySS = $cred.Password 215 | $NuGetApiKey = $cred.GetNetworkCredential().Password 216 | } 217 | } 218 | 219 | if (!$storedKey) { 220 | # Store encrypted NuGet API key to use for future invocations 221 | if (!$apiKeySS) { 222 | $apiKeySS = ConvertTo-SecureString -String $NuGetApiKey -AsPlainText -Force 223 | } 224 | 225 | $parentDir = Split-Path $EncryptedApiKeyPath -Parent 226 | if (!(Test-Path -Path $parentDir)) { 227 | $null = New-Item -Path $parentDir -ItemType Directory 228 | } 229 | 230 | $apiKeySS | ConvertFrom-SecureString | Export-Clixml $EncryptedApiKeyPath 231 | Write-Verbose "Stored encrypted NuGetApiKey to $EncryptedApiKeyPath" 232 | } 233 | 234 | $NuGetApiKey 235 | } 236 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog 2 | 3 | ## [2.2.8] - 2019-10-21 4 | 5 | ### Fixed 6 | 7 | * [BugFix] Fixed issue with `SoftwareProduct` where it was prompting for the `Path` parameter due to an unescaped variable - Thanks [@Glober777](https://github.com/Glober777) 8 | 9 | ## [2.2.7] - 2019-06-13 10 | 11 | ### Added 12 | 13 | * Added `SecurityOption` function for validating Local Security Policy Security Option settings -- Thanks [@markwragg](https://github.com/markwragg) 14 | 15 | ## [2.2.2] - 2018-06-22 16 | 17 | ### Fixed 18 | 19 | * [BugFix] Loading of Pester module moved to the `RequiredModules` field of the Manifest as loading it via `Import-Module` was causing PowerShell Gallery to think the Pester cmdlets were part of this module, which caused issues installing PoshSpec unless `-NoClobber` was used. - Thanks [@AspenForester](https://github.com/AspenForester) 20 | 21 | ## [2.2.1] - 2017-05-13 22 | 23 | ### Changed 24 | 25 | * Added PropertyExpression to `Get-PoshspecParams` 26 | * Support added to Website and AppPool for accessing property values through dot notation. 27 | See [#52](https://github.com/Ticketmaster/poshspec/pull/52) for details. Thanks [Jesse Gigler](https://github.com/jgigler). 28 | 29 | ## [2.1.19] - 2017-04-25 30 | 31 | ### Changed 32 | 33 | * Expanded functionality for WebSite and AppPool [#49](https://github.com/Ticketmaster/poshspec/pull/49) [#50](https://github.com/Ticketmaster/poshspec/pull/50) 34 | 35 | ## [2.1.16] - 2017-02-15 36 | 37 | ### Changed 38 | 39 | * Improved handling of single quotes in Package function 40 | 41 | ## [2.1.12] - 2016-07-26 42 | 43 | ### Added 44 | 45 | * Added Functions for 46 | * LocalUser 47 | * AuditPolicy 48 | * Volume 49 | * ServerFeature 50 | * Share 51 | * UserRightsAssignment 52 | 53 | ### Changed 54 | 55 | * Improved handling of single quotes in Package function 56 | 57 | ## [2.1.10] - 2016-07-05 58 | 59 | ### Changed 60 | 61 | * Added `-UseBasicParsing` switch to Http test function so that it works on a headless deployment (no Internet Explorer) - Thanks [@Sam-Martin](https://github.com/Sam-Martin) 62 | 63 | ## [2.1.6] - 2016-05-27 64 | 65 | ### Added 66 | 67 | * Added Functions for 68 | * Firewall 69 | 70 | ## [2.1.0] 71 | 72 | ### Added 73 | 74 | * Added Functions for 75 | * CheckSite 76 | * CheckAppPool 77 | * WebSite 78 | * SoftwareProduct 79 | 80 | ### Changed 81 | 82 | * Broke Down PSM1 to Many Different Functions in their own files [No change in functionality] 83 | 84 | ## [1.2.2] 85 | 86 | ### Added 87 | 88 | * Merged PR including 5 new functions 89 | * Package 90 | * LocalGroup 91 | * Interface 92 | * Folder 93 | * DnsHost 94 | 95 | ## [1.1.0] 96 | 97 | * Public release. 98 | 99 | ## [1.0] 100 | 101 | * Complete refactor to improve unit testing. 102 | * Build unit tests. 103 | 104 | ## [0.3] 105 | 106 | * Better Help 107 | * A bug fix 108 | 109 | ## [0.2] 110 | 111 | Reworked all functions. 112 | 113 | * Now using Cmdlet syntax to provider better Parameter handling. 114 | * Assertions are now defined in the test script for better flexibility. 115 | 116 | ## [0.1] 117 | 118 | * Initial 6 functions 119 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ticketmaster® & Live Nation Entertainment® 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Private/Expand-PoshspecTestExpression.ps1: -------------------------------------------------------------------------------- 1 | function Expand-PoshspecTestExpression 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [Parameter(Mandatory=$true, Position=0)] 6 | [string] 7 | $ObjectExpression, 8 | 9 | [Parameter(Mandatory=$true, Position=1)] 10 | [string] 11 | $PropertyExpression 12 | ) 13 | 14 | $cmd = [scriptblock]::Create('(' + $ObjectExpression + ')' + '.' + $PropertyExpression) 15 | Write-Output $cmd.ToString() 16 | } 17 | -------------------------------------------------------------------------------- /Private/Get-PoshspecParam.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns an object which is used with Invoke-PoshspecExpression to execute a Pester 'It' block with the generated name and test expression values. 4 | .EXAMPLE 5 | Get-PoshspecParam -TestName File -TestExpression {'C:\Temp'} -Target 'C:\Temp' -Should { Should -Exist } 6 | 7 | Name : File 'C:\Temp' Should -Exist 8 | Expression : 'C:\Temp' | Should -Exist 9 | #> 10 | function Get-PoshspecParam { 11 | [CmdletBinding(DefaultParameterSetName = "Default")] 12 | param( 13 | [Parameter(Mandatory, ParameterSetName = "Default")] 14 | [Parameter(Mandatory, ParameterSetName = "PropertyExpression")] 15 | [string] 16 | $TestName, 17 | 18 | [Parameter(Mandatory, ParameterSetName = "Default")] 19 | [Parameter(Mandatory, ParameterSetName = "PropertyExpression")] 20 | [string] 21 | $TestExpression, 22 | 23 | [Parameter(Mandatory, ParameterSetName = "Default")] 24 | [Parameter(Mandatory, ParameterSetName = "PropertyExpression")] 25 | [string] 26 | $Target, 27 | 28 | [Parameter(ParameterSetName = "Default")] 29 | [string] 30 | $FriendlyName, 31 | 32 | [Parameter(ParameterSetName = "Default")] 33 | [string] 34 | $Property, 35 | 36 | [Parameter(Mandatory, ParameterSetName = "PropertyExpression")] 37 | [string] 38 | $PropertyExpression, 39 | 40 | [Parameter(ParameterSetName = "Default")] 41 | [Parameter(ParameterSetName = "PropertyExpression")] 42 | [string] 43 | $Qualifier, 44 | 45 | [Parameter(Mandatory, ParameterSetName = "Default")] 46 | [Parameter(Mandatory, ParameterSetName = "PropertyExpression")] 47 | [scriptblock] 48 | $Should 49 | ) 50 | 51 | $assertion = $Should.ToString().Trim() 52 | $expressionString = $TestExpression.ToString().Trim() 53 | $PropertyExpression = $PropertyExpression.ToString().Trim() 54 | 55 | if ($PSBoundParameters.ContainsKey("PropertyExpression")) { 56 | $expressionString = $ExecutionContext.InvokeCommand.ExpandString($expressionString) 57 | $expressionString = Expand-PoshspecTestExpression $expressionString $PropertyExpression 58 | 59 | if ($PropertyExpression -like '*.*') { 60 | $lastIndexOfPeriod = $PropertyExpression.LastIndexOf('.') 61 | $Qualifier = $PropertyExpression.substring(0, $lastIndexOfPeriod) 62 | $NewProperty = $PropertyExpression.substring($lastIndexOfPeriod + 1) 63 | $nameString = "{0} property '{1}' for '{2}' at '{3}' {4}" -f $TestName, $NewProperty, $Target, $Qualifier, $assertion 64 | } 65 | else { 66 | $nameString = "{0} property '{1}' for '{2}' {3}" -f $TestName, $PropertyExpression, $Target, $assertion 67 | } 68 | 69 | $expressionString += " | $assertion" 70 | Write-Output -InputObject ([PSCustomObject]@{Name = $nameString; Expression = $expressionString}) 71 | } 72 | else { 73 | if (-not $PSBoundParameters.ContainsKey("FriendlyName")) { 74 | $FriendlyName = $Target 75 | } 76 | 77 | $expressionString = $TestExpression.ToString().Trim() 78 | 79 | if ($PSBoundParameters.ContainsKey("Property")) { 80 | $expressionString += " | Select-Object -ExpandProperty '$Property'" 81 | 82 | if ($PSBoundParameters.ContainsKey("Qualifier")) { 83 | $nameString = "{0} property '{1}' for '{2}' at '{3}' {4}" -f $TestName, $Property, $FriendlyName, $Qualifier, $assertion 84 | } 85 | else { 86 | $nameString = "{0} property '{1}' for '{2}' {3}" -f $TestName, $Property, $FriendlyName, $assertion 87 | } 88 | } 89 | else { 90 | $nameString = "{0} '{1}' {2}" -f $TestName, $FriendlyName, $assertion 91 | } 92 | 93 | $expressionString += " | $assertion" 94 | $expressionString = $ExecutionContext.InvokeCommand.ExpandString($expressionString) 95 | 96 | Write-Output -InputObject ([PSCustomObject]@{ 97 | Name = $nameString 98 | Expression = $expressionString 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Private/Invoke-PoshspecExpression.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Executes a Pester 'It' block using values generated by Get-PoshspecParam 4 | .EXAMPLE 5 | Invoke-PoshspecExpression -InputObject ([pscustomobject]@{Name = "File 'C:\Temp' Should -Exist"; Expression = "'C:\Temp' | Should -Exist" }) 6 | #> 7 | function Invoke-PoshspecExpression { 8 | [CmdletBinding()] 9 | param( 10 | # Poshspec Param Object 11 | [Parameter(Mandatory, Position=0)] 12 | [PSCustomObject] 13 | $InputObject 14 | ) 15 | 16 | Write-Verbose -Message "Invoking 'it' block with expression: $($InputObject.Expression)" 17 | It $InputObject.Name { 18 | Invoke-Expression $InputObject.Expression 19 | } 20 | } -------------------------------------------------------------------------------- /Private/SearchAd.ps1: -------------------------------------------------------------------------------- 1 | function SearchAd { 2 | param( 3 | [Parameter(Mandatory)] 4 | [ValidateNotNullOrEmpty()] 5 | [string]$Name, 6 | 7 | [Parameter(Mandatory)] 8 | [ValidateNotNullOrEmpty()] 9 | [ValidateSet('User','Group','OrganizationalUnit')] 10 | [string]$ObjectType 11 | ) 12 | 13 | $searchString = switch ($ObjectType) { 14 | 'Group' { 15 | "(&(objectClass=group)(objectCategory=group)(name=$Name))" 16 | } 17 | 'User' { 18 | "(&(objectClass=person)(name=$Name))" 19 | } 20 | 'OrganizationalUnit' { 21 | "(&(objectClass=organizationalUnit)(name=$Name))" 22 | } 23 | Default {} 24 | } 25 | $searcher = [adsisearcher]$searchString 26 | $searcher.FindAll() 27 | } -------------------------------------------------------------------------------- /Private/Test-RunAsAdmin.ps1: -------------------------------------------------------------------------------- 1 | Function Test-RunAsAdmin { 2 | <# 3 | .SYNOPSIS 4 | Verifies if the current process is run as admin. 5 | 6 | .DESCRIPTION 7 | This function verifies whether the current process is running with administrator rights or not. 8 | If so, it will return a value of $true; otherwise it will return a valud of $false 9 | #> 10 | ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 11 | } -------------------------------------------------------------------------------- /Private/UserRightsAssignment.ps1: -------------------------------------------------------------------------------- 1 | # The following region of code was retrieved from https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0 2 | # and was written by Tony Pombo for managing user rights assignments. I have stripped out the code for modifying user rights, leaving 3 | # only the code necessary for verifying them. 4 | Add-Type @' 5 | using System; 6 | namespace PS_LSA 7 | { 8 | using System.ComponentModel; 9 | using System.Runtime.InteropServices; 10 | using System.Security; 11 | using System.Security.Principal; 12 | using LSA_HANDLE = IntPtr; 13 | 14 | public enum Rights 15 | { 16 | SeTrustedCredManAccessPrivilege, // Access Credential Manager as a trusted caller 17 | SeNetworkLogonRight, // Access this computer from the network 18 | SeTcbPrivilege, // Act as part of the operating system 19 | SeMachineAccountPrivilege, // Add workstations to domain 20 | SeIncreaseQuotaPrivilege, // Adjust memory quotas for a process 21 | SeInteractiveLogonRight, // Allow log on locally 22 | SeRemoteInteractiveLogonRight, // Allow log on through Remote Desktop Services 23 | SeBackupPrivilege, // Back up files and directories 24 | SeChangeNotifyPrivilege, // Bypass traverse checking 25 | SeSystemtimePrivilege, // Change the system time 26 | SeTimeZonePrivilege, // Change the time zone 27 | SeCreatePagefilePrivilege, // Create a pagefile 28 | SeCreateTokenPrivilege, // Create a token object 29 | SeCreateGlobalPrivilege, // Create global objects 30 | SeCreatePermanentPrivilege, // Create permanent shared objects 31 | SeCreateSymbolicLinkPrivilege, // Create symbolic links 32 | SeDebugPrivilege, // Debug programs 33 | SeDenyNetworkLogonRight, // Deny access this computer from the network 34 | SeDenyBatchLogonRight, // Deny log on as a batch job 35 | SeDenyServiceLogonRight, // Deny log on as a service 36 | SeDenyInteractiveLogonRight, // Deny log on locally 37 | SeDenyRemoteInteractiveLogonRight, // Deny log on through Remote Desktop Services 38 | SeEnableDelegationPrivilege, // Enable computer and user accounts to be trusted for delegation 39 | SeRemoteShutdownPrivilege, // Force shutdown from a remote system 40 | SeAuditPrivilege, // Generate security audits 41 | SeImpersonatePrivilege, // Impersonate a client after authentication 42 | SeIncreaseWorkingSetPrivilege, // Increase a process working set 43 | SeIncreaseBasePriorityPrivilege, // Increase scheduling priority 44 | SeLoadDriverPrivilege, // Load and unload device drivers 45 | SeLockMemoryPrivilege, // Lock pages in memory 46 | SeBatchLogonRight, // Log on as a batch job 47 | SeServiceLogonRight, // Log on as a service 48 | SeSecurityPrivilege, // Manage auditing and security log 49 | SeRelabelPrivilege, // Modify an object label 50 | SeSystemEnvironmentPrivilege, // Modify firmware environment values 51 | SeManageVolumePrivilege, // Perform volume maintenance tasks 52 | SeProfileSingleProcessPrivilege, // Profile single process 53 | SeSystemProfilePrivilege, // Profile system performance 54 | SeUnsolicitedInputPrivilege, // "Read unsolicited input from a terminal device" 55 | SeUndockPrivilege, // Remove computer from docking station 56 | SeAssignPrimaryTokenPrivilege, // Replace a process level token 57 | SeRestorePrivilege, // Restore files and directories 58 | SeShutdownPrivilege, // Shut down the system 59 | SeSyncAgentPrivilege, // Synchronize directory service data 60 | SeTakeOwnershipPrivilege // Take ownership of files or other objects 61 | } 62 | 63 | [StructLayout(LayoutKind.Sequential)] 64 | struct LSA_OBJECT_ATTRIBUTES 65 | { 66 | internal int Length; 67 | internal IntPtr RootDirectory; 68 | internal IntPtr ObjectName; 69 | internal int Attributes; 70 | internal IntPtr SecurityDescriptor; 71 | internal IntPtr SecurityQualityOfService; 72 | } 73 | 74 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 75 | struct LSA_UNICODE_STRING 76 | { 77 | internal ushort Length; 78 | internal ushort MaximumLength; 79 | [MarshalAs(UnmanagedType.LPWStr)] 80 | internal string Buffer; 81 | } 82 | 83 | [StructLayout(LayoutKind.Sequential)] 84 | struct LSA_ENUMERATION_INFORMATION 85 | { 86 | internal IntPtr PSid; 87 | } 88 | 89 | internal sealed class Win32Sec 90 | { 91 | [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] 92 | internal static extern uint LsaOpenPolicy( 93 | LSA_UNICODE_STRING[] SystemName, 94 | ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, 95 | int AccessMask, 96 | out IntPtr PolicyHandle 97 | ); 98 | 99 | [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] 100 | internal static extern uint LsaEnumerateAccountRights( 101 | LSA_HANDLE PolicyHandle, 102 | IntPtr pSID, 103 | out IntPtr /*LSA_UNICODE_STRING[]*/ UserRights, 104 | out ulong CountOfRights 105 | ); 106 | 107 | [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] 108 | internal static extern uint LsaEnumerateAccountsWithUserRight( 109 | LSA_HANDLE PolicyHandle, 110 | LSA_UNICODE_STRING[] UserRights, 111 | out IntPtr EnumerationBuffer, 112 | out ulong CountReturned 113 | ); 114 | 115 | [DllImport("advapi32")] 116 | internal static extern int LsaNtStatusToWinError(int NTSTATUS); 117 | 118 | [DllImport("advapi32")] 119 | internal static extern int LsaClose(IntPtr PolicyHandle); 120 | 121 | [DllImport("advapi32")] 122 | internal static extern int LsaFreeMemory(IntPtr Buffer); 123 | } 124 | 125 | internal sealed class Sid : IDisposable 126 | { 127 | public IntPtr pSid = IntPtr.Zero; 128 | public SecurityIdentifier sid = null; 129 | 130 | public Sid(string account) 131 | { 132 | sid = (SecurityIdentifier)(new NTAccount(account)).Translate(typeof(SecurityIdentifier)); 133 | Byte[] buffer = new Byte[sid.BinaryLength]; 134 | sid.GetBinaryForm(buffer, 0); 135 | 136 | pSid = Marshal.AllocHGlobal(sid.BinaryLength); 137 | Marshal.Copy(buffer, 0, pSid, sid.BinaryLength); 138 | } 139 | 140 | public void Dispose() 141 | { 142 | if (pSid != IntPtr.Zero) 143 | { 144 | Marshal.FreeHGlobal(pSid); 145 | pSid = IntPtr.Zero; 146 | } 147 | GC.SuppressFinalize(this); 148 | } 149 | ~Sid() { Dispose(); } 150 | } 151 | 152 | public sealed class LsaWrapper : IDisposable 153 | { 154 | enum Access : int 155 | { 156 | POLICY_READ = 0x20006, 157 | POLICY_ALL_ACCESS = 0x00F0FFF, 158 | POLICY_EXECUTE = 0X20801, 159 | POLICY_WRITE = 0X207F8 160 | } 161 | const uint STATUS_ACCESS_DENIED = 0xc0000022; 162 | const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a; 163 | const uint STATUS_NO_MEMORY = 0xc0000017; 164 | const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034; 165 | const uint STATUS_NO_MORE_ENTRIES = 0x8000001a; 166 | 167 | IntPtr lsaHandle; 168 | 169 | public LsaWrapper() : this(null) { } // local system if systemName is null 170 | public LsaWrapper(string systemName) 171 | { 172 | LSA_OBJECT_ATTRIBUTES lsaAttr; 173 | lsaAttr.RootDirectory = IntPtr.Zero; 174 | lsaAttr.ObjectName = IntPtr.Zero; 175 | lsaAttr.Attributes = 0; 176 | lsaAttr.SecurityDescriptor = IntPtr.Zero; 177 | lsaAttr.SecurityQualityOfService = IntPtr.Zero; 178 | lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES)); 179 | lsaHandle = IntPtr.Zero; 180 | LSA_UNICODE_STRING[] system = null; 181 | if (systemName != null) 182 | { 183 | system = new LSA_UNICODE_STRING[1]; 184 | system[0] = InitLsaString(systemName); 185 | } 186 | 187 | uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr, (int)Access.POLICY_ALL_ACCESS, out lsaHandle); 188 | if (ret == 0) return; 189 | if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException(); 190 | if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException(); 191 | throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); 192 | } 193 | 194 | public Rights[] EnumerateAccountPrivileges(string account) 195 | { 196 | uint ret = 0; 197 | ulong count = 0; 198 | IntPtr privileges = IntPtr.Zero; 199 | Rights[] rights = null; 200 | 201 | using (Sid sid = new Sid(account)) 202 | { 203 | ret = Win32Sec.LsaEnumerateAccountRights(lsaHandle, sid.pSid, out privileges, out count); 204 | } 205 | if (ret == 0) 206 | { 207 | rights = new Rights[count]; 208 | for (int i = 0; i < (int)count; i++) 209 | { 210 | LSA_UNICODE_STRING str = (LSA_UNICODE_STRING)Marshal.PtrToStructure( 211 | IntPtr.Add(privileges, i * Marshal.SizeOf(typeof(LSA_UNICODE_STRING))), 212 | typeof(LSA_UNICODE_STRING)); 213 | rights[i] = (Rights)Enum.Parse(typeof(Rights), str.Buffer); 214 | } 215 | Win32Sec.LsaFreeMemory(privileges); 216 | return rights; 217 | } 218 | if (ret == STATUS_OBJECT_NAME_NOT_FOUND) return null; // No privileges assigned 219 | if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException(); 220 | if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException(); 221 | throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); 222 | } 223 | 224 | public string[] EnumerateAccountsWithUserRight(Rights privilege) 225 | { 226 | uint ret = 0; 227 | ulong count = 0; 228 | LSA_UNICODE_STRING[] rights = new LSA_UNICODE_STRING[1]; 229 | rights[0] = InitLsaString(privilege.ToString()); 230 | IntPtr buffer = IntPtr.Zero; 231 | string[] accounts = null; 232 | 233 | ret = Win32Sec.LsaEnumerateAccountsWithUserRight(lsaHandle, rights, out buffer, out count); 234 | if (ret == 0) 235 | { 236 | accounts = new string[count]; 237 | for (int i = 0; i < (int)count; i++) 238 | { 239 | LSA_ENUMERATION_INFORMATION LsaInfo = (LSA_ENUMERATION_INFORMATION)Marshal.PtrToStructure( 240 | IntPtr.Add(buffer, i * Marshal.SizeOf(typeof(LSA_ENUMERATION_INFORMATION))), 241 | typeof(LSA_ENUMERATION_INFORMATION)); 242 | 243 | try { 244 | accounts[i] = (new SecurityIdentifier(LsaInfo.PSid)).Translate(typeof(NTAccount)).ToString(); 245 | } catch (System.Security.Principal.IdentityNotMappedException) { 246 | accounts[i] = (new SecurityIdentifier(LsaInfo.PSid)).ToString(); 247 | } 248 | } 249 | Win32Sec.LsaFreeMemory(buffer); 250 | return accounts; 251 | } 252 | if (ret == STATUS_NO_MORE_ENTRIES) return null; // No accounts assigned 253 | if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException(); 254 | if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException(); 255 | throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); 256 | } 257 | 258 | public void Dispose() 259 | { 260 | if (lsaHandle != IntPtr.Zero) 261 | { 262 | Win32Sec.LsaClose(lsaHandle); 263 | lsaHandle = IntPtr.Zero; 264 | } 265 | GC.SuppressFinalize(this); 266 | } 267 | ~LsaWrapper() { Dispose(); } 268 | 269 | // helper functions: 270 | static LSA_UNICODE_STRING InitLsaString(string s) 271 | { 272 | // Unicode strings max. 32KB 273 | if (s.Length > 0x7ffe) throw new ArgumentException("String too long"); 274 | LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING(); 275 | lus.Buffer = s; 276 | lus.Length = (ushort)(s.Length * sizeof(char)); 277 | lus.MaximumLength = (ushort)(lus.Length + sizeof(char)); 278 | return lus; 279 | } 280 | } 281 | 282 | public sealed class TokenManipulator 283 | { 284 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 285 | internal struct TokPriv1Luid 286 | { 287 | public int Count; 288 | public long Luid; 289 | public int Attr; 290 | } 291 | 292 | internal const int SE_PRIVILEGE_DISABLED = 0x00000000; 293 | internal const int SE_PRIVILEGE_ENABLED = 0x00000002; 294 | internal const int TOKEN_QUERY = 0x00000008; 295 | internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; 296 | 297 | internal sealed class Win32Token 298 | { 299 | [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 300 | internal static extern bool AdjustTokenPrivileges( 301 | IntPtr htok, 302 | bool disall, 303 | ref TokPriv1Luid newst, 304 | int len, 305 | IntPtr prev, 306 | IntPtr relen 307 | ); 308 | 309 | [DllImport("kernel32.dll", ExactSpelling = true)] 310 | internal static extern IntPtr GetCurrentProcess(); 311 | 312 | [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 313 | internal static extern bool OpenProcessToken( 314 | IntPtr h, 315 | int acc, 316 | ref IntPtr phtok 317 | ); 318 | 319 | [DllImport("advapi32.dll", SetLastError = true)] 320 | internal static extern bool LookupPrivilegeValue( 321 | string host, 322 | string name, 323 | ref long pluid 324 | ); 325 | 326 | [DllImport("kernel32.dll", ExactSpelling = true)] 327 | internal static extern bool CloseHandle( 328 | IntPtr phtok 329 | ); 330 | } 331 | } 332 | } 333 | '@ # This type (PS_LSA) is used by Get-UserRightsGrantedToAccount and Get-AccountsWithUserRight 334 | 335 | function Get-UserRightsGrantedToAccount { 336 | <# 337 | .SYNOPSIS 338 | Gets all user rights granted to an account 339 | .DESCRIPTION 340 | Retrieves a list of all the user rights (privileges) granted to one or more accounts. The rights retrieved are those granted directly to the user account, and does not include those rights obtained as part of membership to a group. 341 | .EXAMPLE 342 | Get-UserRightsGrantedToAccount "bilbo.baggins" 343 | 344 | Returns a list of all user rights granted to bilbo.baggins on the local computer. 345 | .EXAMPLE 346 | Get-UserRightsGrantedToAccount -Account "Edward","Karen" -Computer TESTPC 347 | 348 | Returns a list of user rights granted to Edward, and a list of user rights granted to Karen, on the TESTPC system. 349 | .PARAMETER Account 350 | Logon name of the account. More than one account can be listed. If the account is not found on the computer, the default domain is searched. To specify a domain, you may use either "DOMAIN\username" or "username@domain.dns" formats. 351 | .PARAMETER Computer 352 | Specifies the name of the computer on which to run this cmdlet. If the input for this parameter is omitted, then the cmdlet runs on the local computer. 353 | .INPUTS 354 | String Account 355 | String Computer 356 | .OUTPUTS 357 | String Account 358 | PS_LSA.Rights Right 359 | .LINK 360 | http://msdn.microsoft.com/en-us/library/ms721790.aspx 361 | http://msdn.microsoft.com/en-us/library/bb530716.aspx 362 | #> 363 | [CmdletBinding()] 364 | param ( 365 | [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true)] 366 | [Alias('User','Username')][String[]] $Account, 367 | [Parameter(ValueFromPipelineByPropertyName=$true, HelpMessage="Computer name")] 368 | [Alias('System','ComputerName','Host')][String] $Computer 369 | ) 370 | process { 371 | $lsa = New-Object PS_LSA.LsaWrapper($Computer) 372 | foreach ($Acct in $Account) { 373 | $output = @{'Account'=$Acct; 'Right'=$lsa.EnumerateAccountPrivileges($Acct); } 374 | Write-Output (New-Object -Typename PSObject -Prop $output) 375 | } 376 | } 377 | } # Gets all user rights granted to an account 378 | 379 | function Get-AccountsWithUserRight { 380 | <# 381 | .SYNOPSIS 382 | Gets all accounts that are assigned a specified privilege 383 | .DESCRIPTION 384 | Retrieves a list of all accounts that hold a specified right (privilege). The accounts returned are those that hold the specified privilege directly through the user account, not as part of membership to a group. 385 | .EXAMPLE 386 | Get-AccountsWithUserRight SeServiceLogonRight 387 | 388 | Returns a list of all accounts that hold the "Log on as a service" right. 389 | .EXAMPLE 390 | Get-AccountsWithUserRight -Right SeServiceLogonRight,SeDebugPrivilege -Computer TESTPC 391 | 392 | Returns a list of accounts that hold the "Log on as a service" right, and a list of accounts that hold the "Debug programs" right, on the TESTPC system. 393 | .PARAMETER Right 394 | Name of the right to query. More than one right may be listed. 395 | 396 | Possible values: 397 | SeTrustedCredManAccessPrivilege Access Credential Manager as a trusted caller 398 | SeNetworkLogonRight Access this computer from the network 399 | SeTcbPrivilege Act as part of the operating system 400 | SeMachineAccountPrivilege Add workstations to domain 401 | SeIncreaseQuotaPrivilege Adjust memory quotas for a process 402 | SeInteractiveLogonRight Allow log on locally 403 | SeRemoteInteractiveLogonRight Allow log on through Remote Desktop Services 404 | SeBackupPrivilege Back up files and directories 405 | SeChangeNotifyPrivilege Bypass traverse checking 406 | SeSystemtimePrivilege Change the system time 407 | SeTimeZonePrivilege Change the time zone 408 | SeCreatePagefilePrivilege Create a pagefile 409 | SeCreateTokenPrivilege Create a token object 410 | SeCreateGlobalPrivilege Create global objects 411 | SeCreatePermanentPrivilege Create permanent shared objects 412 | SeCreateSymbolicLinkPrivilege Create symbolic links 413 | SeDebugPrivilege Debug programs 414 | SeDenyNetworkLogonRight Deny access this computer from the network 415 | SeDenyBatchLogonRight Deny log on as a batch job 416 | SeDenyServiceLogonRight Deny log on as a service 417 | SeDenyInteractiveLogonRight Deny log on locally 418 | SeDenyRemoteInteractiveLogonRight Deny log on through Remote Desktop Services 419 | SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation 420 | SeRemoteShutdownPrivilege Force shutdown from a remote system 421 | SeAuditPrivilege Generate security audits 422 | SeImpersonatePrivilege Impersonate a client after authentication 423 | SeIncreaseWorkingSetPrivilege Increase a process working set 424 | SeIncreaseBasePriorityPrivilege Increase scheduling priority 425 | SeLoadDriverPrivilege Load and unload device drivers 426 | SeLockMemoryPrivilege Lock pages in memory 427 | SeBatchLogonRight Log on as a batch job 428 | SeServiceLogonRight Log on as a service 429 | SeSecurityPrivilege Manage auditing and security log 430 | SeRelabelPrivilege Modify an object label 431 | SeSystemEnvironmentPrivilege Modify firmware environment values 432 | SeManageVolumePrivilege Perform volume maintenance tasks 433 | SeProfileSingleProcessPrivilege Profile single process 434 | SeSystemProfilePrivilege Profile system performance 435 | SeUnsolicitedInputPrivilege "Read unsolicited input from a terminal device" 436 | SeUndockPrivilege Remove computer from docking station 437 | SeAssignPrimaryTokenPrivilege Replace a process level token 438 | SeRestorePrivilege Restore files and directories 439 | SeShutdownPrivilege Shut down the system 440 | SeSyncAgentPrivilege Synchronize directory service data 441 | SeTakeOwnershipPrivilege Take ownership of files or other objects 442 | .PARAMETER Computer 443 | Specifies the name of the computer on which to run this cmdlet. If the input for this parameter is omitted, then the cmdlet runs on the local computer. 444 | .INPUTS 445 | PS_LSA.Rights Right 446 | String Computer 447 | .OUTPUTS 448 | String Account 449 | String Right 450 | .LINK 451 | http://msdn.microsoft.com/en-us/library/ms721792.aspx 452 | http://msdn.microsoft.com/en-us/library/bb530716.aspx 453 | #> 454 | [CmdletBinding()] 455 | param ( 456 | [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true)] 457 | [Alias('Privilege')] [PS_LSA.Rights[]] $Right, 458 | [Parameter(ValueFromPipelineByPropertyName=$true, HelpMessage="Computer name")] 459 | [Alias('System','ComputerName','Host')][String] $Computer 460 | ) 461 | process { 462 | $lsa = New-Object PS_LSA.LsaWrapper($Computer) 463 | foreach ($Priv in $Right) { 464 | $output = @{'Account'=$lsa.EnumerateAccountsWithUserRight($Priv); 'Right'=$Priv; } 465 | Write-Output (New-Object -Typename PSObject -Prop $output) 466 | } 467 | } 468 | } # Gets all accounts that are assigned a specified privilege -------------------------------------------------------------------------------- /Public/AppPool.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test an Application Pool 4 | .DESCRIPTION 5 | Used To Determine if Application Pool is Running and Validate Various Properties 6 | .PARAMETER Target 7 | The name of the App Pool to be Tested 8 | .PARAMETER Property 9 | The Property to be expanded. If Ommitted, Property Will Default to Status. Can handle nested objects within properties 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | AppPool TestSite { Should be Started } 14 | .EXAMPLE 15 | AppPool TestSite ManagedPipelineMode { Should be 'Integrated' } 16 | .EXAMPLE 17 | AppPool TestSite ProcessModel.IdentityType { Should be 'ApplicationPoolIdentity'} 18 | .NOTES 19 | Assertions: be 20 | #> 21 | function AppPool { 22 | [CmdletBinding(DefaultParameterSetName="Default")] 23 | param( 24 | [Parameter(Mandatory, Position=1, ParameterSetName="Default")] 25 | [Parameter(Mandatory, Position=1, ParameterSetName="Property")] 26 | [Alias("Path")] 27 | [string]$Target, 28 | 29 | [Parameter(Position=2, ParameterSetName="Property")] 30 | [string]$Property, 31 | 32 | [Parameter(Mandatory, Position=2, ParameterSetName="Default")] 33 | [Parameter(Mandatory, Position=3, ParameterSetName="Property")] 34 | [scriptblock]$Should 35 | ) 36 | 37 | $IISAdmin = Get-Module -Name 'IISAdministration' 38 | if ($IISAdmin) { 39 | Import-Module IISAdministration 40 | } 41 | else { 42 | . $GetIISAppPool 43 | } 44 | 45 | $expression = $null 46 | $params = $null 47 | 48 | if (-not $PSBoundParameters.ContainsKey('Property')) { 49 | $Property = 'State' 50 | $PSBoundParameters.add('Property', $Property) 51 | $expression = { Get-IISAppPool -Name '$Target' -ErrorAction SilentlyContinue } 52 | $params = Get-PoshspecParam -TestName AppPool -TestExpression $expression @PSBoundParameters 53 | } 54 | 55 | if ($Property -like '*.*' -or $Property -like '*(*' -or $Property -like '*)*') { 56 | $expression = { Get-IISAppPool -Name '$Target' -ErrorAction SilentlyContinue } 57 | $params = Get-PoshspecParam -TestName AppPool -TestExpression $expression -Target $Target -Should $Should -PropertyExpression $Property 58 | } 59 | 60 | else { 61 | $expression = { Get-IISAppPool -Name '$Target' -ErrorAction SilentlyContinue } 62 | $params = Get-PoshspecParam -TestName AppPool -TestExpression $expression @PSBoundParameters 63 | } 64 | 65 | Invoke-PoshspecExpression @params 66 | } 67 | 68 | $GetIISAppPool = { 69 | function Get-IisAppPool 70 | { 71 | [CmdletBinding()] 72 | Param 73 | ( 74 | [Parameter(Mandatory=$true, 75 | Position=1)] 76 | [string]$Name 77 | ) 78 | 79 | Begin 80 | { 81 | [System.Reflection.Assembly]::LoadFrom("$($Env:windir)\system32\inetsrv\Microsoft.Web.Administration.dll") | Out-Null 82 | $ServerManager = [Microsoft.Web.Administration.ServerManager]::OpenRemote("localhost") 83 | } 84 | 85 | Process 86 | { 87 | try 88 | { 89 | Write-Verbose "Getting application pool $Name" 90 | Write-Output $ServerManager.ApplicationPools[$Name] 91 | } 92 | 93 | catch 94 | { 95 | Write-Warning $Error[0] 96 | } 97 | } 98 | 99 | End 100 | { 101 | $ServerManager.Dispose() 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Public/AuditPolicy.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test an Audit Policy. 4 | .DESCRIPTION 5 | Test the setting of a particular audit policy . 6 | .PARAMETER Target 7 | Specifies the category of the Audit Policy. 8 | .PARAMETER Qualifier 9 | Specifies the subcategory of the Audit policy. 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | AuditPolicy System "Security System Extension" { Should Be Success } 14 | .EXAMPLE 15 | AuditPolicy "Logon/Logoff" Logon { Should Be "Success and Failure" } 16 | .EXAMPLE 17 | AuditPolicy "Account Management" "User Account Management" { Should Not Be "No Auditing" } 18 | .NOTES 19 | Assertions: Be, BeExactly, Match, MatchExactly 20 | #> 21 | 22 | function AuditPolicy { 23 | [CmdletBinding(DefaultParameterSetName="Default")] 24 | param( 25 | [Parameter(Mandatory, Position=1)] 26 | [Alias("Category")] 27 | [ValidateSet( 28 | "System", 29 | "Logon/Logoff", 30 | "Object Access", 31 | "Privilege Use", 32 | "Detailed Tracking", 33 | "Policy Change", 34 | "Account Management", 35 | "DS Access", 36 | "Account Logon" 37 | )] 38 | $Qualifier, 39 | [Parameter(Mandatory, Position=2)] 40 | [Alias("Subcategory")] 41 | [ValidateSet( 42 | "Security System Extension", 43 | "System Integrity", 44 | "IPsec Driver", 45 | "Other System Events", 46 | "Security State Change", 47 | "Logon", 48 | "Logoff", 49 | "Account Lockout", 50 | "IPsec Main Mode", 51 | "IPsec Quick Mode", 52 | "IPsec Extended Mode", 53 | "Special Logon", 54 | "Other Logon/Logoff Events", 55 | "Network Policy Server", 56 | "User / Device Claims", 57 | "Group Membership", 58 | "File System", 59 | "Registry", 60 | "Kernel Object", 61 | "SAM", 62 | "Certification Services", 63 | "Application Generated", 64 | "Handle Manipulation", 65 | "File Share", 66 | "Filtering Platform Packet Drop", 67 | "Filtering Platform Connection", 68 | "Other Object Access Events", 69 | "Detailed File Share", 70 | "Removable Storage", 71 | "Central Policy Staging", 72 | "Sensitive Privilege Use", 73 | "Non Sensitive Privilege Use", 74 | "Other Privilege Use Events", 75 | "Process Termination", 76 | "DPAPI Activity", 77 | "RPC Events", 78 | "Plug and Play Events", 79 | "Token Right Adjusted Events", 80 | "Process Creation", 81 | "Audit Policy Change", 82 | "Authentication Policy Change", 83 | "Authorization Policy Change", 84 | "MPSSVC Rule-Level Policy Change", 85 | "Filtering Platform Policy Change", 86 | "Other Policy Change Events", 87 | "User Account Management", 88 | "Computer Account Management", 89 | "Security Group Management", 90 | "Distribution Group Management", 91 | "Application Group Management", 92 | "Other Account Management Events", 93 | "Directory Service Changes", 94 | "Directory Service Replication", 95 | "Detailed Directory Service Replication", 96 | "Directory Service Access", 97 | "Kerberos Service Ticket Operations", 98 | "Other Account Logon Events", 99 | "Kerberos Authentication Service", 100 | "Credential Validation" 101 | )] 102 | [string]$Target, 103 | 104 | [Parameter(Mandatory, Position=3)] 105 | [scriptblock]$Should 106 | ) 107 | Function GetAuditPolicy([string]$Category,[string]$Subcategory) { 108 | If (Test-RunAsAdmin){ 109 | auditpol /get /category:$Category | 110 | Where-Object -FilterScript {$_ -match "^\s+$Subcategory"} | 111 | ForEach-Object -Process {($_.trim() -split "\s{2,}")[1]} 112 | } Else { 113 | Throw "You must run as Administrator to test AuditPolicy" 114 | } 115 | } 116 | $expression = {GetAuditPolicy -Category '$Qualifier' -Subcategory '$Target'} 117 | 118 | $params = Get-PoshspecParam -TestName AuditPolicy -TestExpression $expression @PSBoundParameters 119 | 120 | Invoke-PoshspecExpression @params 121 | } -------------------------------------------------------------------------------- /Public/CimObject.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test the value of a CimObject Property. 4 | .DESCRIPTION 5 | Test the value of a CimObject Property. The Class can be provided with the Namespace. See Example. 6 | .PARAMETER Target 7 | Specifies the name of the CIM class for which to retrieve the CIM instances. Can be just the ClassName 8 | in the default namespace or in the form of namespace/className to access other namespaces. 9 | .PARAMETER Property 10 | Specifies an instance property to retrieve. 11 | .PARAMETER Should 12 | A Script Block defining a Pester Assertion. 13 | .EXAMPLE 14 | CimObject Win32_OperatingSystem SystemDirectory { Should Be C:\WINDOWS\system32 } 15 | .EXAMPLE 16 | CimObject root/StandardCimv2/MSFT_NetOffloadGlobalSetting ReceiveSideScaling { Should Be Enabled } 17 | .NOTES 18 | Assertions: Be, BeExactly, Match, MatchExactly 19 | #> 20 | function CimObject { 21 | [CmdletBinding()] 22 | param( 23 | [Parameter(Mandatory, Position=1)] 24 | [Alias("ClassName")] 25 | [string]$Target, 26 | 27 | [Parameter(Mandatory, Position=2)] 28 | [string]$Property, 29 | 30 | [Parameter(Mandatory, Position=3)] 31 | [scriptblock]$Should 32 | ) 33 | 34 | 35 | $expression = $null 36 | $class = $null 37 | $namespace = $null 38 | if ($Target -match '/') 39 | { 40 | $lastIndexOfSlash = $Target.LastIndexOf('/') 41 | 42 | $class = $Target.Substring($lastIndexOfSlash + 1) 43 | $namespace = $Target.Substring(0,$lastIndexOfSlash) 44 | 45 | $PSBoundParameters["Target"] = $class 46 | $PSBoundParameters.Add("Qualifier", $namespace) 47 | 48 | $expression = {Get-CimInstance -ClassName $Target -Namespace $Qualifier} 49 | } 50 | else 51 | { 52 | $expression = {Get-CimInstance -ClassName $Target} 53 | } 54 | 55 | if ($Property -like '*.*' -or $Property -like '*(*' -or $Property -like '*)*') { 56 | $PSBoundParameters.Remove("Property") 57 | $PSBoundParameters.Add("PropertyExpression", $Property) 58 | $params = Get-PoshspecParam -TestName CimObject -TestExpression $expression @PSBoundParameters 59 | } 60 | 61 | else 62 | { 63 | $params = Get-PoshspecParam -TestName CimObject -TestExpression $expression @PSBoundParameters 64 | } 65 | 66 | 67 | Invoke-PoshspecExpression @params 68 | } 69 | -------------------------------------------------------------------------------- /Public/DnsHost.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test DNS resolution to a host. 4 | .DESCRIPTION 5 | Test DNS resolution to a host. 6 | .PARAMETER Target 7 | The hostname to resolve in DNS. 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | dnshost nonexistenthost.mymadeupdomain.tld { should be $null } 12 | .EXAMPLE 13 | dnshost www.google.com { should not be $null } 14 | .NOTES 15 | Assertions: be 16 | #> 17 | function DnsHost { 18 | [CmdletBinding()] 19 | param( 20 | [Parameter(Mandatory, Position=1)] 21 | [Alias('Name')] 22 | [string]$Target, 23 | 24 | [Parameter(Mandatory, Position=2)] 25 | [scriptblock]$Should 26 | ) 27 | 28 | $expression = {Resolve-DnsName -Name $Target -DnsOnly -NoHostsFile -ErrorAction SilentlyContinue} 29 | 30 | $params = Get-PoshspecParam -TestName DnsHost -TestExpression $expression @PSBoundParameters 31 | 32 | Invoke-PoshspecExpression @params 33 | } -------------------------------------------------------------------------------- /Public/File.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test a File. 4 | .DESCRIPTION 5 | Test the Existance or Contents of a File.. 6 | .PARAMETER Target 7 | Specifies the path to an item. 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | File C:\inetpub\wwwroot\iisstart.htm { Should Exist } 12 | .EXAMPLE 13 | File C:\inetpub\wwwroot\iisstart.htm { Should Contain 'text-align:center' } 14 | .NOTES 15 | Assertions: Exist and Contain 16 | #> 17 | function File { 18 | [CmdletBinding()] 19 | param( 20 | [Parameter(Mandatory, Position=1)] 21 | [Alias("Path")] 22 | [string]$Target, 23 | 24 | [Parameter(Mandatory, Position=2)] 25 | [scriptblock]$Should 26 | ) 27 | 28 | $name = Split-Path -Path $Target -Leaf 29 | $params = Get-PoshspecParam -TestName File -TestExpression {'$Target'} -FriendlyName $name @PSBoundParameters 30 | 31 | Invoke-PoshspecExpression @params 32 | } 33 | -------------------------------------------------------------------------------- /Public/Firewall.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Firewall Settings 4 | .DESCRIPTION 5 | Used To Determine if Firewall is Running Desired Settings 6 | .PARAMETER Target 7 | The name of the Firewall DisplayName to be Tested 8 | .PARAMETER Property 9 | The name of the Property of the Firewall Object to be Tested 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | Firewall putty.exe Enabled { Should be "$True" } 14 | .EXAMPLE 15 | Firewall putty.exe Action { Should be 'Allow' } 16 | .EXAMPLE 17 | Firewall putty.exe Private { Should be 'Public' } 18 | .NOTES 19 | Assertions: Be 20 | #> 21 | function Firewall{ 22 | [CmdletBinding()] 23 | param( 24 | [Parameter(Mandatory, Position=1)] 25 | [Alias('Name')] 26 | [string]$Target, 27 | 28 | [Parameter(Position=2)] 29 | [ValidateSet("Name","DisplayName","Description","DisplayGroup","Group","Enabled","Profile","Direction","Action","EdgeTraversalPolicy","LooseSourceMapping","LocalOnlyMapping","PrimaryStatus","Status","EnforcementStatus","PolicyStoreSource","PolicyStoreSourceType")] 30 | [string]$Property, 31 | 32 | [Parameter(Mandatory, Position=3)] 33 | [scriptblock]$Should 34 | ) 35 | 36 | $expression = {Get-NetFirewallRule -DisplayName '$Target' -ErrorAction SilentlyContinue } 37 | 38 | $params = Get-PoshspecParam -TestName Firewall -TestExpression $expression @PSBoundParameters 39 | 40 | Invoke-PoshspecExpression @params 41 | } -------------------------------------------------------------------------------- /Public/Folder.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test if a folder exists. 4 | .DESCRIPTION 5 | Test if a folder exists. 6 | .PARAMETER Target 7 | The path of the folder to search for. 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | folder $env:ProgramData { should exist } 12 | .EXAMPLE 13 | folder C:\badfolder { should not exist } 14 | .NOTES 15 | Assertions: exist 16 | #> 17 | function Folder { 18 | [CmdletBinding()] 19 | param( 20 | [Parameter(Mandatory, Position=1)] 21 | [Alias('Path')] 22 | [string]$Target, 23 | 24 | [Parameter(Mandatory, Position=2)] 25 | [scriptblock]$Should 26 | ) 27 | 28 | 29 | $params = Get-PoshspecParam -TestName Folder -TestExpression {'$Target'} @PSBoundParameters 30 | 31 | Invoke-PoshspecExpression @params 32 | } 33 | -------------------------------------------------------------------------------- /Public/Hotfix.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test if a Hotfix is installed. 4 | .DESCRIPTION 5 | Test if a Hotfix is installed. 6 | .PARAMETER Target 7 | The Hotfix ID. Eg KB1112233 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | Hotfix KB3116900 { Should Not BeNullOrEmpty} 12 | .EXAMPLE 13 | Hotfix KB1112233 { Should BeNullOrEmpty} 14 | .NOTES 15 | Assertions: BeNullOrEmpty 16 | #> 17 | function Hotfix { 18 | [CmdletBinding()] 19 | param( 20 | 21 | [Parameter(Mandatory,Position=1)] 22 | [Alias("Id")] 23 | [string]$Target, 24 | 25 | [Parameter(Mandatory, Position=2)] 26 | [scriptblock]$Should 27 | ) 28 | 29 | $params = Get-PoshspecParam -TestName Hotfix -TestExpression {Get-HotFix -Id $Target -ErrorAction SilentlyContinue} @PSBoundParameters 30 | 31 | Invoke-PoshspecExpression @params 32 | } 33 | -------------------------------------------------------------------------------- /Public/Http.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test a Web Service. 4 | .DESCRIPTION 5 | Test that a Web Service is reachable and optionally returns specific content. 6 | .PARAMETER Target 7 | Specifies the Uniform Resource Identifier (URI) of the Internet resource to which the web request is sent. 8 | .PARAMETER Property 9 | Specifies a property of the WebResponseObject object to test. 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | Http http://localhost StatusCode { Should Be 200 } 14 | .EXAMPLE 15 | Http http://localhost RawContent { Should Match 'X-Powered-By: ASP.NET' } 16 | .EXAMPLE 17 | Http http://localhost RawContent { Should Not Match 'X-Powered-By: Cobal' } 18 | .NOTES 19 | Assertions: Be, BeExactly, Match, MatchExactly 20 | #> 21 | 22 | function Http { 23 | [CmdletBinding()] 24 | param( 25 | [Parameter(Mandatory, Position=1)] 26 | [Alias("Uri")] 27 | [string]$Target, 28 | 29 | [Parameter(Mandatory, Position=2)] 30 | [ValidateSet("BaseResponse", "Content", "Headers", "RawContent", "RawContentLength", "RawContentStream", "StatusCode", "StatusDescription")] 31 | [string]$Property, 32 | 33 | [Parameter(Mandatory, Position=3)] 34 | [scriptblock]$Should 35 | ) 36 | 37 | $params = Get-PoshspecParam -TestName Http -TestExpression {Invoke-WebRequest -Uri '$Target' -UseBasicParsing -ErrorAction SilentlyContinue} @PSBoundParameters 38 | 39 | Invoke-PoshspecExpression @params 40 | } 41 | -------------------------------------------------------------------------------- /Public/Interface.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test a local network interface. 4 | .DESCRIPTION 5 | Test a local network interface and optionally and specific property. 6 | .PARAMETER Target 7 | Specifies the name of the network adapter to search for. 8 | .PARAMETER Property 9 | Specifies an optional property to test for on the adapter. 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | interface ethernet0 { should not BeNullOrEmpty } 14 | .EXAMPLE 15 | interface ethernet0 status { should be 'up' } 16 | .EXAMPLE 17 | Interface Ethernet0 linkspeed { should be '1 gbps' } 18 | .EXAMPLE 19 | Interface Ethernet0 macaddress { should be '00-0C-29-F2-69-DD' } 20 | .NOTES 21 | Assertions: Be, BeNullOrEmpty 22 | #> 23 | function Interface { 24 | [CmdletBinding(DefaultParameterSetName="Default")] 25 | param( 26 | [Parameter(Mandatory, Position=1,ParameterSetName="Default")] 27 | [Parameter(Mandatory, Position=1,ParameterSetName="Property")] 28 | [Alias('Name')] 29 | [string]$Target, 30 | 31 | [Parameter(Position=2,ParameterSetName="Property")] 32 | [string]$Property, 33 | 34 | [Parameter(Mandatory, Position=2,ParameterSetName="Default")] 35 | [Parameter(Mandatory, Position=3,ParameterSetName="Property")] 36 | [scriptblock]$Should 37 | ) 38 | 39 | $expression = {Get-NetAdapter -Name '$Target' -ErrorAction SilentlyContinue} 40 | 41 | $params = Get-PoshspecParam -TestName Interface -TestExpression $expression @PSBoundParameters 42 | 43 | Invoke-PoshspecExpression @params 44 | } 45 | -------------------------------------------------------------------------------- /Public/LocalGroup.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test if a local group exists. 4 | .DESCRIPTION 5 | Test if a local group exists. 6 | .PARAMETER Target 7 | The local group name to test for. Eg 'Administrators' 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | LocalGroup 'Administrators' { should not BeNullOrEmpty } 12 | .EXAMPLE 13 | LocalGroup 'BadGroup' { should BeNullOrEmpty } 14 | .NOTES 15 | Assertions: BeNullOrEmpty 16 | #> 17 | 18 | function LocalGroup { 19 | [CmdletBinding()] 20 | param( 21 | [Parameter(Mandatory, Position=1)] 22 | [Alias('Name')] 23 | [string]$Target, 24 | 25 | [Parameter(Mandatory, Position=2)] 26 | [scriptblock]$Should 27 | ) 28 | 29 | $expression = {Get-CimInstance -ClassName Win32_Group -Filter "Name = '$Target'"} 30 | 31 | $params = Get-PoshspecParam -TestName LocalGroup -TestExpression $expression @PSBoundParameters 32 | 33 | Invoke-PoshspecExpression @params 34 | } -------------------------------------------------------------------------------- /Public/LocalUser.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test if a local user exists and is enabled. 4 | .DESCRIPTION 5 | Test if a local user exists and is enabled. 6 | .PARAMETER Target 7 | The local user name to test for. Eg 'Guest' 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | LocalUser 'Guest' { should not BeNullOrEmpty } 12 | .EXAMPLE 13 | LocalUser 'Guest' Disabled { should Be $true } 14 | .NOTES 15 | Assertions: Be, BeExactly, BeNullOrEmpty, Match, MatchExactly 16 | #> 17 | 18 | function LocalUser { 19 | [CmdletBinding(DefaultParameterSetName="Default")] 20 | param( 21 | [Parameter(Mandatory, Position=1,ParameterSetName="Default")] 22 | [Parameter(Mandatory, Position=1,ParameterSetName="Property")] 23 | [Alias('Name')] 24 | [string]$Target, 25 | 26 | [Parameter(Position=2,ParameterSetName="Property")] 27 | [string]$Property, 28 | 29 | [Parameter(Mandatory, Position=2,ParameterSetName="Default")] 30 | [Parameter(Mandatory, Position=3,ParameterSetName="Property")] 31 | [scriptblock]$Should 32 | ) 33 | 34 | $expression = {Get-CimInstance -ClassName Win32_UserAccount -filter "LocalAccount=True AND` Name='$Target'"} 35 | 36 | $params = Get-PoshspecParam -TestName LocalUser -TestExpression $expression @PSBoundParameters 37 | 38 | Invoke-PoshspecExpression @params 39 | } 40 | -------------------------------------------------------------------------------- /Public/Package.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test for installed package. 4 | .DESCRIPTION 5 | Test that a specified package is installed. 6 | .PARAMETER Target 7 | Specifies the Display Name of the package to search for. 8 | .PARAMETER Property 9 | Specifies an optional property to test for on the package. 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | package 'Microsoft Visual Studio Code' { should not BeNullOrEmpty } 14 | .EXAMPLE 15 | package 'Microsoft Visual Studio Code' version { should be '1.1.0' } 16 | .EXAMPLE 17 | package 'NonExistentPackage' { should BeNullOrEmpty } 18 | .NOTES 19 | Assertions: Be, BeNullOrEmpty 20 | #> 21 | 22 | function Package { 23 | [CmdletBinding(DefaultParameterSetName="Default")] 24 | param( 25 | [Parameter(Mandatory, Position=1,ParameterSetName="Default")] 26 | [Parameter(Mandatory, Position=1,ParameterSetName="Property")] 27 | [Alias('Name')] 28 | [string]$Target, 29 | 30 | [Parameter(Position=2,ParameterSetName="Property")] 31 | [string]$Property, 32 | 33 | [Parameter(Mandatory, Position=2,ParameterSetName="Default")] 34 | [Parameter(Mandatory, Position=3,ParameterSetName="Property")] 35 | [scriptblock]$Should 36 | ) 37 | 38 | $expression = {Get-Package -Name "$Target" -ErrorAction SilentlyContinue | Select-Object -First 1} 39 | 40 | $params = Get-PoshspecParam -TestName Package -TestExpression $expression @PSBoundParameters 41 | 42 | Invoke-PoshspecExpression @params 43 | } 44 | -------------------------------------------------------------------------------- /Public/Registry.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test a Registry Key. 4 | .DESCRIPTION 5 | Test the Existance of a Key or the Value of a given Property. 6 | .PARAMETER Target 7 | Specifies the path to an item. 8 | .PARAMETER Property 9 | Specifies a property at the specified Path. 10 | .PARAMETER Should 11 | A Script Block defining a Pester Assertion. 12 | .EXAMPLE 13 | Registry HKLM:\SOFTWARE\Microsoft\Rpc\ClientProtocols { Should Exist } 14 | .EXAMPLE 15 | Registry HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\ "NV Domain" { Should Be mybiz.local } 16 | .EXAMPLE 17 | Registry 'HKLM:\SOFTWARE\Callahan Auto\' { Should Not Exist } 18 | .NOTES 19 | Assertions: Be, BeExactly, Exist, Match, MatchExactly 20 | #> 21 | 22 | function Registry { 23 | [CmdletBinding(DefaultParameterSetName="Default")] 24 | param( 25 | [Parameter(Mandatory, Position=1, ParameterSetName="Default")] 26 | [Parameter(Mandatory, Position=1, ParameterSetName="Property")] 27 | [Alias("Path")] 28 | [string]$Target, 29 | 30 | [Parameter(Position=2, ParameterSetName="Property")] 31 | [string]$Property, 32 | 33 | [Parameter(Mandatory, Position=2, ParameterSetName="Default")] 34 | [Parameter(Mandatory, Position=3, ParameterSetName="Property")] 35 | [scriptblock]$Should 36 | ) 37 | 38 | $name = Split-Path -Path $Target -Leaf 39 | 40 | if ($PSBoundParameters.ContainsKey("Property")) 41 | { 42 | $expression = {Get-ItemProperty -Path '$Target'} 43 | } 44 | else 45 | { 46 | $expression = {'$Target'} 47 | } 48 | 49 | $params = Get-PoshspecParam -TestName Registry -TestExpression $expression -FriendlyName $name @PSBoundParameters 50 | 51 | Invoke-PoshspecExpression @params 52 | } 53 | -------------------------------------------------------------------------------- /Public/SecurityOption.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test a Security Option. 4 | .DESCRIPTION 5 | Test the setting of a particular security option. 6 | .PARAMETER Target 7 | Specifies the category of the security option. 8 | .PARAMETER Should 9 | A Script Block defining a Pester Assertion. 10 | .EXAMPLE 11 | SecurityOption 'Accounts: Administrator account status' { Should -Be Disabled } 12 | .EXAMPLE 13 | SecurityOption 'Domain member: Maximum machine account password age' { Should -Be 30 } 14 | .EXAMPLE 15 | SecurityOption 'Accounts: Block Microsoft accounts' { Should -Be $null } 16 | .NOTES 17 | Assertions: Be, BeExactly, Match, MatchExactly 18 | #> 19 | 20 | function SecurityOption { 21 | [CmdletBinding(DefaultParameterSetName = "Default")] 22 | param( 23 | [Parameter(Mandatory, Position = 1)] 24 | [Alias("Category")] 25 | [ValidateSet( 26 | "Accounts: Administrator account status", 27 | "Accounts: Block Microsoft accounts", 28 | "Accounts: Guest account status", 29 | "Accounts: Limit local account use of blank passwords to console logon only", 30 | "Accounts: Rename administrator account", 31 | "Accounts: Rename guest account", 32 | "Audit: Audit the access of global system objects", 33 | "Audit: Audit the use of Backup and Restore privilege", 34 | "Audit: Force audit policy subcategory settings Windows Vista or later to override audit policy category settings", 35 | "Audit: Shut down system immediately if unable to log security audits", 36 | "DCOM: Machine Access Restrictions in Security Descriptor Definition Language SDDL syntax", 37 | "DCOM: Machine Launch Restrictions in Security Descriptor Definition Language SDDL syntax", 38 | "Devices: Allow undock without having to log on", 39 | "Devices: Allowed to format and eject removable media", 40 | "Devices: Prevent users from installing printer drivers", 41 | "Devices: Restrict CD ROM access to locally logged on user only", 42 | "Devices: Restrict floppy access to locally logged on user only", 43 | "Domain controller: Allow server operators to schedule tasks", 44 | "Domain controller: LDAP server signing requirements", 45 | "Domain controller: Refuse machine account password changes", 46 | "Domain member: Digitally encrypt or sign secure channel data always", 47 | "Domain member: Digitally encrypt secure channel data when possible", 48 | "Domain member: Digitally sign secure channel data when possible", 49 | "Domain member: Disable machine account password changes", 50 | "Domain member: Maximum machine account password age", 51 | "Domain member: Require strong Windows 2000 or later session key", 52 | "Interactive logon: Display user information when the session is locked", 53 | "Interactive logon: Do not display last user name", 54 | "Interactive logon: Do not require CTRL ALT DEL", 55 | "Interactive logon: Machine account lockout threshold", 56 | "Interactive logon: Machine inactivity limit", 57 | "Interactive logon: Message text for users attempting to log on", 58 | "Interactive logon: Message title for users attempting to log on", 59 | "Interactive logon: Number of previous logons to cache in case domain controller is not available", 60 | "Interactive logon: Prompt user to change password before expiration", 61 | "Interactive logon: Require Domain Controller authentication to unlock workstation", 62 | "Interactive logon: Require smart card", 63 | "Interactive logon: Smart card removal behavior", 64 | "Microsoft network client: Digitally sign communications always", 65 | "Microsoft network client: Digitally sign communications if server agrees", 66 | "Microsoft network client: Send unencrypted password to third party SMB servers", 67 | "Microsoft network server: Amount of idle time required before suspending session", 68 | "Microsoft network server: Attempt S4U2Self to obtain claim information", 69 | "Microsoft network server: Digitally sign communications always", 70 | "Microsoft network server: Digitally sign communications if client agrees", 71 | "Microsoft network server: Disconnect clients when logon hours expire", 72 | "Microsoft network server: Server SPN target name validation level", 73 | "Network access: Allow anonymous SID Name translation", 74 | "Network access: Do not allow anonymous enumeration of SAM accounts", 75 | "Network access: Do not allow anonymous enumeration of SAM accounts and shares", 76 | "Network access: Do not allow storage of passwords and credentials for network authentication", 77 | "Network access: Let Everyone permissions apply to anonymous users", 78 | "Network access: Named Pipes that can be accessed anonymously", 79 | "Network access: Remotely accessible registry paths", 80 | "Network access: Remotely accessible registry paths and subpaths", 81 | "Network access: Restrict anonymous access to Named Pipes and Shares", 82 | "Network access: Restrict clients allowed to make remote calls to SAM", 83 | "Network access: Shares that can be accessed anonymously", 84 | "Network access: Sharing and security model for local accounts", 85 | "Network security: Allow Local System to use computer identity for NTLM", 86 | "Network security: Allow LocalSystem NULL session fallback", 87 | "Network Security: Allow PKU2U authentication requests to this computer to use online identities", 88 | "Network security: Configure encryption types allowed for Kerberos", 89 | "Network security: Do not store LAN Manager hash value on next password change", 90 | "Network security: Force logoff when logon hours expire", 91 | "Network security: LAN Manager authentication level", 92 | "Network security: LDAP client signing requirements", 93 | "Network security: Minimum session security for NTLM SSP based including secure RPC clients", 94 | "Network security: Minimum session security for NTLM SSP based including secure RPC servers", 95 | "Network security: Restrict NTLM Add remote server exceptions for NTLM authentication", 96 | "Network security: Restrict NTLM Add server exceptions in this domain", 97 | "Network Security: Restrict NTLM Incoming NTLM Traffic", 98 | "Network Security: Restrict NTLM NTLM authentication in this domain", 99 | "Network Security: Restrict NTLM Outgoing NTLM traffic to remote servers", 100 | "Network Security: Restrict NTLM Audit Incoming NTLM Traffic", 101 | "Network Security: Restrict NTLM Audit NTLM authentication in this domain", 102 | "Recovery console: Allow automatic administrative logon", 103 | "Recovery console: Allow floppy copy and access to all drives and folders", 104 | "Shutdown: Allow system to be shut down without having to log on", 105 | "Shutdown: Clear virtual memory pagefile", 106 | "System cryptography: Force strong key protection for user keys stored on the computer", 107 | "System cryptography: Use FIPS compliant algorithms for encryption hashing and signing", 108 | "System objects: Require case insensitivity for non Windows subsystems", 109 | "System objects: Strengthen default permissions of internal system objects eg Symbolic Links", 110 | "System settings: Optional subsystems", 111 | "System settings: Use Certificate Rules on Windows Executables for Software Restriction Policies", 112 | "User Account Control: Admin Approval Mode for the Built in Administrator account", 113 | "User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop", 114 | "User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode", 115 | "User Account Control: Behavior of the elevation prompt for standard users", 116 | "User Account Control: Detect application installations and prompt for elevation", 117 | "User Account Control: Only elevate executables that are signed and validated", 118 | "User Account Control: Only elevate UIAccess applications that are installed in secure locations", 119 | "User Account Control: Run all administrators in Admin Approval Mode", 120 | "User Account Control: Switch to the secure desktop when prompting for elevation", 121 | "User Account Control: Virtualize file and registry write failures to per user locations" 122 | )] 123 | [string] 124 | $Target, 125 | 126 | [Parameter(Mandatory, Position = 2)] 127 | [scriptblock] 128 | $Should 129 | ) 130 | function GetSecurityPolicy([string]$Category) { 131 | 132 | function Get-PolicyOptionData { 133 | [OutputType([hashtable])] 134 | [CmdletBinding()] 135 | Param 136 | ( 137 | [Parameter(Mandatory = $true)] 138 | [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformation()] 139 | [hashtable] 140 | $FilePath 141 | ) 142 | return $FilePath 143 | } 144 | 145 | $securityOptionData = Get-PolicyOptionData -FilePath $("$PSScriptRoot\SecurityOptionData.psd1").Normalize() 146 | 147 | $SecurityOption = $securityOptionData[$Category] 148 | 149 | If ($SecurityOption) { 150 | 151 | $SecurityPolicyFilePath = Join-Path -Path $env:temp -ChildPath 'SecurityPolicy.inf' 152 | secedit.exe /export /cfg $SecurityPolicyFilePath /areas 'SECURITYPOLICY' | Out-Null 153 | 154 | $policyConfiguration = @{ } 155 | 156 | switch -regex -file $SecurityPolicyFilePath { 157 | "^\[(.+)\]" { 158 | # Section 159 | $section = $matches[1] 160 | $policyConfiguration[$section] = @{ } 161 | } 162 | "(.+?)\s*=(.*)" { 163 | # Key 164 | $name, $value = $matches[1..2] -replace "\*" 165 | $policyConfiguration[$section][$name] = $value.Trim() 166 | } 167 | } 168 | 169 | $soSection = $SecurityOption.Section 170 | $soOptions = $SecurityOption.Option 171 | $soValue = $SecurityOption.Value 172 | 173 | $soResultValue = $policyConfiguration.$soSection.$soValue 174 | 175 | If ($soResultValue) { 176 | 177 | If ($soOptions.GetEnumerator().Name -ne 'String') { 178 | $soResult = ($soOptions.GetEnumerator() | Where-Object { $_.Value -eq $soResultValue }).Name 179 | } 180 | Else { 181 | $soOptionsValue = ($soOptions.GetEnumerator() | Where-Object { $_.Name -eq 'String' }).Value 182 | $soResult = $soResultValue -Replace "^$soOptionsValue", '' 183 | } 184 | } 185 | Else { 186 | $soResult = $null 187 | } 188 | 189 | Return $soResult 190 | } 191 | Else { 192 | Throw "The security option $Category was not found." 193 | } 194 | } 195 | 196 | # Modify the target string to match what is in the SecurityOptionData.psd1 file 197 | $Category = $Target.Replace(':','').Replace(' ','_') 198 | 199 | $Expression = { GetSecurityPolicy -Category '$Category' } 200 | $Params = Get-PoshspecParam -TestName SecurityOption -TestExpression $Expression @PSBoundParameters 201 | 202 | Invoke-PoshspecExpression @Params 203 | } -------------------------------------------------------------------------------- /Public/SecurityOptionData.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | "Accounts_Administrator_account_status" = @{ 3 | Value = 'EnableAdminAccount' 4 | Section = 'System Access' 5 | Option = @{ 6 | "Enabled" = '1' 7 | "Disabled" = '0' 8 | } 9 | } 10 | 11 | "Accounts_Block_Microsoft_accounts" = @{ 12 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\NoConnectedUser" 13 | Section = 'Registry Values' 14 | Option = @{ 15 | "This policy is disabled" = '4,0' 16 | "Users cant add Microsoft accounts" = '4,1' 17 | "Users cant add or log on with Microsoft accounts" = '4,3' 18 | } 19 | } 20 | 21 | "Accounts_Guest_account_status" = @{ 22 | Value = 'EnableGuestAccount' 23 | Section = 'System Access' 24 | Option = @{ 25 | "Enabled" = '1' 26 | "Disabled" = '0' 27 | } 28 | } 29 | 30 | "Accounts_Limit_local_account_use_of_blank_passwords_to_console_logon_only" = @{ 31 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\LimitBlankPasswordUse" 32 | Section = 'Registry Values' 33 | Option = @{ 34 | Enabled = '4,1' 35 | Disabled = '4,0' 36 | } 37 | } 38 | 39 | "Accounts_Rename_administrator_account" = @{ 40 | Value = 'NewAdministratorName' 41 | Section = 'System Access' 42 | Option = @{ 43 | String = '' # supply name of administrator account 44 | } 45 | } 46 | 47 | "Accounts_Rename_guest_account" = @{ 48 | Value = 'NewGuestName' 49 | Section = 'System Access' 50 | Option = @{ 51 | String = '' # supply name of guest account 52 | } 53 | } 54 | 55 | "Audit_Audit_the_access_of_global_system_objects" = @{ 56 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\AuditBaseObjects" 57 | Section = 'Registry Values' 58 | Option = @{ 59 | Enabled = '4,1' 60 | Disabled = '4,0' 61 | } 62 | } 63 | 64 | "Audit_Audit_the_use_of_Backup_and_Restore_privilege" = @{ 65 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\FullPrivilegeAuditing" 66 | Section = 'Registry Values' 67 | Option = @{ 68 | Enabled = '3,1' 69 | Disabled = '3,0' 70 | } 71 | } 72 | 73 | "Audit_Force_audit_policy_subcategory_settings_Windows_Vista_or_later_to_override_audit_policy_category_settings" = @{ 74 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\SCENoApplyLegacyAuditPolicy" 75 | Section = 'Registry Values' 76 | Option = @{ 77 | Enabled = '4,1' 78 | Disabled = '4,0' 79 | } 80 | } 81 | 82 | "Audit_Shut_down_system_immediately_if_unable_to_log_security_audits" = @{ 83 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\CrashOnAuditFail" 84 | Section = 'Registry Values' 85 | Option = @{ 86 | Enabled = '4,1' 87 | Disabled = '4,0' 88 | } 89 | } 90 | 91 | "DCOM_Machine_Access_Restrictions_in_Security_Descriptor_Definition_Language_SDDL_syntax" = @{ 92 | Value = "MACHINE\Software\Policies\Microsoft\Windows NT\DCOM\MachineAccessRestriction" 93 | Section = 'Registry Values' 94 | Option = @{ 95 | String = '1,' # + 96 | } 97 | } 98 | 99 | "DCOM_Machine_Launch_Restrictions_in_Security_Descriptor_Definition_Language_SDDL_syntax" = @{ 100 | Value = "MACHINE\Software\Policies\Microsoft\Windows NT\DCOM\MachineLaunchRestriction" 101 | Section = 'Registry Values' 102 | Option = @{ 103 | String = '1,' # + 104 | } 105 | } 106 | 107 | "Devices_Allow_undock_without_having_to_log_on" = @{ 108 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\UndockWithoutLogon" 109 | Section = 'Registry Values' 110 | Option = @{ 111 | Enabled = '4,1' 112 | Disabled = '4,0' 113 | } 114 | } 115 | 116 | "Devices_Allowed_to_format_and_eject_removable_media" = @{ 117 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AllocateDASD" 118 | Section = 'Registry Values' 119 | Option = @{ 120 | 'Administrators' = '1,"0"' 121 | 'Administrators and Power Users' = '1,"1"' 122 | 'Administrators and Interactive Users' = '1,"2"' 123 | } 124 | } 125 | 126 | "Devices_Prevent_users_from_installing_printer_drivers" = @{ 127 | Value = "MACHINE\System\CurrentControlSet\Control\Print\Providers\LanMan Print Services\Servers\AddPrinterDrivers" 128 | Section = 'Registry Values' 129 | Option = @{ 130 | Enabled = '4,1' 131 | Disabled = '4,0' 132 | } 133 | } 134 | 135 | "Devices_Restrict_CD_ROM_access_to_locally_logged_on_user_only" = @{ 136 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AllocateCDRoms" 137 | Section = 'Registry Values' 138 | Option = @{ 139 | Enabled = '1,"1"' 140 | Disabled = '1,"0"' 141 | } 142 | } 143 | 144 | "Devices_Restrict_floppy_access_to_locally_logged_on_user_only" = @{ 145 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AllocateFloppies" 146 | Section = 'Registry Values' 147 | Option = @{ 148 | Enabled = '1,"1"' 149 | Disabled = '1,"0"' 150 | } 151 | } 152 | 153 | "Domain_controller_Allow_server_operators_to_schedule_tasks" = @{ 154 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\SubmitControl" 155 | Section = 'Registry Values' 156 | Option = @{ 157 | Enabled = '4,1' 158 | Disabled = '4,0' 159 | } 160 | } 161 | 162 | "Domain_controller_LDAP_server_signing_requirements" = @{ 163 | Value = "MACHINE\System\CurrentControlSet\Services\NTDS\Parameters\LDAPServerIntegrity" 164 | Section = 'Registry Values' 165 | Option = @{ 166 | 'None' = '4,1' 167 | 'Require Signing' = '4,2' 168 | } 169 | } 170 | 171 | "Domain_controller_Refuse_machine_account_password_changes" = @{ 172 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\RefusePasswordChange" 173 | Section = 'Registry Values' 174 | Option = @{ 175 | Enabled = '4,1' 176 | Disabled = '4,0' 177 | } 178 | } 179 | 180 | "Domain_member_Digitally_encrypt_or_sign_secure_channel_data_always" = @{ 181 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\RequireSignOrSeal" 182 | Section = 'Registry Values' 183 | Option = @{ 184 | Enabled = '4,1' 185 | Disabled = '4,0' 186 | } 187 | } 188 | 189 | "Domain_member_Digitally_encrypt_secure_channel_data_when_possible" = @{ 190 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\SealSecureChannel" 191 | Section = 'Registry Values' 192 | Option = @{ 193 | Enabled = '4,1' 194 | Disabled = '4,0' 195 | } 196 | } 197 | 198 | "Domain_member_Digitally_sign_secure_channel_data_when_possible" = @{ 199 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\SignSecureChannel" 200 | Section = 'Registry Values' 201 | Option = @{ 202 | Enabled = '4,1' 203 | Disabled = '4,0' 204 | } 205 | } 206 | 207 | "Domain_member_Disable_machine_account_password_changes" = @{ 208 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange" 209 | Section = 'Registry Values' 210 | Option = @{ 211 | Enabled = '4,1' 212 | Disabled = '4,0' 213 | } 214 | } 215 | 216 | "Domain_member_Maximum_machine_account_password_age" = @{ 217 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge" 218 | Section = 'Registry Values' 219 | Option = @{ 220 | String = "4," # + 221 | } 222 | } 223 | 224 | "Domain_member_Require_strong_Windows_2000_or_later_session_key" = @{ 225 | Value = "MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\RequireStrongKey" 226 | Section = 'Registry Values' 227 | Option = @{ 228 | Enabled = '4,1' 229 | Disabled = '4,0' 230 | } 231 | } 232 | 233 | "Interactive_logon_Display_user_information_when_the_session_is_locked" = @{ 234 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\DontDisplayLockedUserId" 235 | Section = 'Registry Values' 236 | Option = @{ 237 | 'User displayname, domain and user names' = '4,1' 238 | 'User display name only' = '4,2' 239 | 'Do not display user information' = '4,3' 240 | } 241 | } 242 | 243 | "Interactive_logon_Do_not_display_last_user_name" = @{ 244 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\DontDisplayLastUserName" 245 | Section = 'Registry Values' 246 | Option = @{ 247 | Enabled = '4,1' 248 | Disabled = '4,0' 249 | } 250 | } 251 | 252 | "Interactive_logon_Do_not_require_CTRL_ALT_DEL" = @{ 253 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableCAD" 254 | Section = 'Registry Values' 255 | Option = @{ 256 | Enabled = '4,1' 257 | Disabled = '4,0' 258 | } 259 | } 260 | 261 | "Interactive_logon_Machine_account_lockout_threshold" = @{ 262 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\MaxDevicePasswordFailedAttempts" 263 | Section = 'Registry Values' 264 | Option = @{ 265 | String = "4," # + 266 | } 267 | } 268 | 269 | "Interactive_logon_Machine_inactivity_limit" = @{ 270 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\InactivityTimeoutSecs" 271 | Section = 'Registry Values' 272 | Option = @{ 273 | String = "4," # + 274 | } 275 | } 276 | 277 | "Interactive_logon_Message_text_for_users_attempting_to_log_on" = @{ 278 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\LegalNoticeText" 279 | Section = 'Registry Values' 280 | Option = @{ 281 | String = "7," # + 282 | } 283 | } 284 | 285 | "Interactive_logon_Message_title_for_users_attempting_to_log_on" = @{ 286 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\LegalNoticeCaption" 287 | Section = 'Registry Values' 288 | Option = @{ 289 | String = "1," # + 290 | } 291 | } 292 | 293 | "Interactive_logon_Number_of_previous_logons_to_cache_in_case_domain_controller_is_not_available" = @{ 294 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\CachedLogonsCount" 295 | Section = 'Registry Values' 296 | Option = @{ 297 | String = "1," # + 298 | } 299 | } 300 | 301 | "Interactive_logon_Prompt_user_to_change_password_before_expiration" = @{ 302 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\PasswordExpiryWarning" 303 | Section = 'Registry Values' 304 | Option = @{ 305 | String = "4," # + 306 | } 307 | } 308 | 309 | "Interactive_logon_Require_Domain_Controller_authentication_to_unlock_workstation" = @{ 310 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ForceUnlockLogon" 311 | Section = 'Registry Values' 312 | Option = @{ 313 | Enabled = '4,1' 314 | Disabled = '4,0' 315 | } 316 | } 317 | 318 | "Interactive_logon_Require_smart_card" = @{ 319 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ScForceOption" 320 | Section = 'Registry Values' 321 | Option = @{ 322 | Enabled = '4,1' 323 | Disabled = '4,0' 324 | } 325 | } 326 | 327 | "Interactive_logon_Smart_card_removal_behavior" = @{ 328 | Value = "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ScRemoveOption" 329 | Section = 'Registry Values' 330 | Option = @{ 331 | 'No Action' = '1,"0"' 332 | 'Lock workstation' = '1,"1"' 333 | 'Force logoff' = '1,"2"' 334 | 'Disconnect if a remote Remote Desktop Services session' = '1,"3"' 335 | } 336 | } 337 | 338 | "Microsoft_network_client_Digitally_sign_communications_always" = @{ 339 | Value = "MACHINE\System\CurrentControlSet\Services\LanmanWorkstation\Parameters\RequireSecuritySignature" 340 | Section = 'Registry Values' 341 | Option = @{ 342 | Enabled = '4,1' 343 | Disabled = '4,0' 344 | } 345 | } 346 | 347 | "Microsoft_network_client_Digitally_sign_communications_if_server_agrees" = @{ 348 | Value = "MACHINE\System\CurrentControlSet\Services\LanmanWorkstation\Parameters\EnableSecuritySignature" 349 | Section = 'Registry Values' 350 | Option = @{ 351 | Enabled = '4,1' 352 | Disabled = '4,0' 353 | } 354 | } 355 | 356 | "Microsoft_network_client_Send_unencrypted_password_to_third_party_SMB_servers" = @{ 357 | Value = "MACHINE\System\CurrentControlSet\Services\LanmanWorkstation\Parameters\EnablePlainTextPassword" 358 | Section = 'Registry Values' 359 | Option = @{ 360 | Enabled = '4,1' 361 | Disabled = '4,0' 362 | } 363 | } 364 | 365 | "Microsoft_network_server_Amount_of_idle_time_required_before_suspending_session" = @{ 366 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\AutoDisconnect" 367 | Section = 'Registry Values' 368 | Option = @{ 369 | String = '4,' # + 370 | } 371 | } 372 | 373 | "Microsoft_network_server_Attempt_S4U2Self_to_obtain_claim_information" = @{ 374 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\EnableS4U2SelfForClaims" 375 | Section = 'Registry Values' 376 | Option = @{ 377 | Default = '4,0' 378 | Enabled = '4,1' 379 | Disabled = '4,2' 380 | } 381 | } 382 | 383 | "Microsoft_network_server_Digitally_sign_communications_always" = @{ 384 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\RequireSecuritySignature" 385 | Section = 'Registry Values' 386 | Option = @{ 387 | Enabled = '4,1' 388 | Disabled = '4,0' 389 | } 390 | } 391 | 392 | "Microsoft_network_server_Digitally_sign_communications_if_client_agrees" = @{ 393 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\EnableSecuritySignature" 394 | Section = 'Registry Values' 395 | Option = @{ 396 | Enabled = '4,1' 397 | Disabled = '4,0' 398 | } 399 | } 400 | 401 | "Microsoft_network_server_Disconnect_clients_when_logon_hours_expire" = @{ 402 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\EnableForcedLogOff" 403 | Section = 'Registry Values' 404 | Option = @{ 405 | Enabled = '4,1' 406 | Disabled = '4,0' 407 | } 408 | } 409 | 410 | "Microsoft_network_server_Server_SPN_target_name_validation_level" = @{ 411 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\SmbServerNameHardeningLevel" 412 | Section = 'Registry Values' 413 | Option = @{ 414 | 'Off' = '4,0' 415 | 'Accept if provided by client' = '4,1' 416 | 'Required from client' = '4,2' 417 | } 418 | } 419 | 420 | "Network_access_Allow_anonymous_SID_Name_translation" = @{ 421 | Value = 'LSAAnonymousNameLookup' 422 | Section = 'System Access' 423 | Option = @{ 424 | Enabled = '1' 425 | Disabled = '0' 426 | } 427 | } 428 | 429 | "Network_access_Do_not_allow_anonymous_enumeration_of_SAM_accounts" = @{ 430 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymousSAM" 431 | Section = 'Registry Values' 432 | Option = @{ 433 | Enabled = '4,1' 434 | Disabled = '4,0' 435 | } 436 | } 437 | 438 | "Network_access_Do_not_allow_anonymous_enumeration_of_SAM_accounts_and_shares" = @{ 439 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymous" 440 | Section = 'Registry Values' 441 | Option = @{ 442 | Enabled = '4,1' 443 | Disabled = '4,0' 444 | } 445 | } 446 | 447 | "Network_access_Do_not_allow_storage_of_passwords_and_credentials_for_network_authentication" = @{ 448 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\DisableDomainCreds" 449 | Section = 'Registry Values' 450 | Option = @{ 451 | Enabled = '4,1' 452 | Disabled = '4,0' 453 | } 454 | } 455 | 456 | "Network_access_Let_Everyone_permissions_apply_to_anonymous_users" = @{ 457 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\EveryoneIncludesAnonymous" 458 | Section = 'Registry Values' 459 | Option = @{ 460 | Enabled = '4,1' 461 | Disabled = '4,0' 462 | } 463 | } 464 | 465 | "Network_access_Named_Pipes_that_can_be_accessed_anonymously" = @{ 466 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionPipes" 467 | Section = 'Registry Values' 468 | Option = @{ 469 | String = '7,' # + accounts (Identities seperated by commas) 470 | } 471 | } 472 | 473 | "Network_access_Remotely_accessible_registry_paths" = @{ 474 | Value = "MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine" 475 | Section = 'Registry Values' 476 | Option = @{ 477 | String = '7,' # + accounts (Identities seperated by commas) 478 | } 479 | } 480 | 481 | "Network_access_Remotely_accessible_registry_paths_and_subpaths" = @{ 482 | Value = "MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedPaths\Machine" 483 | Section = 'Registry Values' 484 | Option = @{ 485 | String = '7,' # + accounts (Identities seperated by commas) 486 | } 487 | } 488 | 489 | "Network_access_Restrict_anonymous_access_to_Named_Pipes_and_Shares" = @{ 490 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\RestrictNullSessAccess" 491 | Section = 'Registry Values' 492 | Option = @{ 493 | Enabled = '4,1' 494 | Disabled = '4,0' 495 | } 496 | } 497 | 498 | "Network_access_Restrict_clients_allowed_to_make_remote_calls_to_SAM" = @{ 499 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\RestrictRemoteSAM" 500 | Section = 'Registry Values' 501 | Option = @{ 502 | String = '1,' 503 | } 504 | } 505 | 506 | "Network_access_Shares_that_can_be_accessed_anonymously" = @{ 507 | Value = "MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionShares" 508 | Section = 'Registry Values' 509 | Option = @{ 510 | String = '7,' # + accounts (Identities seperated by commas) 511 | } 512 | } 513 | 514 | "Network_access_Sharing_and_security_model_for_local_accounts" = @{ 515 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\ForceGuest" 516 | Section = 'Registry Values' 517 | Option = @{ 518 | 'Classic - Local users authenticate as themselves' = '4,0' 519 | 'Guest only - Local users authenticate as Guest' = '4,1' 520 | } 521 | } 522 | 523 | "Network_security_Allow_Local_System_to_use_computer_identity_for_NTLM" = @{ 524 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\UseMachineId" 525 | Section = 'Registry Values' 526 | Option = @{ 527 | Enabled = '4,1' 528 | Disabled = '4,0' 529 | } 530 | } 531 | 532 | "Network_security_Allow_LocalSystem_NULL_session_fallback" = @{ 533 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\MSV1_0\allownullsessionfallback" 534 | Section = 'Registry Values' 535 | Option = @{ 536 | Enabled = '4,1' 537 | Disabled = '4,0' 538 | } 539 | } 540 | 541 | "Network_Security_Allow_PKU2U_authentication_requests_to_this_computer_to_use_online_identities" = @{ 542 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\pku2u\AllowOnlineID" 543 | Section = 'Registry Values' 544 | Option = @{ 545 | Enabled = '4,1' 546 | Disabled = '4,0' 547 | } 548 | } 549 | 550 | "Network_security_Configure_encryption_types_allowed_for_Kerberos" = @{ 551 | Value = "MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters\SupportedEncryptionTypes" 552 | Section = 'Registry Values' 553 | Option = @{ 554 | DES_CBC_CRC = '4,1' 555 | DES_CBC_MD5 = '4,2' 556 | RC4_HMAC_MD5 = '4,4' 557 | AES128_HMAC_SHA1 = '4,8' 558 | AES256_HMAC_SHA1 = '4,16' 559 | } 560 | } 561 | 562 | "Network_security_Do_not_store_LAN_Manager_hash_value_on_next_password_change" = @{ 563 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\NoLMHash" 564 | Section = 'Registry Values' 565 | Option = @{ 566 | Enabled = '4,1' 567 | Disabled = '4,0' 568 | } 569 | } 570 | 571 | "Network_security_Force_logoff_when_logon_hours_expire" = @{ 572 | Value = "ForceLogoffWhenHourExpire" 573 | Section = 'System Access' 574 | Option = @{ 575 | Enabled = '1' 576 | Disabled = '0' 577 | } 578 | } 579 | 580 | "Network_security_LAN_Manager_authentication_level" = @{ 581 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\LmCompatibilityLevel" 582 | Section = 'Registry Values' 583 | Option = @{ 584 | 'Send LM & NTLM responses' = '4,0' 585 | 'Send LM & NTLM - use NTLMv2 session security if negotiated' = '4,1' 586 | 'Send NTLM responses only' = '4,2' 587 | 'Send NTLMv2 responses only' = '4,3' 588 | 'Send NTLMv2 responses only. Refuse LM' = '4,4' 589 | 'Send NTLMv2 responses only. Refuse LM & NTLM' = '4,5' 590 | } 591 | } 592 | 593 | "Network_security_LDAP_client_signing_requirements" = @{ 594 | Value = "MACHINE\System\CurrentControlSet\Services\LDAP\LDAPClientIntegrity" 595 | Section = 'Registry Values' 596 | Option = @{ 597 | 'None' = '4,0' 598 | 'Negotiate Signing' = '4,1' 599 | 'Require Signing' = '4,2' 600 | } 601 | } 602 | 603 | "Network_security_Minimum_session_security_for_NTLM_SSP_based_including_secure_RPC_clients" = @{ 604 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\MSV1_0\NTLMMinClientSec" 605 | Section = 'Registry Values' 606 | Option = @{ 607 | 'Require NTLMv2 session security' = '4,524288' 608 | 'Require 128-bit encryption' = '4,536870912' 609 | 'Both options checked' = '4,537395200' 610 | } 611 | } 612 | 613 | "Network_security_Minimum_session_security_for_NTLM_SSP_based_including_secure_RPC_servers" = @{ 614 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\MSV1_0\NTLMMinServerSec" 615 | Section = 'Registry Values' 616 | Option = @{ 617 | 'Require NTLMv2 session security' = '4,524288' 618 | 'Require 128-bit encryption' = '4,536870912' 619 | 'Both options checked' = '4,537395200' 620 | } 621 | } 622 | 623 | "Network_security_Restrict_NTLM_Add_remote_server_exceptions_for_NTLM_authentication" = @{ 624 | Value = "MACHINE\System\CurrentControlSet\Control\Lsa\MSV1_0\ClientAllowedNTLMServers" 625 | Section = 'Registry Values' 626 | Option = @{ 627 | String = '7,' #