When installing a Windows Service remotely as a “Local Service” there are no credentials involved and this is a pretty straight forward task.
But if you need to have the service installed under the account of a local user or a domain user then this is somewhat tricky. The security credentials you create using the PSCredential object are created using the DAPI (Windows Data Protection API) of the local machine and therefor will work only on that machine where they are created. So when passing them to a remote machine using Invoke-Command or PSsession the remote service will get installed but when started it will fail to start due to log on failure error.
The way to handle this is that when using the 2 methods ConvertTo-SecureString and ConvertFrom-SecureString we need to use the Key or SecureKey parameters. This results in using the the Advanced Encryption Standard (AES) encryption algorithm instead of the Windows Data Protection API (DPAPI). The specified key must have a length of 128, 192, or 256 bits because those are the key lengths supported by the AES encryption algorithm (If no key is specified, the Windows Data Protection API (DPAPI) is used to encrypt the standard string representation).
Here is an example of a script that I have used that uses a function I have created to accomplish the task of installing a Windows Service remotely on multiple machines.
<# #https://powershelladministrator.com/2019/12/19/passing-user-credentials-to-a-remote-computer/ # mangment pc Enable-WSManCredSSP -Role Client -DelegateComputer *. -Force # remote pc Invoke-Command -Session $session -ScriptBlock { Enable-WSManCredSSP -Role Server -Force; } Invoke-Command -Session $session -ScriptBlock {New-Service -Name $using:service -BinaryPathName $using:path -StartupType $using:start_mode -DisplayName $using:service -Credential $using:credentials; } Invoke-Command -Session $session -ScriptBlock { Disable-WSManCredSSP Server; } #> function Install-Service { param( $ComputerName, $User, $Password, $Path, $Service, $Description, $StartMode ) $Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $Password; $null = Invoke-Command -ComputerName $ComputerName -ScriptBlock {New-Service -Name $using:Service -BinaryPathName $using:Path -StartupType $using:StartMode -DisplayName $using:Service -Credential $using:Credentials;} } $pw_path = 'c:\temp'; if(-not( Test-Path -Path $pw_path) ) { New-Item -Path $pw_path -ItemType Directory; } $pw_file = 'pw.txt'; $pw_file_full_name = Join-Path $pw_path $pw_file if (-not $Secure) { $Secure = Read-Host -AsSecureString; } $Key = (1,3,2,4,56,34,254,222,1,1,4,23,42,54,33,233,1,34,2,7,6,5,35,43); $Encrypted = ConvertFrom-SecureString -SecureString $Secure -Key $key; $Encrypted | Set-Content $pw_file_full_name; $server = 'ECAESQLWFS11'; $user = 'eca\sqladm'; $service = 'CloudMonitoringCollector'; $path = '"C:\Program Files\CloudMonitoring\CloudMonitoringCollectorConsole.exe"'; $description = 'Collects Monitoring Metrics'; $start_mode = 'Automatic'; $password = Get-Content $pw_file_full_name | ConvertTo-SecureString -Key $Key; Install-Service -ComputerName $server -User $user -Password $password -Path $path -Service $service -Description $description -StartMode $start_mode;
Latest posts by Yaniv Etrogi (see all)
- Monitor AlwaysOn Availabilty Groups - July 6, 2023
- SQL Server – The secret index syntax - February 8, 2023
- Use .net SqlClient with Powershell to access data - January 25, 2023
- Use Powershell to find unused resources in Azure - August 5, 2022
Pingback: SQL Server Utilities - Use SqlCredential with Powershell to connect to an instance of SQL Server - SQL Server Utilities