PowerShell Invoke-Command not passing parameters properly - mongodb

I have a PowerShell Script that will invoke a command on a remote server. I'm trying to set this script up so that I can pass in a service parameter and it will drop that specific table in MongoDB
$service = "DatabaseName"
$username = "username"
$password = "password"
$pass = ConvertTo-SecureString -AsPlainText $password -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $pass
Invoke-Command -ComputerName Remote-Server1 -Credential $cred -ArgumentList $service -ScriptBlock {
param($service)
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' $service --eval 'db.dropDatabase()'
}
Invoke-Command -ComputerName Remote-Server2 -Credential $cred -ArgumentList $service -ScriptBlock {
param($service)
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' $service --eval 'db.dropDatabase()'
}
If I were to use the following it does not drop the MongoDB database:
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' $service --eval 'db.dropDatabase()'
However, If I use the following it works as expected:
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' DatabaseName --eval 'db.dropDatabase()'
Why does it work when I hard code that database name but not when I use a variable.

Since your code only needs $service in a read-only manner you can use the Using:-scope modifier, see additional information here.
Based on that you can change the code to:
$service = "DatabaseName"
$username = "username"
$password = "password"
$pass = ConvertTo-SecureString -AsPlainText $password -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $pass
Invoke-Command -ComputerName Remote-Server1 -Credential $cred -ArgumentList $service -ScriptBlock {
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' $Using:service --eval 'db.dropDatabase()'
}
Invoke-Command -ComputerName Remote-Server2 -Credential $cred -ArgumentList $service -ScriptBlock {
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' $Using:service --eval 'db.dropDatabase()'
}
When performing remote commands via Invoke-Command I either use the Using modifier of prefix the variables in the param block with remote. Based on that I can avoid "unwanted" behaviors (as the one you stated above).
So another alternative would be:
Invoke-Command -ComputerName Remote-Server1 -Credential $cred -ArgumentList $service -ScriptBlock {
param($remoteService)
& 'C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe' $remoteService --eval 'db.dropDatabase()'
}

Related

Powershell run exe as different user

I have the following commands in a powershell script (within Jenkins):
$Command = "C:\Program Files\Microsoft SQL Server\150\DAC\bin\SqlPackage.exe"
$Parms = "/Action:Script /sf:DB.dacpac /Profile:publish.xml"
$Prms = $Parms.Split(" ")
& "$Command" $Prms
How can I run the SqlPackage.exe as another user?
PS: It is within Jenkins so I can't run the ps1 file or SqlPackage.exe using runas windows dialog.
EDIT:
I think I am very close, so far I have the following script.
$sb = [scriptblock]::create("& ""SqlPackage.exe"" ""/Action:Script /sf:DB.dacpac /Profile:publish.xml /TargetServerName:localdb /op:Publish.sql""")
$Secure_Password = ConvertTo-SecureString -String $parPassword -AsPlainText -Force
$Credential = New-Object -Type PSCredential($parUserId,$Secure_Password)
$Session = New-PSSession -ComputerName ServerName -Credential $Credential
Invoke-Command -Session $Session -ScriptBlock $sb
I am getting the following error:
*** Argument 'Action' has an invalid value: 'Script
/sf:DB.dacpac /Profile:publish.xml
/TargetServerName:localdb /op:Publish.sql'
instead of creating session, use start-process. I would recommend providing complete path to the dacpac file with SourceFile switch along with the Profile switch
$Command = "C:\Program Files\Microsoft SQL Server\150\DAC\bin\SqlPackage.exe"
$Parms = "/Action:Script /sf:DB.dacpac /Profile:publish.xml"
$Secure_Password = ConvertTo-SecureString -String $parPassword -AsPlainText -Force
$Credential = New-Object -Type PSCredential($parUserId,$Secure_Password)
Start-Process -Credentials $credential -FilePath $command -ArgumentList $Parms

Call a Powershell Scriptfile that resides on a remote server

how do I call a ps1 file that resides on a target machine? All tutorials mostly say that I run a local ps1 on a remote machine. I tried the following but it just does nothing :/
$username = "theusername"
$password = "thepassword"
$secpassword = ConvertTo-SecureString –String $password –AsPlainText -Force
$credential = New-Object –TypeName "System.Management.Automation.PSCredential" –ArgumentList $username, $secpassword
$so = New-PSSessionOption -SkipCACheck
$session = New-PSSession -ConnectionUri "https://servername:5986/WSMAN" -SessionOption $so -Credential $credential
Invoke-Command -Session $session -ScriptBlock { "powershell E:\\Tools\Powershells\MyPowershell.ps1" }
Exit-PSSession
Executing a script by path (possibly with spaces) is done with
& "path with spaces\script.ps1"
This works just as well when remoted, so to execute a remote script stored remotely, use
Invoke-Command -Session $session -ScriptBlock { & "path with spaces\script.ps1" }

Passing parameters to Invoke-Command

I'm having issues passing parameters to Invoke-Command, I've tried using -Args and -ArgumentList to no avail.
function One {
$errcode = $args
$username = "Ron"
$password = ConvertTo-SecureString -String "Baxter" -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
$cred
$Result = Invoke-Command -ComputerName MyPc -ScriptBlock { & cmd.exe /c "C:\Scripts\test.bat" Param1 $errcode ; $lastexitcode} -Credential $cred
echo $result
}
One 10
You can update your function to pass in your parameter as $errcode rather than using $args, this is better code as it's less confusing. (I'd recommend readng up on parameters and functions as it'll certainly help)
Then you need to pass $errcode into Invoke-Command using the ArgumentList parameter, and use $args[0] in its place:
function One ($errcode) {
$username = "Ron"
$password = ConvertTo-SecureString -String "Baxter" -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
$Result = Invoke-Command -ComputerName MyPc -ScriptBlock { & cmd.exe /c "C:\Scripts\test.bat" Param1 $args[0] ; $lastexitcode} -Credential $cred -ArgumentList $errcode
echo $Result
}
One 10

Executing powershell remotely issue

Hi when i try to do some code:
$Username = 'us'
$Password = 'password'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
powershell.exe -command "Invoke-Command -ComputerName server.com -scriptblock {pathCopyAndUnzip.ps1} -Credential $Cred"
This prompt me for a password but when i try to run this command like here (without powershell.exe):
Invoke-Command -ComputerName server.com -scriptblock {pathCopyAndUnzip.ps1} -Credential $Cred
it works without prompt. Do you know how to resolve that? I need to use option 1 because this command is runned from TFS build definition file like here:
<Exec Command="powershell.exe -command "Invoke-Command -ComputerName $(Server) -scriptblock {path} -Credential $Cred"" Condition="'$(RunTests)' == 'True'"/>
You could put your script into it's own file and then call that from TFS rather inline code.
C:\folder\script.ps1:
Param(
[string]$Username,
[string]$Password,
[string]$OtherParam,
)
$Password = $Password | ConvertTo-SecureString -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$Password
Invoke-Command -ComputerName server.com -FilePath "C:\folder\CopyAndUnzip.ps1 -Something $OtherParam" -Credential $Cred
Then call it like so:
<Exec Command="powershell.exe -command "C:\folder\script.ps1 -username user10 -password P#55w0rd -OtherParam Whatever" Condition="'$(RunTests)' == 'True'"/>
You could try to pipe the commands to powershell.exe like this:
'$Username = "us"; $Password = "password"; $pass = ConvertTo-SecureString -AsPlainText $Password -Force; $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass; Invoke-Command -ComputerName server.com -scriptblock {pathCopyAndUnzip.ps1} -Credential $Cred' | powershell.exe -command -
<Exec Command="$(PsExecPath) -accepteula \\$(Server) cmd /C powershell -File FILEPATH " Condition="'$(RunTests)' == 'True'"/>
I used old good psExec :) Everything is work now.

powershell - Invoke-Command : The value of the FilePath parameter must be a Windows PowerShell script file

I have a re-usable script that I've been using with success calling a remote ps1 file but now I'm trying to call a remote batch file and I get the following error message -
Invoke-Command : The value of the FilePath parameter must be a Windows
PowerShell script file. Enter the path to a file with a .ps1 file name
extension and try the command again.
This is the script -
#Admin Account
$AdminUser = "domain\svc_account"
$Password = Get-Content D:\scripts\pass\crd-appacct.txt | convertto-securestring
$Credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminUser, $Password
$FileName = "runme.bat"
$ItemLocation = "D:\path\to\bat\"
#Invoke Script Remotely
Invoke-Command -ComputerName Servername -filepath "$ItemLocation$FileName" -Authentication CredSSP -Credential $Credential
You should use -ScriptBlock parameter instead of -FilePath:
Invoke-Command -ComputerName Servername -ScriptBlock {& "$using:ItemLocation$using:FileName"} -Authentication CredSSP -Credential $Credential
Or if you are using PowerShell v2, which does not have $using:VariableName syntax:
Invoke-Command -ComputerName Servername -ScriptBlock {param($ItemLocation,$FileName) & "$ItemLocation$FileName"} -ArgumentList $ItemLocation,$FileName -Authentication CredSSP -Credential $Credential