PowerShell: How to remote execute commands on a list of servers using different credentials per server.

Published by Marian Galie-Andriescu on

I will not explain the code since it is quite straightforward and explanations are included inline. You can customize the way you see fit, that should not be to difficult from this point on.

#########################################################################################################
# Marian Galie-Andriescu        marian.galie.andriescu@gmail.com                                        #
# Example executing multiple commands on multiple servers using for each server different credentials.  #
#########################################################################################################

# In this object we will store the information we need per server
Function New-SP_Object {
  Param ([string]$ServerName, [string]$UserName, [string]$Password)
  return New-Object PsObject -Property @{
    ServerName = $ServerName;
    UserName = $UserName
    Password = $Password
  }
}

# This is the list of servers and their credentials
$todo = @()

# For each server definition you need a server name, a user and a password. 
# Do not save the password(s) on disk !
$todo += New-SP_Object -ServerName 'sqlSrv1' -UserName 'admin1' -Password 'secret1'
$todo += New-SP_Object -ServerName 'sqlSrv2' -UserName 'admin2' -Password 'secret2'
$todo += New-SP_Object -ServerName 'sqlSrv3' -UserName 'admin3' -Password 'secret3'
$todo += New-SP_Object -ServerName 'sqlSrv4' -UserName 'admin4' -Password 'secret4'
$todo += New-SP_Object -ServerName 'sqlSrv5' -UserName 'admin5' -Password 'secret5'

# It is also possible to prompt for a password for each server, therefore set the parameter below to $true
[bool]   $AskForPassword = $false
# Domain name will be used in the user name, do not forget to end with a \
[String] $DomainName     = "ABC\"
# If Workgroup is set to true, then we will use the server name as domain name for the user name
[bool]   $Workgroup      = $false
# Append to the server name to generate a fully qualified domain name (FQDN)- you can let this value empty
# Do not forget to begin with a .
[String] $ServerSuffix   = ".DEF.com"

foreach ($item in $todo) 
{
   $ServerName = $item.ServerName + $ServerSuffix
   if ($Workgroup)
   {
     $UserName   = $ServerName + "\" +  $item.UserName
   } else 
   {
     $UserName   = $DomainName + $item.UserName
   }

   if ($AskForPassword)
   {
     $Cred = Get-Credential $UserName
   } else
   {
     $Password = $item.Password
     $SecStrPass = ConvertTo-SecureString $Password -AsPlainText -Force
     $Cred = New-Object System.Management.Automation.PSCredential ($UserName, $SecStrPass)
   }
   
   Write-Verbose "Server Name = $ServerName" -verbose
   Write-Verbose "User   Name = $UserName" -verbose

   #Example execute command with multiple lines. (Set MaxConcurrentApi = 150)
   #Invoke-Command -Computername $ServerName -Credential $Cred -ScriptBlock {
   #  Write-Verbose "MaxConcurrentApi = $((Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters").MaxConcurrentApi)" -Verbose  
   #  Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" -Name MaxConcurrentApi -Value 150 -Force | Out-Null 
   #  restart-service netlogon -force 
   #  Write-Verbose "MaxConcurrentApi = $((Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters").MaxConcurrentApi)" -Verbose 
   #}

   #Example execute full powershell file, but this can only be a local file, not on a networkk share.
   #invoke-command -Computername $ServerName -Credential $Cred -filepath "c:\tmp\Test.ps1"

   #Example read current value of ComputerName
   Invoke-Command -Computername $ServerName -Credential $Cred -ScriptBlock {
     Write-Verbose "ComputerName = $((Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName").ComputerName)" -Verbose
   }
}

Now, if you run this code for the first time, for example at home or at work, you can encounter issues. I experienced a lot of them myself, so this is why I included the troubleshooting guide below. This guide should be executed on the servers or workstations you want to remote execute commands on. In my case this was the same workstation 🙂

1.
Error:
[kamir8] Connecting to remote server kamir8 failed with the following error message : The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. Consult the logs and documentation for the WS-Management service running on the destination, most commonly IIS or WinRM. If the destination is the WinRM service, run the following command on the destination to analyze and configure the WinRM service: “winrm quickconfig”. For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (kamir8:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : CannotConnect,PSSessionStateBroken

Then I executed the command as advised in a dos box:
winrm quickconfig
And this was the result:

WinRM is not set up to receive requests on this machine.
The following changes must be made:
Start the WinRM service.
Set the WinRM service type to delayed auto start.

Fix: WinRM is the Windows Remote Management (WS-Management) service in windows. In my case this service was disabled and not running, you can do that by executing services.msc,
and change startup type to Automatic (Delayed start), then start the service.

2.
Next, execute the command again
winrm quickconfig
in a dos box or powershell command prompt to check if there are any more problems with the WinRM service. In my case i got the following error:

Result:
WinRM service is already running on this machine.
winrm : WSManFault
At line:1 char:1
+ winrm quickconfig
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (WSManFault:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

Message
ProviderFault
WSManFault
Message = WinRM firewall exception will not work since one of the network connection types on this machine is set to Public. Change the network connection type to either Domain or Private and try again.
Error number: -2144108183 0x80338169
WinRM firewall exception will not work since one of the network connection types on this machine is set to Public. Change the network connection type to either Domain or Private and try again.

This means I have a network which is connected to a public type of network and this is less secure than a private one. In my case I could only see one network from the Network Internet settings in Windows 10. After doing some research, I  found out there was another network, hidden, which had a public type of connection.

Fix: Execute the following in a powershell console with admin rights:
Get-NetConnectionProfile

In my case I had two networks, one my normal and one which was installed by the hyper-v functionality in windows 10.
From this point on you have 2 choices:

A.

Execute the following command in a powershell with admin rights:
Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private
For more information you can read:
https://www.servethehome.com/change-hyper-v-network-category-public-private-powershell/

OR

B.

Remove Hyper-V functionality from windows 10 in case you do not need it.
“Control Panel” > “Programs” > “Programs and Features” > “Turn Windows features on or off” on your Windows 10 machine Find the name of the feature/s you would like to disable–in this case, “Containers” and (optionally) “Hyper-V”
https://superuser.com/questions/1282014/how-to-remove-all-the-vethernet-default-switch-once-and-for-all

3.
Next, the following error I encountered was
“Access is denied”

Fix:
Execute the following command in a powershell with admin rights:
Set-PSSessionConfiguration -Name Microsoft.PowerShell -showSecurityDescriptorUI
And then add the user you use for the remote execution to the list with full rights:

For more information you can read this article:
https://4sysops.com/archives/powershell-remoting-without-administrator-rights/


Categories: PowerShell