├── .gitattributes ├── DSCResources ├── StackExchange_CertificateStore │ ├── StackExchange_CertificateStore.psd1 │ ├── StackExchange_CertificateStore.psm1 │ └── StackExchange_CertificateStore.schema.mof ├── StackExchange_FirewallRule │ ├── StackExchange_FirewallRule.psd1 │ ├── StackExchange_FirewallRule.psm1 │ └── StackExchange_FirewallRule.schema.mof ├── StackExchange_NetworkAdapter │ ├── StackExchange_NetworkAdapter.Tests.ps1 │ ├── StackExchange_NetworkAdapter.psd1 │ ├── StackExchange_NetworkAdapter.psm1 │ └── StackExchange_NetworkAdapter.schema.mof ├── StackExchange_Pagefile │ ├── StackExchange_Pagefile.psd1 │ ├── StackExchange_Pagefile.psm1 │ ├── StackExchange_Pagefile.schema.mof │ ├── StackExchange_en-US │ │ ├── StackExchange_PagefileProvider.psd1 │ │ └── StackExchange_about_PageFile_Resource.help.txt │ └── StackExchange_nl-NL │ │ ├── StackExchange_PagefileProvider.psd1 │ │ └── StackExchange_about_PageFile_Resource.help.txt ├── StackExchange_PowerPlan │ ├── StackExchange_PowerPlan.psd1 │ ├── StackExchange_PowerPlan.psm1 │ ├── StackExchange_PowerPlan.schema.mof │ └── StackExchange_en-US │ │ ├── StackExchange_PowerPlanProvider.psd1 │ │ └── StackExchange_about_PowerPlan_Resource.txt ├── StackExchange_ScheduledTask │ ├── StackExchange_ScheduledTask.Tests.ps1 │ ├── StackExchange_ScheduledTask.psd1 │ ├── StackExchange_ScheduledTask.psm1 │ └── StackExchange_ScheduledTask.schema.mof ├── StackExchange_SetExecutionPolicy │ ├── StackExchange_SetExecutionPolicy.psd1 │ ├── StackExchange_SetExecutionPolicy.psm1 │ ├── StackExchange_SetExecutionPolicy.schema.mof │ └── StackExchange_en-US │ │ ├── StackExchange_SetExecutionPolicyProvider.psd1 │ │ └── StackExchange_about_SetExecutionPolicy_Resource.txt └── StackExchange_Timezone │ ├── StackExchange_Timezone.psd1 │ ├── StackExchange_Timezone.psm1 │ └── StackExchange_Timezone.schema.mof ├── LICENSE.txt ├── README.md ├── StackExchangeResources.psd1 ├── appveyor.yml └── test ├── integration └── StackExchange_PageFile │ └── pester │ └── StackExchange_PageFile.Tests.ps1 └── unit └── StackExchange_Pagefile └── pester └── StackExchange_Pagefile.Tests.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | 24 | *.ps1 -text diff merge 25 | *.psm1 -text diff merge 26 | *.psd1 -text diff merge 27 | *.mof -text diff merge 28 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_CertificateStore/StackExchange_CertificateStore.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'CertificateStore' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/30/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_CertificateStore.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.0' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '6e7cd6d9-c42b-4810-98a7-c78a2b8dddd9' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Set-TargetResource', 'Test-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_CertificateStore/StackExchange_CertificateStore.psm1: -------------------------------------------------------------------------------- 1 | function Get-TargetResource 2 | { 3 | [OutputType([Hashtable])] 4 | param ( 5 | [parameter(Mandatory = $true)] 6 | [ValidateNotNullOrEmpty()] 7 | [string] 8 | $Name, 9 | [parameter(Mandatory = $true)] 10 | [ValidateNotNullOrEmpty()] 11 | [string] 12 | $Path, 13 | [parameter()] 14 | [ValidateSet('LocalMachine','CurrentUser')] 15 | [string] 16 | $Location = 'LocalMachine', 17 | [parameter()] 18 | [string] 19 | $Store = 'My', 20 | [parameter()] 21 | [ValidateSet('Present','Absent')] 22 | [string] 23 | $Ensure = 'Present' 24 | ) 25 | 26 | #Needs to return a hashtable that returns the current 27 | #status of the configuration component 28 | $Ensure = 'Present' 29 | 30 | if (Test-TargetResource @PSBoundParameters) 31 | { 32 | $Ensure = 'Present' 33 | } 34 | else 35 | { 36 | $Ensure = 'Absent' 37 | } 38 | 39 | $Configuration = @{ 40 | Name = $Name 41 | Path = $Path 42 | Location = $Location 43 | Store = $Store 44 | Ensure = $Ensure 45 | } 46 | 47 | return $Configuration 48 | } 49 | 50 | function Set-TargetResource 51 | { 52 | param ( 53 | [parameter(Mandatory = $true)] 54 | [ValidateNotNullOrEmpty()] 55 | [string] 56 | $Name, 57 | [parameter(Mandatory = $true)] 58 | [ValidateNotNullOrEmpty()] 59 | [string] 60 | $Path, 61 | [parameter()] 62 | [ValidateSet('LocalMachine','CurrentUser')] 63 | [string] 64 | $Location = 'LocalMachine', 65 | [parameter()] 66 | [string] 67 | $Store = 'My', 68 | [parameter()] 69 | [ValidateSet('Present','Absent')] 70 | [string] 71 | $Ensure = 'Present', 72 | [parameter()] 73 | [pscredential] 74 | $Password 75 | ) 76 | 77 | $CertificateBaseLocation = "cert:\$Location\$Store" 78 | 79 | if ($Ensure -like 'Present') 80 | { 81 | Write-Verbose "Adding $path to $CertificateBaseLocation." 82 | 83 | $passwordSplat = @{} 84 | if ($Password) 85 | { 86 | $passwordSplat['Password'] = $Password.Password 87 | } 88 | 89 | Import-PfxCertificate -CertStoreLocation $CertificateBaseLocation -FilePath $Path @passwordSplat 90 | } 91 | else 92 | { 93 | $CertificateLocation = Join-path $CertificateBaseLocation $Name 94 | Write-Verbose "Removing $CertificateLocation." 95 | dir $CertificateLocation | Remove-Item -Force -Confirm:$false 96 | } 97 | } 98 | 99 | function Test-TargetResource 100 | { 101 | [OutputType([boolean])] 102 | param ( 103 | [parameter(Mandatory = $true)] 104 | [ValidateNotNullOrEmpty()] 105 | [string] 106 | $Name, 107 | [parameter(Mandatory = $true)] 108 | [ValidateNotNullOrEmpty()] 109 | [string] 110 | $Path, 111 | [parameter()] 112 | [ValidateSet('LocalMachine','CurrentUser')] 113 | [string] 114 | $Location = 'LocalMachine', 115 | [parameter()] 116 | [string] 117 | $Store = 'My', 118 | [parameter()] 119 | [ValidateSet('Present','Absent')] 120 | [string] 121 | $Ensure = 'Present', 122 | [parameter()] 123 | [pscredential] 124 | $Password 125 | ) 126 | 127 | $IsValid = $false 128 | 129 | $CertificateLocation = "cert:\$Location\$Store\$Name" 130 | 131 | if ($Ensure -like 'Present') 132 | { 133 | Write-Verbose "Checking for $Name to be present in the $location store under $store." 134 | if (Test-Path $CertificateLocation) 135 | { 136 | Write-Verbose "Found a matching certficate at $CertificateLocation" 137 | 138 | $cert = Get-Item $CertificateLocation 139 | 140 | if ($cert.HasPrivateKey) 141 | { 142 | Write-Verbose "Certficate at $CertificateLocation has a private key installed." 143 | $IsValid = $true 144 | } 145 | else 146 | { 147 | Write-Verbose "Certficate at $CertificateLocation does not have a private key installed." 148 | } 149 | } 150 | else 151 | { 152 | Write-Verbose "Unable to find a matching certficate at $CertificateLocation" 153 | } 154 | } 155 | else 156 | { 157 | Write-Verbose "Checking for $Name to be absent in the $location store under $store." 158 | if (Test-Path $CertificateLocation) 159 | { 160 | Write-Verbose "Found a matching certficate at $CertificateLocation" 161 | } 162 | else 163 | { 164 | Write-Verbose "Unable to find a matching certficate at $CertificateLocation" 165 | $IsValid = $true 166 | } 167 | } 168 | 169 | #Needs to return a boolean 170 | return $IsValid 171 | } 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_CertificateStore/StackExchange_CertificateStore.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.1"), FriendlyName("CertificateStore")] 2 | class StackExchange_CertificateStore : OMI_BaseResource 3 | { 4 | [Key] string Name; 5 | [Key] string Path; 6 | [write,ValueMap{"LocalMachine", "CurrentUser"},Values{"LocalMachine", "CurrentUser"}] string Location; 7 | [write] string Store; 8 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 9 | [write,EmbeddedInstance("MSFT_Credential")] string Password; 10 | }; 11 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_FirewallRule/StackExchange_FirewallRule.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'FirewallRule' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/13/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_FirewallRule.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.7' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '8f3ea446-27ee-4416-85c3-a6590ca05f03' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Test-TargetResource', 'Set-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_FirewallRule/StackExchange_FirewallRule.psm1: -------------------------------------------------------------------------------- 1 | function Get-TargetResource 2 | { 3 | [OutputType([Hashtable])] 4 | param ( 5 | [parameter(Mandatory = $true)] 6 | [ValidateNotNullOrEmpty()] 7 | [Alias('Name')] 8 | [string] 9 | $DisplayName, 10 | [parameter()] 11 | [ValidateSet('Present','Absent')] 12 | [string] 13 | $Ensure = 'Present', 14 | [parameter()] 15 | [ValidateSet('Allow','Block')] 16 | [string] 17 | $Action, 18 | [parameter()] 19 | [string] 20 | $Description, 21 | [parameter()] 22 | [ValidateSet('Inbound','Outbound')] 23 | [string] 24 | $Direction, 25 | [parameter()] 26 | [ValidateSet('Any','ProximityApps', 'ProximitySharing')] 27 | [string] 28 | $DynamicTransport, 29 | [parameter()] 30 | [ValidateSet('Block', 'Allow', 'DeferToUser','DeferToApp')] 31 | [string] 32 | $EdgeTraversalPolicy, 33 | [parameter()] 34 | [ValidateSet('True','False')] 35 | [string] 36 | $Enabled, 37 | [parameter()] 38 | [ValidateSet('NotRequired','Required','Dynamic')] 39 | [string] 40 | $Encryption, 41 | [parameter()] 42 | [string[]] 43 | $IcmpType, 44 | [parameter()] 45 | [string[]] 46 | $InterfaceAlias, 47 | [parameter()] 48 | [ValidateSet('Any','Wired','Wireless', 'RemoteAccess')] 49 | [string] 50 | $InterfaceType, 51 | [parameter()] 52 | [string[]] 53 | $LocalAddress, 54 | [parameter()] 55 | [string[]] 56 | $LocalPort, 57 | [parameter()] 58 | [string] 59 | $LocalUser, 60 | [parameter()] 61 | [ValidateSet('Any', 'Domain','Private','Public', 'NotApplicable')] 62 | [string] 63 | $Profile, 64 | [parameter()] 65 | [string] 66 | $Program, 67 | [parameter()] 68 | [string] 69 | $Protocol, 70 | [parameter()] 71 | [string[]] 72 | $RemoteAddress, 73 | [parameter()] 74 | [string] 75 | $RemoteMachine, 76 | [parameter()] 77 | [string] 78 | $RemoteUser, 79 | [parameter()] 80 | [string] 81 | $Service 82 | ) 83 | 84 | #Needs to return a hashtable that returns the current 85 | #status of the configuration component 86 | $Configuration = @{ 87 | DisplayName = $DisplayName 88 | } 89 | 90 | $Rule = Get-NetFirewallRule -DisplayName $DisplayName -ErrorAction SilentlyContinue | 91 | ForEach-Object { 92 | New-Object PSObject -Property @{ 93 | SourceRule = $_ 94 | AddressFilter = $_ | Get-NetFirewallAddressFilter 95 | ApplicationFilter = $_ | Get-NetFirewallApplicationFilter 96 | InterfaceFilter = $_ | Get-NetFirewallInterfaceFilter 97 | InterfaceTypeFilter = $_ | Get-NetFirewallInterfaceTypeFilter 98 | PortFilter = $_ | Get-NetFirewallPortFilter 99 | SecurityFilter = $_ | Get-NetFirewallSecurityFilter 100 | ServiceFilter = $_ | Get-NetFirewallServiceFilter 101 | } 102 | } 103 | 104 | if ($Rule) 105 | { 106 | $Configuration.Ensure = 'Present' 107 | 108 | } 109 | else 110 | { 111 | $Configuration.Ensure = 'Absent' 112 | } 113 | throw "To do yet" 114 | return $Configuration 115 | } 116 | 117 | function Set-TargetResource 118 | { 119 | param ( 120 | [parameter(Mandatory = $true)] 121 | [ValidateNotNullOrEmpty()] 122 | [Alias('Name')] 123 | [string] 124 | $DisplayName, 125 | [parameter()] 126 | [ValidateSet('Present','Absent')] 127 | [string] 128 | $Ensure = 'Present', 129 | [parameter()] 130 | [ValidateSet('Allow','Block')] 131 | [string] 132 | $Action, 133 | [parameter()] 134 | [string] 135 | $Description, 136 | [parameter()] 137 | [ValidateSet('Inbound','Outbound')] 138 | [string] 139 | $Direction, 140 | [parameter()] 141 | [ValidateSet('Any','ProximityApps', 'ProximitySharing')] 142 | [string] 143 | $DynamicTransport, 144 | [parameter()] 145 | [ValidateSet('Block', 'Allow', 'DeferToUser','DeferToApp')] 146 | [string] 147 | $EdgeTraversalPolicy, 148 | [parameter()] 149 | [ValidateSet('True','False')] 150 | [string] 151 | $Enabled, 152 | [parameter()] 153 | [ValidateSet('NotRequired','Required','Dynamic')] 154 | [string] 155 | $Encryption, 156 | [parameter()] 157 | [string[]] 158 | $IcmpType, 159 | [parameter()] 160 | [string[]] 161 | $InterfaceAlias, 162 | [parameter()] 163 | [ValidateSet('Any','Wired','Wireless', 'RemoteAccess')] 164 | [string] 165 | $InterfaceType, 166 | [parameter()] 167 | [string[]] 168 | $LocalAddress, 169 | [parameter()] 170 | [string[]] 171 | $LocalPort, 172 | [parameter()] 173 | [string] 174 | $LocalUser, 175 | [parameter()] 176 | [ValidateSet('Any', 'Domain','Private','Public', 'NotApplicable')] 177 | [string] 178 | $Profile, 179 | [parameter()] 180 | [string] 181 | $Program, 182 | [parameter()] 183 | [string] 184 | $Protocol, 185 | [parameter()] 186 | [string[]] 187 | $RemoteAddress, 188 | [parameter()] 189 | [string] 190 | $RemoteMachine, 191 | [parameter()] 192 | [string] 193 | $RemoteUser, 194 | [parameter()] 195 | [string] 196 | $Service 197 | ) 198 | 199 | if ($PSBoundParameters.ContainsKey('Debug')) 200 | { 201 | $PSBoundParameters.Remove('Debug') 202 | } 203 | if ($PSBoundParameters.ContainsKey('Ensure')) 204 | { 205 | $PSBoundParameters.Remove('Ensure') | Out-Null 206 | } 207 | 208 | if ($Ensure -like 'Present') 209 | { 210 | Write-Verbose "Checking for an existing rule $DisplayName." 211 | $Rule = Get-NetFirewallRule -DisplayName $DisplayName -ErrorAction SilentlyContinue 212 | if ($rule) 213 | { 214 | Set-NetFirewallRule @PSBoundParameters 215 | } 216 | else 217 | { 218 | New-NetFirewallRule @PSBoundParameters 219 | } 220 | } 221 | else 222 | { 223 | Remove-NetFirewallRule -DisplayName $DisplayName -Confirm:$false 224 | } 225 | 226 | } 227 | 228 | function Test-TargetResource 229 | { 230 | [OutputType([Boolean])] 231 | param ( 232 | [parameter(Mandatory = $true)] 233 | [ValidateNotNullOrEmpty()] 234 | [Alias('Name')] 235 | [string] 236 | $DisplayName, 237 | [parameter()] 238 | [ValidateSet('Present','Absent')] 239 | [string] 240 | $Ensure = 'Present', 241 | [parameter()] 242 | [ValidateSet('Allow','Block')] 243 | [string] 244 | $Action = 'Allow', 245 | [parameter()] 246 | [string] 247 | $Description = '', 248 | [parameter()] 249 | [ValidateSet('Inbound','Outbound')] 250 | [string] 251 | $Direction = 'Inbound', 252 | [parameter()] 253 | [ValidateSet('Any','ProximityApps', 'ProximitySharing')] 254 | [string] 255 | $DynamicTransport, 256 | [parameter()] 257 | [ValidateSet('Block', 'Allow', 'DeferToUser','DeferToApp')] 258 | [string] 259 | $EdgeTraversalPolicy = 'Block', 260 | [parameter()] 261 | [ValidateSet('True','False')] 262 | [string] 263 | $Enabled = 'True', 264 | [parameter()] 265 | [ValidateSet('NotRequired','Required','Dynamic')] 266 | [string] 267 | $Encryption = 'NotRequired', 268 | [parameter()] 269 | [string[]] 270 | $IcmpType = 'Any', 271 | [parameter()] 272 | [string[]] 273 | $InterfaceAlias, 274 | [parameter()] 275 | [ValidateSet('Any','Wired','Wireless', 'RemoteAccess')] 276 | [string] 277 | $InterfaceType, 278 | [parameter()] 279 | [string[]] 280 | $LocalAddress, 281 | [parameter()] 282 | [string[]] 283 | $LocalPort, 284 | [parameter()] 285 | [string] 286 | $LocalUser, 287 | [parameter()] 288 | [ValidateSet('Any', 'Domain','Private','Public', 'NotApplicable')] 289 | [string] 290 | $Profile, 291 | [parameter()] 292 | [string] 293 | $Program, 294 | [parameter()] 295 | [string] 296 | $Protocol, 297 | [parameter()] 298 | [string[]] 299 | $RemoteAddress, 300 | [parameter()] 301 | [string] 302 | $RemoteMachine, 303 | [parameter()] 304 | [string] 305 | $RemoteUser, 306 | [parameter()] 307 | [string] 308 | $Service 309 | ) 310 | $Rule = Get-NetFirewallRule -DisplayName $DisplayName -ErrorAction SilentlyContinue | 311 | ForEach-Object { 312 | New-Object PSObject -Property @{ 313 | SourceRule = $_ 314 | AddressFilter = $_ | Get-NetFirewallAddressFilter 315 | ApplicationFilter = $_ | Get-NetFirewallApplicationFilter 316 | InterfaceFilter = $_ | Get-NetFirewallInterfaceFilter 317 | InterfaceTypeFilter = $_ | Get-NetFirewallInterfaceTypeFilter 318 | PortFilter = $_ | Get-NetFirewallPortFilter 319 | SecurityFilter = $_ | Get-NetFirewallSecurityFilter 320 | ServiceFilter = $_ | Get-NetFirewallServiceFilter 321 | } 322 | } 323 | 324 | $ConfigMatches = $true 325 | if ($Ensure -like 'Present') 326 | { 327 | if ($Rule) 328 | { 329 | $ConfigMatches = $ConfigMatches -and ($Rule.SourceRule.Action -like $Action) 330 | $ConfigMatches = $ConfigMatches -and ($Rule.SourceRule.Description -like $Description) 331 | $ConfigMatches = $ConfigMatches -and ($Rule.SourceRule.Direction -like $Direction) 332 | $ConfigMatches = $ConfigMatches -and ($Rule.SourceRule.EdgeTraversalPolicy -like $EdgeTraversalPolicy) 333 | $ConfigMatches = $ConfigMatches -and ($Rule.SourceRule.Enabled -like $Enabled) 334 | 335 | if ($DynamicTransport) 336 | { 337 | $ConfigMatches = $ConfigMatches -and ($Rule.SourceRule.DynamicTransport -like $DynamicTransport) 338 | } 339 | if ($LocalPort) 340 | { 341 | $ConfigMatches = $ConfigMatches -and ($Rule.PortFilter.LocalPort -like $LocalPort) 342 | $ConfigMatches = $ConfigMatches -and ($Rule.PortFilter.Protocol -like $Protocol) 343 | } 344 | if ($LocalAddress) 345 | { 346 | $ConfigMatches = $ConfigMatches -and ($Rule.AddressFilter.LocalAddress -like $LocalAddress) 347 | } 348 | if ($RemoteAddress) 349 | { 350 | $ConfigMatches = $ConfigMatches -and ($Rule.AddressFilter.RemoteAddress -like $RemoteAddress) 351 | } 352 | if ($Program) 353 | { 354 | $ConfigMatches = $ConfigMatches -and ($Rule.ApplicationFilter.Program -like $Program) 355 | } 356 | 357 | if ($ConfigMatches) 358 | { 359 | Write-Verbose "$DisplayName is present and valid." 360 | } 361 | else 362 | { 363 | Write-Verbose "$DisplayName is not present or not valid." 364 | } 365 | } 366 | else 367 | { 368 | Write-Verbose "$DisplayName is not present or not valid." 369 | $ConfigMatches = $false 370 | } 371 | } 372 | else 373 | { 374 | if ($rule) 375 | { 376 | Write-Verbose "$DisplayName is present and not valid." 377 | $ConfigMatches = $false 378 | } 379 | Write-Verbose "$DisplayName is not present and valid." 380 | } 381 | 382 | return $ConfigMatches 383 | } 384 | 385 | 386 | 387 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_FirewallRule/StackExchange_FirewallRule.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("FirewallRule")] 2 | class StackExchange_FirewallRule : OMI_BaseResource 3 | { 4 | [Key] string DisplayName; 5 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 6 | [write,ValueMap{"Allow", "Block"},Values{"Allow", "Block"}] string Action; 7 | [write] string Description; 8 | [write,ValueMap{"Inbound", "Outbound"},Values{"Inbound", "Outbound"}] string Direction; 9 | [write,ValueMap{"Any", "ProximityApps", "ProximitySharing"},Values{"Any", "ProximityApps", "ProximitySharing"}] string DynamicTransport; 10 | [write,ValueMap{"Block", "Allow", "DeferToUser", "DeferToApp"},Values{"Block", "Allow", "DeferToUser", "DeferToApp"}] string EdgeTraversalPolicy; 11 | [write,ValueMap{"True", "False"},Values{"True", "False"}] string Enabled; 12 | [write,ValueMap{"NotRequired", "Required", "Dynamic"},Values{"NotRequired", "Required", "Dynamic"}] string Encryption; 13 | [write] string IcmpType[]; 14 | [write] string InterfaceAlias[]; 15 | [write,ValueMap{"Any", "Wired", "Wireless", "RemoteAccess"},Values{"Any", "Wired", "Wireless", "RemoteAccess"}] string InterfaceType; 16 | [write] string LocalAddress[]; 17 | [write] string LocalPort[]; 18 | [write] string LocalUser; 19 | [write,ValueMap{"Any", "Domain", "Private", "Public", "NotApplicable"},Values{"Any", "Domain", "Private", "Public", "NotApplicable"}] string Profile; 20 | [write] string Program; 21 | [write] string Protocol; 22 | [write] string RemoteAddress[]; 23 | [write] string RemoteMachine; 24 | [write] string RemoteUser; 25 | [write] string Service; 26 | }; 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_NetworkAdapter/StackExchange_NetworkAdapter.Tests.ps1: -------------------------------------------------------------------------------- 1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.ps1", ".psm1") 3 | $pathtosut = join-path $here $sut 4 | 5 | iex ( gc $pathtosut -Raw ) 6 | 7 | #region Set-TargetResource 8 | Describe 'how Set-TargetResource with Ensure = Absent responds' { 9 | $TargetResourceParams = @{ 10 | Name = 'MyAdapter' 11 | Description = 'MyDescribedAdapter' 12 | Ensure = 'Absent' 13 | } 14 | 15 | Context 'when network adapter is named correctly and not in a team. ' { 16 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {$true} 17 | Mock -verifiable -commandName Rename-NetAdapterWithWait -mockWith {} 18 | Mock -verifiable -commandName Remove-MismatchedNetLbfoTeamMember -mockWith {} 19 | Mock -verifiable -commandName Get-NetAdapter -mockWith { 20 | return ([pscustomobject]@{Name = 'MyAdapter'}) 21 | } 22 | 23 | $result = Set-TargetResource @TargetResourceParams 24 | 25 | It 'should call Test-NetAdapterName' { 26 | Assert-MockCalled -commandName Test-NetAdapterName -times 1 -Exactly 27 | } 28 | It 'should call Rename-NetAdapterWithWait once, to rename to a temporary name' { 29 | Assert-MockCalled -commandName Rename-NetAdapterWithWait -times 1 -Exactly -parameterFilter { 30 | ($NewName -like 'Temp-*') -and ($Name -like $TargetResourceParams['Name']) 31 | } 32 | Assert-MockCalled -commandName Rename-NetAdapterWithWait -times 0 -Exactly -parameterFilter { 33 | $NewName -like $TargetResourceParams['Name'] 34 | } 35 | } 36 | It 'should call Remove-MismatchedNetLbfoTeamMember once, with MyAdapter as the name' { 37 | Assert-MockCalled -commandName Remove-MismatchedNetLbfoTeamMember -times 1 -Exactly -parameterFilter { 38 | $Name -like 'MyAdapter' 39 | } 40 | } 41 | } 42 | Context 'when network adapter is not named correctly and the name is not in use and it is not in a team. ' { 43 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {$false} 44 | Mock -verifiable -commandName Rename-NetAdapterWithWait -mockWith {} 45 | Mock -verifiable -commandName Remove-MismatchedNetLbfoTeamMember -mockWith {} 46 | Mock -verifiable -commandName Get-NetAdapter -mockWith { 47 | return ([pscustomobject]@{Name = 'SomeOtherName'}) 48 | } 49 | 50 | $result = Set-TargetResource @TargetResourceParams 51 | 52 | It 'should call Test-NetAdapterName' { 53 | Assert-MockCalled -commandName Test-NetAdapterName -times 1 -Exactly 54 | } 55 | It 'should not call Rename-NetAdapterWithWait' { 56 | Assert-MockCalled -commandName Rename-NetAdapterWithWait -times 0 -Exactly 57 | } 58 | It 'should call Remove-MismatchedNetLbfoTeamMember once, with SomeOtherName as the name' { 59 | Assert-MockCalled -commandName Remove-MismatchedNetLbfoTeamMember -times 1 -Exactly -parameterFilter { 60 | $Name -like 'SomeOtherName' 61 | } 62 | } 63 | } 64 | } 65 | Describe 'how Set-TargetResource with Ensure = Present responds' { 66 | $TargetResourceParams = @{ 67 | Name = 'MyAdapter' 68 | Description = 'MyDescribedAdapter' 69 | Ensure = 'Present' 70 | } 71 | 72 | Context 'when network adapter is named correctly and not in a team. ' { 73 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {$true} 74 | Mock -verifiable -commandName Rename-NetAdapterWithWait -mockWith {} 75 | 76 | $result = Set-TargetResource @TargetResourceParams 77 | 78 | It 'should call Test-NetAdapterName' { 79 | Assert-MockCalled -commandName Test-NetAdapterName -times 1 -Exactly 80 | } 81 | It 'should not call Rename-NetAdapterWithWait' { 82 | Assert-MockCalled -commandName Rename-NetAdapterWithWait -times 0 -Exactly 83 | } 84 | } 85 | Context 'when network adapter is not named correctly and the name is not in use and it is not in a team. ' { 86 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {$false} 87 | Mock -verifiable -commandName Rename-NetAdapterWithWait -mockWith {} 88 | Mock -verifiable -commandName Get-NetAdapter -mockWith { 89 | return ([pscustomobject]@{Name = 'SomeOtherName'}) 90 | } 91 | 92 | $result = Set-TargetResource @TargetResourceParams 93 | 94 | It 'should call Test-NetAdapterName' { 95 | Assert-MockCalled -commandName Test-NetAdapterName -times 1 -Exactly 96 | } 97 | It 'should call Rename-NetAdapterWithWait once for the desired name' { 98 | Assert-MockCalled -commandName Rename-NetAdapterWithWait -times 1 -Exactly -parameterFilter { 99 | $NewName -like $TargetResourceParams['Name'] 100 | } 101 | } 102 | } 103 | Context 'when network adapter is named correctly and it is not in a team. ' { 104 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {$true} 105 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {$true} 106 | Mock -verifiable -commandName Remove-MismatchedNetLbfoTeamMember -mockWith {} 107 | Mock -verifiable -commandName New-NetLbfoTeamMember -mockWith {} 108 | 109 | $result = Set-TargetResource @TargetResourceParams 110 | 111 | It 'should call Test-NetAdapterName and Test-NetAdapterTeamMembership' { 112 | Assert-MockCalled -commandName Test-NetAdapterName -times 1 -Exactly 113 | Assert-MockCalled -commandName Test-NetAdapterTeamMembership -times 1 -Exactly 114 | } 115 | It 'should not call Clear-MismatchedNetLbfoTeamMember and New-NetLbfoTeamMember' { 116 | Assert-MockCalled -commandName Remove-MismatchedNetLbfoTeamMember -times 0 -Exactly 117 | Assert-MockCalled -commandName New-NetLbfoTeamMember -times 0 -Exactly 118 | } 119 | } 120 | Context 'when network adapter is named correctly and is added to a team. ' { 121 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {$true} 122 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {$false} 123 | Mock -verifiable -commandName Remove-MismatchedNetLbfoTeamMember -mockWith {} 124 | Mock -verifiable -commandName New-NetLbfoTeamMember -mockWith {} 125 | 126 | $result = Set-TargetResource @TargetResourceParams 127 | 128 | It 'should call Test-NetAdapterName and Test-NetAdapterTeamMembership' { 129 | Assert-MockCalled -commandName Test-NetAdapterName -times 1 -Exactly 130 | Assert-MockCalled -commandName Test-NetAdapterTeamMembership -times 1 -Exactly 131 | } 132 | It 'should call Clear-MismatchedNetLbfoTeamMember and New-NetLbfoTeamMember once each' { 133 | Assert-MockCalled -commandName Remove-MismatchedNetLbfoTeamMember -times 1 -Exactly 134 | Assert-MockCalled -commandName New-NetLbfoTeamMember -times 1 -Exactly 135 | } 136 | } 137 | } 138 | #endregion 139 | 140 | #region Test-TargetResource 141 | Describe 'how Test-TargetResource responds with Ensure = Present' { 142 | $TargetResourceParams = @{ 143 | Name = 'MyAdapter' 144 | Description = 'MyDescribedAdapter' 145 | Ensure = 'Present' 146 | } 147 | Context 'when adapter is exists and is named correctly ' { 148 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {return $true} 149 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {return $true} 150 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 151 | 152 | $result = Test-TargetResource @TargetResourceParams 153 | 154 | It "should call all the mocks" { 155 | Assert-VerifiableMocks 156 | } 157 | It 'should return true' { 158 | $result | should be ($true) 159 | } 160 | } 161 | Context 'when adapter is exists and is not named correctly ' { 162 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {return $true} 163 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {return $false} 164 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 165 | 166 | $result = Test-TargetResource @TargetResourceParams 167 | 168 | It "should call all the mocks" { 169 | Assert-VerifiableMocks 170 | } 171 | It 'should return false' { 172 | $result | should be ($false) 173 | } 174 | } 175 | Context 'when adapter is does not exist ' { 176 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {throw 'No Adapter'} 177 | Mock -commandName Test-NetAdapterName -mockWith {return $false} 178 | Mock -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 179 | 180 | $result = $false 181 | try 182 | { 183 | Test-TargetResource @TargetResourceParams 184 | } 185 | catch 186 | { 187 | $result = $true 188 | } 189 | 190 | It "should call all the mocks" { 191 | Assert-VerifiableMocks 192 | } 193 | It 'should return throw an error' { 194 | $result | should be ($true) 195 | } 196 | } 197 | Context 'when adapter is exists, is named correctly, and not in a team ' { 198 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {return $true} 199 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {return $false} 200 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 201 | 202 | $result = Test-TargetResource @TargetResourceParams 203 | 204 | It "should call all the mocks" { 205 | Assert-VerifiableMocks 206 | } 207 | It 'should return false' { 208 | $result | should be ($false) 209 | } 210 | } 211 | } 212 | 213 | Describe 'how Test-TargetResource responds with Ensure = Absent' { 214 | $TargetResourceParams = @{ 215 | Name = 'MyAdapter' 216 | Description = 'MyDescribedAdapter' 217 | Ensure = 'Absent' 218 | } 219 | Context 'when adapter is exists and is named correctly ' { 220 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {return $true} 221 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {return $true} 222 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 223 | 224 | $result = Test-TargetResource @TargetResourceParams 225 | 226 | It "should call all the mocks" { 227 | Assert-VerifiableMocks 228 | } 229 | It 'should return false' { 230 | $result | should be ($false) 231 | } 232 | } 233 | Context 'when adapter is exists and is not named correctly ' { 234 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {return $true} 235 | Mock -verifiable -commandName Test-NetAdapterName -mockWith {return $false} 236 | Mock -verifiable -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 237 | 238 | $result = Test-TargetResource @TargetResourceParams 239 | 240 | It "should call all the mocks" { 241 | Assert-VerifiableMocks 242 | } 243 | It 'should return true' { 244 | $result | should be ($true) 245 | } 246 | } 247 | Context 'when adapter is does not exist ' { 248 | Mock -verifiable -commandName Test-NetAdapterExists -mockWith {throw 'No Adapter'} 249 | Mock -commandName Test-NetAdapterName -mockWith {return $false} 250 | Mock -commandName Test-NetAdapterTeamMembership -mockWith {return $true} 251 | 252 | $result = $false 253 | try 254 | { 255 | Test-TargetResource @TargetResourceParams 256 | } 257 | catch 258 | { 259 | $result = $true 260 | } 261 | 262 | It "should call all the mocks" { 263 | Assert-VerifiableMocks 264 | } 265 | It 'should thow an error' { 266 | $result | should be ($true) 267 | } 268 | } 269 | } 270 | 271 | #endregion 272 | 273 | #region Test-NetAdapterName 274 | Describe 'how Test-NetAdapterName responds' { 275 | Context 'when adapter is in named correctly' { 276 | Mock -verifiable -commandName Get-NetAdapter -mockWith { 277 | return ([pscustomobject]@{InterfaceDescription = 'MyAdapter'}) 278 | } 279 | 280 | $result = Test-NetAdapterName -Name 'Adapter' -Description 'MyAdapter' 281 | 282 | It "should call all the mocks" { 283 | Assert-VerifiableMocks 284 | } 285 | It 'should return true' { 286 | $result | should be ($true) 287 | } 288 | } 289 | 290 | Context 'when wrong adapter has the name' { 291 | Mock -verifiable -commandName Get-NetAdapter -mockWith { 292 | return ([pscustomobject]@{InterfaceDescription = 'MyOtherAdapter'}) 293 | } 294 | 295 | $result = Test-NetAdapterName -Name 'Adapter' -Description 'MyAdapter' 296 | 297 | It "should call all the mocks" { 298 | Assert-VerifiableMocks 299 | } 300 | It 'should return false' { 301 | $result | should be ($false) 302 | } 303 | } 304 | 305 | Context 'when the adapter name is not present' { 306 | Mock -verifiable -commandName Get-NetAdapter -mockWith {} 307 | 308 | $result = Test-NetAdapterName -Name 'Adapter' -Description 'MyAdapter' 309 | 310 | It "should call all the mocks" { 311 | Assert-VerifiableMocks 312 | } 313 | It 'should return false' { 314 | $result | should be ($false) 315 | } 316 | } 317 | } 318 | #endregion 319 | 320 | #region Test-NetAdapterTeamMembership 321 | Describe 'how Test-NetAdapterTeamMembership responds' { 322 | Context 'when adapter is in team' { 323 | Mock -commandName Get-NetLbfoTeamMember -mockWith { 324 | return ([pscustomobject]@{Team = 'MyTeam'}) 325 | } 326 | 327 | $result = Test-NetAdapterTeamMembership -TeamName 'MyTeam' -Name 'Something' 328 | 329 | It "should call all the mocks" { 330 | Assert-VerifiableMocks 331 | } 332 | It 'should be true' { 333 | $result | Should Be ($true) 334 | } 335 | } 336 | 337 | Context 'when adapter is in team and should not be' { 338 | Mock -commandName Get-NetLbfoTeamMember -mockWith { 339 | return ([pscustomobject]@{Team = 'MyOtherTeam'}) 340 | } 341 | 342 | $result = Test-NetAdapterTeamMembership -TeamName 'MyTeam' -Name 'Something' 343 | 344 | It "should call all the mocks" { 345 | Assert-VerifiableMocks 346 | } 347 | It 'should be false' { 348 | $result | Should Be ($false) 349 | } 350 | } 351 | 352 | Context 'when TeamName is empty' { 353 | 354 | $result = Test-NetAdapterTeamMembership -TeamName '' 355 | 356 | It 'should be true' { 357 | $result | Should Be ($true) 358 | } 359 | } 360 | 361 | Context 'when TeamName Does Not Exist' { 362 | Mock -verifiable -commandName Get-NetLbfoTeamMember -mockWith {} 363 | 364 | $result = Test-NetAdapterTeamMembership -TeamName 'NoTeamHere' 365 | 366 | It "should call all the mocks" { 367 | Assert-VerifiableMocks 368 | } 369 | It 'should be false' { 370 | $result | should be ($false) 371 | } 372 | } 373 | } 374 | #endregion 375 | 376 | #region Remove-MismatchedNetLbfoTeamMember 377 | Describe 'how Remove-MismatchedNetLbfoTeamMember responds' { 378 | 379 | Context 'when adapter exists in desired team ' { 380 | Mock -commandName Remove-NetLbfoTeamMember -mockWith {} 381 | Mock -commandName Remove-NetLbfoTeam -mockWith {} 382 | Mock -commandName Get-NetLbfoTeamMember -mockWith { 383 | return ([pscustomobject]@{Name = 'MyAdapter';Team = 'MyTeam'}) 384 | } 385 | 386 | Remove-MismatchedNetLbfoTeamMember -Name 'MyAdapter' -Team 'MyTeam' 387 | 388 | It "should not call Remove-NetLbfoTeamMember or Remove-NetLbfoTeam" { 389 | Assert-MockCalled -commandName Remove-NetLbfoTeamMember -times 0 -Exactly 390 | Assert-MockCalled -commandName Remove-NetLbfoTeam -times 0 -Exactly 391 | } 392 | } 393 | Context 'when adapter exists in desired team but RemoveFromAll is specfied' { 394 | Mock -commandName Remove-NetLbfoTeamMember -mockWith {} 395 | Mock -commandName Remove-NetLbfoTeam -mockWith {} 396 | Mock -commandName Get-NetLbfoTeamMember -mockWith { 397 | return ([pscustomobject]@{Name = 'MyAdapter';Team = 'MyTeam'}) 398 | } 399 | 400 | Remove-MismatchedNetLbfoTeamMember -Name 'MyAdapter' -Team 'MyTeam' -RemoveFromAll 401 | 402 | It "should call Remove-NetLbfoTeamMember and not Remove-NetLbfoTeam" { 403 | Assert-MockCalled -commandName Remove-NetLbfoTeamMember -times 1 -Exactly 404 | Assert-MockCalled -commandName Remove-NetLbfoTeam -times 0 -Exactly 405 | } 406 | } 407 | Context 'when adapter exists in different team and is only Nic in that team.' { 408 | Mock -commandName Remove-NetLbfoTeamMember -mockWith { throw 'not me' } 409 | Mock -commandName Remove-NetLbfoTeam -mockWith {} 410 | Mock -commandName Get-NetLbfoTeamMember -mockWith { 411 | return ([pscustomobject]@{Name = 'MyAdapter';Team = 'MyOtherTeam'}) 412 | } 413 | 414 | Remove-MismatchedNetLbfoTeamMember -Name 'MyAdapter' -Team 'MyTeam' 415 | 416 | It "should call Remove-NetLbfoTeamMember, error, and Remove-NetLbfoTeam" { 417 | Assert-MockCalled -commandName Remove-NetLbfoTeamMember -times 1 -Exactly 418 | Assert-MockCalled -commandName Remove-NetLbfoTeam -times 1 -Exactly -parameterFilter { 419 | $Name -like 'MyOtherTeam' 420 | } 421 | } 422 | } 423 | } 424 | #endregion 425 | 426 | #region New-NetLbfoTeamMember 427 | Describe 'how New-NetLbfoTeamMember responds' { 428 | Context 'when the team exists' { 429 | Mock -commandName Get-NetLbfoTeam -mockWith { return 1} 430 | Mock -commandName Add-NetLbfoTeamMember -mockWith {} 431 | Mock -commandName New-NetLbfoTeam -mockWith {} 432 | 433 | New-NetLbfoTeamMember -Name 'MyAdapter' -TeamName 'MyTeam' 434 | 435 | It 'should call Add-NetLbfoTeamMember and not New-NetLbfoTeam' { 436 | Assert-MockCalled -commandName Add-NetLbfoTeamMember -times 1 -Exactly 437 | Assert-MockCalled -commandName New-NetLbfoTeam -times 0 -Exactly 438 | } 439 | } 440 | Context 'when the team does not exist' { 441 | Mock -commandName Get-NetLbfoTeam -mockWith {} 442 | Mock -commandName Add-NetLbfoTeamMember -mockWith {} 443 | Mock -commandName New-NetLbfoTeam -mockWith {} 444 | 445 | New-NetLbfoTeamMember -Name 'MyAdapter' -TeamName 'MyTeam' 446 | 447 | It 'should call New-NetLbfoTeam and not Add-NetLbfoTeamMember' { 448 | Assert-MockCalled -commandName Add-NetLbfoTeamMember -times 0 -Exactly 449 | Assert-MockCalled -commandName New-NetLbfoTeam -times 1 -Exactly 450 | } 451 | } 452 | } 453 | #endregion 454 | 455 | 456 | 457 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_NetworkAdapter/StackExchange_NetworkAdapter.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'NetworkAdapter' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/13/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_NetworkAdapter.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.7' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = 'ee710f4c-f5d8-48d8-9677-9e36a40850dd' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Test-TargetResource', 'Set-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_NetworkAdapter/StackExchange_NetworkAdapter.psm1: -------------------------------------------------------------------------------- 1 | 2 | 3 | function Get-TargetResource 4 | { 5 | [OutputType([Hashtable])] 6 | param ( 7 | [parameter(Mandatory = $true)] 8 | [ValidateNotNullOrEmpty()] 9 | [string] 10 | $Name, 11 | [parameter(Mandatory = $true)] 12 | [ValidateNotNullOrEmpty()] 13 | [string] 14 | $Description, 15 | [parameter()] 16 | [ValidateNotNullOrEmpty()] 17 | [string] 18 | $TeamName, 19 | [parameter()] 20 | [ValidateSet('Present','Absent')] 21 | [string] 22 | $Ensure = 'Present' 23 | ) 24 | 25 | #Needs to return a hashtable that returns the current 26 | #status of the configuration component 27 | $Adapter = Get-NetAdapter -InterfaceDescription $Description 28 | if (($Adapter.Name -like $Name) -and ($Adapter.InterfaceDescription -like $Description)) 29 | { 30 | $Ensure = 'Present' 31 | } 32 | else 33 | { 34 | $Ensure = 'Absent' 35 | } 36 | 37 | $Configuration = @{ 38 | Name = $Name 39 | Ensure = $Ensure 40 | Description = $Description 41 | } 42 | 43 | return $Configuration 44 | } 45 | 46 | function Set-TargetResource 47 | { 48 | param ( 49 | [parameter(Mandatory = $true)] 50 | [ValidateNotNullOrEmpty()] 51 | [string] 52 | $Name, 53 | [parameter(Mandatory = $true)] 54 | [ValidateNotNullOrEmpty()] 55 | [string] 56 | $Description, 57 | [parameter()] 58 | [ValidateNotNullOrEmpty()] 59 | [string] 60 | $TeamName, 61 | [parameter()] 62 | [ValidateSet('Present','Absent')] 63 | [string] 64 | $Ensure = 'Present' 65 | ) 66 | if ($Ensure -like 'Present') 67 | { 68 | if (Test-NetAdapterName -Name $Name -Description $Description) 69 | { 70 | Write-Verbose "Adapter with $Description already named Correctly." 71 | } 72 | else 73 | { 74 | Write-Verbose "If the adapter name is already used, rename it to a temporary name." 75 | Rename-NetAdapterWithWait -Name $Name -NewName "Temp-$(Get-Random -min 1 -max 100)" 76 | Write-Verbose "Rename the network adapter." 77 | Rename-NetAdapterWithWait -Name (Get-NetAdapter -InterfaceDescription $Description).Name -NewName $Name 78 | } 79 | 80 | if (Test-NetAdapterTeamMembership -Name $Name -TeamName $TeamName) 81 | { 82 | Write-Verbose "Network adapter is correctly configured for teaming." 83 | } 84 | else 85 | { 86 | Remove-MismatchedNetLbfoTeamMember -TeamName $TeamName -Name $Name 87 | New-NetLbfoTeamMember -TeamName $TeamName -Name $Name 88 | } 89 | } 90 | else 91 | { 92 | if (Test-NetAdapterName -Name $Name -Description $Description) 93 | { 94 | Write-Verbose "Adapter should not be named $Name." 95 | Write-Verbose "renaming it to a temporary name." 96 | Rename-NetAdapterWithWait -Name $Name -NewName "Temp-$(Get-Random -min 1 -max 100)" 97 | } 98 | else 99 | { 100 | Write-Verbose "Adapter with description $Description is not named $Name." 101 | } 102 | Write-Verbose "Clearing team membership." 103 | Remove-MismatchedNetLbfoTeamMember -TeamName $TeamName -Name (Get-NetAdapter -InterfaceDescription $Description).Name -RemoveFromAll 104 | } 105 | } 106 | 107 | function Test-TargetResource 108 | { 109 | [OutputType([boolean])] 110 | param ( 111 | [parameter(Mandatory = $true)] 112 | [ValidateNotNullOrEmpty()] 113 | [string] 114 | $Name, 115 | [parameter(Mandatory = $true)] 116 | [ValidateNotNullOrEmpty()] 117 | [string] 118 | $Description, 119 | [parameter()] 120 | [ValidateNotNullOrEmpty()] 121 | [string] 122 | $TeamName = '', 123 | [parameter()] 124 | [ValidateSet('Present','Absent')] 125 | [string] 126 | $Ensure = 'Present' 127 | ) 128 | $IsValid = $true 129 | Write-Verbose "Checking if network adapter with $Description exists." 130 | $IsValid = (Test-NetAdapterExists -Description $Description) -and $IsValid 131 | Write-Verbose "Checking if network adapter is named correctly." 132 | $IsValid = (Test-NetAdapterName -Name $Name -Description $Description) -and $IsValid 133 | Write-Verbose "Checking if network adapter is teamed correctly." 134 | $IsValid = (Test-NetAdapterTeamMembership -TeamName $TeamName -Name $Name) -and $IsValid 135 | 136 | 137 | if ($Ensure -like 'Absent') 138 | { 139 | Write-Verbose "Adapter $Description should not have $Name." 140 | $IsValid = -not $IsValid 141 | } 142 | 143 | Write-Verbose "Network adapter status is" 144 | return $IsValid 145 | } 146 | 147 | #region Support Functions 148 | function Test-NetAdapterExists 149 | { 150 | [cmdletbinding()] 151 | param ( 152 | [string]$Description 153 | ) 154 | if (Get-NetAdapter -InterfaceDescription $Description) 155 | { 156 | Write-Verbose "Network adapter with $Description exists." 157 | return $true 158 | } 159 | else 160 | { 161 | throw "No adapter matching that description." 162 | } 163 | 164 | } 165 | 166 | function Test-NetAdapterName 167 | { 168 | [cmdletbinding()] 169 | param ( 170 | [string]$Name, 171 | [string]$Description 172 | ) 173 | $Adapter = Get-NetAdapter -Name $Name -ErrorAction SilentlyContinue 174 | 175 | if ( $Adapter | Where-Object {$_.InterfaceDescription -like $Description} ) 176 | { 177 | Write-Verbose "The Name $Name is already used by the right adapter." 178 | return $true 179 | } 180 | elseif ( $Adapter | Where-Object {$_.InterfaceDescription -notlike $Description} ) 181 | { 182 | Write-Verbose "The Name $Name is already being used by another adapter." 183 | return $false 184 | } 185 | else 186 | { 187 | Write-Verbose "The Name $Name is not in use " 188 | return $false 189 | } 190 | } 191 | 192 | function Test-NetAdapterState 193 | { 194 | param ( 195 | [string]$State, 196 | [switch]$Up, 197 | [switch]$Disconnected, 198 | [switch]$Disabled 199 | ) 200 | 201 | $ValidStates = @() 202 | if ($Up) 203 | { 204 | $ValidStates += 'Up' 205 | } 206 | if ($Disabled) 207 | { 208 | $ValidStates += 'Disabled' 209 | } 210 | if ($Disconnected) 211 | { 212 | $ValidStates += 'Disconnected' 213 | } 214 | 215 | $OFS = ', ' 216 | Write-Verbose "Valid states are $ValidStates." 217 | Write-Verbose "Current state is $state." 218 | return ($ValidStates -contains $State) 219 | 220 | } 221 | 222 | function Test-NetAdapterTeamMembership 223 | { 224 | [cmdletbinding()] 225 | param ([string]$Name, [string]$TeamName) 226 | 227 | Write-Verbose "Testing if $Name is present in NIC Team - $TeamName" 228 | $IsValid = $true 229 | $ShouldBeOnTeam = -not [string]::IsNullOrEmpty($TeamName) 230 | 231 | Write-Verbose "Checking for NIC to be present in $TeamName" 232 | $TeamMember = Get-NetLbfoTeamMember -Name $Name -ErrorAction SilentlyContinue 233 | 234 | if ($TeamMember -and $ShouldBeOnTeam) 235 | { 236 | Write-Verbose "NIC $Name is in a team - $($TeamMember.Team)." 237 | $IsValid = ($TeamMember.Team -like $TeamName) -and $IsValid 238 | } 239 | elseif ($ShouldBeOnTeam) 240 | { 241 | Write-Verbose "$Name is not in a team." 242 | $IsValid = $IsValid -and $false 243 | } 244 | elseif ($TeamMember -and (-not $ShouldBeOnTeam)) 245 | { 246 | Write-Verbose "$Name is in a team and should not be." 247 | $IsValid = $IsValid -and $false 248 | } 249 | else 250 | { 251 | Write-Verbose "$Name is not in a team and should not be." 252 | } 253 | 254 | return $IsValid 255 | } 256 | 257 | function Remove-MismatchedNetLbfoTeamMember 258 | { 259 | [cmdletbinding()] 260 | param ( 261 | [string]$Name, 262 | [string]$TeamName, 263 | [switch]$RemoveFromAll 264 | ) 265 | 266 | Get-NetLbfoTeamMember -Name $Name -ErrorAction SilentlyContinue | 267 | Where-Object { if ($RemoveFromAll) {$true} else {$_.Team -notlike $TeamName} } | 268 | ForEach-Object { 269 | $TeamMember = $_ 270 | try 271 | { 272 | Write-Verbose "Removing $Name from team $($TeamMember.team)." 273 | Remove-NetLbfoTeamMember -Name $TeamMember.name -Team $TeamMember.Team -Confirm:$false -ErrorAction Stop 274 | } 275 | catch 276 | { 277 | Write-Verbose "Failed to remove $Name from team $($TeamMember.team)." 278 | Write-Verbose "Removing team $($TeamMember.Team)." 279 | Remove-NetLbfoTeam -Name $TeamMember.Team -Confirm:$false 280 | } 281 | } 282 | } 283 | 284 | function New-NetLbfoTeamMember 285 | { 286 | [cmdletbinding()] 287 | param ( 288 | [string]$Name, 289 | [string]$TeamName 290 | ) 291 | 292 | Write-Verbose "Checking for NIC Team - $TeamName" 293 | if (Get-NetLBFOTeam -Name $TeamName -ErrorAction SilentlyContinue) 294 | { 295 | Write-Verbose "Adding NIC $Name to team $teamname." 296 | Add-NetLbfoTeamMember -Team $TeamName -Name $Name -Confirm:$false 297 | } 298 | else 299 | { 300 | Write-Verbose "Team $TeamName does not exist. Creating team with $Name." 301 | $TeamParameters = @{ 302 | LoadBalancingAlgorithm = 'TransportPorts' 303 | Name = $TeamName 304 | TeamNicName = $TeamName 305 | TeamingMode = 'SwitchIndependent' 306 | TeamMembers = $Name 307 | Confirm = $false 308 | } 309 | New-NetLbfoTeam @TeamParameters 310 | } 311 | 312 | 313 | } 314 | 315 | function Rename-NetAdapterWithWait 316 | { 317 | [cmdletbinding()] 318 | param ( 319 | $Name, 320 | $NewName 321 | ) 322 | 323 | Get-NetAdapter -Name $Name -ErrorAction SilentlyContinue | 324 | Rename-NetAdapter -NewName $NewName -Confirm:$false | 325 | ForEach-Object { 326 | while ( -not (Get-NetAdapter -Name $NewName -ErrorAction SilentlyContinue) ) 327 | { 328 | Write-Verbose "Waiting for rename of improperly named NIC to take effect." 329 | Start-Sleep -Seconds 2 330 | } 331 | Write-Verbose "Improperly named NIC has been renamed." 332 | } 333 | } 334 | #endregion 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_NetworkAdapter/StackExchange_NetworkAdapter.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0"), FriendlyName("NetworkAdapter")] 2 | class StackExchange_NetworkAdapter : OMI_BaseResource 3 | { 4 | [Key] string Name; 5 | [Key] string Description; 6 | [write] string TeamName; 7 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 8 | }; 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_Pagefile.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'Pagefile' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/13/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_Pagefile.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.7' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '6328017a-8ac3-424d-90e3-ca3299fdaa8a' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Test-TargetResource', 'Set-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_Pagefile.psm1: -------------------------------------------------------------------------------- 1 | 2 | # Fallback message strings in en-US 3 | DATA localizedData 4 | { 5 | # same as culture = "en-US" 6 | ConvertFrom-StringData @' 7 | AutomaticPageFileConfigured=The page file is set to automatic configuration. 8 | PageFileStaticallyConfigured=The page file is statically configured with the initial size of {0} and a maximum size of {1}. 9 | DisabledAutomaticPageFile=The automatic page file configuration is disabled. 10 | RebootRequired=A reboot is required to finalize the changes to the page file. 11 | InitialSizeDifferent=Configured Initial Size {0} different than Desired size {1}. 12 | MaximumSizeDifferent=Configured Maximum Size {0} different than Desired size {1}. 13 | '@ 14 | } 15 | 16 | if (Test-Path $PSScriptRoot\en-us) 17 | { 18 | Import-LocalizedData LocalizedData -filename PagefileProvider.psd1 19 | } 20 | 21 | function Get-TargetResource 22 | { 23 | [OutputType([Hashtable])] 24 | param ( 25 | [parameter(Mandatory = $true)] 26 | [long] 27 | $InitialSize, 28 | [parameter(Mandatory = $true)] 29 | [long] 30 | $MaximumSize, 31 | [parameter()] 32 | [ValidateSet('Present','Absent')] 33 | [string] 34 | $Ensure = 'Present' 35 | ) 36 | 37 | #Needs to return a hashtable that returns the current 38 | #status of the configuration component 39 | $ComputerSystem = Get-WmiObject win32_computersystem 40 | if ($ComputerSystem.AutomaticManagedPageFile) 41 | { 42 | Write-Verbose $LocalizedData.AutomaticPageFileConfigured 43 | $Configuration = @{ 44 | Ensure = 'Absent' 45 | } 46 | } 47 | else 48 | { 49 | $PageFileSetting = Get-WmiObject Win32_PageFileSetting 50 | $Configuration = @{ 51 | Ensure = 'Present' 52 | InitialSize = $PageFileSetting.InitialSize * 1mb 53 | MaximumSize = $PageFileSetting.MaximumSize * 1mb 54 | } 55 | 56 | Write-Verbose ($LocalizedData.PageFileStaticallyConfigured -f $Configuration.InitialSize, $Configuration.MaximumSize) 57 | } 58 | return $Configuration 59 | } 60 | 61 | function Set-TargetResource 62 | { 63 | param ( 64 | [parameter(Mandatory = $true)] 65 | [long] 66 | $InitialSize, 67 | [parameter(Mandatory = $true)] 68 | [long] 69 | $MaximumSize, 70 | [parameter()] 71 | [ValidateSet('Present','Absent')] 72 | [string] 73 | $Ensure = 'Present' 74 | ) 75 | $ComputerSystem = Get-WmiObject win32_computersystem 76 | 77 | if ($ComputerSystem.AutomaticManagedPageFile) 78 | { 79 | if ($Ensure -like 'Present') 80 | { 81 | Write-Verbose $LocalizedData.AutomaticPageFileConfigured 82 | $ComputerSystem.AutomaticManagedPageFile = $false 83 | $ComputerSystem.Put() | Out-Null 84 | Write-Verbose $LocalizedData.DisabledAutomaticPageFile 85 | } 86 | else 87 | { 88 | Write-Verbose "Nothing to configure here." 89 | } 90 | } 91 | else 92 | { 93 | if ($Ensure -like 'Present') 94 | { 95 | $PageFileSetting = Get-WmiObject Win32_PageFileSetting 96 | $PageFileSetting.InitialSize = $InitialSize / 1MB 97 | $PageFileSetting.MaximumSize = $MaximumSize / 1MB 98 | $PageFileSetting.put() | Out-Null 99 | 100 | Write-Verbose ($LocalizedData.PageFileStaticallyConfigured -f $InitialSize, $MaximumSize) 101 | } 102 | else 103 | { 104 | $ComputerSystem.AutomaticManagedPageFile = $true 105 | $ComputerSystem.Put() | Out-Null 106 | Write-Verbose $LocalizedData.AutomaticPageFileConfigured 107 | } 108 | } 109 | 110 | Write-Verbose $LocalizedData.RebootRequired 111 | $global:DSCMachineStatus = 1 112 | } 113 | 114 | function Test-TargetResource 115 | { 116 | [OutputType([boolean])] 117 | param ( 118 | [parameter(Mandatory = $true)] 119 | [long] 120 | $InitialSize, 121 | [parameter(Mandatory = $true)] 122 | [long] 123 | $MaximumSize, 124 | [parameter()] 125 | [ValidateSet('Present','Absent')] 126 | [string] 127 | $Ensure = 'Present' 128 | ) 129 | 130 | $Valid = $true 131 | $ComputerSystem = Get-WmiObject win32_computersystem 132 | $PageFileSetting = Get-WmiObject Win32_PageFileSetting 133 | 134 | if ($Ensure -like 'Present') 135 | { 136 | 137 | if ($ComputerSystem.AutomaticManagedPageFile) 138 | { 139 | Write-Verbose $LocalizedData.AutomaticPageFileConfigured 140 | $Valid = $Valid -and $false 141 | } 142 | 143 | 144 | if ($PageFileSetting -ne $null) 145 | { 146 | if (-not ($PageFileSetting.InitialSize -eq ($InitialSize / 1MB))) 147 | { 148 | Write-Verbose ($LocalizedData.InitialSizeDifferent -f ($PageFileSetting.InitialSize * 1mb), $InitialSize) 149 | $Valid = $Valid -and $false 150 | } 151 | 152 | if (-not ($PageFileSetting.MaximumSize -eq ($MaximumSize / 1MB))) 153 | { 154 | Write-Verbose ($LocalizedData.MaximumSizeDifferent -f ($PageFileSetting.MaximumSize * 1mb), $MaximumSize) 155 | $Valid = $Valid -and $false 156 | } 157 | } 158 | } 159 | else 160 | { 161 | if (-not $ComputerSystem.AutomaticManagedPageFile) 162 | { 163 | Write-Verbose $LocalizedData.DisabledAutomaticPageFile 164 | $Valid = $Valid -and $false 165 | } 166 | } 167 | 168 | #Needs to return a boolean 169 | return $valid 170 | } 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_Pagefile.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("Pagefile")] 2 | class StackExchange_Pagefile : OMI_BaseResource 3 | { 4 | [Key] sint64 InitialSize; 5 | [Key] sint64 MaximumSize; 6 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 7 | }; 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_en-US/StackExchange_PagefileProvider.psd1: -------------------------------------------------------------------------------- 1 | # Localized PagefileProvider.psd1 2 | 3 | ConvertFrom-StringData @' 4 | ###PSLOC 5 | AutomaticPageFileConfigured=The page file is set to automatic configuration. 6 | PageFileStaticallyConfigured=The page file is statically configured with the initial size of {0} and a maximum size of {1}. 7 | DisabledAutomaticPageFile=The automatic page file configuration is disabled. 8 | RebootRequired=A reboot is required to finalize the changes to the page file. 9 | InitialSizeDifferent=Configured Initial Size {0} different than Desired size {1}. 10 | MaximumSizeDifferent=Configured Maximum Size {0} different than Desired size {1}. 11 | ###PSLOC 12 | '@ 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_en-US/StackExchange_about_PageFile_Resource.help.txt: -------------------------------------------------------------------------------- 1 | Syntax 2 | 3 | Pagefile [string] #ResourceName 4 | { 5 | InitialSize = [long] 6 | MaximumSize = [long] 7 | [ Ensure = [string] { Absent | Present } ] 8 | } 9 | 10 | Properties 11 | 12 | InitialSize - The minimum size for the machine's page file, in bytes. 13 | MaximumSize - The maximum size for the machine's page file, in bytes. 14 | Ensure - Set this property to "Present" to disable automatic page file and set the minimum and maximum sizes for the page file. Set this file to "Absent" to enable automatic page file management. Values are required for Initial and Maximum size, but they will be ignored when Ensure is set to "Absent". 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_nl-NL/StackExchange_PagefileProvider.psd1: -------------------------------------------------------------------------------- 1 | # Localized PagefileProvider.psd1 2 | 3 | ConvertFrom-StringData @' 4 | ###PSLOC 5 | AutomaticPageFileConfigured=De automatische instelling van het wisselbestand is ingeschakeld. 6 | PageFileStaticallyConfigured=Het wisselbestand is statisch geconfigureerd met een startgrootte van {0} en een maximale grootte van {1} 7 | DisabledAutomaticPageFile=De automatische instelling van het wisselbestand is uitgeschakeld. 8 | RebootRequired=Een herstart is vereist om de wijzigingen aan het wisselbestand af te ronden. 9 | InitialSizeDifferent=Geconfigureerde startgrootte {0} wijkt af van de gewenste grootte {1}. 10 | MaximumSizeDifferent=Geconfigureerde maximal grootte {0} wijkt af van de gewenste grootte {1}. 11 | ###PSLOC 12 | '@ 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Pagefile/StackExchange_nl-NL/StackExchange_about_PageFile_Resource.help.txt: -------------------------------------------------------------------------------- 1 | Syntax 2 | 3 | Pagefile [string] #ResourceName 4 | { 5 | InitialSize = [long] 6 | MaximumSize = [long] 7 | [ Ensure = [string] { Absent | Present } ] 8 | } 9 | 10 | Properties 11 | 12 | InitialSize - De startgrootte voor het wisselbestand in bytes. 13 | MaximumSize - De maximale grootte voor het wisselbestand in bytes. 14 | Ensure - Stel deze waarde in op "Present" om de automatische configuratie van het wisselbestand uit te schakelen. Hierna kunt u een startgrootte en een maximale grootte opgeven. Stel deze waarde in op "Absent" om de grootte van het wisselbestand automatisch in te stellen. Waardes voor "Initial" en "Maximum" zijn verplicht maar deze worden genegeerd wanneer Ensure is ingesteld op "Absent". 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_PowerPlan/StackExchange_PowerPlan.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PowerPlan' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/13/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_PowerPlan.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.7' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '8c9f080b-f7e6-456b-92cb-12aeba980eaa' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Test-TargetResource', 'Set-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_PowerPlan/StackExchange_PowerPlan.psm1: -------------------------------------------------------------------------------- 1 | $CIMParameters = @{ 2 | Namespace = 'root\cimv2\power' 3 | Class = 'Win32_PowerPlan' 4 | } 5 | 6 | DATA localizedData 7 | { 8 | # same as culture = "en-US" 9 | ConvertFrom-StringData @' 10 | ElementName=Adding filter for Element Name of {0} 11 | FilterText=Adding the filter text ({0}) to the query. 12 | IsActiveFilter=Adding filter for IsActive = True 13 | NoFilterCriteria=No filter criteria. Making sure nothing is hanging around. 14 | Cruft=Found some cruft. Removing. 15 | MatchingActivePowerPlan=Found a matching active powerplan. 16 | NoMatchingActivePowerPlan=Did not a matching active powerplan. 17 | SettingActivePowerPlan=Setting active Power Plan to {0} 18 | CurrentPowerPlan=Current Power Plan is set to {0}. 19 | CheckingForActivePowerPlan=Checking for an active powerplan called {0}. 20 | ActivePlanNotSetTo=The active Power Plan is not set to {0}. 21 | ActivePlanSetTo=The active Power Plan is set to {0}. All good here. 22 | ActivePlanSetToAndShouldNotBe=The active Power Plan is set to {0}, and should not be. 23 | ActivePlanNotSetToAndShouldNotBe=The active Power Plan is not set to {0}, and should not be. All good here. 24 | '@ 25 | } 26 | 27 | if (Test-Path $PSScriptRoot\en-us) 28 | { 29 | Import-LocalizedData LocalizedData -filename PowerPlanProvider.psd1 30 | } 31 | 32 | 33 | function Get-TargetResource 34 | { 35 | [OutputType([Hashtable])] 36 | param ( 37 | [parameter(Mandatory = $true)] 38 | [string] 39 | $Name, 40 | [parameter()] 41 | [ValidateSet('Present','Absent')] 42 | [string] 43 | $Ensure = 'Present' 44 | ) 45 | 46 | $powerplan = Get-CIMPowerPlan -name $Name -active 47 | 48 | $Configuration = @{ 49 | Name = $Name 50 | } 51 | 52 | If ($PowerPlan) 53 | { 54 | #Needs to return a hashtable that returns the current 55 | #status of the configuration component 56 | Write-Verbose $LocalizedData.MatchingActivePowerPlan 57 | $Configuration.Ensure = 'Present' 58 | } 59 | else 60 | { 61 | Write-Verbose $LocalizedData.NoMatchingActivePowerPlan 62 | $Configuration.Ensure = 'Absent' 63 | } 64 | return $Configuration 65 | } 66 | 67 | function Set-TargetResource 68 | { 69 | param ( 70 | [parameter(Mandatory = $true)] 71 | [string] 72 | $Name, 73 | [parameter()] 74 | [ValidateSet('Present','Absent')] 75 | [string] 76 | $Ensure = 'Present' 77 | ) 78 | 79 | if ($Ensure -like 'Present') 80 | { 81 | Set-CIMPowerPlan -name $Name 82 | } 83 | else 84 | { 85 | Write-Verbose ($localizedData.CurrentPowerPlan -f $Name) 86 | switch ($Name) 87 | { 88 | 'Balanced' { Set-CimPowerPlan -name 'High Performance' } 89 | default { Set-CimPowerPlan -name 'Balanced' } 90 | } 91 | } 92 | 93 | } 94 | 95 | function Test-TargetResource 96 | { 97 | [OutputType([boolean])] 98 | param ( 99 | [parameter(Mandatory = $true)] 100 | [string] 101 | $Name, 102 | [parameter()] 103 | [ValidateSet('Present','Absent')] 104 | [string] 105 | $Ensure = 'Present' 106 | ) 107 | 108 | $Valid = $true 109 | 110 | Write-Verbose ($LocalizedData.CheckingForActivePowerPlan -f $Name) 111 | $PowerPlan = Get-CIMPowerPlan -active -name $Name 112 | 113 | if ($Ensure -like 'Present') 114 | { 115 | if ( $PowerPlan -eq $null ) 116 | { 117 | Write-Verbose ($LocalizedData.ActivePlanNotSetTo -f $Name) 118 | $Valid = $false 119 | } 120 | else 121 | { 122 | Write-Verbose ($LocalizedData.ActivePlanSetTo -f $Name) 123 | } 124 | } 125 | else 126 | { 127 | if ( $PowerPlan -ne $null ) 128 | { 129 | Write-Verbose ($LocalizedData.ActivePlanSetToAndShouldNotBe -f $Name) 130 | $Valid = $false 131 | } 132 | else 133 | { 134 | Write-Verbose ($LocalizedData.ActivePlanNotSetToAndShouldNotBe -f $Name) 135 | } 136 | } 137 | return $valid 138 | } 139 | 140 | Function Get-CIMPowerPlan 141 | { 142 | param ([string]$name, [switch]$active) 143 | 144 | $FilterText = '' 145 | if (-not [string]::IsNullOrEmpty($name)) 146 | { 147 | if (-not [string]::IsNullOrEmpty($FilterText)) 148 | { 149 | $FilterText += ' and ' 150 | } 151 | Write-Debug ($LocalizedData.ElementName -f $Name) 152 | $FilterText += "ElementName like '$Name'" 153 | } 154 | if ($active) 155 | { 156 | if (-not [string]::IsNullOrEmpty($FilterText)) 157 | { 158 | $FilterText += ' and ' 159 | } 160 | Write-Debug $LocalizedData.IsActiveFilter 161 | $FilterText += "IsActive = 'True'" 162 | } 163 | 164 | if ([string]::IsNullOrEmpty($FilterText)) 165 | { 166 | Write-Debug $LocalizedData.NoFilterCriteria 167 | if ($CIMParameters.ContainsKey('Filter')) 168 | { 169 | Write-Debug $LocalizedData.Cruft 170 | $CIMParameters.Remove('Filter') | Out-Null 171 | } 172 | } 173 | else 174 | { 175 | Write-Debug ($LocalizedData.FilterText -f $FilterText) 176 | $CIMParameters.Filter = $FilterText 177 | } 178 | 179 | Get-CimInstance @CIMParameters 180 | 181 | } 182 | 183 | function Set-CIMPowerPlan 184 | { 185 | param ($name) 186 | 187 | Write-Verbose ($LocalizedData.SettingActivePowerPlan -f $Name) 188 | 189 | Get-CIMPowerPlan -name $name | 190 | Invoke-CimMethod -MethodName Activate 191 | } 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_PowerPlan/StackExchange_PowerPlan.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("PowerPlan")] 2 | class StackExchange_PowerPlan : OMI_BaseResource 3 | { 4 | [Key] string Name; 5 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 6 | }; 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_PowerPlan/StackExchange_en-US/StackExchange_PowerPlanProvider.psd1: -------------------------------------------------------------------------------- 1 | 2 | ConvertFrom-StringData @' 3 | ###PSLOC 4 | ElementName=Adding filter for Element Name of {0} 5 | FilterText=Adding the filter text ({0}) to the query. 6 | IsActiveFilter=Adding filter for IsActive = True 7 | NoFilterCriteria=No filter criteria. Making sure nothing is hanging around. 8 | Cruft=Found some cruft. Removing. 9 | MatchingActivePowerPlan=Found a matching active powerplan. 10 | NoMatchingActivePowerPlan=Did not a matching active powerplan. 11 | SettingActivePowerPlan=Setting active Power Plan to {0} 12 | CurrentPowerPlan=Current Power Plan is set to {0}. 13 | CheckingForActivePowerPlan=Checking for an active powerplan called {0}. 14 | ActivePlanNotSetTo=The active Power Plan is not set to {0}. 15 | ActivePlanSetTo=The active Power Plan is set to {0}. All good here. 16 | ActivePlanSetToAndShouldNotBe=The active Power Plan is set to {0}, and should not be. 17 | ActivePlanNotSetToAndShouldNotBe=The active Power Plan is not set to {0}, and should not be. All good here. 18 | ###PSLOC 19 | '@ 20 | 21 | 22 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_PowerPlan/StackExchange_en-US/StackExchange_about_PowerPlan_Resource.txt: -------------------------------------------------------------------------------- 1 | Syntax 2 | 3 | PowerPlan [string] #ResourceName 4 | { 5 | Name = [string] 6 | [ Ensure = [string] { Absent | Present } ] 7 | } 8 | 9 | Properties 10 | 11 | Name - Name of the PowerPlan. Common plans are "Balanced", "High performance", and "Power saver". 12 | Ensure - Set this property to "Present" to activate the desired Power Plan. Set this property to "Absent" to return to "Balanced" from other plans (if it is already set to "Balanced", it'll set it to "High performance"). 13 | 14 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_ScheduledTask/StackExchange_ScheduledTask.Tests.ps1: -------------------------------------------------------------------------------- 1 | $here = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.ps1", ".psm1") 3 | $pathtosut = join-path $here $sut 4 | 5 | iex (gc $pathtosut -Raw) 6 | 7 | Describe 'how Test-JobFilePath responds' { 8 | Context 'when the file path is correct' { 9 | $script:TargetResource = [pscustomobject]@{ 10 | FilePath = 'c:\scripts\test.ps1' 11 | Job = [pscustomobject]@{ 12 | Command = 'c:\scripts\test.ps1' 13 | } 14 | IsValid = $true 15 | } 16 | 17 | Test-JobFilePath 18 | it 'should return true' { 19 | $script:TargetResource.IsValid | should be $true 20 | } 21 | } 22 | 23 | Context 'when the file path is correct' { 24 | $script:TargetResource = [pscustomobject]@{ 25 | FilePath = 'c:\scripts\test.ps1' 26 | Job = [pscustomobject]@{ 27 | Command = 'c:\scripts\nottest.ps1 ' 28 | } 29 | IsValid = $true 30 | } 31 | 32 | Test-JobFilePath 33 | it 'should return false' { 34 | $script:TargetResource.IsValid | should be $false 35 | } 36 | } 37 | } 38 | 39 | Describe 'how Test-JobTriggerAtTime responds' { 40 | Context 'when job At time matches configured At time' { 41 | $script:TargetResource = [pscustomobject]@{ 42 | At = '1/1/2014' 43 | Job = [pscustomobject]@{ 44 | JobTriggers = @( 45 | [pscustomobject]@{ 46 | At = [pscustomobject]@{ 47 | Value = [datetime]::Parse('1/1/2014') 48 | HasValue = $true 49 | } 50 | } 51 | ) 52 | } 53 | IsValid = $true 54 | } 55 | 56 | Test-JobTriggerAtTime 57 | 58 | It 'should return true ' { 59 | $script:TargetResource.IsValid | should be ($true) 60 | } 61 | } 62 | 63 | Context 'when job At time does not match configured At time' { 64 | $script:TargetResource = [pscustomobject]@{ 65 | At = '1/1/2014' 66 | Job = [pscustomobject]@{ 67 | JobTriggers = @( 68 | [pscustomobject]@{ 69 | At = [pscustomobject]@{ 70 | Value = [datetime]::Parse('2/1/2014') 71 | HasValue = $true 72 | } 73 | } 74 | ) 75 | } 76 | IsValid = $true 77 | } 78 | 79 | Test-JobTriggerAtTime 80 | 81 | It 'should return false ' { 82 | $script:TargetResource.IsValid | should be ($false) 83 | } 84 | } 85 | } 86 | 87 | Describe 'how Test-JobFrequency responds' { 88 | context 'when job frequency is once and the requested frequency is once' { 89 | $script:TargetResource = [pscustomobject]@{ 90 | Once = $true 91 | Job = [pscustomobject]@{ 92 | JobTriggers = @( 93 | [pscustomobject]@{ 94 | Frequency = 'once' 95 | } 96 | ) 97 | } 98 | IsValid = $true 99 | } 100 | Test-JobFrequency 101 | it 'should be true' { 102 | $script:TargetResource.IsValid | should be $true 103 | } 104 | } 105 | 106 | context 'when job frequency is once and the requested frequency is daily' { 107 | $script:TargetResource = [pscustomobject]@{ 108 | Daily = $true 109 | Job = [pscustomobject]@{ 110 | JobTriggers = @( 111 | [pscustomobject]@{ 112 | Frequency = 'once' 113 | } 114 | ) 115 | } 116 | IsValid = $true 117 | } 118 | Test-JobFrequency 119 | it 'should be false' { 120 | $script:TargetResource.IsValid | should be $false 121 | } 122 | } 123 | 124 | context 'when job frequency is once and the requested frequency is weekly' { 125 | $script:TargetResource = [pscustomobject]@{ 126 | Weekly = $true 127 | Job = [pscustomobject]@{ 128 | JobTriggers = @( 129 | [pscustomobject]@{ 130 | Frequency = 'once' 131 | } 132 | ) 133 | } 134 | IsValid = $true 135 | } 136 | Test-JobFrequency 137 | it 'should be false' { 138 | $script:TargetResource.IsValid | should be $false 139 | } 140 | } 141 | 142 | context 'when job frequency is daily and the requested frequency is once' { 143 | $script:TargetResource = [pscustomobject]@{ 144 | Once = $true 145 | Job = [pscustomobject]@{ 146 | JobTriggers = @( 147 | [pscustomobject]@{ 148 | Frequency = 'Daily' 149 | } 150 | ) 151 | } 152 | IsValid = $true 153 | } 154 | Test-JobFrequency 155 | it 'should be false' { 156 | $script:TargetResource.IsValid | should be $false 157 | } 158 | } 159 | 160 | context 'when job frequency is daily and the requested frequency is daily' { 161 | $script:TargetResource = [pscustomobject]@{ 162 | Daily = $true 163 | Job = [pscustomobject]@{ 164 | JobTriggers = @( 165 | [pscustomobject]@{ 166 | Frequency = 'Daily' 167 | } 168 | ) 169 | } 170 | IsValid = $true 171 | } 172 | Test-JobFrequency 173 | it 'should be true' { 174 | $script:TargetResource.IsValid | should be $true 175 | } 176 | } 177 | 178 | context 'when job frequency is daily and the requested frequency is weekly' { 179 | $script:TargetResource = [pscustomobject]@{ 180 | Weekly = $true 181 | Job = [pscustomobject]@{ 182 | JobTriggers = @( 183 | [pscustomobject]@{ 184 | Frequency = 'Daily' 185 | } 186 | ) 187 | } 188 | IsValid = $true 189 | } 190 | Test-JobFrequency 191 | it 'should be false' { 192 | $script:TargetResource.IsValid | should be $false 193 | } 194 | } 195 | 196 | context 'when job frequency is weekly and the requested frequency is once' { 197 | $script:TargetResource = [pscustomobject]@{ 198 | Once = $true 199 | Job = [pscustomobject]@{ 200 | JobTriggers = @( 201 | [pscustomobject]@{ 202 | Frequency = 'Weekly' 203 | } 204 | ) 205 | } 206 | IsValid = $true 207 | } 208 | Test-JobFrequency 209 | it 'should be false' { 210 | $script:TargetResource.IsValid | should be $false 211 | } 212 | } 213 | 214 | context 'when job frequency is weekly and the requested frequency is daily' { 215 | $script:TargetResource = [pscustomobject]@{ 216 | Daily = $true 217 | Job = [pscustomobject]@{ 218 | JobTriggers = @( 219 | [pscustomobject]@{ 220 | Frequency = 'Weekly' 221 | } 222 | ) 223 | } 224 | IsValid = $true 225 | } 226 | Test-JobFrequency 227 | it 'should be false' { 228 | $script:TargetResource.IsValid | should be $false 229 | } 230 | } 231 | 232 | context 'when job frequency is weekly and the requested frequency is weekly' { 233 | $script:TargetResource = [pscustomobject]@{ 234 | Weekly = $true 235 | Job = [pscustomobject]@{ 236 | JobTriggers = @( 237 | [pscustomobject]@{ 238 | Frequency = 'Weekly' 239 | } 240 | ) 241 | } 242 | IsValid = $true 243 | } 244 | Test-JobFrequency 245 | it 'should be true' { 246 | $script:TargetResource.IsValid | should be $true 247 | } 248 | } 249 | } 250 | 251 | Describe 'how Test-OnceJobTrigger responds' { 252 | 253 | Context 'when job frequency is Once and set to repeat every hour and a half.' { 254 | $script:TargetResource = [pscustomobject]@{ 255 | Once = $true 256 | Hours = 1 257 | Minutes = 30 258 | Job = [pscustomobject]@{ 259 | JobTriggers = @( 260 | [pscustomobject]@{ 261 | Frequency = 'Once' 262 | RepetitionInterval = [pscustomobject]@{ 263 | Value = [pscustomobject]@{ 264 | Hours = 1 265 | Minutes = 30 266 | } 267 | HasValue = $true 268 | } 269 | } 270 | ) 271 | } 272 | IsValid = $true 273 | } 274 | 275 | Test-OnceJobTrigger 276 | 277 | It 'should return true' { 278 | $script:TargetResource.IsValid | should be ($true) 279 | } 280 | } 281 | 282 | Context 'when job frequency is Once and set to repeat every hour and a half but should be every two hours' { 283 | $script:TargetResource = [pscustomobject]@{ 284 | Once = $true 285 | Hours = 2 286 | Minutes = 0 287 | Job = [pscustomobject]@{ 288 | JobTriggers = @( 289 | [pscustomobject]@{ 290 | Frequency = 'Once' 291 | RepetitionInterval = [pscustomobject]@{ 292 | Value = [pscustomobject]@{ 293 | Hours = 1 294 | Minutes = 30 295 | } 296 | HasValue = $true 297 | } 298 | } 299 | ) 300 | } 301 | IsValid = $true 302 | } 303 | 304 | Test-OnceJobTrigger 305 | 306 | It 'should return false' { 307 | $script:TargetResource.IsValid | should be ($false) 308 | } 309 | } 310 | 311 | Context 'when job frequency is Once and repetition interval is null' { 312 | $script:TargetResource = [pscustomobject]@{ 313 | Once = $true 314 | Hours = 2 315 | Minutes = 0 316 | Job = [pscustomobject]@{ 317 | JobTriggers = @( 318 | [pscustomobject]@{ 319 | Frequency = 'Once' 320 | RepetitionInterval = [pscustomobject]@{ 321 | Value = $null 322 | HasValue = $false 323 | } 324 | } 325 | ) 326 | } 327 | IsValid = $true 328 | } 329 | 330 | Test-OnceJobTrigger 331 | 332 | It 'should return false' { 333 | $script:TargetResource.IsValid | should be ($false) 334 | } 335 | } 336 | } 337 | 338 | Describe 'how Test-DailyJobTrigger responds' { 339 | Context 'when job frequency is Daily and should have an interval of 1' { 340 | $script:TargetResource = [pscustomobject]@{ 341 | Daily = $true 342 | DaysInterval = 1 343 | Job = [pscustomobject]@{ 344 | JobTriggers = @( 345 | [pscustomobject]@{ 346 | Frequency = 'Daily' 347 | Interval = 1 348 | } 349 | ) 350 | } 351 | IsValid = $true 352 | } 353 | 354 | Test-DailyJobTrigger 355 | 356 | It 'should return true ' { 357 | $script:TargetResource.IsValid | should be ($true) 358 | } 359 | } 360 | 361 | Context 'when job frequency is Daily with an interval of 1 and should have an interval of 2' { 362 | $script:TargetResource = [pscustomobject]@{ 363 | Daily = $true 364 | DaysInterval = 2 365 | Job = [pscustomobject]@{ 366 | JobTriggers = @( 367 | [pscustomobject]@{ 368 | Frequency = 'Daily' 369 | Interval = 1 370 | } 371 | ) 372 | } 373 | IsValid = $true 374 | } 375 | 376 | Test-DailyJobTrigger 377 | 378 | It 'should return false ' { 379 | $script:TargetResource.IsValid | should be ($false) 380 | } 381 | } 382 | } 383 | 384 | Describe 'how Test-WeeklyJobTrigger responds' { 385 | 386 | Context 'when job frequency is Weekly with days of the week should be Weekly with days of week ' { 387 | $script:TargetResource = [pscustomobject]@{ 388 | Weekly = $true 389 | DaysOfWeek = 'Monday', 'Wednesday', 'Friday' 390 | Job = [pscustomobject]@{ 391 | JobTriggers = @( 392 | [pscustomobject]@{ 393 | Frequency = 'Weekly' 394 | DaysOfWeek = 'Monday', 'Wednesday', 'Friday' 395 | } 396 | ) 397 | } 398 | IsValid = $true 399 | } 400 | 401 | Test-WeeklyJobTrigger 402 | 403 | It 'should return true ' { 404 | $script:TargetResource.IsValid | should be ($true) 405 | } 406 | } 407 | 408 | Context 'when job frequency is Weekly with days of week, but should be Weekly ' { 409 | $script:TargetResource = [pscustomobject]@{ 410 | Weekly = $true 411 | DaysOfWeek = [string[]]@() 412 | Job = [pscustomobject]@{ 413 | JobTriggers = @( 414 | [pscustomobject]@{ 415 | Frequency = 'Weekly' 416 | DaysOfWeek = 'Monday', 'Wednesday', 'Friday' 417 | } 418 | ) 419 | } 420 | IsValid = $true 421 | } 422 | 423 | Test-WeeklyJobTrigger 424 | 425 | It 'should return false ' { 426 | $script:TargetResource.IsValid | should be ($false) 427 | } 428 | } 429 | } 430 | 431 | Describe 'how Test-TargetResource responds' { 432 | Context 'when the job does not exist ' { 433 | Mock -commandName Get-ScheduledJob -mockWith {$null} 434 | 435 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -Once $true -Hours 1 -Minutes 1 436 | 437 | It "should call all the mocks" { 438 | Assert-MockCalled -commandName Get-ScheduledJob -times 1 -Exactly 439 | } 440 | It 'should be false' { 441 | $result | should be ($false) 442 | } 443 | } 444 | 445 | Context 'when the job exists but should not ' { 446 | Mock -commandName Get-ScheduledJob -mockWith { 447 | return ([pscustomobject]@{ 448 | FilePath = 'c:\scripts\test2.ps1' 449 | }) 450 | } 451 | 452 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -Once $true -Hours 1 -Minutes 1 -Ensure Absent 453 | 454 | It "should call Get-ScheduledJob" { 455 | Assert-MockCalled -commandName Get-ScheduledJob -times 1 -Exactly 456 | } 457 | It 'should be false' { 458 | $result | should be ($false) 459 | } 460 | } 461 | 462 | Context 'when the job exists, but the file path is wrong ' { 463 | Mock -commandName Get-ScheduledJob -mockWith { 464 | return ([pscustomobject]@{ 465 | Command = 'c:\scripts\test.ps1' 466 | JobTriggers = ,([pscustomobject]@{ 467 | Frequency = 'Once' 468 | RepetitionInterval = [pscustomobject]@{ 469 | Value = [pscustomobject]@{ 470 | Hours = 1 471 | Minutes = 30 472 | } 473 | HasValue = $true 474 | } 475 | }) 476 | }) 477 | } 478 | 479 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -Once $true -Hours 1 -Minutes 1 480 | 481 | It 'should be false ' { 482 | $result | should be ($false) 483 | } 484 | } 485 | 486 | Context 'when the job exits exist, and is configured to repeat every hour and a half ' { 487 | 488 | Mock -commandName Get-ScheduledJob -mockWith { 489 | return ([pscustomobject]@{ 490 | Command = 'c:\scripts\test.ps1' 491 | JobTriggers = ,([pscustomobject]@{ 492 | Frequency = 'Once' 493 | RepetitionInterval = [pscustomobject]@{ 494 | Value = [pscustomobject]@{ 495 | Hours = 1 496 | Minutes = 30 497 | } 498 | HasValue = $true 499 | } 500 | }) 501 | }) 502 | } 503 | 504 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -Once $true -Hours 1 -Minutes 30 -At '1/1/2014' 505 | 506 | It 'should be true ' { 507 | $result | should be ($true) 508 | } 509 | } 510 | 511 | Context 'when the job exists, and is configured to repeat every hour and a half ' { 512 | 513 | Mock -commandName Get-ScheduledJob -mockWith { 514 | return ([pscustomobject]@{ 515 | Command = 'c:\scripts\test.ps1' 516 | JobTriggers = ,([pscustomobject]@{ 517 | Frequency = 'Once' 518 | RepetitionInterval = [pscustomobject]@{ 519 | Value = [pscustomobject]@{ 520 | Hours = 1 521 | Minutes = 30 522 | } 523 | HasValue = $true 524 | } 525 | }) 526 | }) 527 | } 528 | 529 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -Once $true -Hours 1 -Minutes 30 -At '1/1/2014' 530 | 531 | It 'should be true ' { 532 | $result | should be ($true) 533 | } 534 | } 535 | 536 | Context 'when the job exists, and is configured to repeat every hour and a half but should be weekly ' { 537 | 538 | Mock -commandName Get-ScheduledJob -mockWith { 539 | return ([pscustomobject]@{ 540 | Command = 'c:\scripts\test.ps1' 541 | JobTriggers = ,([pscustomobject]@{ 542 | Frequency = 'Once' 543 | RepetitionInterval = [pscustomobject]@{ 544 | Value = [pscustomobject]@{ 545 | Hours = 1 546 | Minutes = 30 547 | } 548 | HasValue = $true 549 | } 550 | }) 551 | }) 552 | } 553 | 554 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -weekly $true 555 | It 'should be false ' { 556 | $result | should be ($false) 557 | } 558 | } 559 | 560 | Context 'when the job exists, but should not ' { 561 | Mock -commandName Get-ScheduledJob -mockWith { 562 | return ([pscustomobject]@{ 563 | Command = 'c:\scripts\test.ps1' 564 | JobTriggers = ,([pscustomobject]@{ 565 | Frequency = 'Once' 566 | RepetitionInterval = [pscustomobject]@{ 567 | Value = [pscustomobject]@{ 568 | Hours = 1 569 | Minutes = 30 570 | } 571 | HasValue = $true 572 | } 573 | }) 574 | }) 575 | } 576 | 577 | $result = Test-TargetResource -Name Test -FilePath c:\scripts\test.ps1 -Ensure Absent 578 | 579 | It 'should be false ' { 580 | $result | should be ($false) 581 | } 582 | } 583 | } 584 | 585 | <# 586 | Describe 'how Set-TargetResource responds' { 587 | Context 'when ' { 588 | $expected = '' 589 | $result = '' 590 | 591 | It "should call all the mocks" { 592 | Assert-VerifiableMocks 593 | } 594 | It 'should ' { 595 | $result | should be ($expected) 596 | } 597 | 598 | } 599 | } 600 | 601 | 602 | #> 603 | 604 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_ScheduledTask/StackExchange_ScheduledTask.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'StackExchange_ScheduledTask' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 1/24/2014 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_ScheduledTask.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.0' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '7d03a6ad-75f7-4b3c-9adb-1ae489e77877' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2014 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Set-TargetResource', 'Test-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_ScheduledTask/StackExchange_ScheduledTask.psm1: -------------------------------------------------------------------------------- 1 | 2 | 3 | function Get-TargetResource 4 | { 5 | [OutputType([Hashtable])] 6 | param ( 7 | [parameter(Mandatory = $true)] 8 | [ValidateNotNullOrEmpty()] 9 | [string] 10 | $Name, 11 | 12 | [parameter(Mandatory = $true)] 13 | [ValidateNotNullOrEmpty()] 14 | [string] 15 | $FilePath, 16 | 17 | [parameter()] 18 | [string] 19 | $At = (Get-Date), 20 | 21 | [parameter()] 22 | [int] 23 | $Hours = 0, 24 | 25 | [parameter()] 26 | [int] 27 | $Minutes = 0, 28 | 29 | [parameter()] 30 | [bool] 31 | $Once = $false, 32 | 33 | [parameter()] 34 | [int] 35 | $DaysInterval, 36 | 37 | [parameter()] 38 | [bool] 39 | $Daily = $false, 40 | 41 | [parameter()] 42 | #[ValidateSet('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')] 43 | [string[]] 44 | $DaysOfWeek, 45 | 46 | [parameter()] 47 | [bool] 48 | $Weekly = $false, 49 | 50 | [parameter()] 51 | [System.Management.Automation.PSCredential] 52 | $Credential = [System.Management.Automation.PSCredential]::Empty, 53 | 54 | [ValidateSet('Present','Absent')] 55 | [string] 56 | $Ensure = 'Present' 57 | ) 58 | 59 | $Session = new-pssession -computername $env:computername -Credential $Credential -Authentication CredSSP 60 | $Job =Invoke-Command -Session $Session { Get-ScheduledJob -Name $Name -ErrorAction SilentlyContinue } 61 | 62 | #Needs to return a hashtable that returns the current 63 | #status of the configuration component 64 | 65 | $Configuration = @{ 66 | Name = $Name 67 | } 68 | if ($Job) 69 | { 70 | $Configuration.FilePath = $Job.Command 71 | if ($Job.JobTriggers[0].At.HasValue) 72 | { 73 | $Configuration.At = $job.JobTriggers[0].At.Value.ToString() 74 | } 75 | if ($Job.JobTriggers[0].RepetitionInterval.HasValue) 76 | { 77 | $Configuration.Hours = $Job.JobTriggers[0].RepetitionInterval.Value.Hours 78 | $Configuration.Minutes = $Job.JobTriggers[0].RepetitionInterval.Value.Minutes 79 | } 80 | 81 | if ( 'Once' -like $Job.JobTriggers[0].Frequency ) 82 | { 83 | $Configuration.Once = $true 84 | } 85 | else 86 | { 87 | $Configuration.Once = $false 88 | } 89 | if ( 'Daily' -like $Job.JobTriggers[0].Frequency ) 90 | { 91 | $Configuration.Daily = $true 92 | $Configuration.DaysInterval = $Job.JobTriggers[0].Interval 93 | } 94 | else 95 | { 96 | $Configuration.Daily = $false 97 | } 98 | if ( 'Weekly' -like $Job.JobTriggers[0].Frequency ) 99 | { 100 | $Configuration.Weekly = $true 101 | [string[]]$Configuration.DaysOfWeek = $job.JobTriggers[0].DaysOfWeek 102 | } 103 | else 104 | { 105 | $Configuration.Weekly = $false 106 | } 107 | $Configuration.Ensure = 'Present' 108 | } 109 | else 110 | { 111 | $Configuration.FilePath = $FilePath 112 | $Configuration.Ensure = 'Absent' 113 | } 114 | 115 | return $Configuration 116 | } 117 | 118 | function Set-TargetResource 119 | { 120 | param ( 121 | [parameter(Mandatory = $true)] 122 | [ValidateNotNullOrEmpty()] 123 | [string] 124 | $Name, 125 | 126 | [parameter(Mandatory = $true)] 127 | [ValidateNotNullOrEmpty()] 128 | [string] 129 | $FilePath, 130 | 131 | [parameter()] 132 | [string] 133 | $At = (Get-Date), 134 | 135 | [parameter()] 136 | [int] 137 | $Hours = 0, 138 | 139 | [parameter()] 140 | [int] 141 | $Minutes = 0, 142 | 143 | [parameter()] 144 | [bool] 145 | $Once = $false, 146 | 147 | [parameter()] 148 | [int] 149 | $DaysInterval = 0, 150 | 151 | [parameter()] 152 | [bool] 153 | $Daily = $false, 154 | 155 | [parameter()] 156 | #[ValidateSet('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')] 157 | [string[]] 158 | $DaysOfWeek, 159 | 160 | [parameter()] 161 | [bool] 162 | $Weekly = $false, 163 | 164 | [parameter()] 165 | [System.Management.Automation.PSCredential] 166 | $Credential = [System.Management.Automation.PSCredential]::Empty, 167 | 168 | [ValidateSet('Present','Absent')] 169 | [string] 170 | $Ensure = 'Present' 171 | ) 172 | 173 | $Session = new-pssession -computername $env:computername -Credential $Credential 174 | 175 | $Job = Invoke-Command -Session $Session { Get-ScheduledJob -Name $Using:Name -ErrorAction SilentlyContinue } 176 | 177 | if ($Ensure -like 'Present') 178 | { 179 | 180 | $JobParameters = @{ 181 | Name = $Name 182 | FilePath = $FilePath 183 | #Credential = $credential 184 | MaxResultCount = 10 185 | } 186 | $JobTriggerParameters = @{} 187 | $JobTriggerParameters.At = $At 188 | if ($Once) 189 | { 190 | $JobTriggerParameters.Once = $true 191 | if (($Hours -gt 0) -or ($Minutes -gt 0)) 192 | { 193 | $JobTriggerParameters.RepetitionInterval = New-TimeSpan -Hours $Hours -Minutes $Minutes 194 | $JobTriggerParameters.RepetitionDuration = [timespan]::MaxValue 195 | } 196 | } 197 | elseif ($Daily) 198 | { 199 | $JobTriggerParameters.Daily = $true 200 | if ($DaysInterval -gt 0) 201 | { 202 | $JobTriggerParameters.DaysInterval = $DaysInterval 203 | } 204 | } 205 | elseif ($Weekly) 206 | { 207 | $JobTriggerParameters.Weekly = $true 208 | if ($DaysOfWeek.count -gt 0) 209 | { 210 | $JobTriggerParameters.DaysOfWeek = $DaysOfWeek 211 | } 212 | } 213 | 214 | ### If the job exists, then remove it before adding again 215 | if ($Job) 216 | { 217 | #Jobber Clobber 218 | Invoke-Command -Session $Session {Unregister-ScheduledJob -Name $Using:Name} 219 | } 220 | 221 | Invoke-Command -Session $Session { 222 | #TODO: this seems like a hacky way to do splatting, but I don't know a better way to do it 223 | $jobParameters = $using:JobParameters 224 | $jobTriggerParameters = $using:JobTriggerParameters 225 | $jobParameters.Trigger = New-JobTrigger @jobTriggerParameters 226 | Register-ScheduledJob @jobParameters -ErrorAction SilentlyContinue 227 | } 228 | } 229 | else 230 | { 231 | Write-Verbose "Job $Name removed." 232 | } 233 | 234 | } 235 | 236 | function Test-TargetResource 237 | { 238 | [OutputType([boolean])] 239 | param ( 240 | [parameter(Mandatory = $true)] 241 | [ValidateNotNullOrEmpty()] 242 | [string] 243 | $Name, 244 | 245 | [parameter(Mandatory = $true)] 246 | [ValidateNotNullOrEmpty()] 247 | [string] 248 | $FilePath, 249 | 250 | [parameter()] 251 | [string] 252 | $At = (Get-Date), 253 | 254 | [parameter()] 255 | [int] 256 | $Hours = 0, 257 | 258 | [parameter()] 259 | [int] 260 | $Minutes = 0, 261 | 262 | [parameter()] 263 | [bool] 264 | $Once = $false, 265 | 266 | [parameter()] 267 | [int] 268 | $DaysInterval, 269 | 270 | [parameter()] 271 | [bool] 272 | $Daily = $false, 273 | 274 | [parameter()] 275 | #[ValidateSet('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')] 276 | [string[]] 277 | $DaysOfWeek, 278 | 279 | [parameter()] 280 | [bool] 281 | $Weekly = $false, 282 | 283 | [parameter()] 284 | [System.Management.Automation.PSCredential] 285 | $Credential = [System.Management.Automation.PSCredential]::Empty, 286 | 287 | [ValidateSet('Present','Absent')] 288 | [string] 289 | $Ensure = 'Present' 290 | ) 291 | 292 | New-TargetResourceObject @psboundparameters 293 | 294 | if ($script:TargetResource.Ensure -like 'Present') 295 | { 296 | if ($script:TargetResource.Job) 297 | { 298 | Test-JobFilePath 299 | Test-JobTriggerAtTime 300 | Test-JobFrequency 301 | 302 | if ($script:TargetResource.Once) { 303 | Test-OnceJobTrigger 304 | } 305 | if ($script:TargetResource.Daily) { 306 | Test-DailyJobTrigger 307 | } 308 | if ($script:TargetResource.Weekly) { 309 | Test-WeeklyJobTrigger 310 | } 311 | } 312 | else 313 | { 314 | $script:TargetResource.IsValid = $false 315 | Write-Verbose "Unable to find matching job." 316 | } 317 | } 318 | else 319 | { 320 | if ($script:TargetResource.job) 321 | { 322 | $script:TargetResource.IsValid = $false 323 | Write-Verbose "Job should not be present, but is registered." 324 | } 325 | else 326 | { 327 | Write-Verbose "No job found and no job should be present." 328 | } 329 | } 330 | 331 | 332 | return $script:TargetResource.IsValid 333 | } 334 | 335 | $TargetResource = $null 336 | function New-TargetResourceObject { 337 | param ( 338 | [parameter(Mandatory = $true)] 339 | [ValidateNotNullOrEmpty()] 340 | [string] 341 | $Name, 342 | 343 | [parameter(Mandatory = $true)] 344 | [ValidateNotNullOrEmpty()] 345 | [string] 346 | $FilePath, 347 | 348 | [parameter()] 349 | [string] 350 | $At = (Get-Date), 351 | 352 | [parameter()] 353 | [int] 354 | $Hours = 0, 355 | 356 | [parameter()] 357 | [int] 358 | $Minutes = 0, 359 | 360 | [parameter()] 361 | [bool] 362 | $Once = $false, 363 | 364 | [parameter()] 365 | [int] 366 | $DaysInterval, 367 | 368 | [parameter()] 369 | [bool] 370 | $Daily = $false, 371 | 372 | [parameter()] 373 | #[ValidateSet('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')] 374 | [string[]] 375 | $DaysOfWeek, 376 | 377 | [parameter()] 378 | [bool] 379 | $Weekly = $false, 380 | 381 | [parameter()] 382 | [System.Management.Automation.PSCredential] 383 | $Credential = [System.Management.Automation.PSCredential]::Empty, 384 | 385 | [ValidateSet('Present','Absent')] 386 | [string] 387 | $Ensure = 'Present' 388 | ) 389 | if (-not $psboundparameters.containskey('At')) { 390 | $psboundparameters.Add('At', $At) 391 | } 392 | if (-not $psboundparameters.containskey('Hours')) { 393 | $psboundparameters.Add('Hours', $Hours) 394 | } 395 | if (-not $psboundparameters.containskey('Minutes')) { 396 | $psboundparameters.Add('Minutes', $Minutes) 397 | } 398 | if (-not $psboundparameters.containskey('Once')) { 399 | $psboundparameters.Add('Once', $Once) 400 | } 401 | if (-not $psboundparameters.containskey('Daily')) { 402 | $psboundparameters.Add('Daily', $Daily) 403 | } 404 | if (-not $psboundparameters.containskey('Weekly')) { 405 | $psboundparameters.Add('Weekly', $Weekly) 406 | } 407 | 408 | 409 | $Job = Get-ScheduledJob -Name $Name -ErrorAction SilentlyContinue 410 | if ($Job) { 411 | $psboundparameters.Add('Job', $Job) 412 | } 413 | if (-not $psboundparameters.containskey('Ensure')) { 414 | $psboundparameters.Add('Ensure', $Ensure) 415 | } 416 | $psboundparameters.Add('IsValid', $true) 417 | $script:TargetResource = [pscustomobject]$psboundparameters 418 | } 419 | 420 | function Remove-Job { 421 | param ( 422 | [parameter()] 423 | [string] 424 | $Name, 425 | [parameter()] 426 | [System.Management.Automation.PSCredential] 427 | $Credential = [System.Management.Automation.PSCredential]::Empty 428 | ) 429 | $Session = new-pssession -computername $env:computername -Credential $Credential -Authentication CredSSP 430 | 431 | Invoke-Command -Session $Session { 432 | $Job = Get-ScheduledJob -Name $using:Name -ErrorAction SilentlyContinue 433 | if ($Job) 434 | { 435 | $job | Unregister-ScheduledJob -Force -Confirm:$False 436 | } 437 | } 438 | } 439 | 440 | function Test-JobFilePath { 441 | [cmdletbinding()] 442 | param () 443 | 444 | if ($script:TargetResource.IsValid) { 445 | Write-Verbose "Comparing $($script:TargetResource.FilePath) to $($script:TargetResource.Job.Command)" 446 | $script:TargetResource.IsValid = $script:TargetResource.FilePath -like $script:TargetResource.Job.Command 447 | } 448 | Write-Verbose "Checking Filepath against existing command. Status is $($script:TargetResource.IsValid)." 449 | } 450 | 451 | function Test-JobTriggerAtTime { 452 | [cmdletbinding()] 453 | param () 454 | 455 | $Trigger = $script:TargetResource.job.JobTriggers[0] 456 | if ($script:TargetResource.IsValid) { 457 | if ($Trigger.At.HasValue) { 458 | $script:TargetResource.IsValid = [datetime]::Parse($script:TargetResource.At) -eq $Trigger.At.Value 459 | } 460 | else { 461 | $script:TargetResource.IsValid = $False 462 | } 463 | } 464 | Write-Verbose "Checking Job Trigger At time. Status is $($script:TargetResource.IsValid)." 465 | } 466 | 467 | function Test-JobFrequency { 468 | [cmdletbinding()] 469 | param() 470 | 471 | $Frequency = $script:TargetResource.Job.JobTriggers[0].Frequency 472 | if ($script:TargetResource.Once) { 473 | $script:TargetResource.IsValid = 'Once' -like $Frequency 474 | } 475 | if ($script:TargetResource.Daily) { 476 | $script:TargetResource.IsValid = 'Daily' -like $Frequency 477 | } 478 | if ($script:TargetResource.Weekly) { 479 | $script:TargetResource.IsValid = 'Weekly' -like $Frequency 480 | } 481 | } 482 | 483 | function Test-OnceJobTrigger { 484 | [cmdletbinding()] 485 | param () 486 | 487 | $Trigger = $script:TargetResource.Job.JobTriggers[0] 488 | if ($script:TargetResource.IsValid -and $script:TargetResource.Once) { 489 | if ($Trigger.RepetitionInterval.HasValue) { 490 | $script:TargetResource.IsValid = $script:TargetResource.Hours -eq $Trigger.RepetitionInterval.Value.Hours 491 | $script:TargetResource.IsValid = $script:TargetResource.Minutes -eq $Trigger.RepetitionInterval.Value.Minutes 492 | } 493 | else { 494 | $script:TargetResource.IsValid = $false 495 | } 496 | } 497 | Write-Verbose "Checking Job Trigger repetition is set to Once. Status is $($script:TargetResource.IsValid)." 498 | } 499 | 500 | function Test-DailyJobTrigger { 501 | [cmdletbinding()] 502 | param () 503 | 504 | $Trigger = $script:TargetResource.Job.JobTriggers[0] 505 | if ($script:TargetResource.IsValid -and $script:TargetResource.Daily) { 506 | $script:TargetResource.IsValid = $script:TargetResource.DaysInterval -eq $Trigger.Interval 507 | } 508 | Write-Verbose "Checking Job Trigger repetition is set to Daily. Status is $($script:TargetResource.IsValid)." 509 | } 510 | 511 | function Test-WeeklyJobTrigger 512 | { 513 | [cmdletbinding()] 514 | param() 515 | 516 | $Trigger = $script:TargetResource.Job.JobTriggers[0] 517 | if ($script:TargetResource.IsValid -and $script:TargetResource.Weekly) { 518 | Test-DaysOfWeekInWeeklyJobTrigger 519 | } 520 | Write-Verbose "Checking Job Trigger repetition is set to Weekly. Status is $($script:TargetResource.IsValid)." 521 | } 522 | 523 | function Test-DaysOfWeekInWeeklyJobTrigger { 524 | [cmdletbinding()] 525 | param() 526 | 527 | if ( $script:TargetResource.DaysOfWeek.Count -eq $Trigger.DaysOfWeek.count ){ 528 | if ($script:TargetResource.DaysOfWeek.count -gt 0) { 529 | foreach ($day in $Trigger.DaysOfWeek) { 530 | if (-not $script:TargetResource.IsValid) { 531 | break 532 | } 533 | $script:TargetResource.IsValid = ($script:TargetResource.DaysOfWeek -contains $day) 534 | } 535 | } 536 | } 537 | else { 538 | $script:TargetResource.IsValid = $false 539 | } 540 | } 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_ScheduledTask/StackExchange_ScheduledTask.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0"), FriendlyName("ScheduledTask")] 2 | class StackExchange_ScheduledTask : OMI_BaseResource 3 | { 4 | [Key] string Name; 5 | [Key] string FilePath; 6 | [write] string At; 7 | [write] sint32 Hours; 8 | [write] sint32 Minutes; 9 | [write] boolean Once; 10 | [write] sint32 DaysInterval; 11 | [write] boolean Daily; 12 | [write] string DaysOfWeek[]; 13 | [write] boolean Weekly; 14 | [write,EmbeddedInstance("MSFT_Credential")] string Credential; 15 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 16 | }; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_SetExecutionPolicy/StackExchange_SetExecutionPolicy.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'SetExecutionPolicy' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/13/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_SetExecutionPolicy.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.7' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '6ee60831-33c5-46ad-880d-91a9e011cfaa' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Test-TargetResource', 'Set-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_SetExecutionPolicy/StackExchange_SetExecutionPolicy.psm1: -------------------------------------------------------------------------------- 1 | # Fallback message strings in en-US 2 | DATA localizedData 3 | { 4 | # same as culture = "en-US" 5 | ConvertFrom-StringData @' 6 | CheckingCurrentExecutionPolicy=Checking for the existing execution policy. 7 | ExecutionPolicyFound=Located an execution policy of {0}. 8 | ExecutionPolicyNotFound=Did not find an execution policy of {0}. 9 | ApplyingExecutionPolicy=Starting to apply {0} as the execution policy. 10 | AppliedExecutionPolicy=Applied {0} as the execution policy. 11 | AnErrorOccurred=An error occurred trying to apply {0} as the execution policy: {1}. 12 | InnerException=Nested error trying to apply {0} as the execution policy: {1}. 13 | DoesNotApply=Absent does not apply to this configuration item. 14 | '@ 15 | } 16 | 17 | if (Test-Path $PSScriptRoot\en-us) 18 | { 19 | Import-LocalizedData LocalizedData -filename SetExecutionPolicyProvider.psd1 20 | } 21 | 22 | function Get-TargetResource 23 | { 24 | [OutputType([Hashtable])] 25 | param ( 26 | [parameter(Mandatory = $true)] 27 | [ValidateSet('Restricted', 'AllSigned', 'RemoteSigned', 'Unrestricted')] 28 | [string] 29 | $Name, 30 | [parameter()] 31 | [ValidateSet('Present','Absent')] 32 | [string] 33 | $Ensure = 'Present' 34 | ) 35 | 36 | $Configuration = @{ 37 | Name = $Name 38 | } 39 | 40 | Write-Verbose $LocalizedData.CheckingCurrentExecutionPolicy 41 | $CurrentExecutionPolicy = Get-ExecutionPolicy 42 | if ($Name -like $CurrentExecutionPolicy) 43 | { 44 | Write-Verbose ($LocalizedData.ExecutionPolicyFound -f $Name) 45 | $Configuration.Ensure = 'Present' 46 | } 47 | else 48 | { 49 | Write-Verbose ($LocalizedData.ExecutionPolicyNotFound -f $Name) 50 | $Configuration.Ensure = 'Absent' 51 | } 52 | 53 | return $Configuration 54 | } 55 | 56 | function Set-TargetResource 57 | { 58 | param ( 59 | [parameter(Mandatory = $true)] 60 | [ValidateSet('Restricted', 'AllSigned', 'RemoteSigned', 'Unrestricted')] 61 | [string] 62 | $Name, 63 | [parameter()] 64 | [ValidateSet('Present','Absent')] 65 | [string] 66 | $Ensure = 'Present' 67 | ) 68 | 69 | if ($Ensure -like 'Present') 70 | { 71 | Write-Verbose ($LocalizedData.ApplyingExecutionPolicy -f $Name) 72 | try 73 | { 74 | Set-ExecutionPolicy -ExecutionPolicy $Name -Force -ErrorAction Stop 75 | Write-Verbose ($LocalizedData.AppliedExecutionPolicy -f $Name) 76 | } 77 | catch 78 | { 79 | $exception = $_ 80 | Write-Verbose ($LocalizedData.AnErrorOccurred -f $name, $exception.message) 81 | while ($exception.InnerException -ne $null) 82 | { 83 | $exception = $exception.InnerException 84 | Write-Verbose ($LocalizedData.InnerException -f $name, $exception.message) 85 | } 86 | } 87 | } 88 | else 89 | { 90 | Write-Verbose $LocalizedData.DoesNotApply 91 | } 92 | 93 | 94 | } 95 | 96 | function Test-TargetResource 97 | { 98 | [OutputType([boolean])] 99 | param ( 100 | [parameter(Mandatory = $true)] 101 | [ValidateSet('Restricted', 'AllSigned', 'RemoteSigned', 'Unrestricted')] 102 | [string] 103 | $Name, 104 | [parameter()] 105 | [ValidateSet('Present','Absent')] 106 | [string] 107 | $Ensure = 'Present' 108 | ) 109 | 110 | switch (Get-ExecutionPolicy) 111 | { 112 | {($Name -like $_) -and ($Ensure -like 'Present')} { 113 | Write-Verbose ($LocalizedData.ExecutionPolicyFound -f $name) 114 | return $true 115 | } 116 | 117 | default { 118 | Write-Verbose ($LocalizedData.ExecutionPolicyNotFound -f $Name) 119 | return $false 120 | } 121 | } 122 | } 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_SetExecutionPolicy/StackExchange_SetExecutionPolicy.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("SetExecutionPolicy")] 2 | class StackExchange_SetExecutionPolicy : OMI_BaseResource 3 | { 4 | [Key,ValueMap{"Restricted", "AllSigned", "RemoteSigned", "Unrestricted"},Values{"Restricted", "AllSigned", "RemoteSigned", "Unrestricted"}] string Name; 5 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 6 | }; 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_SetExecutionPolicy/StackExchange_en-US/StackExchange_SetExecutionPolicyProvider.psd1: -------------------------------------------------------------------------------- 1 | ConvertFrom-StringData @' 2 | CheckingCurrentExecutionPolicy=Checking for the existing execution policy. 3 | ExecutionPolicyFound=Located an execution policy of {0}. 4 | ExecutionPolicyNotFound=Did not find an execution policy of {0}. 5 | ApplyingExecutionPolicy=Starting to apply {0} as the execution policy. 6 | AppliedExecutionPolicy=Applied {0} as the execution policy. 7 | AnErrorOccurred=An error occurred trying to apply {0} as the execution policy: {1}. 8 | InnerException=Nested error trying to apply {0} as the execution policy: {1}. 9 | DoesNotApply=Absent does not apply to this configuration item. 10 | '@ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_SetExecutionPolicy/StackExchange_en-US/StackExchange_about_SetExecutionPolicy_Resource.txt: -------------------------------------------------------------------------------- 1 | Syntax 2 | 3 | Pagefile [string] #ResourceName 4 | { 5 | Name = [string] { Restricted | AllSigned | RemoteSigned | Unrestricted } 6 | 7 | [ Ensure = [string] { Absent | Present } ] 8 | } 9 | 10 | Properties 11 | 12 | Name - The name of the execution policy. 13 | 14 | Ensure - Set this property to "Present" set the named execution policy. Absent does not apply. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Timezone/StackExchange_Timezone.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'Timezone' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 12/13/2013 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'StackExchange_Timezone.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.7' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = 'd2b7eb0f-b0e4-493d-a26a-862d65f76900' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2013 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = 'Get-TargetResource', 'Test-TargetResource', 'Set-TargetResource' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Timezone/StackExchange_Timezone.psm1: -------------------------------------------------------------------------------- 1 | 2 | function Get-TargetResource 3 | { 4 | [OutputType([Hashtable])] 5 | param ( 6 | [parameter(Mandatory = $true)] 7 | [ValidateNotNullOrEmpty()] 8 | [string] 9 | $Name 10 | ) 11 | 12 | #Needs to return a hashtable that returns the current 13 | #status of the configuration component 14 | 15 | $Configuration = @{ 16 | Name = (tzutil /g) 17 | Ensure = 'Present' 18 | } 19 | 20 | return $Configuration 21 | } 22 | 23 | function Set-TargetResource 24 | { 25 | param ( 26 | [parameter(Mandatory = $true)] 27 | [ValidateNotNullOrEmpty()] 28 | [string] 29 | $Name, 30 | [parameter()] 31 | [ValidateSet('Present','Absent')] 32 | [string] 33 | $Ensure = 'Present' 34 | ) 35 | 36 | if ($ensure -like 'Present') 37 | { 38 | tzutil /s "$Name" 39 | } 40 | 41 | 42 | } 43 | 44 | function Test-TargetResource 45 | { 46 | [OutputType([boolean])] 47 | param ( 48 | [parameter(Mandatory = $true)] 49 | [ValidateNotNullOrEmpty()] 50 | [string] 51 | $Name, 52 | [parameter()] 53 | [ValidateSet('Present','Absent')] 54 | [string] 55 | $Ensure = 'Present' 56 | ) 57 | 58 | $CurrentTimeZone = tzutil.exe /g 59 | 60 | if ($Ensure -like 'present') 61 | { 62 | if ($Name -like $CurrentTimeZone) 63 | { 64 | return $true 65 | } 66 | else 67 | { 68 | return $false 69 | } 70 | } 71 | else 72 | { 73 | if ($Name -like $CurrentTimeZone) 74 | { 75 | return $false 76 | } 77 | else 78 | { 79 | return $true 80 | } 81 | } 82 | 83 | } 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /DSCResources/StackExchange_Timezone/StackExchange_Timezone.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0"), FriendlyName("Timezone")] 2 | class StackExchange_Timezone : OMI_BaseResource 3 | { 4 | [Key] string Name; 5 | [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; 6 | }; 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 PowerShell.Org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/0k029m73lbkom7pg/branch/master?svg=true)](https://ci.appveyor.com/project/smurawski/stackexchangeresources/branch/master) 2 | 3 | Basic resources for managing Windows Server. Tested on Server 2012 and newer. 4 | 5 | -------------------------------------------------------------------------------- /StackExchangeResources.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'StackExchangeResources' 3 | # 4 | # Generated by: Steven Murawski 5 | # 6 | # Generated on: 1/27/2014 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | # RootModule = '' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.9.11.0' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '7cec8ec5-91d8-435e-8136-51088d62fbed' 19 | 20 | # Author of this module 21 | Author = 'Steven Murawski' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Stack Exchange' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2014 Steven Murawski. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | # Description = '' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | # PowerShellVersion = '' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | # NestedModules = @() 67 | 68 | # Functions to export from this module 69 | FunctionsToExport = '*' 70 | 71 | # Cmdlets to export from this module 72 | CmdletsToExport = '*' 73 | 74 | # Variables to export from this module 75 | VariablesToExport = '*' 76 | 77 | # Aliases to export from this module 78 | AliasesToExport = '*' 79 | 80 | # List of all modules packaged with this module 81 | # ModuleList = @() 82 | 83 | # List of all files packaged with this module 84 | # FileList = @() 85 | 86 | # Private data to pass to the module specified in RootModule/ModuleToProcess 87 | # PrivateData = '' 88 | 89 | # HelpInfo URI of this module 90 | # HelpInfoURI = '' 91 | 92 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 93 | # DefaultCommandPrefix = '' 94 | 95 | } 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Notes: 2 | # - Minimal appveyor.yml file is an empty file. All sections are optional. 3 | # - Indent each level of configuration with 2 spaces. Do not use tabs! 4 | # - All section names are case-sensitive. 5 | # - Section names should be unique on each level. 6 | 7 | #---------------------------------# 8 | # general configuration # 9 | #---------------------------------# 10 | 11 | # version format 12 | version: 1.0.{build} 13 | 14 | # Do not build on tags (GitHub only) 15 | skip_tags: false 16 | 17 | #---------------------------------# 18 | # environment configuration # 19 | #---------------------------------# 20 | 21 | # Operating system (build VM template) 22 | os: Windows Server 2012 R2 23 | 24 | #---------------------------------# 25 | # build configuration # 26 | #---------------------------------# 27 | 28 | install: 29 | - cinst pester 30 | 31 | # to run your custom scripts instead of automatic MSBuild 32 | #build_script: 33 | # - ps: 34 | 35 | # to disable automatic builds 36 | build: off 37 | 38 | #---------------------------------# 39 | # tests configuration # 40 | #---------------------------------# 41 | 42 | # to run your custom scripts instead of automatic tests 43 | test_script: 44 | ps: | 45 | if (test-path ./test/unit) { 46 | Invoke-Pester -path ./test/unit -EnableExit 47 | } 48 | else { 49 | Write-Host "No tests found under $(join-path $pwd '/test/unit')" 50 | } 51 | 52 | # to disable automatic tests 53 | #test: off 54 | 55 | #---------------------------------# 56 | # deployment configuration # 57 | #---------------------------------# 58 | 59 | # to run your custom scripts instead of provider deployments 60 | #deploy_script: 61 | 62 | # to disable deployment 63 | deploy: off 64 | -------------------------------------------------------------------------------- /test/integration/StackExchange_PageFile/pester/StackExchange_PageFile.Tests.ps1: -------------------------------------------------------------------------------- 1 | describe 'When using the Pagefile resource' { 2 | 3 | } -------------------------------------------------------------------------------- /test/unit/StackExchange_Pagefile/pester/StackExchange_Pagefile.Tests.ps1: -------------------------------------------------------------------------------- 1 | $ModuleName = (Split-Path -leaf $MyInvocation.MyCommand.Path) -replace '\.[Tt][Ee][Ss][Tt][Ss].[Pp][Ss]1' 2 | $TestsFolder = 1..4 | 3 | foreach {$Path = $MyInvocation.MyCommand.Path } {$Path = Split-Path $Path} {$Path} 4 | $RootOfModule = Split-Path $TestsFolder 5 | $CurrentResourceModulePath = Join-Path $RootOfModule "DscResources/$ModuleName" 6 | 7 | Import-Module $CurrentResourceModulePath 8 | 9 | InModuleScope $ModuleName { 10 | Describe 'how Get-TargetResource reponds' { 11 | Context 'when automatic page file is configured' { 12 | mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_ComputerSystem'} -mockWith { 13 | return ([pscustomobject]@{AutomaticManagedPageFile = $true}) 14 | } 15 | mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_PageFileSetting'} -mockWith {} 16 | 17 | $result = Get-TargetResource -initialsize 4GB -MaximumSize 4GB -Ensure 'Present' 18 | 19 | It 'should call once Get-WmiObject Win32_ComputerSystem ' { 20 | Assert-MockCalled -commandName Get-WmiObject -times 1 -Exactly -parameterFilter { 21 | $Class -like 'Win32_ComputerSystem' 22 | } 23 | } 24 | It 'should not call Get-WmiObject Win32_PageFileSetting' { 25 | Assert-MockCalled -commandName Get-WmiObject -times 0 -Exactly -parameterFilter { 26 | $Class -like 'Win32_PageFileSetting' 27 | } 28 | } 29 | It "should return Ensure = 'Absent'" { 30 | $result['Ensure'] | should be ('Absent') 31 | } 32 | } 33 | Context 'when automatic page file not configured' { 34 | mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_ComputerSystem'} -mockWith { 35 | return ([pscustomobject]@{AutomaticManagedPageFile = $false}) 36 | } 37 | mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_PageFileSetting'} -mockWith { 38 | return ([pscustomobject]@{ 39 | InitialSize = (3GB/1MB) 40 | MaximumSize = (3GB/1MB) 41 | }) 42 | } 43 | 44 | $result = Get-TargetResource -initialsize 4GB -MaximumSize 4GB -Ensure 'Present' 45 | 46 | It 'should call once Get-WmiObject Win32_ComputerSystem ' { 47 | Assert-MockCalled -commandName Get-WmiObject -times 1 -Exactly -parameterFilter { 48 | $Class -like 'Win32_ComputerSystem' 49 | } 50 | } 51 | It 'should call once Get-WmiObject Win32_PageFileSetting' { 52 | Assert-MockCalled -commandName Get-WmiObject -times 1 -Exactly -parameterFilter { 53 | $Class -like 'Win32_PageFileSetting' 54 | } 55 | } 56 | It "should return Ensure = 'Present' with Intial and Maximum size at 3GB" { 57 | $result['Ensure'] | should be ('Present') 58 | $result['InitialSize'] | should be (3GB) 59 | $result['MaximumSize'] | should be (3GB) 60 | } 61 | 62 | } 63 | } 64 | 65 | Describe 'how Set-TargetResource responds' { 66 | 67 | Context 'when Ensure is set to Absent and AutomaticPageFile is set' { 68 | Mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_ComputerSystem'} -mockWith { 69 | $r = [pscustomobject]@{ 70 | AutomaticManagedPageFile = $true 71 | } | Add-Member -MemberType ScriptMethod -Name Put -Value { 72 | $global:PutWasCalled = $true 73 | $global:PutValue = $this 74 | } -PassThru 75 | return ($r) 76 | } 77 | $global:PutValue = $null 78 | $global:PutWasCalled = $False 79 | Set-TargetResource -initialsize 4GB -MaximumSize 4GB -Ensure 'Absent' 80 | 81 | It 'should not call put' { 82 | $global:PutWasCalled | should be ($false) 83 | } 84 | } 85 | 86 | Context 'when Ensure is set to Absent and AutomaticPageFile is not set' { 87 | Mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_ComputerSystem'} -mockWith { 88 | $r = [pscustomobject]@{ 89 | AutomaticManagedPageFile = $false 90 | } | Add-Member -MemberType ScriptMethod -Name Put -Value { 91 | $global:PutWasCalled = $true 92 | $global:PutValue = $this 93 | } -PassThru 94 | return ($r) 95 | } 96 | $global:PutValue = $null 97 | $global:PutWasCalled = $False 98 | Set-TargetResource -initialsize 4GB -MaximumSize 4GB -Ensure 'Absent' 99 | 100 | It 'should call put' { 101 | $global:PutWasCalled | should be ($true) 102 | } 103 | It 'should set AutomaticManagedPageFile set to $true' { 104 | $global:PutValue.AutomaticManagedPageFile | should be ($true) 105 | } 106 | 107 | } 108 | Context 'when Ensure is set to Absent and AutomaticPageFile is not set' { 109 | Mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_ComputerSystem'} -mockWith { 110 | $r = [pscustomobject]@{ AutomaticManagedPageFile = $false 111 | } | 112 | Add-Member -MemberType ScriptMethod -Name Put -Value { 113 | $global:Win32_ComputerPutWasCalled = $true 114 | $global:Win32_ComputerPutValue = $this 115 | } -PassThru 116 | return ($r) 117 | } 118 | Mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_PageFileSetting'} -mockWith { 119 | $r = [pscustomobject]@{ 120 | InitialSize = 0 121 | MaximumSize = 0 122 | } | Add-Member -MemberType ScriptMethod -Name Put -Value { 123 | $global:Win32_PageFileSettingPutWasCalled = $true 124 | $global:Win32_PageFileSettingPutValue = $this 125 | } -PassThru 126 | return ($r) 127 | } 128 | 129 | $global:Win32_ComputerPutValue = $null 130 | $global:Win32_ComputerPutWasCalled = $False 131 | $global:Win32_PageFileSettingPutValue = $null 132 | $global:Win32_PageFileSettingPutWasCalled = $False 133 | 134 | Set-TargetResource -initialsize 4GB -MaximumSize 4GB -Ensure 'Absent' 135 | 136 | It 'should call put to Win32_ComputerSystem' { 137 | $global:Win32_ComputerPutWasCalled | should be ($true) 138 | } 139 | It 'should set AutomaticManagedPageFile set to $true' { 140 | $global:Win32_ComputerPutValue.AutomaticManagedPageFile | should be ($true) 141 | } 142 | 143 | } 144 | Context 'when Ensure is set to Present and AutomaticPageFile is not set' { 145 | Mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_ComputerSystem'} -mockWith { 146 | $r = [pscustomobject]@{ AutomaticManagedPageFile = $false 147 | } | 148 | Add-Member -MemberType ScriptMethod -Name Put -Value { 149 | $global:Win32_ComputerPutWasCalled = $true 150 | $global:PutVWin32_ComputerPutValuealue = $this 151 | } -PassThru 152 | return ($r) 153 | } 154 | Mock -commandName Get-WmiObject -parameterFilter {$Class -like 'Win32_PageFileSetting'} -mockWith { 155 | $r = [pscustomobject]@{ 156 | InitialSize = 0 157 | MaximumSize = 0 158 | } | Add-Member -MemberType ScriptMethod -Name Put -Value { 159 | $global:Win32_PageFileSettingPutWasCalled = $true 160 | $global:Win32_PageFileSettingPutValue = $this 161 | } -PassThru 162 | return ($r) 163 | } 164 | 165 | $global:Win32_ComputerPutValue = $null 166 | $global:Win32_ComputerPutWasCalled = $False 167 | $global:Win32_PageFileSettingPutValue = $null 168 | $global:Win32_PageFileSettingPutWasCalled = $False 169 | 170 | Set-TargetResource -initialsize 4GB -MaximumSize 4GB -Ensure 'Present' 171 | 172 | It 'should call put on Win32_PageFileSetting' { 173 | $global:PutWasCalled | should be ($true) 174 | } 175 | It 'should not set AutomaticManagedPageFile set to $true' { 176 | $global:Win32_ComputerPutValue.AutomaticManagedPageFile | should beNullOrEmpty 177 | } 178 | It 'should set Initial and Maximum size to 4 GB' { 179 | $global:Win32_PageFileSettingPutValue.InitialSize | should be (4gb/1mb) 180 | $global:Win32_PageFileSettingPutValue.MaximumSize | should be (4gb/1mb) 181 | } 182 | 183 | } 184 | 185 | 186 | Get-Variable -Scope Global -Name Win32_ComputerPutValue | 187 | Remove-Variable -Scope Global -Force 188 | Get-Variable -Scope Global -Name Win32_ComputerPutWasCalled | 189 | Remove-Variable -Scope Global -Force 190 | Get-Variable -Scope Global -Name Win32_PageFileSettingPutValue | 191 | Remove-Variable -Scope Global -Force 192 | Get-Variable -Scope Global -Name Win32_PageFileSettingPutWasCalled | 193 | Remove-Variable -Scope Global -Force 194 | } 195 | } 196 | 197 | 198 | --------------------------------------------------------------------------------