Remoting Through an Array of Webservers to Deploy Code - powershell

I'm looking to pop through a few webservers and import-module WebAdministration in order to change some recycling properties.
The issue is, it seems like foreach doesn't like being used for remote sessions. I'm guessing this is because a single block of code can only be executed in 1 remote session? Is there a way to pop through multiple sessions or do I have to do that by hand?
Just looking for some input on how to write a code to deploy to all my apppools on all my servers.
I've tested wildcarding the appPool directory and that seems to work.
IIS10
Powershell 5.1.14393.2189
$servers = #("MyEnvironment-web01","MyEnvironment-web02","MyEnvironment-web03")
foreach ($server in $servers) {
enter-Pssession -ComputerName $server
Write-Host $server
Read-Host -Prompt "Press Enter to continue" #This was added because I thought maybe it just needed time to connect? Doesn't need to be in here.
import-module WebAdministration
Get-ItemProperty -Path IIS:\AppPools\*
exit-PSSession
}
Lots of this:
import-module : The specified module 'WebAdministration' was not loaded because no valid module file was found in any module directory.
At line:1 char:1
Which is odd because that works just fine if I run the for-each loop manually. Except about 20% of the time when it doesn't....
I'm willing to bet I'm going about this ALL wrong.

$Cred = Get-Credential -UserName <domain\user> -Message 'Enter Password'
$servers = #("myserver1"."myserver2","etc")
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -Credential $cred {
import-module WebAdministration
Get-ItemProperty -Path IIS:\AppPools\*
}
}

Related

Installing Program remotely through Remote PowerShell

I am trying to install ActivClient remotely onto some machines, I copy the file to the Public Downloads separately.
I am running into an issue where when I try to run this script, it runs locally on my machine. I need to run that Deploy-Application.PS1 file for this.
I also can't figure out how to Unblock the entire folder, there is a few sub folders and files I would like to unblock.
I can't remote into the computer through RDP because I need ActivClient installed to remote in. Remote PowerShell is the only method I can find to run this.
If I am missing information or need to provide more, please let me know.
$mypath = $MyInvocation.MyCommand.Path
$Path = Split-Path $mypath -Parent
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$title = 'Computer Name'
$msg = 'Enter the Computer Name you need to reinstall ActivClient on:'
$CName = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
if (Test-Connection -ComputerName $CName -Count 1){
Write-Host "Entering Remote Powershell Session"
$PSSession = New-PSSession -Name $CName
Invoke-Command -Session $PSSession -ScriptBlock{
Get-ChildItem "C:\Users\Public\Downloads\SDC NIPR - ActivClient v7.2.x - 210811_18NOV" | Unblock-File
cd "C:\Users\Public\Downloads\SDC NIPR - ActivClient v7.2.x - 210811_18NOV"
.\Deploy-Application.ps1 Install 'NonInteractive'
pause
}
Use New-PSSession -ComputerName $CName, not New-PSSession -Name $CName.
-Name only gives the session being created a friendly name, it is unrelated to which computer you target. In the absence of a -ComputerName argument, the local machine is (somewhat uselessly) targeted, which is why the script ran on your local machine.
Note that if you're only calling Invoke-Command remotely once per remote computer, you needn't create a session explicitly and can instead use -ComputerName $CName directly with Invoke-Command:
# No need for New-PSSession.
Invoke-Command -ComputerName $CName -ScriptBlock { ... }
Add -Recurse -File to your Get-ChildItem call in order to unblock all files in the target folder recursively (all files in the target folder's subtree).

PowerShell Invoke-Command Speed (win32_product)

I wrote a short script to uninstall a program on multiple computers (from a text doc of hostnames). The script is working as expected but is taking about 2-3 minutes per host. Is there a way to perform this on all the machines simultaneously?
Here's my script.
$computers = Get-Content C:\Computernames.txt
foreach($Computer in $computers){
Invoke-Command -ComputerName $Computer -ScriptBlock{
$application = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Appname%'"
#uninstall the app if it exists
if($application){
$application.Uninstall()
Write-Output "Application uninstalled successfully.."
}
else{
Write-Output "Application not found.."
}
}
}
Can I do Invoke-Command -ComputerName $Computers and do all machines simultaneously to avoid looping through?
As suggested, using $Computers worked successfully. I was able to get rid of my loop and speed the script up tremendously.
Here's the updated script - thanks for letting me know it supports arrays.
#list of computers
$computers = Get-Content C:\Computernames.txt
Invoke-Command -ComputerName $computers -ScriptBlock{
$application = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%appname%'"
if($application){
$application.Uninstall()
Write-Output "Successful uninstall on $env:COMPUTERNAME "
}
else{
Write-Output "Application not found on $env:COMPUTERNAME"
}
}
The win32_product class is notoriously slow, because it verifies every msi whenever it's used. I assume appname is replaced with a specific name. You can use the little known get-package and uninstall-package in powershell 5.1, but only with msi providers:
get-package appname | uninstall-package

PowerShell - Invoke Command on Remote Machines/Computers

There's plenty of forums/material regarding the subject line, but cannot seem to get an answer for my problem.
I'm trying to execute a script from the main server (SRV01) that will clean the temp folders on the secondary servers (SRV02, SRV03).
Here is the script:
#Set the machines on the network to run the script on
$VDST = #("SRV02", "SRV03")
#Folder locations to clean out
$TempFolder = #("C:\Windows\Temp\*", "C:\Documents and Settings\*\Local Settings\temp\*")
#This function actually performs the clean up operation
Function executeCleanUp
{
$TempFolder = $args[0]
$machineNames = $args[2]
ForEach($machine in $machineNames){
Get-PSSession -ComputerName $machine | Format-Table -Property ComputerName, InstanceID
Write-Host 'Starting Clean Up...'
#Loop through the sub folders in the registry location
ForEach($folderLocation in $TempFolder)
{
$StrInput = 'Remove-Item -Path ' + $folderLocation + ' -Force -Recurse -ErrorAction SilentlyContinue'
$action = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument $StrInput
Register-ScheduledTask -Action $action -TaskName "CleanUp"
Start-ScheduledTask -TaskName "CleanUp"
Unregister-ScheduledTask -TaskName "CleanUp" -Confirm:$false -ErrorAction SilentlyContinue
}
}
#Execute Script on specified machines - provided in array above
Invoke-Command -ComputerName $VDST -ScriptBlock ${function:executeCleanUp} -ArgumentList $TempFolder, $VDST
After running the above, I get the error:
A specified logon session does not exist
So, I came across a forum where it was suggested to do the following:
#Remote Server (VDI)
Enable-WSManCredSSP -Role server
#Expected Output
#This computer is configured to receive credentials from a remote client computer.
#Local Machine
Enable-WSManCredSSP -Role Client -DelegatedCredentials 'SRV01'
#Expected Output
#The machine is configured to allow delegating fresh credentials to the following target(s): wsman/SRV01.
#Local Machine
#Open gpedit.msc
#Browse to Computer Configuration > Administrative Templates > System > Credentials Delegation.
#Double-click "Allow delegating fresh credentials with NTLM-only Server Authentication"
#Enable the setting
#Add the build server to the server list as WSMAN/BuildServerName.
#Example Execution:
#Invoke-Command -ComputerName <REMOTE_COMPUTER_NAME> -Authentication CredSSP -Credential <USERNAME> -ScriptBlock { #code}
I've done all this, but now I get the error:
A computer policy does not allow the delegation of the user
credentials to the target computer
Also, I am assuming the line
WSMAN/BuildServerName
should be written
WSMAN/SRV02
The 2 hop authentication issue came up because you are trying to list remote sessions with in your remote session
Get-PSSession -ComputerName $machine | Format-Table -Property ComputerName, InstanceID
If you just want to clear some files on the remote servers the code below should work with no need for CredSPP.
Setting -ErrorAction SilentlyContinue will make trouble shooting difficult, It's easier to check if the file exists before you try to delete it.
$TempFolder = $args[0]
$ComputerArray = "SRV02","SRV03"
$ScriptBlock =
{
foreach ($Folder in $TempFolders)
{
if (Test-Path -Path $TempFolder)
{
Remove-Item -Path $Folder -force
}
}
}
Invoke-Command -ComputerName $ComputerArray -ScriptBlock $ScriptBlock -ArgumentList $TempFolder
Wrong answer:
Your issue is two hop authentication.
You can't nest remote sessions with default windows settings.
While this would not be considered to be best practice, you can enable CredSSP to bypass the problem.
https://learn.microsoft.com/en-us/windows/win32/secauthn/credential-security-support-provider
https://learn.microsoft.com/en-us/powershell/module/microsoft.wsman.management/enable-wsmancredssp?view=powershell-7
Could you either log on to SVR01 to run the script or run the script against the target machines from your own computer?

How do you run the same job on multiple machines powershell?

BasicallyIm trying to run a powershell command from a list of machines.
I can invoke the command on each machine, but i have to wait for each machine to complete the installations before moving on to the next one. When I try creating a job for each machine nothing happens, i suspect its because my script has disconnected from that machines session when it send the command to the next machine.
#Start/Var
$creds = Get-Credential
$computers = Get-Content -Path .\computers.txt
$job = start-job -scriptblock { choco install c:\packages.config -y }
foreach($server in $computers) {
CP .\packages.config \\$server\C$
Invoke-Command -ComputerName $server -ScriptBlock {$job} -Credential $creds
}
As BenH mentioned in the comments you can have Invoke-Command perform things in parallel. The slow down is that you're going to have to wait the files to copy on a per-machine basis, but you can execute the installation on all of the computers at the same time.
#Start/Var
$creds = Get-Credential
$computers = Get-Content -Path .\computers.txt
#Copy files to servers one at a time
foreach($server in $computers) {
CP .\packages.config \\$server\C$
}
#Install the package on all servers in parallel
Invoke-Command -ComputerName $computers -ScriptBlock {choco install c:\packages.config -y} -Credential $creds

Get IIS Bindings from many webservers using powershell remoting, invoke command and module webadministration

Right now I made a small script to see my actual webbindings on a server.
Import-Module WebAdministration;
$today = Get-Date -format M.d.yyyy
$machine = hostname
function IISRport
{
Get-ChildItem -path IIS:\Sites | out-file "\\server01\d$\_utils\PowerShell Scripts\IISexport\IISExport$machine$today.txt"
}
IISReport
This wil outfile my IIS bindings to txt which works brilliant.
I now need to invoke that command to several other servers and save the output file on one server. since the machine name will be diffrent I expect as many outputs as servers.
I tried for example the following :
icm -comp server02 {get-childitem -path IIS:\Sites}
But than the imported Module webadministration is not working, since I only loaded on one server. So I tried to load that remotely using :
icm -comp server02 {import-module webadministration}
without success.
How to achieve that?
This will get the data from all machines defined in $machines and output to \\server01\d$_utils\PowerShell Scripts\IISexport\.
$today = Get-Date -format M.d.yyyy
$machines = #("server01","server02")
foreach($machine in $machines) {
icm -comp $machine { param($machine,$today)
import-module webadministration;
Get-ChildItem -path IIS:\Sites |
out-file "\\server01\d$\_utils\PowerShell Scripts\IISexport\IISExport$machine$today.txt"
} -ArgumentList $machine,$today
}
You can of course change the output path( and import list of machines from a file,AD or some other source).