Unable to install program in self extracting cabinet using Invoke-Command - powershell

I'm writing a script to set up a test SharePoint server for trusted (AD FS) authentication on a stamped test environment that consists of a SharePoint server (server 2016) and a domain controller (server 2008R2). I'm writing the script to run on the SharePoint server and use a remote session to configure the DC because the DC only has PowerShell 2.0 which is missing some convenient functionality.
I have a specific segment of the script that runs a script block on the DC which downloads the AD FS 2.0 installer, a self extracting cabinet, and tries to install it. Every line of the block executes except for the actual installation. If I log onto the machine and run those same lines it works perfectly.
Invoke-Command -Session $domainControllerSession -ScriptBlock {
$installerUrl = "https://download.microsoft.com/download/F/3/D/F3D66A7E-C974-4A60-B7A5-382A61EB7BC6/RTW/W2K8R2/amd64/AdfsSetup.exe"
$filename = "$($PWD.Path)\AdfsSetup.exe"
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($installerUrl, $filename)
Start-Process -FilePath $filename -ArgumentList "/quiet" -Wait
}
I tried manually extracting the contents (using /x:) and then executing the setup file but there was no change in result (Note: The files are extracted but the extractor process never exits, this doesn't seem pertinent to the problem). I also moved to the DC and created a session to localhost and got the same exact behavior.
PS C:\Users\Administrator> $session = New-PSSession -ComputerName Localhost
PS C:\Users\Administrator> Invoke-Command -Session $session -ScriptBlock {
>> $filename = "$($PWD.Path)\AdfsSetup.exe"
>> write-host $filename
>> Test-Path -Path $filename
>> Start-Process -FilePath $filename -ArgumentList "/quiet" -Wait
>> Test-Path -Path 'C:\Program Files\Active Directory Federation Services 2.0'
>> }
>>
C:\Users\Administrator\Documents\AdfsSetup.exe
True
False
PS C:\Users\Administrator>
Update 1
I ran the process with the /Logfile parameter and confirmed that the installation is failing due to an access denied error. I've also confirmed that, as expected, the remote session is running under the same administrator account that I am using to initiate the session. I am assuming that the missing ingredient here is that the remote session is not running in an elevated shell. However, I can't seem to get that working either.
Invoke-Command -Session $session -ScriptBlock {
Start-Process PowerShell -Verb RunAs -ArgumentList "& C:\Users\Administrator\Documents\AdfsSetup.exe /quiet /Logfile C:\Users\Administrator\Documents\AdfsSetup.log" -Wait -PassThru
}
The error is the same.

Related

MSI installation command works locally, but not over PowerShell Remoting

I am trying to use Invoke-Command to install an MSI on a remote computer. I am creating the session using credentials for a domain admin account, and have verified it connects correctly.
# DEBUG: Test that the connection is running as admin.
$IsAdmin = Invoke-Command -Session $Session -ScriptBlock {[bool] (net session 2>$null)}
Write-Verbose "Is running as admin: $IsAdmin"
# Now we need to run the MSI install file.
$TempInstallFile = Join-Path -Path $TempDir -ChildPath $InstallFile
$Script = "Start-Process $TempInstallFile -Wait -ArgumentList '/quiet COLLECTORAGENTLIST=`"$CollectorIP`:$CollectorPort`" PORTPOOLRANGES=`"$Ports`" MAXPORTRANGESPERSESSION=""2"" PORTNUMPERALLOC=`"200`" LOGLEVEL=`"3`" SSLMODE=`"2`"'"
Write-Verbose "Installation command: $Script"
Invoke-Command -Session $Session -ScriptBlock {$Script}
The verbose output:
VERBOSE: PSSession to RDPServer created
VERBOSE: Is running as admin: True
VERBOSE: Installation command: Start-Process C:\temp\TSAgent_Setup_5.0.0301.msi -Wait -ArgumentList '/quiet COLLECTORAGENTLIST="REMOVED:8002" PORTPOOLRANGES="1024-49151" MAXPORTRANGESPERSESSION="2" PORTNUMPERALLOC="200" LOGLEVEL="3" SSLMODE="2"'
VERBOSE: PSSession to RDPServer closed
Nothing happens though. The program is not installed on the remote computer and there are no errors. When I copy the "Installation Command" directly from the output, however, and run it in an admin PowerShell on the remote machine, it installs the program correctly. So there must be some issue with the PowerShell remote session, no? I am fairly new to this, what am I missing here?

Wait for remote Powershell script to finish

I'm creating a powershell script to import Dynamics NAV Application Objects to my Dynamics NAV 2018 database.
Microsoft is providing a PS cmdlet - Import-NAVApplicationObjects - to do so, but I have trouble to wait for the command to finish.
I have a calling script which does the following
$PSSession = New-PSSession -ComputerName $TargetMachine -Credential $MyCredential
Invoke-Command -Session $PSSession -ArgumentList $Database_Name_user, $MyCredential -ScriptBlock {
$process = Start-Process powershell.exe -Verb RunAs -Wait -PassThru -ArgumentList "-File `"C:\Users\User\Desktop\Database\Import1.ps1`" $args[0]"
$process.WaitForExit()
if ($process.ExitCode -ne 0) {
throw $process.StandardError.ReadToEnd()
}
}
The script Import1.ps1 on my $TargetMachine looks like this
param(
[String]$Database_Name_user
)
try {
$AllFiles = "C:\Users\User\Documents\AllFiles.txt"
$Modules = "C:\GIT\Loading Components\NAVModuleImport.ps1"
$OutputBuffer = import-module $Modules
Import-NAVApplicationObject -Path $AllFiles -DatabaseServer "SQLSRV001" -DatabaseName $Database_Name_user -SynchronizeSchemaChanges "No" -ImportAction "Overwrite" -Confirm:$false | Out-Null
}
catch{
$_ | Out-File "C:\Users\User\Documents\Import1.txt"
}
The file AllFiles.txt has a size of 220 MB and contains more than 7700 Dynamics NAV Application Objects (tables, pages, codeunits and so on).
When I launch the script which executes Import-NAVApplicationObject directly from the remote computer stored in $TargetMachine everything works smootly and the process takes up to 10 to 15 minutes, as expected.
When calling the script as shown in the first code example the output stops for a minute and then says everything is done.
Any help is appreciated, thank you in advance.
Edit: Solution
I noticed that my scripts as shown are working, the Import-NAVApplicationObjects cmdlet just failed.
When I elevate the powershell process on the remote computer and run the import, the cmdlet tried to authenticate as NT-Authority\Anonymous to the database.
Then I passed the credentials of the user that opens the remote PSSession to Import1.ps1 and used the parameters -UserName and -Password of the import cmdlet.
Sadly this process failed again.
Now I tried some things with the user I want to use for authenticating, changing passwords etc and it worked! The password contained a semicolon ; and apparently the import cmdlet was not happy with that.
So my simple solution is: Removing the semicolon from the password.

Using PowerShell to execute a remote script that calls a batch file

I am having an issue with running a batch file that is located on a remote server.
I have a batch file located on a remote server that i want to run that kicks off an automated Selenium test. For simplicity, let's say the name of my batch file is mybatch.bat
I have the following code in a Powershell script located on the server:
$BatchFile = "mybatch.bat"
Start-Process -FilePath $BatchFile -Wait -Verb RunAs
If I run this PowerShell script locally on the server in ISE then it runs fine and it kicks off the selenium test which takes a couple minutes to run.
Now I want to try to execute this test from another machine by using PowerShell remoting. Let's assume that remoting is already configured on the servers.
I have a PowerShell script located on another server which has the following code segment. Assume that all of the session variables have the correct information set:
$CMD = "D:\mybatch.bat"
$TargetSession = New-PSSession -ComputerName $FullComputerName -Credential $myCreds -ConfigurationName RemoteExecution
$command = "powershell.exe -File $CMD -Wait"
Invoke-Command -Session $TargetSession -ScriptBlock { $command }
When this script runs, it does connect to the remote machine and create a remote session. It does look like it kicks off the batch file because PowerShell does not give me an error. But it does not wait for the full 3 or 4 minutes for the Selenium test to finish. It seems like it just times out. Also if I am logged onto the other machine, I don't see any Selenium web test running. No Selenium log files or results files are created on remote server as should be expected.
I was wondering what I could be doing wrong with my code.
Also, it seems that the server always returns the echo outputs of the batch file to my local machine. I see these random blinking white screen on ISE which looks like output from the batch file
$command = "powershell.exe -File $CMD -Wait"
Invoke-Command -Session $TargetSession -ScriptBlock { $command }
There are 2 issues with the above code:
$command inside the scriptblock and $command outside the scriptblock are different variables due to different scopes. The variable inside the scriptblock is thus undefined and the scriptblock will simply echo an emtpy value.
Even if $command weren't undefined, the scriptblock would still just echo its value, since it's defined as a string. PowerShell does not execute strings unless you're using something like Invoke-Expression (which you shouldn't).
This should do what you want:
$CMD = "D:\mybatch.bat"
$TargetSession = New-PSSession -ComputerName $FullComputerName -Credential $myCreds -ConfigurationName RemoteExecution
Invoke-Command -Session $TargetSession -ScriptBlock { & $using:CMD }
If you would like execute a bat file from another machine by using PowerShell Remote Session, simply enter dot and then follow by a whitespace, then enter the exact path of bat file located on that remote machine.
Example
Invoke-Command -ComputerName RemoteComputerName -Credential $credential -ScriptBlock {. "D:\Temp\Install_Something.bat"}

How do I remotely start a VM on VMWare Workstation using Powershell?

I have VMWare Workstation and beginner's knowledge of PowerShell.
I've created a script that successfully starts a VM on my local machine by using the vmrun tool. However, if I run it through a remote session, nothing happens. Any idea why?
Get-PSSession | Remove-PSSession
$VMHostMachine | New-PSSession
$rs = Get-PSSession # testing using localhost
Write-Debug ("Now starting VM on host: " + $VMHostMachine)
$script = {param($VMImagePath, $VMConsolePath);
$QuotedVMPath = "`"{0}`"" -f $VMImagePath
$Result = Start-Process -FilePath $VMConsolePath -ArgumentList "-T", "ws", "start", $QuotedVMPath -Wait -PassThru -NoNewWindow
}
Invoke-Command -Session $rs -ScriptBlock $script -ArgumentList $vmConfig.VMImagePathOnHost, $vmConfig.VMRunUtiltyPath
Invoke-Command works if I remove the session parameter:
Invoke-Command -ScriptBlock $script -ArgumentList $vmConfig.VMImagePathOnHost, $vmConfig.VMRunUtiltyPath
I have a similar script that successfully reverts to a snapshot on my localhost through a PSSession, so why is starting a VM giving me trouble?
Does it work if you "enter-pssession" and then try to invoke?
I'm assuming it's "not working" for you here, because you invoke commands through PSSession where there are no visible desktops / gui-session, and you are expecting the VMWare workstation to appear? The receiving end is a service.
You could check if the process is running VMWare with Get-Process.
To do what you want to achieve here you could take a look at PsExec, which allows to start applications into an active session.
https://technet.microsoft.com/en-US/sysinternals/bb897553.aspx
Note the "-i" parameter on PSExec.

Run powershell commands in parallel

How can I run a PowerShell script in parallel on multiple computers?
$TempFolder = "C:\DOWNLOADED_APPLICATIONS"
if(!(test-path $TempFolder))
{New-Item -path $TempFolder -type directory}
Write-Host ""
Write-Host "Downloading .NET framework v4.0 installation package" -ForegroundColor Yellow;
$src = "\\onesoul\tools\DOTNET45\dotNetFx45_Full_x86_x64.exe"
$dest = "$TempFolder" + "\" + "dotNetFx45_Full_x86_x64.exe"
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($src, $dest)
$args = " /q /norestart"
Write-Host "Installing .NET framework v4.0" -ForegroundColor Yellow;
Start-Process -FilePath $dest -ArgumentList $args -Wait
Write-Output "Dot net 4.5 installed"
This script works fine if I run it remotely on one computer at a time. How do I make it run in parallel?
To run scripts on multiple remote computers you use PowerShell remoting. This requires that every computer you connect to has to have PowerShell remoting enabled which you do with the command:
Enable-PSRemoting -Force
Then from your PC, running an elevated console, use the Invoke-Command to run a script against multiple computers e.g.:
Invoke-Command -Computer server1,server2,server3 -Auth CredSSP `
-FilePath c:\script.ps1 -ArgumentList scriptParameter1, scriptParameter2
I suggest you use the -Auth CredSSP to avoid a second hop issue with your credentials since you're accessing a network share from the remote computer. Also the FilePath parameter will take the path to a local script and copy its contents across the wire to each remote computer. That script should not rely on other scripts unless they exist on all the remote computers. Finally, if you use your credentials, you should admin privs on all the remote computers. If you don't, use the -Credential parameter to provides credentials for an account that does.