PSSessionStateBroken with start-job -credential in scheduled task - powershell

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]

Related

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.

Access Denied when waiting for a Process started with Credentials

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.

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
}

How to run Start-Process in Powershell using user credentials?

I've got a Windows service (Jenkins) that runs a script which needs to run a command as a specific user.
I tried to do this but it doesn't work:
$secpasswd = ConvertTo-SecureString "myPassword" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential("DOMAIN\myUsername", $secpasswd)
$Arguments = #()
$Arguments += "-Command"
$Arguments += "pwd"
$Arguments += ">"
$Arguments += "output.txt"
Start-Process powershell.exe -ArgumentList $Arguments -Credential $mycreds -NoNewWindow -WorkingDirectory $workingDir
Start-Sleep 2
Get-Content "$workingDir\output.txt"
I get this output:
Start-Process : This command cannot be executed due to the error: Access is denied.
At C:\Windows\TEMP\hudson2382859596554223918.ps1:32 char:14
+ Start-Process <<<< powershell.exe -ArgumentList $Arguments -Credential $mycreds -NoNewWindow -WorkingDirectory $workingDir
+ CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
Now if I remove -Credential $mycreds it works fine. The reason why there is that Start-Sleep at the end is that I removed the -Wait after reading this question on SO.
Am I missing something here?
$username = "username"
$password = "password"
$credentials = New-Object System.Management.Automation.PSCredential -ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
Start-Process dnscrypt-proxy.exe -WorkingDirectory path_here -Credential ($credentials)
--from powershell forums; i searched for this same solution just a couple days ago and this worked. hope it helps you.
Source: http://powershell.com/cs/forums/t/9502.aspx
Finally found the solution: by default, Jenkins is run as a service log on as the "Local System account". To change this launch the services application (type "services" in the start menu), look for Jenkins, double click on it and go to the "Log On" tab.
You should now see what account the service is using. Change to "This account" and fill in your account details and voila!
For the record the command I was originally trying to run works fine now, without having to add any of the "changing user" things on top.
Special thanks to #Poorkenny that put me on the correct track with his comment, THANK YOU! Stackoverflow rocks! (that moment when thanks to someone you just solved an issue that took you the whole day to figure it out...)

Calling batch with user creds not working in powershell

I have a powershell script that contains the following
$username = 'username'
$password = 'password'
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
start-process -FilePath $deploymentAppPath -Credential $cred
Yet when I execute this I get the following error.
start-process <<<< -FilePath $deploymentAppPath -Credential $cred
+ CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
While I don't think it is probably obvious, my end goal here is to call the batch file with the user credentials that I specify.
I would start by removing the use of securestring. Some things just don't seem to work with it in my experiences.
It appears that your process is local, so you're not transmitting the u/p over the wire. Is the securestring really neccessary (considering that the u/p is in the script and available to whoever has perms to the script)?
I believe you do not have the right version of windows powershell to use the start-process command. I ran this and it worked other than the obvious -FilePath error that I did not set. Where as you seem to be getting the basic 'command does not exist' exception. To check your version number use the get-host cmdlet. Run get-host | select version and if it outputs 1.0 to console you should go Here to get a 2.0 version.