mirror of
https://github.com/PowerShell/PSDscResources
synced 2026-06-21 13:45:29 +00:00
adding WindowsFeature
This commit is contained in:
@@ -0,0 +1,543 @@
|
||||
# Global needed to indicate if a restart is required
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
|
||||
param ()
|
||||
|
||||
Import-Module -Name (Join-Path -Path (Split-Path $PSScriptRoot -Parent) `
|
||||
-ChildPath 'CommonResourceHelper.psm1')
|
||||
|
||||
# Localized messages for verbose and error messages in this resource
|
||||
$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_WindowsFeature'
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Retrieves the status of the role or feature with the given name on the target machine.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the role or feature to retrieve
|
||||
|
||||
.PARAMETER Credential
|
||||
The credential (if required) to retrieve the role or feature.
|
||||
Optional.
|
||||
|
||||
.NOTES
|
||||
If the specified role or feature does not contain any subfeatures then
|
||||
IncludeAllSubFeature will be set to $false. If the specified feature contains one
|
||||
or more subfeatures then IncludeAllSubFeature will be set to $true only if all the
|
||||
subfeatures are installed. Otherwise, IncludeAllSubFeature will be set to $false.
|
||||
#>
|
||||
function Get-TargetResource
|
||||
{
|
||||
[CmdletBinding()]
|
||||
[OutputType([Hashtable])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$Name,
|
||||
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.Management.Automation.PSCredential]
|
||||
[System.Management.Automation.Credential()]
|
||||
$Credential
|
||||
)
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.GetTargetResourceStartMessage -f $Name)
|
||||
|
||||
Import-ServerManager
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.QueryFeature -f $Name)
|
||||
|
||||
$isWinServer2008R2SP1 = Test-IsWinServer2008R2SP1
|
||||
if ($isWinServer2008R2SP1 -and $PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
$feature = Invoke-Command -ScriptBlock { Get-WindowsFeature -Name $Name } `
|
||||
-ComputerName . `
|
||||
-Credential $Credential `
|
||||
}
|
||||
else
|
||||
{
|
||||
$feature = Get-WindowsFeature @PSBoundParameters
|
||||
}
|
||||
|
||||
Assert-SingleFeatureExists -Feature $feature -Name $Name
|
||||
|
||||
$includeAllSubFeature = $true
|
||||
|
||||
if ($feature.SubFeatures.Count -eq 0)
|
||||
{
|
||||
$includeAllSubFeature = $false
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($currentSubFeatureName in $feature.SubFeatures)
|
||||
{
|
||||
|
||||
$getWindowsFeatureParameters = @{
|
||||
Name = $currentSubFeatureName
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
$getWindowsFeatureParameters['Credential'] = $Credential
|
||||
}
|
||||
|
||||
if ($isWinServer2008R2SP1 -and $PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
<#
|
||||
Calling Get-WindowsFeature through Invoke-Command to start a new process with
|
||||
the given credential since Get-WindowsFeature doesn't support the Credential
|
||||
attribute on this server.
|
||||
#>
|
||||
$subFeature = Invoke-Command -ScriptBlock { Get-WindowsFeature -Name $currentSubFeatureName } `
|
||||
-ComputerName . `
|
||||
-Credential $Credential `
|
||||
}
|
||||
else
|
||||
{
|
||||
$subFeature = Get-WindowsFeature @getWindowsFeatureParameters
|
||||
}
|
||||
|
||||
Assert-SingleFeatureExists -Feature $subFeature -Name $currentSubFeatureName
|
||||
|
||||
if (-not $subFeature.Installed)
|
||||
{
|
||||
$includeAllSubFeature = $false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($feature.Installed)
|
||||
{
|
||||
$ensureResult = 'Present'
|
||||
}
|
||||
else
|
||||
{
|
||||
$ensureResult = 'Absent'
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.GetTargetResourceEndMessage -f $Name)
|
||||
|
||||
# Add all feature properties to the hash table
|
||||
return @{
|
||||
Name = $Name
|
||||
DisplayName = $feature.DisplayName
|
||||
Ensure = $ensureResult
|
||||
IncludeAllSubFeature = $includeAllSubFeature
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs or uninstalls the role or feature with the given name on the target machine
|
||||
with the option of installing or uninstalling all subfeatures as well.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the role or feature to install or uninstall.
|
||||
|
||||
.PARAMETER Ensure
|
||||
Specifies whether the role or feature should be installed ('Present')
|
||||
or uninstalled ('Absent').
|
||||
By default this is set to Present.
|
||||
|
||||
.PARAMETER IncludeAllSubFeature
|
||||
Specifies whether or not all subfeatures should be installed or uninstalled with
|
||||
the specified role or feature. Default is false.
|
||||
If this property is true and Ensure is set to Present, all subfeatures will be installed.
|
||||
If this property is false and Ensure is set to Present, subfeatures will not be installed or uninstalled.
|
||||
If Ensure is set to Absent, all subfeatures will be uninstalled.
|
||||
|
||||
.PARAMETER Credential
|
||||
The credential (if required) to install or uninstall the role or feature.
|
||||
Optional.
|
||||
|
||||
.PARAMETER LogPath
|
||||
The custom path to the log file to log this operation.
|
||||
If not passed in, the default log path will be used (%windir%\logs\ServerManager.log).
|
||||
#>
|
||||
function Set-TargetResource
|
||||
{
|
||||
[CmdletBinding(SupportsShouldProcess = $true)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$Name,
|
||||
|
||||
[ValidateSet('Present', 'Absent')]
|
||||
[String]
|
||||
$Ensure = 'Present',
|
||||
|
||||
[Boolean]
|
||||
$IncludeAllSubFeature = $false,
|
||||
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.Management.Automation.PSCredential]
|
||||
[System.Management.Automation.Credential()]
|
||||
$Credential,
|
||||
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$LogPath
|
||||
)
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.SetTargetResourceStartMessage -f $Name)
|
||||
|
||||
Import-ServerManager
|
||||
|
||||
$isWinServer2008R2SP1 = Test-IsWinServer2008R2SP1
|
||||
|
||||
if ($Ensure -eq 'Present')
|
||||
{
|
||||
$addWindowsFeatureParameters = @{
|
||||
Name = $Name
|
||||
IncludeAllSubFeature = $IncludeAllSubFeature
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('LogPath'))
|
||||
{
|
||||
$addWindowsFeatureParameters['LogPath'] = $LogPath
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.InstallFeature -f $Name)
|
||||
|
||||
if ($isWinServer2008R2SP1 -and $PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
<#
|
||||
Calling Add-WindowsFeature through Invoke-Command to start a new process with
|
||||
the given credential since Add-WindowsFeature doesn't support the Credential
|
||||
attribute on this server.
|
||||
#>
|
||||
$feature = Invoke-Command -ScriptBlock { Add-WindowsFeature @addWindowsFeatureParameters } `
|
||||
-ComputerName . `
|
||||
-Credential $Credential
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
$addWindowsFeatureParameters['Credential'] = $Credential
|
||||
}
|
||||
|
||||
$feature = Add-WindowsFeature @addWindowsFeatureParameters
|
||||
}
|
||||
|
||||
if ($null -ne $feature -and $feature.Success)
|
||||
{
|
||||
Write-Verbose -Message ($script:localizedData.InstallSuccess -f $Name)
|
||||
|
||||
# Check if reboot is required, if so notify the Local Configuration Manager.
|
||||
if ($feature.RestartNeeded -eq 'Yes')
|
||||
{
|
||||
Write-Verbose -Message $script:localizedData.RestartNeeded
|
||||
$global:DSCMachineStatus = 1
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
New-InvalidOperationException -Message ($script:localizedData.FeatureInstallationFailureError -f $Name)
|
||||
}
|
||||
}
|
||||
# Ensure = 'Absent'
|
||||
else
|
||||
{
|
||||
$removeWindowsFeatureParameters = @{
|
||||
Name = $Name
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('LogPath'))
|
||||
{
|
||||
$removeWindowsFeatureParameters['LogPath'] = $LogPath
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.UninstallFeature -f $Name)
|
||||
|
||||
if ($isWinServer2008R2SP1 -and $PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
<#
|
||||
Calling Remove-WindowsFeature through Invoke-Command to start a new process with
|
||||
the given credential since Remove-WindowsFeature doesn't support the Credential
|
||||
attribute on this server.
|
||||
#>
|
||||
$feature = Invoke-Command -ScriptBlock { Remove-WindowsFeature @removeWindowsFeatureParameters } `
|
||||
-ComputerName . `
|
||||
-Credential $Credential
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
$addWindowsFeatureParameters['Credential'] = $Credential
|
||||
}
|
||||
|
||||
$feature = Remove-WindowsFeature @removeWindowsFeatureParameters
|
||||
}
|
||||
|
||||
if ($null -ne $feature -and $feature.Success)
|
||||
{
|
||||
Write-Verbose ($script:localizedData.UninstallSuccess -f $Name)
|
||||
|
||||
# Check if reboot is required, if so notify the Local Configuration Manager.
|
||||
if ($feature.RestartNeeded -eq 'Yes')
|
||||
{
|
||||
Write-Verbose -Message $script:localizedData.RestartNeeded
|
||||
$global:DSCMachineStatus = 1
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
New-InvalidOperationException -Message ($script:localizedData.FeatureUninstallationFailureError -f $Name)
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.SetTargetResourceEndMessage -f $Name)
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Tests if the role or feature with the given name is in the desired state.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the role or feature to test the state of.
|
||||
|
||||
.PARAMETER Ensure
|
||||
Specifies whether the role or feature should be installed ('Present')
|
||||
or uninstalled ('Absent').
|
||||
By default this is set to Present.
|
||||
|
||||
.PARAMETER IncludeAllSubFeature
|
||||
Specifies whether the subfeatures of the indicated role or feature should also be checked
|
||||
to ensure they are in the desired state. If Ensure is set to 'Present' and this is set to
|
||||
$true then each subfeature is checked to ensure it is installed as well. If Ensure is set to
|
||||
Absent and this is set to $true, then each subfeature is checked to ensure it is uninstalled.
|
||||
As of now, this test can't be used to check if a feature is Installed but all of its
|
||||
subfeatures are uninstalled.
|
||||
By default this is set to $false.
|
||||
|
||||
.PARAMETER Credential
|
||||
The Credential (if required) to test the status of the role or feature.
|
||||
Optional.
|
||||
|
||||
.PARAMETER LogPath
|
||||
The path to the log file to log this operation.
|
||||
Not used in Test-TargetResource.
|
||||
|
||||
#>
|
||||
function Test-TargetResource
|
||||
{
|
||||
[CmdletBinding()]
|
||||
[OutputType([System.Boolean])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$Name,
|
||||
|
||||
[ValidateSet('Present', 'Absent')]
|
||||
[String]
|
||||
$Ensure = 'Present',
|
||||
|
||||
[Boolean]
|
||||
$IncludeAllSubFeature = $false,
|
||||
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.Management.Automation.PSCredential]
|
||||
[System.Management.Automation.Credential()]
|
||||
$Credential,
|
||||
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$LogPath
|
||||
|
||||
)
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.TestTargetResourceStartMessage -f $Name)
|
||||
|
||||
Import-ServerManager
|
||||
|
||||
$testTargetResourceResult = $false
|
||||
|
||||
$getWindowsFeatureParameters = @{
|
||||
Name = $Name
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
$getWindowsFeatureParameters['Credential'] = $Credential
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.QueryFeature -f $Name)
|
||||
|
||||
$isWinServer2008R2SP1 = Test-IsWinServer2008R2SP1
|
||||
if ($isWinServer2008R2SP1 -and $PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
<#
|
||||
Calling Get-WindowsFeature through Invoke-Command to start a new process with
|
||||
the given credential since Get-WindowsFeature doesn't support the Credential
|
||||
attribute on this server.
|
||||
#>
|
||||
$feature = Invoke-Command -ScriptBlock { Get-WindowsFeature -Name $Name } `
|
||||
-ComputerName . `
|
||||
-Credential $Credential
|
||||
}
|
||||
else
|
||||
{
|
||||
$feature = Get-WindowsFeature @getWindowsFeatureParameters
|
||||
}
|
||||
|
||||
Assert-SingleFeatureExists -Feature $feature -Name $Name
|
||||
|
||||
# Check if the feature is in the requested Ensure state.
|
||||
if (($Ensure -eq 'Present' -and $feature.Installed -eq $true) -or `
|
||||
($Ensure -eq 'Absent' -and $feature.Installed -eq $false))
|
||||
{
|
||||
$testTargetResourceResult = $true
|
||||
|
||||
if ($IncludeAllSubFeature)
|
||||
{
|
||||
# Check if each subfeature is in the requested state.
|
||||
foreach ($currentSubFeatureName in $feature.SubFeatures)
|
||||
{
|
||||
$getWindowsFeatureParameters['Name'] = $currentSubFeatureName
|
||||
|
||||
if ($isWinServer2008R2SP1 -and $PSBoundParameters.ContainsKey('Credential'))
|
||||
{
|
||||
<#
|
||||
Calling Get-WindowsFeature through Invoke-Command to start a new process with
|
||||
the given credential since Get-WindowsFeature doesn't support the Credential
|
||||
attribute on this server.
|
||||
#>
|
||||
$subFeature = Invoke-Command -ScriptBlock { Get-WindowsFeature -Name $currentSubFeatureName } `
|
||||
-ComputerName . `
|
||||
-Credential $Credential
|
||||
}
|
||||
else
|
||||
{
|
||||
$subFeature = Get-WindowsFeature @getWindowsFeatureParameters
|
||||
}
|
||||
|
||||
Assert-SingleFeatureExists -Feature $subFeature -Name $currentSubFeatureName
|
||||
|
||||
if (-not $subFeature.Installed -and $Ensure -eq 'Present')
|
||||
{
|
||||
$testTargetResourceResult = $false
|
||||
break
|
||||
}
|
||||
|
||||
if ($subFeature.Installed -and $Ensure -eq 'Absent')
|
||||
{
|
||||
$testTargetResourceResult = $false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Ensure is not in the correct state
|
||||
$testTargetResourceResult = $false
|
||||
}
|
||||
|
||||
Write-Verbose -Message ($script:localizedData.TestTargetResourceEndMessage -f $Name)
|
||||
|
||||
return $testTargetResourceResult
|
||||
}
|
||||
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Asserts that a single instance of the given role or feature exists.
|
||||
|
||||
.PARAMETER Feature
|
||||
The role or feature object to check.
|
||||
|
||||
.PARAMETER Name
|
||||
The name of the role or feature to include in any error messages that are thrown.
|
||||
(Not used to assert validity of the feature).
|
||||
#>
|
||||
function Assert-SingleFeatureExists
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[PSObject]
|
||||
$Feature,
|
||||
|
||||
[String]
|
||||
$Name
|
||||
)
|
||||
|
||||
if ($null -eq $Feature)
|
||||
{
|
||||
New-InvalidOperationException -Message ($script:localizedData.FeatureNotFoundError -f $Name)
|
||||
}
|
||||
|
||||
if ($Feature.Count -gt 1)
|
||||
{
|
||||
New-InvalidOperationException -Message ($script:localizedData.MultipleFeatureInstancesError -f $Name)
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets up the ServerManager module on the target node.
|
||||
Throws an error if not on a machine running Windows Server.
|
||||
#>
|
||||
function Import-ServerManager
|
||||
{
|
||||
param
|
||||
()
|
||||
|
||||
<#
|
||||
Enable ServerManager-PSH-Cmdlets feature if OS is WS2008R2 Core.
|
||||
Datacenter = 12, Standard = 13, Enterprise = 14
|
||||
#>
|
||||
$serverCoreOSCodes = @( 12, 13, 14 )
|
||||
|
||||
$operatingSystem = Get-CimInstance -Class 'Win32_OperatingSystem'
|
||||
|
||||
# Check if this operating system needs an update to the ServerManager cmdlets
|
||||
if ($operatingSystem.Version.StartsWith('6.1.') -and `
|
||||
$serverCoreOSCodes -contains $operatingSystem.OperatingSystemSKU)
|
||||
{
|
||||
Write-Verbose -Message $script:localizedData.EnableServerManagerPSHCmdletsFeature
|
||||
|
||||
<#
|
||||
ServerManager-PSH-Cmdlets has a depndency on Powershell 2 update: MicrosoftWindowsPowerShell,
|
||||
so enabling the MicrosoftWindowsPowerShell update.
|
||||
#>
|
||||
$null = Dism\online\enable-feature\FeatureName:MicrosoftWindowsPowerShell
|
||||
$null = Dism\online\enable-feature\FeatureName:ServerManager-PSH-Cmdlets
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Import-Module -Name 'ServerManager'
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose -Message $script:localizedData.ServerManagerModuleNotFoundMessage
|
||||
New-InvalidOperationException -Message $script:localizedData.SkuNotSupported
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Tests if the machine is a Windows Server 2008 R2 SP1 machine.
|
||||
|
||||
.NOTES
|
||||
Since Assert-PrequisitesValid ensures that ServerManager is available on the machine,
|
||||
this function only checks the OS version.
|
||||
#>
|
||||
function Test-IsWinServer2008R2SP1
|
||||
{
|
||||
param
|
||||
()
|
||||
|
||||
return ([Environment]::OSVersion.Version.ToString().Contains('6.1.'))
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function *-TargetResource
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
[ClassVersion("1.0.0.0"), FriendlyName("WindowsFeature")]
|
||||
class MSFT_WindowsFeature : OMI_BaseResource
|
||||
{
|
||||
[Key, Description("The name of the role or feature to install or uninstall.")] String Name;
|
||||
[Write, Description("Specifies whether the role or feature should be installed or uninstalled. To install the feature, set this property to Present. To uninstall the feature, set the property to Absent."), ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure;
|
||||
[Write, Description("Specifies whether the subfeatures of the main feature should also be installed.")] Boolean IncludeAllSubFeature;
|
||||
[Write, Description("The path to the log file to log this operation.")] String LogPath;
|
||||
[Write, Description("A credential, if needed, to install or uninstall the role or feature."), EmbeddedInstance("MSFT_Credential")] String Credential;
|
||||
[Read, Description("The display name of the retrieved role or feature.")] String DisplayName;
|
||||
};
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
# Localized strings for MSFT_WindowsFeature.psd1
|
||||
|
||||
ConvertFrom-StringData @'
|
||||
FeatureNotFoundError = The requested feature {0} could not be found on the target machine.
|
||||
MultipleFeatureInstancesError = Failure to get the requested feature {0} information from the target machine. Wildcard pattern is not supported in the feature name.
|
||||
FeatureInstallationFailureError = Failure to successfully install the feature {0} .
|
||||
FeatureUninstallationFailureError = Failure to successfully uninstall the feature {0} .
|
||||
QueryFeature = Querying for feature {0} using Server Manager cmdlet Get-WindowsFeature.
|
||||
InstallFeature = Trying to install feature {0} using Server Manager cmdlet Add-WindowsFeature.
|
||||
UninstallFeature = Trying to uninstall feature {0} using Server Manager cmdlet Remove-WindowsFeature.
|
||||
RestartNeeded = The Target machine needs to be restarted.
|
||||
GetTargetResourceStartMessage = Begin executing Get functionality on the {0} feature.
|
||||
GetTargetResourceEndMessage = End executing Get functionality on the {0} feature.
|
||||
SetTargetResourceStartMessage = Begin executing Set functionality on the {0} feature.
|
||||
SetTargetResourceEndMessage = End executing Set functionality on the {0} feature.
|
||||
TestTargetResourceStartMessage = Begin executing Test functionality on the {0} feature.
|
||||
TestTargetResourceEndMessage = End executing Test functionality on the {0} feature.
|
||||
ServerManagerModuleNotFoundMessage = ServerManager module is not installed on the machine.
|
||||
SkuNotSupported = Installing roles and features using PowerShell Desired State Configuration is supported only on Server SKU's. It is not supported on Client SKU.
|
||||
EnableServerManagerPSHCmdletsFeature = Windows Server 2008R2 Core operating system detected: ServerManager-PSH-Cmdlets feature has been enabled.
|
||||
UninstallSuccess = Successfully uninstalled the feature {0}.
|
||||
InstallSuccess = Successfully installed the feature {0}.
|
||||
'@
|
||||
@@ -0,0 +1,45 @@
|
||||
<#
|
||||
Create a custom configuration by passing in whatever values you need.
|
||||
$Name is the only parameter that is required which indicates which
|
||||
Windows Feature you want to install (or uninstall if you set Ensure to Absent).
|
||||
LogPath and Credential are not included here, but if you would like to specify
|
||||
a custom log path or need a credential just pass in the desired values and add
|
||||
LogPath = $LogPath and/or Credential = $Credential to the configuration here
|
||||
#>
|
||||
|
||||
Configuration 'Install_Feature_Telnet_Client'
|
||||
{
|
||||
param
|
||||
(
|
||||
[System.String]
|
||||
$Name = 'Telnet-Client',
|
||||
|
||||
[ValidateSet('Present', 'Absent')]
|
||||
[System.String]
|
||||
$Ensure = 'Present',
|
||||
|
||||
[System.Boolean]
|
||||
$IncludeAllSubFeature = $false,
|
||||
|
||||
[System.Management.Automation.PSCredential]
|
||||
[System.Management.Automation.Credential()]
|
||||
$Credential,
|
||||
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.String]
|
||||
$LogPath
|
||||
)
|
||||
|
||||
Import-DscResource -ModuleName 'PSDscResources'
|
||||
|
||||
Node Localhost {
|
||||
|
||||
WindowsFeature WindowsFeatureTest
|
||||
{
|
||||
Name = $Name
|
||||
Ensure = $Ensure
|
||||
IncludeAllSubFeature = $IncludeAllSubFeature
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
<#
|
||||
Integration tests for Installing/uninstalling a Windows Feature. Currently Telnet-Client is
|
||||
set as the feature to test since it's fairly small and doesn't require a restart. ADRMS
|
||||
is set as the feature to test installing/uninstalling a feature with subfeatures,
|
||||
but this takes a good chunk of time, so by default these tests are set to be skipped.
|
||||
If there's any major changes to the resource, then set the skipLongTests variable to $false
|
||||
and run those tests at least once to test the new functionality more completely.
|
||||
#>
|
||||
|
||||
# Suppressing this rule since we need to create a plaintext password to test this resource
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')]
|
||||
param ()
|
||||
|
||||
Import-Module -Name (Join-Path -Path (Split-Path $PSScriptRoot -Parent) `
|
||||
-ChildPath 'CommonTestHelper.psm1') `
|
||||
-Force
|
||||
|
||||
$script:testEnvironment = Enter-DscResourceTestEnvironment `
|
||||
-DscResourceModuleName 'PSDscResources' `
|
||||
-DscResourceName 'MSFT_WindowsFeature' `
|
||||
-TestType 'Integration'
|
||||
|
||||
$script:testFeatureName = 'Telnet-Client'
|
||||
$script:testFeatureWithSubFeaturesName = 'ADRMS'
|
||||
$script:installStateOfTestFeature
|
||||
$script:installStateOfTestWithSubFeatures
|
||||
|
||||
<#
|
||||
If this is set to $true then the tests that test installing/uninstalling a feature with
|
||||
its subfeatures will not run.
|
||||
#>
|
||||
$script:skipLongTests = $false
|
||||
|
||||
try {
|
||||
|
||||
#Saving the state so we can clean up afterwards
|
||||
$testFeature = Get-WindowsFeature -Name $script:testFeatureName
|
||||
$script:installStateOfTestFeature = $testFeature.Installed
|
||||
|
||||
$testFeatureWithSubFeatures = Get-WindowsFeature -Name $script:testFeatureWithSubFeaturesName
|
||||
$script:installStateOfTestWithSubFeatures = $testFeatureWithSubFeatures.Installed
|
||||
|
||||
$configFile = Join-Path -Path $PSScriptRoot -ChildPath 'MSFT_WindowsFeature.config.ps1'
|
||||
|
||||
Describe 'WindowsFeature Integration Tests' {
|
||||
|
||||
$testIncludeAllSubFeature = $false
|
||||
|
||||
Remove-WindowsFeature -Name $script:testFeatureName
|
||||
|
||||
Context "Should Install the Windows Feature: $script:testFeatureName" {
|
||||
$configurationName = 'MSFT_WindowsFeature_InstallFeature'
|
||||
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
|
||||
|
||||
$logPath = Join-Path -Path $TestDrive -ChildPath 'InstallFeatureTest.log'
|
||||
|
||||
try
|
||||
{
|
||||
# Ensure the feature is not already on the machine
|
||||
Remove-WindowsFeature -Name $script:testFeatureName
|
||||
|
||||
It 'Should compile without throwing' {
|
||||
{
|
||||
. $configFile -ConfigurationName $configurationName
|
||||
& $configurationName -Name $script:testFeatureName `
|
||||
-IncludeAllSubFeature $testIncludeAllSubFeature `
|
||||
-Ensure 'Present' `
|
||||
-OutputPath $configurationPath `
|
||||
-ErrorAction 'Stop'
|
||||
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
|
||||
} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should be able to call Get-DscConfiguration without throwing' {
|
||||
{ Get-DscConfiguration -ErrorAction 'Stop' } | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should return the correct configuration' {
|
||||
$currentConfig = Get-DscConfiguration -ErrorAction 'Stop'
|
||||
$currentConfig.Name | Should Be $script:testFeatureName
|
||||
$currentConfig.IncludeAllSubFeature | Should Be $testIncludeAllSubFeature
|
||||
$currentConfig.Ensure | Should Be 'Present'
|
||||
}
|
||||
|
||||
It 'Should be Installed' {
|
||||
$feature = Get-WindowsFeature -Name $script:testFeatureName
|
||||
$feature.Installed | Should Be $true
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Test-Path -Path $logPath) {
|
||||
Remove-Item -Path $logPath -Recurse -Force
|
||||
}
|
||||
|
||||
if (Test-Path -Path $configurationPath)
|
||||
{
|
||||
Remove-Item -Path $configurationPath -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "Should Uninstall the Windows Feature: $script:testFeatureName" {
|
||||
$configurationName = 'MSFT_WindowsFeature_UninstallFeature'
|
||||
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
|
||||
|
||||
$logPath = Join-Path -Path $TestDrive -ChildPath 'UninstallFeatureTest.log'
|
||||
|
||||
try
|
||||
{
|
||||
It 'Should compile without throwing' {
|
||||
{
|
||||
. $configFile -ConfigurationName $configurationName
|
||||
& $configurationName -Name $script:testFeatureName `
|
||||
-IncludeAllSubFeature $testIncludeAllSubFeature `
|
||||
-Ensure 'Absent' `
|
||||
-OutputPath $configurationPath `
|
||||
-ErrorAction 'Stop'
|
||||
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
|
||||
} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should be able to call Get-DscConfiguration without throwing' {
|
||||
{ Get-DscConfiguration -ErrorAction 'Stop' } | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should return the correct configuration' {
|
||||
$currentConfig = Get-DscConfiguration -ErrorAction 'Stop'
|
||||
$currentConfig.Name | Should Be $script:testFeatureName
|
||||
$currentConfig.IncludeAllSubFeature | Should Be $testIncludeAllSubFeature
|
||||
$currentConfig.Ensure | Should Be 'Absent'
|
||||
}
|
||||
|
||||
It 'Should not be installed' {
|
||||
$feature = Get-WindowsFeature -Name $script:testFeatureName
|
||||
$feature.Installed | Should Be $false
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Test-Path -Path $logPath) {
|
||||
Remove-Item -Path $logPath -Recurse -Force
|
||||
}
|
||||
|
||||
if (Test-Path -Path $configurationPath)
|
||||
{
|
||||
Remove-Item -Path $configurationPath -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "Should Install the Windows Feature: $script:testFeatureWithSubFeaturesName" {
|
||||
$configurationName = 'MSFT_WindowsFeature_InstallFeatureWithSubFeatures'
|
||||
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
|
||||
|
||||
$logPath = Join-Path -Path $TestDrive -ChildPath 'InstallSubFeatureTest.log'
|
||||
|
||||
try
|
||||
{
|
||||
if (-not $script:skipLongTests)
|
||||
{
|
||||
# Ensure that the feature is not already installed
|
||||
Remove-WindowsFeature -Name $script:testFeatureWithSubFeaturesName
|
||||
}
|
||||
|
||||
It 'Should compile without throwing' -Skip:$script:skipLongTests {
|
||||
{
|
||||
. $configFile -ConfigurationName $configurationName
|
||||
& $configurationName -Name $script:testFeatureWithSubFeaturesName `
|
||||
-IncludeAllSubFeature $true `
|
||||
-Ensure 'Present' `
|
||||
-OutputPath $configurationPath `
|
||||
-ErrorAction 'Stop'
|
||||
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
|
||||
} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should be able to call Get-DscConfiguration without throwing' -Skip:$script:skipLongTests {
|
||||
{ Get-DscConfiguration -ErrorAction 'Stop' } | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should return the correct configuration' -Skip:$script:skipLongTests {
|
||||
$currentConfig = Get-DscConfiguration -ErrorAction 'Stop'
|
||||
$currentConfig.Name | Should Be $script:testFeatureWithSubFeaturesName
|
||||
$currentConfig.IncludeAllSubFeature | Should Be $true
|
||||
$currentConfig.Ensure | Should Be 'Present'
|
||||
}
|
||||
|
||||
It 'Should be Installed (includes check for subFeatures)' -Skip:$script:skipLongTests {
|
||||
$feature = Get-WindowsFeature -Name $script:testFeatureWithSubFeaturesName
|
||||
$feature.Installed | Should Be $true
|
||||
|
||||
foreach ($subFeatureName in $feature.SubFeatures)
|
||||
{
|
||||
$subFeature = Get-WindowsFeature -Name $subFeatureName
|
||||
$subFeature.Installed | Should Be $true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Test-Path -Path $logPath) {
|
||||
Remove-Item -Path $logPath -Recurse -Force
|
||||
}
|
||||
|
||||
if (Test-Path -Path $configurationPath)
|
||||
{
|
||||
Remove-Item -Path $configurationPath -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "Should Uninstall the Windows Feature: $script:testFeatureWithSubFeaturesName" {
|
||||
$configurationName = 'MSFT_WindowsFeature_UninstallFeatureWithSubFeatures'
|
||||
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
|
||||
|
||||
$logPath = Join-Path -Path $TestDrive -ChildPath 'UninstallSubFeatureTest.log'
|
||||
|
||||
try
|
||||
{
|
||||
It 'Should compile without throwing' -Skip:$script:skipLongTests {
|
||||
{
|
||||
. $configFile -ConfigurationName $configurationName
|
||||
& $configurationName -Name $script:testFeatureWithSubFeaturesName `
|
||||
-IncludeAllSubFeature $true `
|
||||
-Ensure 'Absent' `
|
||||
-OutputPath $configurationPath `
|
||||
-ErrorAction 'Stop'
|
||||
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
|
||||
} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should be able to call Get-DscConfiguration without throwing' -Skip:$script:skipLongTests {
|
||||
{ Get-DscConfiguration -ErrorAction 'Stop' } | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should return the correct configuration' -Skip:$script:skipLongTests {
|
||||
$currentConfig = Get-DscConfiguration -ErrorAction 'Stop'
|
||||
$currentConfig.Name | Should Be $script:testFeatureWithSubFeaturesName
|
||||
$currentConfig.IncludeAllSubFeature | Should Be $false
|
||||
$currentConfig.Ensure | Should Be 'Absent'
|
||||
}
|
||||
|
||||
It 'Should not be installed (includes check for subFeatures)' -Skip:$script:skipLongTests {
|
||||
$feature = Get-WindowsFeature -Name $script:testFeatureWithSubFeaturesName
|
||||
$feature.Installed | Should Be $false
|
||||
|
||||
foreach ($subFeatureName in $feature.SubFeatures)
|
||||
{
|
||||
$subFeature = Get-WindowsFeature -Name $subFeatureName
|
||||
$subFeature.Installed | Should Be $false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Test-Path -Path $logPath) {
|
||||
Remove-Item -Path $logPath -Recurse -Force
|
||||
}
|
||||
|
||||
if (Test-Path -Path $configurationPath)
|
||||
{
|
||||
Remove-Item -Path $configurationPath -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
# Ensure that features used for testing are re-installed/uninstalled
|
||||
if ($script:installStateOfTestFeature)
|
||||
{
|
||||
Add-WindowsFeature -Name $script:testFeatureName
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove-WindowsFeature -Name $script:testFeatureName
|
||||
}
|
||||
|
||||
if (-not $script:skipLongTests)
|
||||
{
|
||||
if ($script:installStateOfTestWithSubFeatures)
|
||||
{
|
||||
Add-WindowsFeature -Name $script:testFeatureWithSubFeaturesName -IncludeAllSubFeature
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove-WindowsFeature -Name $script:testFeatureWithSubFeaturesName
|
||||
}
|
||||
}
|
||||
Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory)]
|
||||
[System.String]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
|
||||
Configuration $ConfigurationName
|
||||
{
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.String]
|
||||
$Name,
|
||||
|
||||
[ValidateSet('Present', 'Absent')]
|
||||
[System.String]
|
||||
$Ensure = 'Present',
|
||||
|
||||
[System.Boolean]
|
||||
$IncludeAllSubFeature = $false
|
||||
)
|
||||
|
||||
Import-DscResource -ModuleName 'PSDscResources'
|
||||
|
||||
Node Localhost {
|
||||
|
||||
WindowsFeature WindowsFeatureTest
|
||||
{
|
||||
Name = $Name
|
||||
Ensure = $Ensure
|
||||
IncludeAllSubFeature = $IncludeAllSubFeature
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,597 @@
|
||||
# Needed to create a fake credential
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')]
|
||||
param ()
|
||||
|
||||
Import-Module -Name (Join-Path -Path (Split-Path $PSScriptRoot -Parent) `
|
||||
-ChildPath (Join-Path -Path 'TestHelpers' `
|
||||
-ChildPath 'CommonTestHelper.psm1')) `
|
||||
-Force
|
||||
|
||||
$script:testEnvironment = Enter-DscResourceTestEnvironment `
|
||||
-DSCResourceModuleName 'PSDscResources' `
|
||||
-DSCResourceName 'MSFT_WindowsFeature' `
|
||||
-TestType Unit
|
||||
|
||||
try {
|
||||
InModuleScope 'MSFT_WindowsFeature' {
|
||||
|
||||
$testUserName = 'TestUserName12345'
|
||||
$testUserPassword = 'StrongOne7.'
|
||||
$testSecurePassword = ConvertTo-SecureString -String $testUserPassword -AsPlainText -Force
|
||||
$testCredential = New-Object -TypeName PSCredential -ArgumentList ($testUserName, $testSecurePassword)
|
||||
|
||||
$testWindowsFeatureName1 = 'Test1'
|
||||
$testWindowsFeatureName2 = 'Test2'
|
||||
$testSubFeatureName1 = 'SubTest1'
|
||||
$testSubFeatureName2 = 'SubTest2'
|
||||
$testSubFeatureName3 = 'SubTest3'
|
||||
|
||||
|
||||
$mockWindowsFeatures = @{
|
||||
Test1 = @{
|
||||
Name = 'Test1'
|
||||
DisplayName = 'Test Feature 1'
|
||||
Description = 'Test Feature with 3 subfeatures'
|
||||
Installed = $false
|
||||
InstallState = 'Available'
|
||||
FeatureType = 'Role Service'
|
||||
Path = 'Test1'
|
||||
Depth = 1
|
||||
DependsOn = @()
|
||||
Parent = ''
|
||||
ServerComponentDescriptor = 'ServerComponent_Test_Cert_Authority'
|
||||
Subfeatures = @('SubTest1','SubTest2','SubTest3')
|
||||
SystemService = @()
|
||||
Notification = @()
|
||||
BestPracticesModelId = $null
|
||||
EventQuery = $null
|
||||
PostConfigurationNeeded = $false
|
||||
AdditionalInfo = @('MajorVersion', 'MinorVersion', 'NumericId', 'InstallName')
|
||||
}
|
||||
|
||||
SubTest1 = @{
|
||||
Name = 'SubTest1'
|
||||
DisplayName = 'Sub Test Feature 1'
|
||||
Description = 'Sub Test Feature with parent as test1'
|
||||
Installed = $true
|
||||
InstallState = 'Available'
|
||||
FeatureType = 'Role Service'
|
||||
Path = 'Test1\SubTest1'
|
||||
Depth = 2
|
||||
DependsOn = @()
|
||||
Parent = 'Test1'
|
||||
ServerComponentDescriptor = $null
|
||||
Subfeatures = @()
|
||||
SystemService = @()
|
||||
Notification = @()
|
||||
BestPracticesModelId = $null
|
||||
EventQuery = $null
|
||||
PostConfigurationNeeded = $false
|
||||
AdditionalInfo = @('MajorVersion', 'MinorVersion', 'NumericId', 'InstallName')
|
||||
}
|
||||
|
||||
SubTest2 = @{
|
||||
Name = 'SubTest2'
|
||||
DisplayName = 'Sub Test Feature 2'
|
||||
Description = 'Sub Test Feature with parent as test1'
|
||||
Installed = $true
|
||||
InstallState = 'Available'
|
||||
FeatureType = 'Role Service'
|
||||
Path = 'Test1\SubTest2'
|
||||
Depth = 2
|
||||
DependsOn = @()
|
||||
Parent = 'Test1'
|
||||
ServerComponentDescriptor = $null
|
||||
Subfeatures = @()
|
||||
SystemService = @()
|
||||
Notification = @()
|
||||
BestPracticesModelId = $null
|
||||
EventQuery = $null
|
||||
PostConfigurationNeeded = $false
|
||||
AdditionalInfo = @('MajorVersion', 'MinorVersion', 'NumericId', 'InstallName')
|
||||
}
|
||||
|
||||
SubTest3 = @{
|
||||
Name = 'SubTest3'
|
||||
DisplayName = 'Sub Test Feature 3'
|
||||
Description = 'Sub Test Feature with parent as test1'
|
||||
Installed = $true
|
||||
InstallState = 'Available'
|
||||
FeatureType = 'Role Service'
|
||||
Path = 'Test\SubTest3'
|
||||
Depth = 2
|
||||
DependsOn = @()
|
||||
Parent = 'Test1'
|
||||
ServerComponentDescriptor = $null
|
||||
Subfeatures = @()
|
||||
SystemService = @()
|
||||
Notification = @()
|
||||
BestPracticesModelId = $null
|
||||
EventQuery = $null
|
||||
PostConfigurationNeeded = $false
|
||||
AdditionalInfo = @('MajorVersion', 'MinorVersion', 'NumericId', 'InstallName')
|
||||
}
|
||||
|
||||
Test2 = @{
|
||||
Name = 'Test2'
|
||||
DisplayName = 'Test Feature 2'
|
||||
Description = 'Test Feature with 0 subfeatures'
|
||||
Installed = $true
|
||||
InstallState = 'Available'
|
||||
FeatureType = 'Role Service'
|
||||
Path = 'Test2'
|
||||
Depth = 1
|
||||
DependsOn = @()
|
||||
Parent = ''
|
||||
ServerComponentDescriptor = 'ServerComponent_Test_Cert_Authority'
|
||||
Subfeatures = @()
|
||||
SystemService = @()
|
||||
Notification = @()
|
||||
BestPracticesModelId = $null
|
||||
EventQuery = $null
|
||||
PostConfigurationNeeded = $false
|
||||
AdditionalInfo = @('MajorVersion', 'MinorVersion', 'NumericId', 'InstallName')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Describe 'WindowsFeature/Get-TargetResource' {
|
||||
Mock -CommandName Import-ServerManager -MockWith {}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testWindowsFeatureName2 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testWindowsFeatureName2]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testWindowsFeatureName1 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testWindowsFeatureName1]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testSubFeatureName1 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testSubFeatureName1]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testSubFeatureName2 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testSubFeatureName2]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testSubFeatureName3 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testSubFeatureName3]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
|
||||
Context 'Windows Feature exists with no sub features' {
|
||||
|
||||
It 'Should return the correct hashtable when not on a 2008 Server' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
$getTargetResourceResult = Get-TargetResource -Name $testWindowsFeatureName2
|
||||
$getTargetResourceResult.Name | Should Be $testWindowsFeatureName2
|
||||
$getTargetResourceResult.DisplayName | Should Be $mockWindowsFeatures[$testWindowsFeatureName2].DisplayName
|
||||
$getTargetResourceResult.Ensure | Should Be 'Present'
|
||||
$getTargetResourceResult.IncludeAllSubFeature | Should Be $false
|
||||
}
|
||||
|
||||
It 'Should return the correct hashtable when on a 2008 Server' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $true }
|
||||
|
||||
$getTargetResourceResult = Get-TargetResource -Name $testWindowsFeatureName2
|
||||
$getTargetResourceResult.Name | Should Be $testWindowsFeatureName2
|
||||
$getTargetResourceResult.DisplayName | Should Be $mockWindowsFeatures[$testWindowsFeatureName2].DisplayName
|
||||
$getTargetResourceResult.Ensure | Should Be 'Present'
|
||||
$getTargetResourceResult.IncludeAllSubFeature | Should Be $false
|
||||
}
|
||||
|
||||
It 'Should return the correct hashtable when on a 2008 Server and Credential is passed' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $true }
|
||||
Mock -CommandName Invoke-Command -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testWindowsFeatureName2]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
$getTargetResourceResult = Get-TargetResource -Name $testWindowsFeatureName2 -Credential $testCredential
|
||||
$getTargetResourceResult.Name | Should Be $testWindowsFeatureName2
|
||||
$getTargetResourceResult.DisplayName | Should Be $mockWindowsFeatures[$testWindowsFeatureName2].DisplayName
|
||||
$getTargetResourceResult.Ensure | Should Be 'Present'
|
||||
$getTargetResourceResult.IncludeAllSubFeature | Should Be $false
|
||||
|
||||
Assert-MockCalled -CommandName Invoke-Command -Times 1 -Exactly -Scope It
|
||||
|
||||
}
|
||||
}
|
||||
Context 'Windows Feature exists with sub features' {
|
||||
|
||||
It 'Should return the correct hashtable when all subfeatures are installed' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
$getTargetResourceResult = Get-TargetResource -Name $testWindowsFeatureName1
|
||||
$getTargetResourceResult.Name | Should Be $testWindowsFeatureName1
|
||||
$getTargetResourceResult.DisplayName | Should Be $mockWindowsFeatures[$testWindowsFeatureName1].DisplayName
|
||||
$getTargetResourceResult.Ensure | Should Be 'Absent'
|
||||
$getTargetResourceResult.IncludeAllSubFeature | Should Be $true
|
||||
|
||||
Assert-MockCalled -CommandName Test-IsWinServer2008R2SP1 -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should return the correct hashtable when not all subfeatures are installed' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
$mockWindowsFeatures[$testSubFeatureName3].Installed = $false
|
||||
|
||||
$getTargetResourceResult = Get-TargetResource -Name $testWindowsFeatureName1
|
||||
$getTargetResourceResult.Name | Should Be $testWindowsFeatureName1
|
||||
$getTargetResourceResult.DisplayName | Should Be $mockWindowsFeatures[$testWindowsFeatureName1].DisplayName
|
||||
$getTargetResourceResult.Ensure | Should Be 'Absent'
|
||||
$getTargetResourceResult.IncludeAllSubFeature | Should Be $false
|
||||
|
||||
Assert-MockCalled -CommandName Test-IsWinServer2008R2SP1 -Times 1 -Exactly -Scope It
|
||||
|
||||
$mockWindowsFeatures[$testSubFeatureName3].Installed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Windows Feature does not exist' {
|
||||
|
||||
It 'Should throw invalid operation exception' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
$invalidName = 'InvalidFeature'
|
||||
{ Get-TargetResource -Name $invalidName } | Should Throw ($script:localizedData.FeatureNotFoundError -f $invalidName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'WindowsFeature/Set-TargetResource' {
|
||||
Mock -CommandName Import-ServerManager -MockWith {}
|
||||
|
||||
Context 'Install/Uninstall successful' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
Mock -CommandName Add-WindowsFeature -MockWith {
|
||||
$windowsFeature = @{
|
||||
Success = $true
|
||||
RestartNeeded = 'No'
|
||||
FeatureResult = @($testWindowsFeatureName2)
|
||||
ExitCode = 'Success'
|
||||
}
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Remove-WindowsFeature -MockWith {
|
||||
$windowsFeature = @{
|
||||
Success = $true
|
||||
RestartNeeded = 'No'
|
||||
FeatureResult = @($testWindowsFeatureName2)
|
||||
ExitCode = 'Success'
|
||||
}
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
It 'Should call Add-WindowsFeature when Ensure set to Present' {
|
||||
{ Set-TargetResource -Name $testWindowsFeatureName2 -Ensure 'Present' } | Should Not Throw
|
||||
Assert-MockCalled -CommandName Add-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should call Remove-WindowsFeature when Ensure set to Absent' {
|
||||
{ Set-TargetResource -Name $testWindowsFeatureName2 -Ensure 'Absent' } | Should Not Throw
|
||||
Assert-MockCalled -CommandName Remove-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Context 'Install/Uninstall unsuccessful' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
Mock -CommandName Add-WindowsFeature -MockWith {
|
||||
$windowsFeature = @{
|
||||
Success = $false
|
||||
RestartNeeded = 'No'
|
||||
FeatureResult = @($testWindowsFeatureName2)
|
||||
ExitCode = 'Nothing succeeded'
|
||||
}
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Remove-WindowsFeature -MockWith {
|
||||
$windowsFeature = @{
|
||||
Success = $false
|
||||
RestartNeeded = 'No'
|
||||
FeatureResult = @($testWindowsFeatureName2)
|
||||
ExitCode = 'Nothing succeeded'
|
||||
}
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
It 'Should throw invalid operation exception when Ensure set to Present' {
|
||||
{ Set-TargetResource -Name $testWindowsFeatureName2 -Ensure 'Present' } |
|
||||
Should Throw ($script:localizedData.FeatureInstallationFailureError -f $testWindowsFeatureName2)
|
||||
Assert-MockCalled -CommandName Add-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should throw invalid operation exception when Ensure set to Absent' {
|
||||
{ Set-TargetResource -Name $testWindowsFeatureName2 -Ensure 'Absent' } |
|
||||
Should Throw ($script:localizedData.FeatureUninstallationFailureError -f $testWindowsFeatureName2)
|
||||
Assert-MockCalled -CommandName Remove-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Context 'Uninstall/Install with R2/SP1' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $true }
|
||||
|
||||
Mock -CommandName Invoke-Command -MockWith {
|
||||
$windowsFeature = @{
|
||||
Success = $true
|
||||
RestartNeeded = 'No'
|
||||
FeatureResult = @($testWindowsFeatureName2)
|
||||
ExitCode = 'Success'
|
||||
}
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
It 'Should install the feature when Ensure set to Present and Credential passed in' {
|
||||
|
||||
{
|
||||
Set-TargetResource -Name $testWindowsFeatureName2 `
|
||||
-Ensure 'Present' `
|
||||
-Credential $testCredential
|
||||
} | Should Not Throw
|
||||
Assert-MockCalled -CommandName Invoke-Command -Times 1 -Exactly -Scope It
|
||||
Assert-MockCalled -CommandName Add-WindowsFeature -Times 0 -Scope It
|
||||
}
|
||||
|
||||
It 'Should uninstall the feature when Ensure set to Absent and Credential passed in' {
|
||||
|
||||
{
|
||||
Set-TargetResource -Name $testWindowsFeatureName2 `
|
||||
-Ensure 'Absent' `
|
||||
-Credential $testCredential
|
||||
} | Should Not Throw
|
||||
Assert-MockCalled -CommandName Invoke-Command -Times 1 -Exactly -Scope It
|
||||
Assert-MockCalled -CommandName Remove-WindowsFeature -Times 0 -Scope It
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'WindowsFeature/Test-TargetResource' {
|
||||
Mock -CommandName Import-ServerManager -MockWith {}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testWindowsFeatureName1 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testWindowsFeatureName1]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testSubFeatureName1 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testSubFeatureName1]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testSubFeatureName2 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testSubFeatureName2]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Mock -CommandName Get-WindowsFeature -ParameterFilter { $Name -eq $testSubFeatureName3 } -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testSubFeatureName3]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
# Used as Get-WindowsFeature when on R2/SP1 2008
|
||||
Mock -CommandName Invoke-Command -MockWith {
|
||||
$windowsFeature = $mockWindowsFeatures[$testWindowsFeatureName1]
|
||||
$windowsFeatureObject = New-Object -TypeName PSObject -Property $windowsFeature
|
||||
$windowsFeatureObject.PSTypeNames[0] = 'Microsoft.Windows.ServerManager.Commands.Feature'
|
||||
|
||||
return $windowsFeatureObject
|
||||
}
|
||||
|
||||
Context 'Feature is in the desired state' {
|
||||
|
||||
It 'Should return true when Ensure set to Absent and Feature not installed' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Absent' `
|
||||
-IncludeAllSubFeature $false
|
||||
$testTargetResourceResult | Should Be $true
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should return true when Ensure set to Present and Feature installed not checking subFeatures' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $true
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Present' `
|
||||
-IncludeAllSubFeature $false
|
||||
$testTargetResourceResult | Should Be $true
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $false
|
||||
}
|
||||
|
||||
It 'Should return true when Ensure set to Present and Feature and subFeatures installed' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $true
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Present' `
|
||||
-IncludeAllSubFeature $true
|
||||
$testTargetResourceResult | Should Be $true
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 4 -Exactly -Scope It
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $false
|
||||
}
|
||||
|
||||
It 'Should return true when Ensure set to Absent and Feature not installed and on R2/SP1 2008' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $true }
|
||||
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Absent' `
|
||||
-IncludeAllSubFeature $false `
|
||||
-Credential $testCredential
|
||||
$testTargetResourceResult | Should Be $true
|
||||
Assert-MockCalled -CommandName Invoke-Command -Times 1 -Exactly -Scope It
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Feature is not in the desired state' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $false }
|
||||
|
||||
It 'Should return false when Ensure set to Present and Feature not installed' {
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Present' `
|
||||
-IncludeAllSubFeature $false
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should return false when Ensure set to Absent and Feature installed not checking subFeatures' {
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $true
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Absent' `
|
||||
-IncludeAllSubFeature $false
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $false
|
||||
}
|
||||
|
||||
It 'Should return false when Ensure set to Present, Feature not installed and subFeatures installed' {
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Present' `
|
||||
-IncludeAllSubFeature $true
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should return false when Ensure set to Absent and Feature not installed but subFeatures installed' {
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Absent' `
|
||||
-IncludeAllSubFeature $true
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 2 -Exactly -Scope It
|
||||
}
|
||||
|
||||
It 'Should return false when Ensure set to Absent and Feature installed and subFeatures installed' {
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $true
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Absent' `
|
||||
-IncludeAllSubFeature $true
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 1 -Exactly -Scope It
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $false
|
||||
}
|
||||
|
||||
It 'Should return false when Ensure set to Present and Feature installed but not all subFeatures installed' {
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $true
|
||||
$mockWindowsFeatures[$testSubFeatureName2].Installed = $false
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Present' `
|
||||
-IncludeAllSubFeature $true
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Get-WindowsFeature -Times 3 -Exactly -Scope It
|
||||
$mockWindowsFeatures[$testWindowsFeatureName1].Installed = $false
|
||||
$mockWindowsFeatures[$testSubFeatureName2].Installed = $true
|
||||
}
|
||||
|
||||
It 'Should return false when Ensure set to Present and Feature not installed and on R2/SP1 2008' {
|
||||
Mock -CommandName Test-IsWinServer2008R2SP1 -MockWith { return $true }
|
||||
|
||||
$testTargetResourceResult = Test-TargetResource -Name $testWindowsFeatureName1 `
|
||||
-Ensure 'Present' `
|
||||
-IncludeAllSubFeature $false `
|
||||
-Credential $testCredential
|
||||
$testTargetResourceResult | Should Be $false
|
||||
Assert-MockCalled -CommandName Invoke-Command -Times 1 -Exactly -Scope It
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'WindowsFeature/Assert-SingleFeatureExists' {
|
||||
$multipleFeature = @{
|
||||
Name = 'MultiFeatureName'
|
||||
Count = 2
|
||||
}
|
||||
|
||||
It 'Should throw invalid operation when feature equals null' {
|
||||
$nonexistentName = 'NonexistentFeatureName'
|
||||
{ Assert-SingleFeatureExists -Feature $null -Name $nonexistentName } |
|
||||
Should Throw ($script:localizedData.FeatureNotFoundError -f $nonexistentName)
|
||||
}
|
||||
|
||||
It 'Should throw invalid operation when there are multiple features with the given name' {
|
||||
{ Assert-SingleFeatureExists -Feature $multipleFeature -Name $multipleFeature.Name } |
|
||||
Should Throw ($script:localizedData.MultipleFeatureInstancesError -f $multipleFeature.Name)
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'WindowsFeature/Import-ServerManager' {
|
||||
$mockOperatingSystem = @{
|
||||
Name = 'mockOS'
|
||||
Version = '6.1.'
|
||||
OperatingSystemSKU = 10
|
||||
}
|
||||
Mock -CommandName Get-WmiObject -MockWith { return $mockOperatingSystem }
|
||||
|
||||
It 'Should Not Throw' {
|
||||
Mock -CommandName Import-Module -MockWith {}
|
||||
{ Import-ServerManager } | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should throw invalid operation exception' {
|
||||
Mock -CommandName Import-Module -MockWith { Throw }
|
||||
|
||||
{ Import-ServerManager } | Should Throw ($script:localizedData.SkuNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment
|
||||
}
|
||||
Reference in New Issue
Block a user