MegaBites-AI/Windows-powershell
0372
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3 4[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')]5param()6 7Import-Module (Join-Path -Path $PSScriptRoot '..\Microsoft.PowerShell.Security\certificateCommon.psm1')8 9Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows" {10 BeforeAll {11 $originalDefaultParameterValues = $PSDefaultParameterValues.Clone()12 if ( -not $IsWindows ) {13 $PSDefaultParameterValues["it:skip"] = $true14 }15 if ($IsWindows) {16 $userName = "testuserservices"17 $testPass = [Net.NetworkCredential]::new("", (New-ComplexPassword)).SecurePassword18 $creds = [pscredential]::new(".\$userName", $testPass)19 $SecurityDescriptorSddl = 'D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;SU)'20 $WrongSecurityDescriptorSddl = 'D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BB)(A;;CCLCSWLOCRRC;;;SU)'21 net user $userName $creds.GetNetworkCredential().Password /add > $null22 23 $testservicename1 = "testservice1"24 $testservicename2 = "testservice2"25 $svcbinaryname = "TestService"26 $svccmd = Get-Command $svcbinaryname27 $svccmd | Should -Not -BeNullOrEmpty28 $svcfullpath = $svccmd.Path29 $testservice1 = New-Service -BinaryPathName $svcfullpath -Name $testservicename130 $testservice1 | Should -Not -BeNullOrEmpty31 $testservice2 = New-Service -BinaryPathName $svcfullpath -Name $testservicename2 -DependsOn $testservicename132 $testservice2 | Should -Not -BeNullOrEmpty33 }34 35 Function CheckSecurityDescriptorSddl {36 Param(37 [Parameter(Mandatory)]38 $SecurityDescriptorSddl,39 40 [Parameter(Mandatory)]41 $ServiceName42 )43 $Counter = 044 $ExpectedSDDL = ConvertFrom-SddlString -Sddl $SecurityDescriptorSddl45 46 # Selecting the first item in the output array as below command gives plain text output from the native sc.exe.47 $UpdatedSDDL = ConvertFrom-SddlString -Sddl (sc sdshow $ServiceName)[1]48 49 $UpdatedSDDL.Owner | Should -Be $ExpectedSDDL.Owner50 $UpdatedSDDL.Group | Should -Be $ExpectedSDDL.Group51 $UpdatedSDDL.DiscretionaryAcl.Count | Should -Be $ExpectedSDDL.DiscretionaryAcl.Count52 $UpdatedSDDL.DiscretionaryAcl | ForEach-Object -Process {53 $_ | Should -Be $ExpectedSDDL.DiscretionaryAcl[$Counter]54 $Counter++55 }56 }57 }58 AfterAll {59 $global:PSDefaultParameterValues = $originalDefaultParameterValues60 if ($IsWindows) {61 net user $userName /delete > $null62 63 Stop-Service $testservicename264 Stop-Service $testservicename165 Remove-Service $testservicename266 Remove-Service $testservicename167 }68 }69 70 It "SetServiceCommand can be used as API for '<parameter>' with '<value>'" -TestCases @(71 @{parameter = "Name" ; value = "bar"},72 @{parameter = "DisplayName" ; value = "hello"},73 @{parameter = "Description" ; value = "hello world"},74 @{parameter = "StartupType" ; value = "Automatic"},75 @{parameter = "StartupType" ; value = "Disabled"},76 @{parameter = "StartupType" ; value = "Manual"},77 @{parameter = "Status" ; value = "Running"},78 @{parameter = "Status" ; value = "Stopped"},79 @{parameter = "Status" ; value = "Paused"},80 @{parameter = "InputObject" ; script = {Get-Service | Select-Object -First 1}},81 # cmdlet inherits this property, but it's not exposed as parameter so it should be $null82 @{parameter = "Include" ; value = "foo", "bar" ; expectedNull = $true},83 # cmdlet inherits this property, but it's not exposed as parameter so it should be $null84 @{parameter = "Exclude" ; value = "foo", "bar" ; expectedNull = $true}85 ) {86 param($parameter, $value, $script, $expectedNull)87 88 $setServiceCommand = [Microsoft.PowerShell.Commands.SetServiceCommand]::new()89 if ($script -ne $null) {90 $value = & $script91 }92 $setServiceCommand.$parameter = $value93 if ($expectedNull -eq $true) {94 $setServiceCommand.$parameter | Should -BeNullOrEmpty95 }96 else {97 $setServiceCommand.$parameter | Should -Be $value98 }99 }100 101 It "Set-Service parameter validation for invalid values: <script>" -TestCases @(102 @{103 script = {Set-Service foo -StartupType bar -ErrorAction Stop};104 errorid = "CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetServiceCommand"105 },106 @{107 script = {Set-Service -Name $testservicename1 -SecurityDescriptorSddl $WrongSecurityDescriptorSddl };108 errorid = "System.ArgumentException,Microsoft.PowerShell.Commands.SetServiceCommand"109 }110 ) {111 param($script, $errorid)112 { & $script } | Should -Throw -ErrorId $errorid113 }114 115 116 It "Sets securitydescriptor of service using Set-Service " {117 Set-Service -Name $TestServiceName1 -SecurityDescriptorSddl $SecurityDescriptorSddl118 CheckSecurityDescriptorSddl -SecurityDescriptor $SecurityDescriptorSddl -ServiceName $TestServiceName1119 }120 121 It "Set-Service can change '<parameter>' to '<value>'" -TestCases @(122 @{parameter = "Description"; value = "hello"},123 @{parameter = "DisplayName"; value = "test spooler"},124 @{parameter = "StartupType"; value = "Disabled"},125 @{parameter = "Status" ; value = "running" ; expected = "OK"}126 ) {127 param($parameter, $value, $expected)128 $currentService = Get-CimInstance -ClassName Win32_Service -Filter "Name='spooler'"129 $originalStartupType = (Get-Service -Name spooler).StartType130 try {131 $setServiceCommand = [Microsoft.PowerShell.Commands.SetServiceCommand]::new()132 $setServiceCommand.Name = "Spooler"133 $setServiceCommand.$parameter = $value134 $setServiceCommand.Invoke()135 $updatedService = Get-CimInstance -ClassName Win32_Service -Filter "Name='spooler'"136 if ($expected -eq $null) {137 $expected = $value138 }139 if ($parameter -eq "StartupType") {140 $updatedService.StartMode | Should -Be $expected141 }142 else {143 $updatedService.$parameter | Should -Be $expected144 }145 }146 finally {147 if ($parameter -eq "StartupType") {148 $setServiceCommand.StartupType = $originalStartupType149 }150 else {151 $setServiceCommand.$parameter = $currentService.$parameter152 }153 $setServiceCommand.Invoke()154 $updatedService = Get-CimInstance -ClassName Win32_Service -Filter "Name='spooler'"155 $updatedService.$parameter | Should -Be $currentService.$parameter156 }157 }158 159 It "NewServiceCommand can be used as API for '<parameter>' with '<value>'" -TestCases @(160 @{parameter = "Name" ; value = "bar"},161 @{parameter = "BinaryPathName" ; value = "hello"},162 @{parameter = "DisplayName" ; value = "hello world"},163 @{parameter = "Description" ; value = "this is a test"},164 @{parameter = "StartupType" ; value = "Automatic"},165 @{parameter = "StartupType" ; value = "Disabled"},166 @{parameter = "StartupType" ; value = "Manual"},167 @{parameter = "SecurityDescriptorSddl" ; value = $SecurityDescriptorSddl},168 @{parameter = "Credential" ; value = (169 [System.Management.Automation.PSCredential]::new("username",170 #[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Demo/doc/test secret.")]171 (ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force)))172 }173 @{parameter = "DependsOn" ; value = "foo", "bar"}174 ) {175 param($parameter, $value)176 177 $newServiceCommand = [Microsoft.PowerShell.Commands.NewServiceCommand]::new()178 $newServiceCommand.$parameter = $value179 $newServiceCommand.$parameter | Should -Be $value180 }181 182 It "Set-Service can change credentials of a service" -Pending {183 try {184 $startUsername = "user1"185 $endUsername = "user2"186 $servicename = "testsetcredential"187 $testPass = [Net.NetworkCredential]::new("", (New-ComplexPassword)).SecurePassword188 $creds = [pscredential]::new(".\$endUsername", $testPass)189 net user $startUsername $creds.GetNetworkCredential().Password /add > $null190 net user $endUsername $creds.GetNetworkCredential().Password /add > $null191 $parameters = @{192 Name = $servicename;193 BinaryPathName = "$PSHOME\pwsh.exe";194 StartupType = "Manual";195 Credential = $creds196 }197 $service = New-Service @parameters198 $service | Should -Not -BeNullOrEmpty199 $service = Get-CimInstance Win32_Service -Filter "name='$servicename'"200 $service.StartName | Should -BeExactly $creds.UserName201 202 Set-Service -Name $servicename -Credential $creds203 $service = Get-CimInstance Win32_Service -Filter "name='$servicename'"204 $service.StartName | Should -BeExactly $creds.UserName205 }206 finally {207 Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue208 net user $startUsername /delete > $null209 net user $endUsername /delete > $null210 }211 }212 213 It "New-Service can create a new service called '<name>'" -TestCases @(214 @{name = "testautomatic"; startupType = "Automatic"; description = "foo" ; displayname = "one" ; securityDescriptorSddl = $null},215 @{name = "testmanual" ; startupType = "Manual" ; description = "bar" ; displayname = "two" ; securityDescriptorSddl = $SecurityDescriptorSddl},216 @{name = "testdisabled" ; startupType = "Disabled" ; description = $null ; displayname = $null ; securityDescriptorSddl = $null},217 @{name = "testsddl" ; startupType = "Disabled" ; description = "foo" ; displayname = $null ; securityDescriptorSddl = $SecurityDescriptorSddl}218 ) {219 param($name, $startupType, $description, $displayname, $securityDescriptorSddl)220 try {221 $parameters = @{222 Name = $name;223 BinaryPathName = "$PSHOME\pwsh.exe";224 StartupType = $startupType;225 }226 if ($description) {227 $parameters += @{description = $description}228 }229 if ($displayname) {230 $parameters += @{displayname = $displayname}231 }232 if ($securityDescriptorSddl) {233 $parameters += @{SecurityDescriptorSddl = $securityDescriptorSddl}234 }235 236 $service = New-Service @parameters237 $service | Should -Not -BeNullOrEmpty238 $service.displayname | Should -Be $(if($displayname){$displayname}else{$name})239 $service.startType | Should -Be $startupType240 241 $service = Get-CimInstance Win32_Service -Filter "name='$name'"242 $service | Should -Not -BeNullOrEmpty243 $service.Name | Should -Be $name244 $service.Description | Should -Be $description245 $expectedStartup = $(246 switch ($startupType) {247 "Automatic" {"Auto"}248 "Manual" {"Manual"}249 "Disabled" {"Disabled"}250 default { throw "Unsupported StartupType in TestCases" }251 }252 )253 $service.StartMode | Should -Be $expectedStartup254 if ($displayname -eq $null) {255 $service.DisplayName | Should -Be $name256 }257 else {258 $service.DisplayName | Should -Be $displayname259 }260 if ($securityDescriptorSddl) {261 CheckSecurityDescriptorSddl -SecurityDescriptorSddl $SecurityDescriptorSddl -ServiceName $name262 }263 }264 finally {265 $service = Get-CimInstance Win32_Service -Filter "name='$name'"266 if ($service -ne $null) {267 $service | Remove-CimInstance268 }269 }270 }271 272 It "Remove-Service can remove a service" {273 try {274 $servicename = "testremoveservice"275 $parameters = @{276 Name = $servicename;277 BinaryPathName = "$PSHOME\pwsh.exe"278 }279 $service = New-Service @parameters280 $service | Should -Not -BeNullOrEmpty281 Remove-Service -Name $servicename282 $service = Get-Service -Name $servicename -ErrorAction SilentlyContinue283 $service | Should -BeNullOrEmpty284 }285 finally {286 Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue287 }288 }289 290 It "Remove-Service can accept a ServiceController as pipeline input" {291 try {292 $servicename = "testremoveservice"293 $parameters = @{294 Name = $servicename;295 BinaryPathName = "$PSHOME\pwsh.exe"296 }297 $service = New-Service @parameters298 $service | Should -Not -BeNullOrEmpty299 Get-Service -Name $servicename | Remove-Service300 $service = Get-Service -Name $servicename -ErrorAction SilentlyContinue301 $service | Should -BeNullOrEmpty302 }303 finally {304 Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue305 }306 }307 308 It "Remove-Service cannot accept a service that does not exist" {309 { Remove-Service -Name "testremoveservice" -ErrorAction 'Stop' } | Should -Throw -ErrorId "InvalidOperationException,Microsoft.PowerShell.Commands.RemoveServiceCommand"310 }311 312 It "Get-Service can get the '<property>' of a service" -Pending -TestCases @(313 @{property = "Description"; value = "This is a test description"}314 @{property = "BinaryPathName"; value = "$PSHOME\powershell.exe";},315 @{property = "UserName"; value = $creds.UserName; parameters = @{ Credential = $creds }},316 @{property = "StartupType"; value = "AutomaticDelayedStart";}317 ) {318 param($property, $value, $parameters)319 try {320 $servicename = "testgetservice"321 $startparameters = @{Name = $servicename; BinaryPathName = "$PSHOME\powershell.exe"}322 if($parameters -ne $null) {323 foreach($key in $parameters.Keys) {324 $startparameters.$key = $parameters.$key325 }326 } else {327 $startparameters.$property = $value328 }329 $service = New-Service @startparameters330 $service | Should -Not -BeNullOrEmpty331 $service = Get-Service -Name $servicename332 $service.$property | Should -BeExactly $value333 }334 finally {335 Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue336 }337 }338 339 It "Set-Service can accept a ServiceController as pipeline input" {340 try {341 $servicename = "testsetservice"342 $newdisplayname = "newdisplayname"343 $parameters = @{344 Name = $servicename;345 BinaryPathName = "$PSHOME\pwsh.exe"346 }347 $service = New-Service @parameters348 $service | Should -Not -BeNullOrEmpty349 Get-Service -Name $servicename | Set-Service -DisplayName $newdisplayname350 $service = Get-Service -Name $servicename351 $service.DisplayName | Should -BeExactly $newdisplayname352 }353 finally {354 Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue355 }356 }357 358 It "Set-Service can accept a ServiceController as positional input" {359 try {360 $servicename = "testsetservice"361 $newdisplayname = "newdisplayname"362 $parameters = @{363 Name = $servicename;364 BinaryPathName = "$PSHOME\pwsh.exe"365 }366 367 $script = { New-Service @parameters | Set-Service -DisplayName $newdisplayname }368 { & $script } | Should -Not -Throw369 $service = Get-Service -Name $servicename370 $service.DisplayName | Should -BeExactly $newdisplayname371 }372 finally {373 Get-CimInstance Win32_Service -Filter "name='$servicename'" | Remove-CimInstance -ErrorAction SilentlyContinue374 }375 }376 377 It "Using bad parameters will fail for '<name>' where '<parameter>' = '<value>'" -TestCases @(378 @{cmdlet="New-Service"; name = 'credtest' ; parameter = "Credential" ; value = (379 [System.Management.Automation.PSCredential]::new("username",380 #[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Demo/doc/test secret.")]381 (ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force)));382 errorid = "CouldNotNewService,Microsoft.PowerShell.Commands.NewServiceCommand"},383 @{cmdlet="New-Service"; name = 'badstarttype'; parameter = "StartupType"; value = "System";384 errorid = "CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.NewServiceCommand"},385 @{cmdlet="New-Service"; name = 'winmgmt' ; parameter = "DisplayName"; value = "foo";386 errorid = "CouldNotNewService,Microsoft.PowerShell.Commands.NewServiceCommand"},387 @{cmdlet="Set-Service"; name = 'winmgmt' ; parameter = "StartupType"; value = "Boot";388 errorid = "CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetServiceCommand"}389 ) {390 param($cmdlet, $name, $parameter, $value, $errorid)391 $parameters = @{$parameter = $value; Name = $name; ErrorAction = "Stop"}392 if ($cmdlet -eq "New-Service") {393 $parameters += @{Binary = "$PSHOME\pwsh.exe"};394 }395 { & $cmdlet @parameters } | Should -Throw -ErrorId $errorid396 }397 398 Context "Set-Service test cases on the services with dependent relationship" {399 BeforeEach {400 { Set-Service -Status Running $testservicename2 } | Should -Not -Throw401 (Get-Service $testservicename1).Status | Should -BeExactly "Running"402 (Get-Service $testservicename2).Status | Should -BeExactly "Running"403 }404 405 It "Set-Service can stop a service with dependency" {406 $script = { Set-Service -Status Stopped $testservicename2 -ErrorAction Stop }407 { & $script } | Should -Not -Throw408 (Get-Service $testservicename2).Status | Should -BeExactly "Stopped"409 }410 411 It "Set-Service cannot stop a service with running dependent service" {412 $script = { Set-Service -Status Stopped $testservicename1 -ErrorAction Stop }413 { & $script } | Should -Throw414 (Get-Service $testservicename1).Status | Should -BeExactly "Running"415 (Get-Service $testservicename2).Status | Should -BeExactly "Running"416 }417 418 It "Set-Service can stop a service with running dependent service by parameter -Force" {419 $script = { Set-Service -Status Stopped -Force $testservicename1 -ErrorAction Stop }420 { & $script } | Should -Not -Throw421 (Get-Service $testservicename1).Status | Should -BeExactly "Stopped"422 (Get-Service $testservicename2).Status | Should -BeExactly "Stopped"423 }424 }425}426 