adding Service resource

This commit is contained in:
Mariah Breakey
2016-10-07 22:50:20 -07:00
parent 412cf14de8
commit f9e0ed550d
13 changed files with 4602 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
[ClassVersion("1.0.0"),FriendlyName("Service")]
class MSFT_ServiceResource : OMI_BaseResource
{
[Key,Description("Indicates the service name. Note that sometimes this is different from the display name. You can get a list of the services and their current state with the Get-Service cmdlet.")] String Name;
[Write,Description("Ensures that the service is present or absent. Defaults to Present."),ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] String Ensure;
[Write,Description("The path to the service executable file.")] String Path;
[Write,Description("Indicates the startup type for the service."),ValueMap{"Automatic", "Manual", "Disabled"},Values{"Automatic", "Manual", "Disabled"}] String StartupType;
[Write,Description("Indicates the sign-in account to use for the service."),ValueMap{"LocalSystem", "LocalService", "NetworkService"},Values{"LocalSystem", "LocalService", "NetworkService"}] String BuiltInAccount;
[Write,Description("The credential to run the service under."),EmbeddedInstance("MSFT_Credential")] String Credential;
[Write,Description("The service can create or communicate with a window on the desktop. Must be false for services not running as LocalSystem. Defaults to False.")] Boolean DesktopInteract;
[Write,Description("Indicates the state you want to ensure for the service. Defaults to Running."),ValueMap{"Running", "Stopped", "Ignore"},Values{"Running", "Stopped", "Ignore"}] String State;
[Write,Description("The display name of the service.")] String DisplayName;
[Write,Description("The description of the service.")] String Description;
[Write,Description("An array of strings indicating the names of the dependencies of the service.")] String Dependencies[];
[Write,Description("The time to wait for the service to start in milliseconds. Defaults to 30000.")] uint32 StartupTimeout;
[Write,Description("The time to wait for the service to stop in milliseconds. Defaults to 30000.")] uint32 TerminateTimeout;
};
@@ -0,0 +1,49 @@
# Localized resources for MSFT_ServiceResource
ConvertFrom-StringData @'
ServiceNotFound = Service '{0}' not found.
CannotStartAndDisable = Cannot start and disable a service.
CannotStopServiceSetToStartAutomatically = Cannot stop a service and set it to start automatically.
ServiceAlreadyStarted = Service '{0}' already started, no action required.
ServiceStarted = Service '{0}' started.
ServiceStopped = Service '{0}' stopped.
ErrorStartingService = Failure starting service '{0}'. Please check the path '{1}' provided for the service. Message: '{2}'
OnlyOneParameterCanBeSpecified = Only one of the following parameters can be specified: '{0}', '{1}'.
StartServiceWhatIf = Start Service
StopServiceWhatIf = Stop Service
ServiceAlreadyStopped = Service '{0}' already stopped, no action required.
ErrorStoppingService = Failure stopping service '{0}'. Message: '{1}'
ErrorRetrievingServiceInformation = Failure retrieving information for service '{0}'. Message: '{1}'
ErrorSettingServiceCredential = Failure setting credentials for service '{0}'. Message: '{1}'
SetCredentialWhatIf = Set Credential
SetStartupTypeWhatIf = Set Start Type
ErrorSettingServiceStartupType = Failure setting start type for service '{0}'. Message: '{1}'
TestBinaryPathMismatch = Binary path for service '{0}' is '{1}'. It does not match '{2}'.
TestUserNameMismatch = User name for service '{0}' is '{1}'. It does not match '{2}'.
TestStartupTypeMismatch = Startup type for service '{0}' is '{1}'. It does not match '{2}'.
TestDesktopInteractMismatch = Desktop interact for service '{0}' is '{1}'. It does not match '{2}'.
TestStateMismatch = State of service '{0}' is '{1}'. It does not match '{2}'.
MethodFailed = The '{0}' method of '{1}' failed with error code: '{2}'.
ErrorChangingProperty = Failed to change '{0}' property. Message: '{1}'
ErrorSettingLogOnAsServiceRightsForUser = Error granting '{0}' the right to log on as a service. Message: '{1}'.
CannotOpenPolicyErrorMessage = Cannot open policy manager.
UserNameTooLongErrorMessage = User name is too long.
CannotLookupNamesErrorMessage = Failed to lookup user name.
CannotOpenAccountErrorMessage = Failed to open policy for user.
CannotCreateAccountAccessErrorMessage = Failed to create policy for user.
CannotGetAccountAccessErrorMessage = Failed to get user policy rights.
CannotSetAccountAccessErrorMessage = Failed to set user policy rights.
BinaryPathNotSpecified = Specify the path to the executable when trying to create a new service.
ServiceAlreadyExists = The service '{0}' to create already exists.
ServiceExistsSamePath = The service '{0}' to create already exists with path '{1}'.
ServiceDoesNotExistPathMissingError = The service '{0}' does not exist. Specify the path to the executable to create a new service.
ErrorDeletingService = Error in deleting service '{0}'.
ServiceDeletedSuccessfully = Service '{0}' Deleted Successfully.
TryDeleteAgain = Wait for 2 milliseconds for a service to get deleted.
WritePropertiesIgnored = Service '{0}' already exists. Write properties such as Status, DisplayName, Description, Dependencies will be ignored for existing services.
ErrorCreatingService = Error creating service '{0}'; Exception Message: '{1}'
ServiceNeedsRestartMessage = Service '{0}' needs to be restarted.
ServiceExecutablePathChangeNotSupported = Changing the path to an existing service executable is not yet supported.
NotCheckingOtherValuesEnsureAbsent = Not checking other values since Ensure is set to Absent.
ServiceDoesNotExist = Service does not exist.
'@
+60
View File
@@ -0,0 +1,60 @@
Configuration Sample_Service_CreateService
{
param
(
[System.String[]]
$nodeName = 'localhost',
[System.String]
$Name,
[System.String]
[ValidateSet('Automatic', 'Manual', 'Disabled')]
$StartupType='Automatic',
[System.String]
[ValidateSet('LocalSystem', 'LocalService', 'NetworkService')]
$BuiltInAccount='LocalSystem',
[System.Management.Automation.PSCredential]
$Credential,
[System.String]
[ValidateSet('Running', 'Stopped')]
$State='Running',
[System.String]
[ValidateSet('Present', 'Absent')]
$Ensure='Present',
[System.String]
$Path,
[System.String]
$DisplayName,
[System.String]
$Description,
[System.String[]]
$Dependencies
)
Import-DscResource -Name MSFT_ServiceResource -ModuleName PSDscResources
Node $nodeName
{
Service service
{
Name = $Name
Ensure = $Ensure
Path = $Path
}
}
}
Sample_Service_CreateService -Name 'Sample Service' -Ensure 'Present' -Path 'C:\DSC\TestService.exe'
+59
View File
@@ -0,0 +1,59 @@
Configuration Sample_Service_DeleteService
{
param
(
[System.String[]]
$nodeName = 'localhost',
[System.String]
$Name,
[System.String]
[ValidateSet('Automatic', 'Manual', 'Disabled')]
$StartupType,
[System.String]
[ValidateSet('LocalSystem', 'LocalService', 'NetworkService')]
$BuiltInAccount,
[System.Management.Automation.PSCredential]
$Credential ,
[System.String]
[ValidateSet('Running', 'Stopped')]
$State='Running',
[System.String]
[ValidateSet('Present', 'Absent')]
$Ensure='Present',
[System.String]
$Path,
[System.String]
$DisplayName,
[System.String]
$Description,
[System.String[]]
$Dependencies
)
Import-DscResource -Name MSFT_ServiceResource -ModuleName PSDscResources
Node $nodeName
{
Service service
{
Name = $Name
Ensure = $Ensure
}
}
}
Sample_Service_DeleteService -Name 'Sample Service' -Ensure 'Absent'
@@ -0,0 +1,68 @@
Configuration Sample_Service_ServiceWithCredential
{
param
(
[System.String[]]
$nodeName = 'localhost',
[System.String]
$Name,
[System.String]
[ValidateSet('Automatic', 'Manual', 'Disabled')]
$StartupType='Automatic',
[System.String]
[ValidateSet('LocalSystem', 'LocalService', 'NetworkService')]
$BuiltInAccount='LocalSystem',
[System.Management.Automation.PSCredential]
$Credential,
[System.String]
[ValidateSet('Running', 'Stopped')]
$State='Running',
[System.String]
[ValidateSet('Present', 'Absent')]
$Ensure='Present',
[System.String]
$Path,
[System.String]
$DisplayName,
[System.String]
$Description,
[System.String[]]
$Dependencies
)
Import-DscResource -Name MSFT_ServiceResource -ModuleName PSDscResources
Node $nodeName
{
Service service
{
Name = $Name
DisplayName = $DisplayName
Ensure = $Ensure
Path = $Path
StartupType = $StartupType
Credential = $credential
DesktopInteract = 'False'
}
}
}
# To use the sample(s) with credentials, see blog at http://blogs.msdn.com/b/powershell/archive/2014/01/31/want-to-secure-credentials-in-windows-powershell-desired-state-configuration.aspx
@@ -0,0 +1,185 @@
$script:DscResourceName = 'MSFT_ServiceResource'
Import-Module -Name (Join-Path -Path (Split-Path $PSScriptRoot -Parent) `
-ChildPath 'CommonTestHelper.psm1') `
-Force
$script:testEnvironment = Enter-DscResourceTestEnvironment `
-DscResourceModuleName 'PSDscResources' `
-DscResourceName 'MSFT_ServiceResource' `
-TestType 'Integration'
try
{
$script:testServiceName = 'DscTestService'
$script:testServiceCodePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'DscTestService.cs'
$script:testServiceDisplayName = 'DSC test service display name'
$script:testServiceDescription = 'This is a DSC test service used for integration testing MSFT_ServiceResource'
$script:testServiceDependsOn = 'winrm'
$script:testServiceExecutablePath = Join-Path -Path $ENV:Temp -ChildPath 'DscTestService.exe'
$script:testServiceNewCodePath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'DscTestService.cs'
$script:testServiceNewDisplayName = 'New: DSC test service display name'
$script:testServiceNewDescription = 'New: This is a DSC test service used for integration testing MSFT_ServiceResource'
$script:testServiceNewDependsOn = 'spooler'
$script:testServiceNewExecutablePath = Join-Path -Path $ENV:Temp -ChildPath 'NewDscTestService.exe'
<#
Nano Server doesn't recognize 'spooler', so if these tests are being run on Nano
this value must stay as 'winrm'
#>
if ($PSVersionTable.PSEdition -ieq 'Core') { $script:testServiceNewDependsOn = 'winrm' }
Import-Module -Name (Join-Path -Path (Split-Path $PSScriptRoot -Parent) `
-ChildPath 'MSFT_ServiceResource.TestHelper.psm1') `
-Force
Stop-Service $script:testServiceName -ErrorAction SilentlyContinue
# Create new Service binaries for the new service.
New-ServiceBinary `
-ServiceName $script:testServiceName `
-ServiceCodePath $script:testServiceCodePath `
-ServiceDisplayName $script:testServiceDisplayName `
-ServiceDescription $script:testServiceDescription `
-ServiceDependsOn $script:testServiceDependsOn `
-ServiceExecutablePath $script:testServiceExecutablePath
New-ServiceBinary `
-ServiceName $script:testServiceName `
-ServiceCodePath $script:testServiceNewCodePath `
-ServiceDisplayName $script:testServiceNewDisplayName `
-ServiceDescription $script:testServiceNewDescription `
-ServiceDependsOn $script:testServiceNewDependsOn `
-ServiceExecutablePath $script:testServiceExecutablePath
#region Integration Tests
$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DscResourceName)_Add.config.ps1"
. $configFile
Describe "$($script:DscResourceName) Add Service" {
It 'Should compile and apply the MOF without throwing' {
{
& "$($script:DscResourceName)_Add_Config" `
-OutputPath $script:testEnvironment.WorkingFolder `
-ServiceName $script:testServiceName `
-ServicePath $script:testServiceExecutablePath `
-ServiceDisplayName $script:testServiceDisplayName `
-ServiceDescription $script:testServiceDescription `
-ServiceDependsOn $script:testServiceDependsOn
Start-DscConfiguration -Path $script:testEnvironment.WorkingFolder `
-ComputerName localhost -Wait -Verbose -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction Stop } | Should Not Throw
}
$script:service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$($script:testServiceName)'"
It 'Should return a service of type CimInstance' {
$script:service | Should BeOfType 'Microsoft.Management.Infrastructure.CimInstance'
}
It 'Should have set the resource and all the parameters should match' {
# Get the current service details
$script:service.status | Should Be 'OK'
$script:service.pathname | Should Be $script:testServiceExecutablePath
$script:service.description | Should Be $script:testServiceDescription
$script:service.displayname | Should Be $script:testServiceDisplayName
$script:service.started | Should Be $true
$script:service.state | Should Be 'Running'
$script:service.desktopinteract | Should Be $true
$script:service.startname | Should Be 'LocalSystem'
$script:service.startmode | Should Be 'Auto'
}
}
Reset-DSC
$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DscResourceName)_Edit.config.ps1"
. $configFile
Describe "$($script:DscResourceName) Edit Service" {
It 'Should compile and apply the MOF without throwing' {
{
& "$($script:DscResourceName)_Edit_Config" `
-OutputPath $script:testEnvironment.WorkingFolder `
-ServiceName $script:testServiceName `
-ServicePath $script:testServiceNewExecutablePath `
-ServiceDisplayName $script:testServiceNewDisplayName `
-ServiceDescription $script:testServiceNewDescription `
-ServiceDependsOn $script:testServiceNewDependsOn
Start-DscConfiguration -Path $script:testEnvironment.WorkingFolder `
-ComputerName localhost -Wait -Verbose -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction Stop } | Should Not Throw
}
# Get the current service details
$script:service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$($script:testServiceName)'"
It 'Should return a service or type CimInstance' {
$script:service | Should BeOfType 'Microsoft.Management.Infrastructure.CimInstance'
}
It 'Should have set the resource and all the parameters should match' {
# Get the current service details
$script:service.status | Should Be 'OK'
$script:service.pathname | Should Be $script:testServiceNewExecutablePath
$script:service.description | Should Be $script:testServiceNewDescription
$script:service.displayname | Should Be $script:testServiceNewDisplayName
$script:service.started | Should Be $false
$script:service.state | Should Be 'Stopped'
$script:service.desktopinteract | Should Be $false
$script:service.startname | Should Be 'NT Authority\LocalService'
$script:service.startmode | Should Be 'Manual'
}
}
Reset-DSC
$configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DscResourceName)_Remove.config.ps1"
. $configFile
Describe "$($script:DscResourceName) Remove Service" {
It 'Should compile and apply the MOF without throwing' {
{
& "$($script:DscResourceName)_Remove_Config" `
-OutputPath $script:testEnvironment.WorkingFolder `
-ServiceName $script:testServiceName
Start-DscConfiguration -Path $script:testEnvironment.WorkingFolder `
-ComputerName localhost -Wait -Verbose -Force
} | Should not throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction Stop } | Should Not throw
}
# Get the current service details
$script:service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$($script:testServiceName)'"
It 'Should return the service as null' {
$script:service | Should BeNullOrEmpty
}
}
#endregion
}
finally
{
# Clean up
Remove-TestService `
-ServiceName $script:testServiceName `
-ServiceExecutablePath $script:testServiceExecutablePath
Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment
}
@@ -0,0 +1,27 @@
Configuration MSFT_ServiceResource_Add_Config {
param
(
$ServiceName,
$ServicePath,
$ServiceDisplayName,
$ServiceDescription,
$ServiceDependsOn
)
Import-DscResource -ModuleName PSDscResources
node localhost {
Service AddService {
Name = $ServiceName
Ensure = 'Present'
Path = $ServicePath
StartupType = 'Automatic'
BuiltInAccount = 'LocalSystem'
DesktopInteract = $true
State = 'Running'
DisplayName = $ServiceDisplayName
Description = $ServiceDescription
Dependencies = $ServiceDependsOn
}
}
}
@@ -0,0 +1,27 @@
Configuration MSFT_ServiceResource_Edit_Config {
param
(
$ServiceName,
$ServicePath,
$ServiceDisplayName,
$ServiceDescription,
$ServiceDependsOn
)
Import-DscResource -ModuleName PSDscResources
node localhost {
Service EditService {
Name = $ServiceName
Ensure = 'Present'
Path = $ServicePath
StartupType = 'Manual'
BuiltInAccount = 'LocalService'
DesktopInteract = $false
State = 'Stopped'
DisplayName = $ServiceDisplayName
Description = $ServiceDescription
Dependencies = $ServiceDependsOn
}
}
}
@@ -0,0 +1,15 @@
Configuration MSFT_ServiceResource_Remove_Config {
param
(
$ServiceName
)
Import-DscResource -ModuleName PSDscResources
node localhost {
Service RemoveService {
Name = $ServiceName
Ensure = 'Absent'
}
}
}
@@ -0,0 +1,243 @@
<#
.SYNOPSIS
Creates a service binary file.
.PARAMETER ServiceName
The name of the service to create the binary file for.
.PARAMETER ServiceCodePath
The path to the code for the service to create the binary file for.
.PARAMETER ServiceDisplayName
The display name of the service to create the binary file for.
.PARAMETER ServiceDescription
The description of the service to create the binary file for.
.PARAMETER ServiceDependsOn
Dependencies of the service to create the binary file for.
.PARAMETER ServiceExecutablePath
The path to write the service executable to.
#>
function New-ServiceBinary
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[String]
$ServiceName,
[Parameter(Mandatory = $true)]
[String]
$ServiceCodePath,
[Parameter(Mandatory = $true)]
[String]
$ServiceDisplayName,
[Parameter(Mandatory = $true)]
[String]
$ServiceDescription,
[Parameter(Mandatory = $true)]
[String]
$ServiceDependsOn,
[Parameter(Mandatory = $true)]
[String]
$ServiceExecutablePath
)
if (Get-Service $ServiceName -ErrorAction Ignore)
{
Stop-Service $ServiceName -ErrorAction SilentlyContinue
Remove-TestService -ServiceName $ServiceName -ServiceExecutablePath $ServiceExecutablePath
}
$fileText = Get-Content $ServiceCodePath -Raw
$fileText = $fileText.Replace('TestServiceReplacementName', $ServiceName)
$fileText = $fileText.Replace('TestServiceReplacementDisplayName', $ServiceDisplayName)
$fileText = $fileText.Replace('TestServiceReplacementDescription', $ServiceDescription)
$fileText = $fileText.Replace('TestServiceReplacementDependsOn', $ServiceDependsOn)
Add-Type $fileText `
-OutputAssembly $ServiceExecutablePath `
-OutputType WindowsApplication `
-ReferencedAssemblies @('System.ServiceProcess', 'System.Configuration.Install')
}
<#
.SYNOPSIS
Creates a new service for testing.
.PARAMETER ServiceName
The name of the service to create.
.PARAMETER ServiceCodePath
The path to the code for the service to create.
.PARAMETER ServiceDisplayName
The display name of the service to create.
.PARAMETER ServiceDescription
The description of the service to create.
.PARAMETER ServiceDependsOn
Dependencies of the service to create.
.PARAMETER ServiceExecutablePath
The path to write the service executable to.
#>
function New-TestService
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[String]
$ServiceName,
[Parameter(Mandatory = $true)]
[String]
$ServiceCodePath,
[Parameter(Mandatory = $true)]
[String]
$ServiceDisplayName,
[Parameter(Mandatory = $true)]
[String]
$ServiceDescription,
[Parameter(Mandatory = $true)]
[String]
$ServiceDependsOn,
[Parameter(Mandatory = $true)]
[String]
$ServiceExecutablePath
)
New-ServiceBinary `
-ServiceName $ServiceName `
-ServiceCodePath $ServiceCodePath `
-ServiceDisplayName $ServiceDisplayName `
-ServiceDescription $ServiceDescription `
-ServiceDependsOn $ServiceDependsOn `
-ServiceExecutablePath $ServiceExecutablePath
if (-not (Test-Path $ServiceExecutablePath))
{
throw 'Failed to create service executable file.'
}
$configurationName = 'TestServiceConfig'
$configurationPath = Join-Path -Path (Get-Location) -ChildPath $ServiceName
Configuration $configurationName
{
Import-DscResource -ModuleName PSDscResources
Service Service1
{
Name = $ServiceName
Path = $ServiceExecutablePath
DisplayName = $ServiceDisplayName
Description = $ServiceDescription
Dependencies = $ServiceDependsOn
StartupType = 'Manual'
BuiltInAccount = 'LocalSystem'
State = 'Stopped'
Ensure = 'Present'
}
}
& $configurationName -OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -Wait -Force -Verbose
}
<#
.SYNOPSIS
Retrieves the path to the install utility.
#>
function Get-InstallUtilPath
{
[CmdletBinding()]
param ()
if ($env:Processor_Architecture -ieq 'amd64')
{
$frameworkName = 'Framework64'
}
else
{
$frameworkName = 'Framework'
}
return Join-Path -Path (Resolve-Path "$env:WinDir\Microsoft.Net\$frameworkName\v4*") `
-ChildPath 'installUtil.exe'
}
<#
.SYNOPSIS
Removes a service.
.PARAMETER ServiceName
The name of the service to remove.
.PARAMETER ServiceExecutablePath
The path to the executable of the service to remove.
#>
function Remove-TestService
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[String]
$ServiceName,
[Parameter(Mandatory = $true)]
[String]
$ServiceExecutablePath
)
if (Get-Service -Name $ServiceName -ErrorAction SilentlyContinue)
{
$installUtility = Get-InstallUtilPath
& $installUtility /u $ServiceExecutablePath
}
Remove-Item $ServiceExecutablePath -Force -ErrorAction SilentlyContinue
Remove-Item *.InstallLog -Force -ErrorAction SilentlyContinue
Remove-Item $ServiceName -Force -Recurse -ErrorAction SilentlyContinue
}
function Get-InvalidArgumentRecord
{
[CmdletBinding()]
param
(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[System.String]
$ErrorId,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[System.String]
$ErrorMessage
)
$exception = New-Object -TypeName System.InvalidOperationException `
-ArgumentList $ErrorMessage
$errorCategory = [System.Management.Automation.ErrorCategory]::InvalidOperation
$errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord `
-ArgumentList $exception, $ErrorId, $errorCategory, $null
return $errorRecord
}
Export-ModuleMember -Function `
New-ServiceBinary, `
New-TestService, `
Remove-TestService, `
Get-InvalidArgumentRecord
File diff suppressed because it is too large Load Diff