Access Denied when waiting for a Process started with Credentials - powershell

I have a script which runs in a user context of a user that does not have permission to Install Applications. I need to install an exe, so I need to do it as a domain admin.
After the Installation I'd like to do other stuff in the script, but the Installation must be finished before continueing with the script.
When I Wait-Process for the installation to end, I get an access denied error.
Is there a way to wait for a Process to finish, which was started on another user context?
This is my code:
$P = Start-Process $Pfad\vcredist_x64.exe -Argumentlist "/install","/passive","/norestart" `
-WorkingDirectory $Pfad -Credential $cred -PassThru | Wait-Process
This are the error messages (translated from german):
Access denied
Wait-Process : This command terminated the "vcredist_x64 (6284)" operation due to the following error: Access denied. In Zeile:6
Zeichen:84
+ ... -WorkingDirectory $Pfad -Credential $cred -PassThru | Wait-Process
+ ~~~~~~~~~~~~
+ CategoryInfo : CloseError: (System.Diagnost... (vcredist_x64):Process) [Wait-Process], ProcessCommandException
+ FullyQualifiedErrorId : ProcessNotTerminated,Microsoft.PowerShell.Commands.WaitProcessCommand
Timeout issue
Wait-Process : This command terminated the process because the "vcredist_x64 (6284)" process was not completed within the specified timeout. In Zeile:6 Zeichen:84
+ ... -WorkingDirectory $Pfad -Credential $cred -PassThru | Wait-Process
+ ~~~~~~~~~~~~
+ CategoryInfo : CloseError: (System.Diagnost... (vcredist_x64):Process) [Wait-Process], TimeoutException
+ FullyQualifiedErrorId : ProcessNotTerminated,Microsoft.PowerShell.Commands.WaitProcessCommand

Posting my earlier comment as an answer
$proc = Start-Process "Notepad.exe" -PassThru
$proc.WaitForExit()
$proc1 = Start-Process "Calc.exe" -PassThru
$proc1.WaitForExit()

I did something like this the other day. My case was a little different. I was kicking something off, I wanted something to happen once that process ended, in the meantime I was doing another thing. For that, I used an event. Here is an example using Notepad:
$do_other_stuff = {
Write-Host 'Do Other Stuff'
Get-EventSubscriber | Unregister-Event
}
$p = Start-Process notepad.exe -PassThru
...do other stuff...
$job = Register-ObjectEvent -InputObject $p `
-EventName Exited `
-SourceIdentifier notepad `
-Action $do_other_stuff
If I wanted to wait for the even to trigger, I'd use Wait-Event. Stuff whatever you want done once the installer finishes running in the $do_other_stuff script block.
To your question, the following worked for me:
$p = Start-Process notepad.exe -PassThru -Wait
...do stuff...
As did...
$p = Start-Process notepad.exe -PassThru
$p.WaitForExit()
...do stuff...
These cases worked when running the script in elevated and un-elevated context. It worked when passing credentials to Start-Process via the -Credential parameter. I wasn't able to try it where the account calling Start-Process is a low privileged account; I have a meeting in a few, sorry.

Related

Powershell remote execution of Oracle installer Silent from unc

Meanwhile I've read and tried so many options and none of them worked for me.
I need to run a command on a remote machine that will install an application.
The setup.exe is an Oracle installer and is able to accept silent parameters.
"\\SVR1\Share\remote application Install\install\Setup.exe" -silent -force -nowait -waitforcompletion PACKAGE_NAME=abcde INSTALL_MODE=Typical ORACLE_HOME=C:\some_dir ORACLE_HOME_NAME=some_dir_Client1 APP_USER=itsmeagain APP_PASSWORD=surexxx
When I paste this command in a cmd it works as expected
When I put this in a ps1 script and run it, it works too:
cmd /c "\\SVR1\Share\remote application Install\install\Setup.exe" -silent -force -nowait -waitforcompletion PACKAGE_NAME=abcde INSTALL_MODE=Typical ORACLE_HOME=C:\some_dir ORACLE_HOME_NAME=some_dir_Client1 APP_USER=itsmeagain APP_PASSWORD=surexxx
However trying to run this 1 line script from a remote computer, it fails with: [Start-Process], InvalidOperationException
$svr="mach1"
$cmdFile="install.ps1"
$RemDir = "\\${svr}\C$\All_files\Scripts\"
$fn = "${RemDir}\${cmdFile}"
$password = ConvertTo-SecureString "${pazwd}" -AsPlainText -Force
# can't change the remote dir without spaces
"cmd /c `"\\SVR1\Share\remote application Install\install\Setup.exe`" -silent -force -nowait -waitforcompletion PACKAGE_NAME=abcde INSTALL_MODE=Typical ORACLE_HOME=C:\some_dir ORACLE_HOME_NAME=some_dir_Client1 APP_USER=itsmeagain APP_PASSWORD=surexxx " | Out-File -FilePath $fn
$cred = New-Object System.Management.Automation.PSCredential($user,$password)
$sb = { Start-Process -FilePath "${LocalDir}\${cmdFile}" }
Invoke-Command -ComputerName $svr -Credential $cred -ScriptBlock $sb
Suggestions? what Am I doing wrong here?

powershell script fails: This command cannot be run due to the error: %1 is not a valid Win32 application

Trying to write my first powershell script to trigger an MSI.
The msi file is located in the same folder as the ps file.
Problem
I'm getting the error message in the title when i try to run.
PS C:\Users\jj\source\github\electron\j> .\test.ps1
Start-Process : This command cannot be run due to the error: %1 is not a valid Win32 application.
At C:\Users\jj\source\github\electron\j\test.ps1:12 char:1
+ Start-Process .\node-v12.18.4-x64.msi -Wait -NoNewWindow
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
Yay. Install script executed successfully
Code
This is what the code looks like:
$DataStamp = get-date -Format yyyyMMddTHHmmss
$logFile = '{0}-{1}.log' -f $file.fullname,$DataStamp
$MSIArguments = #(
"/i"
('"{0}"' -f $file.fullname)
"/qn"
"/norestart"
"/L*v"
$logFile
)
Start-Process .\node-v12.18.4-x64.msi -ArgumentList $MSIArguments -Wait -NoNewWindow
Write-Host "Yay. Install script executed successfully"
What I've tried
I've tried triggering the msi directly from the powershell command line and it works fine.
Also removed all the commandline options in the ps file... but it still fails.
Lastly tried this for the start process command:
Start-Process -FilePath "$.\node-v12.18.4-x64.msi" -ArgumentList $MSIArguments -Wait -NoNewWindow
Any tips would be appreciated.
Thanks.

How to Install Windows Updates on Remote Computer with PowerShell

I'm trying to install Windows Updates on a Remote Computer with this command:
$InstallSplat = #{
AcceptAll = $true
SendReport = $true
IgnoreReboot = if ($Reboot) { $false } else { $true }
PSWUSettings = #{
SmtpServer = "my mail server"
From = "myfrom <myfrom#myfrom.com>"
To = "myto <myto#myto.com>"
Port = 25
}
}
Invoke-Command -ComputerName $_ -Credential $cred -AsJob -ArgumentList $InstallSplat -ScriptBlock {
param([hashtable]$InstallSplat)
Import-Module PSWindowsUpdate
Install-WindowsUpdate #InstallSplat
$Error | out-file C:\install\installwinupdate.log -Append
}
I pass a credential Object with domain admin privileges in $cred but I still always get this error
Install-WindowsUpdate : Access denied (Ausnahme von HRESULT: 0x80070005 (E_ACCESSDENIED)) In Zeile:4 Zeichen:25
+ Install-WindowsUpdate #InstallSplat
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WindowsUpdate], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,PSWindowsUpdate.GetWindowsUpdate
The Command Install-WindowsUpdate itself does not have a credential parameter I could use. The Command needs to run in an elevated PowerShell, but I use an elevated PowerShell when starting this command on my Computer.
I Also tried creating a New-PSSession with my $cred and run Invoke-Command -Session $session instead of Invoke-Command -ComputerName $_ with the same result.
Does anybody know what's happening here? Why do I get Access denied?
It can't have anything to do with passing the $InstallSplat because the same thing happens if I don't pass any parameter at all and write the parameters and their Values directly at the command instead of splatting.
The Problem was, that you can't Download or Install Updates on a machine from another remote machine. Here's a list what you can or can't do remotely when it comes to Windows Updates
The solution is, to create a scheduled task on each server you want to install updates from a remote script, and start that task.
luckily, when you use the PSWindowsUpdate module, you don't have to do that yourself, you can just use Invoke-WUJob (formerly Invoke-WUInstall) which does the trick for you.
I used it like so ($ServerData.Value contains a list of my Servers) and it works like a charm. It creates a scheduled task on each server, and runs them immediately, if you add the -RunNow Parameter.
invoke-WUJob -ComputerName $ServerData.Value -Script { Import-Module PSWindowsUpdate ; Install-WindowsUpdate -AcceptAll -SendReport -IgnoreReboot -PSWUSettings #{From='xy';Port=25;SmtpServer='xy';To='xy'} | Out-File C:\install\PSWindowsUpdateLog.txt -Append} -Confirm:$false -verbose -RunNow
Note that what you specify as a script block in -Script will be pasted to -Command " <here> " in your scheduled task, so you should work with ' inside -Script.

Start-Job including custom cmdlet terminates with strange error

I developed some custom cmdlets that serve for different importing tasks to a SharePoint system. Currently all those cmdlets are being run in a serial kind in a single PowerShell script. I want to change this so that each cmdlet gets executed in a separate task (job).
The main script starts a new job with Start-Job relating to a separate script that contains the call to the cmdlet. The script starts and executes the cmdlet. I also debugged the code of the cmdlet that gets executed. So far so fine.
But after around 15-20 seconds the job just gets terminated with the following error message:
There is an error processing data from the background process. Error reported:
Cannot process an element with node type "Text". Only Element and EndElement
node types are supported..
+ CategoryInfo : OperationStopped: (localhost:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : JobFailure
+ PSComputerName : localhost
I can't find any information on how to handle such an error. I just don't know what is the problem here.
Do I have to add further functionalities to my custom cmdlets so they can be handled in a job?
Here are the scripts.
Main:
[object]$credentials = Get-Credential -UserName "domain\user" -Message "Log in"
$job = start-job -FilePath "C:\ImportItems.ps1" -Name ImportItems -ArgumentList $credentials
$job | Wait-Job
ImportItems:
[CmdletBinding()]
Param(
[object]$credentials
)
Import-Module C:\Migration\MigrationShell.dll
Import-Items -Credential $credentials
I found a workaround on uservoice, did the trick for me
https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/14915283-job-cmdlets-fail-with-utf-8-codepage
if (
[Console]::InputEncoding -is [Text.UTF8Encoding] -and
[Console]::InputEncoding.GetPreamble().Length -ne 0
) {
[Console]::InputEncoding = New-Object Text.UTF8Encoding $false
}

PSSessionStateBroken with start-job -credential in scheduled task

The lines below work fine from a Powershell prompt, but fail from a scheduled task.
$pass = gc C:\secrets\shhh.txt | convertTo-secureString
$Cred = new-object -typeName System.management.automation.psCredential -argumentlist "domain\domainUser",$pass
$path = "\\server\share\folder"
$j = start-job {gci -path $args[0]} -cred $Cred -argumentList $path | wait-job | receive-job
$body = $j | out-string
$error | out-file C:\temp\err.txt
send-mailMessage -to me#domain.tld -from server#domain.tld -subject halp -smtpserver mailserver.domain.tld -body $body
In c:\temp\err.txt the Windows 2008R2 Scheduled Task leaves a breadcrumb:
[localhost] The background process exited abnormally.
+ CategoryInfo : OpenError: (localhost:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : 2101,PSSessionStateBroken
...which brings us to this Microsoft bug report. The report mentions a workaround with localhost loopback remoting, which sounds kinda dirty. Should I go there?
Is there a better solution? Maybe with one of the *session cmdlets or invoke-command? The scheduled task's Start in value is set, but maybe the background process uses some variable in some bad way, like so?
No luck yet calling powershell.exe with –version 2 or with -command "& {bigKlugeyScriptblock}" syntax.
edit: I'm trying to avoid creating a new domain account to run the task. The task can't run as domainUser from $cred, because that account should not have permissions on localhost.
As some possible work arounds how about:
Put alternate credentials on the scheduled task itself
Using the runas command to start powershell.exe as a different user
Using net use /user parameter to authenticate access to the network path
[/USER:[dotted domain name\]username]
[/USER:[username#dotted domain name]