Executing Powershell script as different User in Exchange 2007 Powershell - powershell

My scenario looks like this:
Java opens a Powershell in which Exchange Powershell Command/Scripts should be executed as a different user and the output should be displayed in the Powershell windows that Java opened (so Java can read the output).
So: Normal Powershell --> Add Exchange functionality --> Execute Script/Command as different user
To add Exchange functionality to the normal Powershell I use either
add-pssnapin Microsoft.Exchange.Management.PowerShell.Admin or start Powershell like this C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -PSConsoleFile "C:\Program Files\Microsoft\Exchange Server\bin\exshell.psc1" -command ". 'PathToScript/script1.ps1'"
The problem is the execution as a different user:
runAs (or other tools like PSEXEC or minirunAs) is not working because it opens a new window so the output is not shown in the powershell window opened by Java (an therefore cant be read by Java) and is not suitable for automation
I tried 2 different ways to do it with Powershell:
Way 1:
$username = 'domain\user'
$password = 'Pa$$w0rd'
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
Invoke-Command -Credential $cred -ComputerName localhost -FilePath PathToScript/script1.ps1
But i get the following Error:
An Active Directory error 0x80072020 occurred while searching for domain controllers in domain MYDOMAIN: An operations error occurred.
+ CategoryInfo : NotSpecified: (0:Int32) [Get-MailboxStatistics], ADTransientException
A simple whoami works this way an prints the user specified in $username but according to this link it looks like that this is not possible with Exchange command (but I dont know how reliable the source is): http://thwack.solarwinds.com/thread/40524
Way 2 (as suggested here http://social.technet.microsoft.com/Forums/en-US/ITCG/thread/f805cbe0-bca9-401a-a381-a7f5520244d2):
$computerName = "localhost"
$username = 'domain\user'
$password = 'Pa$$w0rd'
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$computerName/powershell -Credential $cred
Import-PSSession $session
But the problem here is that the URI http://$computerName/powershell does not exist (I get WinRM 502 exception) and I dont know how to get a Powershell Virtual Directory on a Server where just the Exchange 2007 Management Tools are installed.
So my questions are: Is there another way to do this? What am I doing wrong in Way 1 & 2 (more how can I add the Powershell VD with Way 2)? Is it possible at all?
I run Java (7 x64) on a WinSrv2012 with Exchange 2007 Management Tools installed. The Exchange Server runs on version 2007. The script is Get-MailboxStatistics -server ExSrv.
This bothers me for nearly a week now so I highly appreciate any help.

I just found out that executing Remote Powershell Commands/Skripts is not supported with Exchange 2007 (http://howexchangeworks.com/2009/11/exchange-2007-sp2-supports-powershell.html). So I need to wait until the upgrade to 2013.
Some workarounds: http://social.technet.microsoft.com/Forums/en-US/exchangesvrgeneral/thread/4596035a-cede-4541-8b8e-e2e9bf1b40dc
Or: http://peerfect.blogspot.co.at/2012/10/re-blog-of-my-exchange-remote.html

Related

Executing CMD or EXE file using PSSession (remote powershell) caused Error 1603 access denied

I have the following script powershell command but it returns access denied. I assume the Error 1603 is caused by remote accessing the server. However, the $username has admin rights in the computer01 server.
To recheck if my hunch was right, I tried to test with the following and I got access denied:
Start-Process cmd -Credential $Cred
Update
The error was due to the $Cred . Removing the -Credential argument works fine.
End of Update
The commands have no problems executing directly in the computer01 machine using the cmd.exe.
I want to use cmd /c in this case as I need to get the real exit code from the SETUP.EXE installer.
See full script below:
$script = {
#Param(
# [String]$username,
# [String]$password
#)
# $Cred = New-Object System.Management.Automation.PSCredential ($username, $password)
$respfile = "$env:TEMP\test.resp"
echo 'key=value' > $respfile
$username = "$env:USERDOMAIN\$env:USERNAME"
Write-Host Hello $username
$Creds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME" )
Start-Process cmd -Credential $Creds
#This command cannot be run due to the error: Access is denied.
# + CategoryInfo : InvalidOperation: (:) [Start-Process], #InvalidOperationException
# + FullyQualifiedErrorId : #InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
# + PSComputerName : computer01
# cmd /c "$path\SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'"
runas /user:$Username "SETUP.EXE" /INSTALL -s /RESPFILE:"$respfile"
echo $LASTEXITCODE
# Error 1603
}
#$username = 'domain/user'
#$password = 'password'
$server = 'computer01'
$Creds = New-Object System.Management.Automation.PSCredential
$session = New-PSSession -ComputerName $server
#Invoke-Command -Session $session -Scriptblock $script -Argumentlist $username, $password
Invoke-Command -Session $session -Scriptblock $script -Credential $Creds #updated based on #postanote advise
Remove-PSSession -ComputerName $server
I have found the following similar link install-remotely but do not want to use the ENTER-PSSession command. I do not want to exit the current PSSession and remotely join again in server just to install then exit.
Any suggestions how to use only PSSession and successfully executing installers in the remote server?
As one mentioned in the comments, you don't need cmd.exe. You can use the call/invocation operator - & - to specify that the next token on the line is a command:
& "$path\SETUP.EXE" /INSTALL -s /RESPFILE:$respfile
Of course, for this to work, the parameters to SETUP.EXE need to be correct (I don't know whether that's the case or not).
Never pass plain text passwords in scripts. It exposes you to uneeded risks.
Use proper secured credentials models.
• Working with Passwords, Secure Strings and Credentials in Windows PowerShell
• quickly-and-securely-storing-your-credentials-powershell
PowerShell remoting requires the use of an implicit (New-PSSession) or explicit (Enter-PSSession) session.
• About Remote Requirements
There are only a handful of cmdlets you can use as non-Admin ir run without PSRemoting enabled.
• Tip: Work Remotely with Windows PowerShell without using Remoting or WinRM
As noted in the Powershell Help file | MS Docs link above, with PSRemoting, you must be using an account that is an admin on the remote host.
In Windows OS proper, to install software, you must be an admin and running that in an admin session.
PowerShell runs in the context of the user who started it.
If you are trying to run in another user context, that is a Windows Security boundary, and you cannot do that without PowerShell natively, you'd need other tools like MS Sysinternals PSExec. See also:
Find-Module -Name '*Invoke*' | Format-Table -AutoSize
# Results
<#
Version Name Repository Description
------- ---- ---------- -----------
...
3.1.6 Invoke-CommandAs PSGallery Invoke Command as System/User on Local/Remote computer using ScheduleTask.
...
#>
Try this refactored option...
$script = {
$Creds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME" )
$respfile = 'whatever this is'
& "SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'"
Write-Output $LASTEXITCODE
}
$server = 'computer01'
$session = New-PSSession -ComputerName $server
Invoke-Command -Session $session -Scriptblock $script -Credential $Creds
Remove-PSSession -ComputerName $server
Details
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Invoke-Command).Parameters
(Get-Command -Name Invoke-Command).Parameters.Keys
Get-help -Name Invoke-Command -Examples
# Results
<#
Invoke-Command -ComputerName server01 -Credential domain01\user01 -ScriptBlock {Get-Culture}
$s = New-PSSession -ComputerName Server02 -Credential Domain01\User01
$LiveCred = Get-Credential
Invoke-Command -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.exchangelabs.com/PowerShell -Credential $LiveCred -Authentication Basic
Invoke-Command -Session $s -ScriptBlock { Get-HotFix } -SessionOption $so -Credential server01\user01
Enable-WSManCredSSP -Delegate Server02
Set-Item WSMan:\Server02*\Service\Auth\CredSSP -Value $True
Invoke-Command -Session $s -ScriptBlock {Get-Item \\Net03\Scripts\LogFiles.ps1} -Authentication CredSSP -Credential Domain01\Admin01
#>
Get-help -Name Invoke-Command -Full
Get-help -Name Invoke-Command -Online
So, I was able to solve my problem.
1603 is the error thrown by the setup.exe.
Just to be sure, I manually executed first the following directly in the server using CMD and it was working!
$path\SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'
I did a lot of testings. Researched and as mentioned from comments above, I did different ways to execute programs using powershell. I even used ACL to change ownership of installer directory/ files, switching to different user accounts (with different priviledges) but still getting access denied (including the Admin account).
It took days before I realized the difference in output file size of manual run in machine and the remote. The cause was the $respfile. It really is worth checking every possible reason/ scenario why there's access denied. Plus I cannot extract the setup.exe and its contents to troubleshoot.
The $respfile was created via powershell. I noticed the size created by powershell is doubled compared to a CMD size that was needed. With that, I assumed that the setup.exe reads file in UTF-8 format. I only know that it's working when triggered via CMD and not via powershell.
I suddenly bumped on this links differrent Powershell and CMD sizes and convert file content to CMD readable file - utf8. After converting the $respfile to UTF-8 format, I was able to run the exe successfully.
Hopefully, this can help others too!

PowerShell Computer StartUp-Script - Switch user-context?

Through Microsoft Group Policy I did define to run a Powershell-Script on Computer Start-Up. Also I have the requirement to run a Powershell-Script as Scheduled Task without saving credentials.
On both scenarios I have the same problem ...
I want to run a Citrix Powershell-Command (PSSnapIn) like:
Set-BrokerMachine -MachineName "domain.local\$env:COMPUTERNAME" -AdminAddress "RemoteServer.domain.local" -InMaintenanceMode $True
Manual: https://citrix.github.io/delivery-controller-sdk/Broker/Set-BrokerMachine/
Of course only users who have the permission could run those Citrix-commands. I would be able to give a domain-user the permission to run the command "Set-BrokerMachine", but in the mentioned scenarios the PowerShell-scripts run in context of the system-user.
I did simulate the system-user by PSExec:
Error running as System-User
My scripts do other things of course and I want to keep them running as System-User, but now I am looking for a clean solution to get those Citrix-commands running.
If possible, I don't want to save credentials in my scripts.
EDIT #1:
I would be able to workaround with the following code:
$Username = "MySpecialUser"
$Password = 'MyPassword'
$SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential $Username, $SecurePassword
$Result = Invoke-Command -Session ( New-PSSession -ComputerName "RemoteServer.domain.local" -Credential $Credential ) -ScriptBlock {
Add-PSSnapin Citrix*
Set-BrokerMachine -MachineName "domain.local\$args" -InMaintenanceMode $True
} -ArgumentList $env:COMPUTERNAME -HideComputerName
Remove-PSSession -InstanceId $Result.RunspaceId
I don't like this because:
The code has to contain credentials (ofc I could encrypt it ...)
I have to create a permission-system for this special user in Citrix
I have to put the special-user into a local-group on every server, to allow the remote-administration (security-risk)
I don't like to use PSSession
...
Is there a better/cleaner solution? Any ideas?

Remote powershell sessions can only be established with interactively entered credentials?

I'm trying to automate a powershell script which gathers data from O365. I've got a special limited user setup with the privileges required on O365 and also with local logon allowed on the server so that I can "run-as" that user (which I do for all the scripts below. I have verified different, expected errors when running as other users).
The script works fine interactively when credentials are set like this and the session opened:
$cred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $cred -Authentication Basic –AllowRedirection
However, if I create the credentials file for automation with:
Get-Credential | Export-Clixml -Path C:\batch\${env:USERNAME}_cred.xml
And then access from the script via:
$cred = Import-Clixml -Path C:\batch\${env:USERNAME}_cred.xml
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $cred -Authentication Basic –AllowRedirection
The credential file load appears to succeed. I then get "Access Denied" on the session open, and then of course the rest of the script fails due to the session being null. I'm cutting and pasting the password in all cases (plus have tried many, MANY times including hand typing) so I don't think it's a simple typo issue. Seems more like something I'm fundamentally misunderstanding about powershell. Ultimately I'd like to not just have the credentials automated, but also have it run from task scheduler if there's any special settings above and beyond that I also need.
I don't see anything wrong from your code from PowerShell perspective. I have tested the way you are creating credentials within a company domain and I was able to create new session by importing credential XML file that was created by exporting the credentials the way you did. I then assume it might be MS Exchange related.
I can suggest alternatives for you to try:
# First we need to get the encrypted password:
$TempCred = Get-Credential
# provide credentials to the prompt
# now the encryption to be saved in a file
$TempCred.Password | ConvertFrom-SecureString | Set-Content C:\mypass.txt
This was the encrypted version of your password is saved as a text.
In your automation script you can now do this:
$username = "yourusername"
$password = Get-Content C:\mypass.txt | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PsCredential($username, $password)
$session = New-PSSession -Credential $cred .....
I am not sure if this works in your case, it worked in my company domain. Once again it worked for me the XML version too. I am just providing alternatives to try if you are not keen to find out as to why the XML way did not work.
I was able to get this working, in my environment at least, by including a call to Import-PSSession:
$Credential = Import-Clixml -Path D:\Modules\O365Credentials.xml
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Credential -Authentication Basic -AllowRedirection
Import-PSSession $Session -DisableNameChecking
Get-Mailbox
Does the account in question have MFA enabled? If so, you might try this.
This script:
Downloads Exchange Online Remote PowerShell Module
Installs Exchange Online PowerShell Module
Connects Exchange Online PowerShell using MFA
Or, you can perform these manually. More information, including a detailed walk-through, is available here:
https://o365reports.com/2019/04/17/connect-exchange-online-using-mfa/

Invoking-Command for Exchange in Powershell - block is not allowed in a Data section

What I'm trying to do is run this script:
$WPFcmdCreateNewUser.Add_Click({
$ScriptBlockContent = {
param ($first,
$last,
$upn,
$ou,
$password
)
$encryptedpass = ConvertTo-SecureString -AsPlainText $password -Force
New-RemoteMailbox -Name $name -OnPremisesOrganizationalUnit $ou -UserPrincipalName $upn -FirstName $first -LastName $last -Password $encryptedpass -ResetPasswordOnNextLogon $false
}
$ex = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://SERVERNAME/PowerShell/
Invoke-Command -Session $ex -ScriptBlock $ScriptBlockContent -ArgumentList ($WPFtxtNewFirstName.Text, $WPFtxtNewLastName.Text, $WPFtxtNewAlias.Text, $WPFcboNewOU.SelectedItem.Content, $WPFtxtNewPassword.Text)
})
But it's giving me the error:
ERROR: A Begin statement block, Process statement block, or parameter statement is not allowed in a Data section.
ERROR: + CategoryInfo : ParserError: (:) [], ParseException
ERROR: + FullyQualifiedErrorId : InvalidScriptBlockInDataSection
ERROR: + PSComputerName : SERVERNAME
I'm running the whole command from a button click in a XAML Powershell GUI. I googled alot trying to solve the problem as I usually do but no luck :(
Any help would be GREATLY appreciated.
It looks like Exchange uses restricted language mode for remote sessions and you can't execute scriptblocks in your session.
As a security feature, the language mode is obviously controlled at
the server (Exchange), so if you want to enable execution of
scriptblocks you need to interactively logon (RDP or console) to
Exchange and create a new session configuration via
Register-PSSessionConfiguration. You may then connect to Exchange
using this session configuration via New-PSSession -ConfigurationName
and you will then be able to execute scriptblocks by passing this
session instance to Invoke-Command -Session.
Reference:
Remote powershell scriptblock execution question
Bit of an old bump here, but seeing as it is rather high on Google search I figured I could add how I fixed this issue:
$DomainCredential = (Get-Credential)
$fqdn = "<The fully qualified domain name of the target server>"
#Creates a session to the Exchange Remote Management Shell so that we can run Exchange commands. Use https:// if you have a proper setup with certificates. ( Mine was in test env )
$ConfigSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$fqdn/powershell `
-Credential $DomainCredential -Authentication Kerberos
#Imports the module that exists in the session, in this case, Exchange Management -AllowClobber gives the imported commands presedence.
Import-Module (Import-PSSession $ConfigSession -AllowClobber)
This imports the Exchange Commands as you would in a local session. The Exchange commands will still be executed on the remote server. Remember to close the session when done.

“Access Denied” trying to execute a command using alternate credentials as user SYSTEM

I have a script that runs as SYSTEM, if i try to start-process notepad.exe it's working fine. if i add -credentials $cred it shows Access Denied. The credentials i pass over has local admin access, so why is there Access Denied? with procmon on powershell.exe i can not identify any access denied operation, i can see that powershell access notepad.exe with success result.
any ideas?
in one forum-post I read that it's not possible to execute a command with -credentials as SYSTEM. is that so?
if so, is there any workaround?
to my background, i use a software distribution where any installation runs as SYSTEM, from there i want to execute a powershell script as different user.
i found a solution:
$secpasswd = ConvertTo-SecureString 'password' -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ('domain\user', $secpasswd)
Invoke-Command -ScriptBlock { Start-Process powershell c:\temp\mmc.ps1 -verb runas -wait} -ComputerName localhost -Credential $mycreds -Verbose
its not exactly what i want because here you need to enable psremoting first. but its like a workaround.
any idea how this is possible without invoke-command would be appreciated