I have a script that copies another script to a remote server then executes the 2nd script. This was working ok last week but today execution of the first script failed saying the 2nd script couldn't be found. As part of troubleshooting I created a simple version of the 2nd script (containing only Write-Host "Wrong Server!) on the local server. Now when I run the 1st script, the dummy 2nd script is executed on the local server!
I have pasted by test-harness script below:
$DeploymentFolderOnTargetServer = "c:\biztalkdeployment"
$TargetServer = "d-vasbiz01"
$Username = "TFS_Service"
$Password = "x"
$SecPass = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $Username,$SecPass
$Session = New-PSSession -ComputerName $TargetServer -Authentication CredSSP -Credential $Cred
$Environment = "Dev"
$ExecuteScriptFilePath = join-path "$DeploymentFolderOnTargetServer" "ExecuteBizTalkAppMSI.ps1"
$MSI = "bin\debug\x.int.mis-3.0.0.msi"
$InstallFolderOnTargetServer = "C:\Program Files (x86)\x.Int.MIS for BizTalk 2010\3.0"
Write-Host "Session = $Session"
Write-Host "ExecuteScriptFilePath = $ExecuteScriptFilePath"
Write-Host "MSI = $MSI"
Write-Host "InstallFolderOnTargetServer = $InstallFolderOnTargetServer"
Write-Host "Environment = $Environment"
Write-Host "DeploymentFolderOnTargetServer = $DeploymentFolderOnTargetServer"
Invoke-Command -Session $Session -FilePath $ExecuteScriptFilePath -argumentlist $MSI, $InstallFolderOnTargetServer, $Environment, $DeploymentFolderOnTargetServer
The output from the test is as follows:
Session = System.Management.Automation.Runspaces.PSSession
ExecuteScriptFilePath = c:\biztalkdeployment\ExecuteBizTalkAppMSI.ps1
MSI = bin\debug\x.int.mis-3.0.0.msi
InstallFolderOnTargetServer = C:\Program Files (x86)\Vasanta.Int.MIS for BizTalk 2010\3.0
Environment = Dev
DeploymentFolderOnTargetServer = c:\biztalkdeployment
Wrong Server!
If I run get-session then the Computer Name for the session is correctly pointing at the 2nd Server.
Any ideas?
The -FilePath parameter to Invoke-Command is specifying a local path to a script - not a path on the target computer. Invoke-Command will take care of getting the local script file over to the target computer so that it can execute there.
Related
I'm trying to make a script that changes the HostnameAlias for a given dns record.
But only certain users have access to editing these records, for example ADMIN can edit it but CURRENTUSER cannot.
Currently I have this piece of code:
param(
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
$Credential = $(Get-Credential)
)
$Command = "Set-DnsServerResourceRecord -NewInputObject $($NewObject) -OldInputObject $($OldObject) -ZoneName $($ZoneName)"
Start-Process -FilePath PowerShell -NoNewWindow -Credential $Credential -ArgumentList $Command
But i just keep getting Start-Process : This command cannot be run due to the error: The user name or password is incorrect even though I am absolutely sure they are indeed correct.
What am I doing wrong here.
Ps, I have looked at all the related questions, none seem to answer my question.
You can call System.Management.Automation.PSCredential object to specify any credentials you want and run with it in any process
$User = 'yourdomain\youruser'
$Password = 'yourpassword'
$Secure_Password = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($User, $Secure_Password)
$Command = "Set-DnsServerResourceRecord -NewInputObject $($NewObject) -OldInputObject $($OldObject) -ZoneName $($ZoneName)"
Start-Process -FilePath PowerShell -NoNewWindow -Credential $Credential -ArgumentList $Command
You can use this:
#Get User credential
$Credential = Get-Credential Domain\UserNameYouWant
#Use System.Diagnostics to start the process as User
$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
#With FileName we're basically telling powershell to run another powershell process
$ProcessInfo.FileName = "powershell.exe"
#CreateNoWindow helps avoiding a second window to appear whilst the process runs
$ProcessInfo.CreateNoWindow = $true
#Note the line below contains the Working Directory where the script will start from
$ProcessInfo.WorkingDirectory = $env:windir
$ProcessInfo.RedirectStandardError = $true
$ProcessInfo.RedirectStandardOutput = $true
$ProcessInfo.UseShellExecute = $false
#The line below is basically the command you want to run and it's passed as text, as an argument
$ProcessInfo.Arguments = "The command you want"
#The next 3 lines are the credential for User as you can see, we can't just pass $Credential
$ProcessInfo.Username = $Credential.GetNetworkCredential().username
$ProcessInfo.Domain = $Credential.GetNetworkCredential().Domain
$ProcessInfo.Password = $Credential.Password
#Finally start the process and wait for it to finish
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessInfo
$Process.Start() | Out-Null
$Process.WaitForExit()
#Grab the output
$GetProcessResult = $Process.StandardOutput.ReadToEnd()
# Print the Job results
$GetProcessResult
Just a mistake on my part, forgot to specify domain before username when entering credentials.
Can solve it like this Get-Credential Domain\
So here's the code I have so far:
$computerName = read-host "Enter Computer Name"
$IPCName = read-host "Enter IPC Profile name"
$uName = read-Host "Enter SU account"
$pw = read-host "Password"
$pwe = convertto-securestring -AsPlainText -Force -String $pw
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "CHILDRENS\$uName",$pwe
[string]$ipcdevcmd="FREEFORMDEVICENAME=`"$IPCName`""
[string]$tftp1='TFTP1="10.200.254.69"'
[string]$tftp2='TFTP2="172.16.90.205"'
$arrayofargs= ('/i','C:\IPCommunicator\CiscoIPCommunicatorSetup.msi','/qn',$ipcdevcmd,$tftp1,$tftp2)
$rtn = Test-Connection -CN $computerName -Count 1 -BufferSize 16 -Quiet
IF($rtn -match 'TRUE'){
echo 'machine Pings'
$session = New-PSSession -ComputerName $computerName -credential $cred
echo 'Testing Path'
$path = Invoke-Command -Session $session {Test-Path C:\IPCommunicator}
IF($path -match "False"){
echo "Need to make Directory"
Invoke-Command -Session $session {mkdir C:\IPCommunicator}
robocopy C:\IPCommunicator \\$computername\C$\IPCommunicator /MIR
echo 'Files Copied to New Directory'
}
ELSE {
robocopy C:\IPCommunicator \\$computername\C$\IPCommunicator /MIR
echo 'Files Copied to Existing Directory'
}
echo 'invoking install'
Invoke-Command -Session $session {Start-Process msiexec.exe -argumentlist $arrayofargs}
echo 'install invoked'
}
ELSE {
echo 'unable to ping system'
}
read-host "Press enter"
What I get back is:
invoking install(for reference)
"Cannot validate argument on parameter 'ArgumentList'. The argument is null or empty. Provide an argument that is not null or empty and then try the command again."
install invoked(for reference)
What I think is happening is that it is trying to use the machine local variables instead of the user supplied variables on the originating box.
The whole aim is to trigger an install that pre-sets certain variables thru the MSI arguments. Those are valid and from a batch with i can do it on the local pc just fine. When I try to pass those variables from MY computer running the script to the user's pc via invoke-command it is not seeing my locally set variables. How the heck do I pass them through.
Broken down by itself...
...returns my inputs for each of the arguments correctly, in a valid stringy form. Somehow that is getting lost in the invoke command. :/ not sure how to pass those variable over? Should I write to text and then move the file over and load it from the local pssession? There has to be a better way!
Because your are executing the command in another session, unless you define the variable in that other session it has no idea what you're talking about. To get around that use the $using: scope. That line then look like:
Invoke-Command -Session $session {Start-Process msiexec.exe -argumentlist $using:arrayofargs}
I'm a beginner with Powershell and while working on a script I ran into a very weird issue.
I have the following code which works as expected:
$deploymentMachine = Read-Host "Please enter the name of the machine on which you want to deploy: "
$deploymentMachineUsername = Read-Host "Please enter the username: "
$deploymentMachinePassword = Read-Host "Please enter your password: " -AsSecureString
$credentials = New-Object System.Management.Automation.PSCredential ($deploymentMachineUsername, $deploymentMachinePassword)
$remoteSession = New-PSSession -ComputerName $deploymentMachine -Credential $credentials -ErrorAction Stop
and then I'm trying to check for the existence of a folder on the remote machine using:
if(Invoke-Command -Session $remoteSession { Test-Path "C:\Test" })
which throws the following error:
Cannot bind argument to parameter 'Path' because it is null.
If I run the same code line by line in the Powershell everything works as expected and get true or false depending on what folder I test.
Can somebody tell me why the code fails in the script, but works in the command prompt? What am I missing?
Thank you!
After some more digging I managed to find answer: I need to pass local variables used by the script block using the -ArgumentList (in my script the "C:\Test" was stored in a variable)
So the code looks like this now:
if(Invoke-Command -Session $remoteSession -ScriptBlock { Test-Path -Path $args[0] } -ArgumentList $tmp)
Thanks for the help!
I am trying to send some commands from a server to about 50 clients running Powershell. Most commands work using Invoke-Command. I used the exact same format as my other commands, yet this one won't work. Basically I want to have each client fetch an .xml file from my server to import it later on. I am missing $credentials and other variables from my code sample here but they are setup correctly somewhere else in my script.
Permission wise, TrustedHosts in winrm is set to * and script execution is set to Unrestricted.
clear
$temp = RetrieveStatus
$results = $temp.up #Contains pinged hosts that successfully replied.
$profileName = Read-Host "Enter the profile name(XML file must be present in c:\share\profiles\)"
$File = "c:\profiles\profile.xml"
$webclient = New-Object System.Net.WebClient
$webclient.Proxy = $NULL
$ftp = "ftp://anonymous:anonymous#192.168.2.200/profiles/$profileName"
$uri = New-Object System.Uri($ftp)
$command = {write-host (hostname) $webclient.DownloadFile($uri, $File)}
foreach($result in $results)
{
# download profile from C:\share\profiles
Invoke-Command $result.address -ScriptBlock $command -Credential $credentials
# add profile to wireless networks
# Invoke-Command $result.address -ScriptBlock {write-host (hostname) (netsh wlan add profile filename="c:\profiles\$args[0].xml")} -argumentlist $profileName -Credential $credentials
}
I get the following error:
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (DownloadFile:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Any idea? The same command works flawlessly on the clients when run locally.
You use $webclient within a scriptblock where $webclient will not be defined on the other end. Why don't you create the web client in the scriptblock e.g.:
$command = {
param($profileName)
$File = "c:\profiles\profile.xml"
$webclient = New-Object System.Net.WebClient
$webclient.Proxy = $NULL
$ftp = "ftp://anonymous:anonymous#192.168.2.200/profiles/$profileName"
$uri = New-Object System.Uri($ftp)
Write-Host (hostname)
$webclient.DownloadFile($uri, $File)}
}
$profileName = Read-Host "Enter the profile name(XML file must be present in c:\share\profiles\)"
Invoke-Command $result.address -ScriptBlock $command -Credential $credentials -Arg $profileName
This will require you to provide some of the variables from the client to the remote machine via the -ArgumentList parameter on Invoke-Command. Those supplied arguments then map to the param() statement in the scriptblock.
I'm trying to send this:
Get-WmiObject Win32_PNPEntity |Where{$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}
over rdesktop like:
rdesktop -a8 209.** -u ** -p ** -s "cmd.exe /K powershell.exe Get-WmiObject Win32_PNPEntity |Where{\$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}"
But windows' shell says:
'Where{$_.DeviceID.StartsWith' is not recognized as an internal or externa....
What am I doing wrong?
why not using powershell wmi remoting?
$cred = get-credential
Get-WmiObject Win32_PNPEntity -computerName MyRemoteComputerName - credential $cred |Where{$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}
-credential are only needed if the actual user running powershell isn't administrator of remote machine.
Hi I needed to do some thing like this once so i wrote some code that can send any ps code to a remote computes and display the results in the ps window on your pc.
Just remember to enable powershell remoting on both pc's.
function remote-pscode ($ServerName,$UserName,$password,$PSCode)
{
$global:RemoteCode = $args[0]
Write-Host $RemoteCode
$conprops = (Get-Host).UI.RawUI
$buffsize = $conprops.BufferSize
$buffsize.Height = 800
$conprops.BufferSize= $buffsize
# Set the user name you would like to use for the connection
$global:RemoteUserName = $UserName
$global:RemoteServerName = $ServerName
# Set the password you would like to use for the connection
# Check to see if you have a file on you drive c:\cred.txt with a password to use in it,if you don't it will create one
# for you and ask you for the password you would like to use
$global:RemotePassword = convertto-securestring $password -AsPlainText -Force
$global:credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $RemoteUserName,$RemotePassword
#Create a connection to the remote computer , put a list of IPAddresses or Computer Names.
$global:session = new-PSSession -ComputerName $RemoteServerName -Credential $credentials
$ScriptBlock = $executioncontext.invokecommand.NewScriptBlock($RemoteCode)
invoke-command -Session $session -ScriptBlock $ScriptBlock
#Close the sessions that where created
$global:closesession = Get-PSSession
Remove-PSSession -Session $closesession
}
remote-pscode -ServerName "NameOfRemotePC" -UserName "UserName" -password "password" -PSCode "any powershell code you want to send to the remote pc"
Several things here: put your PS commands in a script block (or a script). Also, why don't you simply use wmic.exe ?