Run an setup file (.exe) on mutiple machines remotely using powershell - powershell

I am trying to run an exe copied to a specified folder on all servers along with an argument list. This however is failing without any errors, file copy is working fine, however remote execution of the setup is failing.
The following is what I am writing.
Kindly suggest, any assistance would be appreciated.
$servers = Get-Content c:\temp\servers.txt
foreach ($server in $servers){
"Processing $server"
Copy-Item -Path "\\$serverA\utility$\Setup.exe" -Destination "\\$server\c$\temp\Setup.exe" -Force
$copy_complete = Test-Path "\\$server\c$\temp\Setup.exe"
if ($copy_complete) {
"copy successful"
Invoke-Command -ComputerName $server -ScriptBlock { Start-Process 'c:\temp\Setup.exe' -ArgumentList '/quiet /noreboot /enable_remote_assistance /Exclude "Smart Tools agent","Profile Manager WMI Plugin","Personal vDisk"' }
"$server completed"
}
else {
"Failed copy, retry manually on $server"
}
}

You could try it with the call operator (&)
Invoke-Command -ComputerName $server -ScriptBlock {
$executable='c:\temp\Setup.exe'
$arguments='/quiet /noreboot /enable_remote_assistance /Exclude "Smart Tools agent","Profile Manager WMI Plugin","Personal vDisk"'
& $executable $arguments
}

Related

How to run script against windows servers WinRM

I am trying to run a script that searches/downloads/installs windows updates on remote computers using WinRM. I am running this script as a domain user with Admin access. However, I get an ACCESS Denied error.
Now, I have the script copied over to the remote servers but I am unable to view output to see whether the script is running or not.
OUTPUT I want to see:
# Continue running on other servers on error
$ErrorActionPreference = "Continue"
# Server list
$servers = Get-Content "C:\Users\admin\Desktop\vm-nonprod.txt"
# Logs
$log = "C:\Users\admin\Desktop\log-nonprod.txt"
# Path to script on server list
$scriptpath = "C:\Patch.ps1"
$results = #()
foreach ($server in $servers) {
try {
$Credential = Import-CliXml -Path "C:\Users\admin\Desktop\admin.Cred"
#New-PSSession -ComputerName $server -Credential $Credential
Invoke-Command -ComputerName $server -Credential $Credential -ScriptBlock {$scriptpath} -ArgumentList "Y" | Out-File -FilePath C:\Users\admin\Desktop\WinPatch.txt
#Invoke-Command -ComputerName $server -Credential hhq\admin -FilePath "C:\Users\admin\Documents\Patch.ps1"
#Copy-Item -Path C:\Users\admin\Documents\Patch.ps1 -Destination 'C:\' -ToSession (New-PSSession –ComputerName $server -Credential $Credential)
}
catch {
Write-Output ("Error running script on remote host: " + $server)
}
}
$results | Export-Csv -NoTypeInformation $log
There's a few issues here.
Does the script exist on the server?
Sounds like yes, you have Patch.ps1 in C:\ on each $server
The scriptblock does not run the script - just prints the variable.
To run it, change {$scriptpath} to {. $scriptpath} or {& $scriptpath}
The variable $scriptpath is not in the scriptblock scope - you will have to pass it in the -ArgumentList
Change: {$scriptpath} -ArgumentList "Y"
____To: {param($p); . $p} -ArgumentList $scriptpath
The argument "Y" is being passed to the scriptbock, not the script. The scriptblock is not looking for it, so this value is being lost.
Assume you want it to be passed to the script - this needs to be done in the scriptblock:
{$scriptpath "Y"}
I would recommend getting rid of Out-File until you are happy with the output in the console.
Putting it all together:
-ScriptBlock {$scriptpath} -ArgumentList "Y" | Out-File -FilePath C:\Users\admin\Desktop\WinPatch.txt
-ScriptBlock {param($p); . $p "Y"} -ArgumentList $scriptpath
I believe you have the wrong Invoke-Command commented out. The one that is running only has the user name hhq\admin in the credential parameter. It might be failing due to that because it would be prompting for the password during run-time.

How to change startup type and task to start/stop services from csv file?

I have the following csv file:
Server,Service,Startup Type,Task
server1,SQL Server Analysis Services (MSSQLSERVER),automatic,start
server2,"SQL Server Analysis Services (MSSQLSERVER), SQL Server Analysis Services (MSSQLSERVER) CEIP",Manual,stop
I have the following script but it uses built-in Stop-Service or Start-Service for now.
I want to allow the flexibility to define all parameters in the csv file and the service is started/stopped based on what the csv file has, as well as setting the startup type to a different startup type if its changed/different from csv file and current state on the server(s).
$csvFile = Import-CSV .\SSAS_services.csv
ForEach ($Server in $csvFile)
{ Invoke-Command -ScriptBlock { Stop-Service $args[0] } -ComputerName $Server.Server -ArgumentList $Server.Service.Split(",")
}
Start-Sleep -Seconds 60
ForEach ($service in (($csvFile.Count - 1)..0))
{ Invoke-Command -ScriptBlock { Stop-Service $args[0] } -ComputerName $csvFile[$service].Server -ArgumentList $csvFile[$service].Service.Split(",")
}
You can use the $using to read a local variable in a remote session, see the about_remote_variables section.
I'm assuming you want to do the following on the remote macines:
Stop the service
Adapt the startup type
Start the service
So the code should approp. look like:
$rows = Import-CSV .\SSAS_services.csv
ForEach ($row in $rows)
{
# Stop the service on the remote machine
Invoke-Command -ScriptBlock { Stop-Service $using:row.Service } -ComputerName $row.Server -ArgumentList $row
Start-Sleep 60
Invoke-Command -ScriptBlock {
# Set the startup type on the remote machine
Set-Service $using:row.Service -StartupType $using:row."Startup Type"
Start-Service $using:row.Service
} -ComputerName $row.Server -ArgumentList $row
}
Hope that helps.

Check the AppPool status through power-shell and start that on remote machine

The requirement is to extract the server name one by one and check the AppPool status, if that is found to be stopped, make it running. below code is not helping out.
$ErrorActionPreference = "Continue"
$status = gc -path "D:\Servers\server.txt"|ForEach-Object (invoke-command -ComputerName $_ -ScriptBlock {Import-Module Webadministration Get-WebAppPoolState -name (gc "D:\AppPool.txt")})
if ($status.value -eq "Started")
{
Write-Host ("ApppPool already running")
}
else
{
Invoke-Command -ScriptBlock {Start-WebAppPool}
Write-host ("AppPool has started successfully")
}
There were multiple problems with your code, I've gone through them individually so you can see what was stopping it from working correctly.
The syntax for foreach was wrong, you needed to use {} not () in this case. Normal brackets are only used like this ForEach ($number in $numArray ) {CODE} which you aren't.
You were checking $status outside the foreach loop - so it so was evaluating $status only once (with the final computers AppPool status) rather than for each computer.
Your second Invoke-Command didn't have a ComputerName parameter specified so was only running the command locally not against the remote computer, meaning the AppPool would never be started.
As you were specifying the AppPool name using gc "D:\AppPool.txt" this file would have to be present on every remote computer for it to work. I've changed this to be passed into the command as an argument so the file only needs to be on the computer running the script.
$Credentials = Get-Credential
$AppPools = Get-Content "D:\AppPool.txt"
$Servers = Get-Content -Path "D:\Servers\server.txt"
ForEach ($Server in $Servers) {
ForEach ($AppPool in $AppPools) {
$AppPoolState = Invoke-Command -ComputerName $Server -ScriptBlock {Import-Module WebAdministration; Get-WebAppPoolState -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
if ($AppPoolState.Value -eq "Started")
{
Write-Host "$AppPool AppPool already running on $Server"
}
else
{
Invoke-Command -ComputerName $Server -ScriptBlock {Start-WebAppPool -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
Write-Host "$AppPool AppPool started on $Server"
}
}
}
Note: I run a non-privileged account so have to supply Credentials. If the account you're running the script as has appropriate permissions to all the remote computers you can remove the three Credentials references.

Use PowerShell to remotely bulk override a file and restart a certain service

I need your help.
I need to write a script that will from a windows server,
Will connect to a list of servers (provided by a csv that has IP Addresses)
on those servers will overwrite a file located either on
C:\Program Files (x86)\Folder1 or C:\Program Files\Folder1
Taking the correct version from the server Running the script from D:\
and then restart a service called sname1.
(we can assume all target servers have the WinRM Active)
Your help will be greatly appriciated.
What I have so far is this, but I'm not sure it's correct assuming I'm working with IP Addresses and not Hostnames (Hostnames aren't an option as I'm not using this in a domain environment)
$servers=Get-Content D:\List.txt
foreach ($server in $servers)
{
if (Test-Path "\\$_\c$\Program Files\Folder1")
{
Copy-Item \\127.0.0.1\D$\file1.ini "\\$_\c$\Program Files\Folder1\file1.ini"
}
if (Test-Path "\\$_\c$\Program Files (x86)\Folder1")
{
Copy-Item \\127.0.0.1\D$\file1.ini "\\$_\c$\Program Files (x86)\Folder1\file1.ini"
}
Restart-Service -InputObject $(Get-Service -Computer $server -Name sname1)
}
REF:
$servers=Import-Csv E:\Temp\serverlist.csv
$Source = "D:\file1.ini"
foreach ($server in $servers)
{
$Password = ConvertTo-SecureString -AsPlainText -Force -String "$server.Password"
$User = "$server.Domain\$server.Usernaem"
$credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user,$password
if (Test-Path "\\$server.Alias\c$\Program Files\Folder1")
{
$Destination = "\\$server.Alias\c$\Program Files\Folder1"
}
if (Test-Path "\\$server.Alias\c$\Program Files (x86)\Folder1")
{
$Destination = "\\$server.Alias\c$\Program Files (x86)\Folder1"
}
Copy-Item $Source -Destination $Destination -Credential $credentials -Force
Restart-Service -InputObject $(Get-Service -Computer $server,Alias -Name sname1)
}
Note that you CANNOT access properties or methods of variables if you enclose it in quotes. For example, if you say;
$test = 1234
Write-Output "House $test.ToString()"
You will get the output "House 1234.ToString()" because the method is not resolved, it just assumes it's a string. You need to either split it up or enclose it:
Write-Output ("House " + $test.ToString())
Write-Output "House $($test.ToString())"
Additionally you've misspelled UserName when declaring $User. Fix those up and it should work fine.
I recommend checking out Microsoft's MVAs PowerShell 3.0 JumpStart and Advanced Tools & Scripting as they explain a lot of this stuff, get you into good habits and are actually pretty fun to watch.

powershell invoke-command not working, but psexec does

I am trying to uninstall an old version of Flash on multiple PCs with a powershell script using the invoke-command cmdlet. The script runs without errors, but flash is never uninstalled. Here is what I am using:
$flash = get-content "C:\11.6.txt"
$flash | Foreach {
if (Test-Connection -ComputerName $_ -Count 1 -ErrorAction SilentlyContinue) {
Invoke-Command -ComputerName $_ -ScriptBlock {Start-Process cmd.exe "/c start /wait MsiExec.exe /X{346137E0-7160-403B-AD21-3FF01D25037B} /qn" -NoNewWindow}
Write-Host "Uninstall from $_ complete."}
else {
Write-Host "$_ is offline"
}
}
If I run the uninstaller via psexec it works fine:
start /wait msiexec.exe /X{346137E0-7160-403B-AD21-3FF01D25037B} /qn
I cannot for the life of me figure out why invoke-command won't work. I am relatively new to PowerShell so it could be something silly, but I can't figure it out.
When it comes to executing code on a remote computer i have never been successful with Invoke-Command. However, PSExec has been nothing but good to me.
Try something like this. I can't test at the moment but let me know if it works for you.
Note: Change the FilePath location to your PSExec.exe location.
Start-Process -FilePath "C:\PSExec.exe" -ArgumentList {"\\$ComputerNameHere CMD.exe '/C start /wait msiexec.exe /X{346137E0-7160-403B-AD21-3FF01D25037B} /qn'"}
Here is the code that ended up working for me:
$flashPuters = Get-Content "C:\11.8.800.txt"
foreach ($computer in $flashPuters)
{
if (test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue) {
& 'C:\PSTools\psexec.exe' #("\\$computer", 'msiexec.exe', '/X{BFBC6337-B7B9-4AEE-BC19-CA910EED755D}', '/qn')
"Uninstall complete for $computer" >> C:\11.8.800.log
}else {
"$computer is not online" >> C:\11.8.800.log
}
}
Thank you to #HiTech for helping me!