Background: I am creating a script to send out a message to everyone in my Domain. I was able to complete this using Invoke-WMImethod and MSG.exe. However, my supervisor wants a more customizable message to be sent. Like changing Color, font size, font style...etc. Which i have created using PowerShell.
Script:
Invoke-WmiMethod -ComputerName $Computer -Class Win32_Process -Name Create -ArgumentList {"C:\x\x\x\Powershell.exe -File `"\\Server\Share\Folder\Script.ps1`""}
When i run this script against my Computer it works perfectly. However, when i attempt to run it on a remote computer it fails.
I don't understand why.
It's the same exact script that i used with MSG.exe, which worked, but it still doesn't work with a powershell script.
I attempted to copy the script to the remote computers 'C:\' and run it from that file path but it still didn't work.
I've verified the file path to Powershell.exe is the same as the script and that the remote workstation can access the .PS1 Script.
However, the script does run and says it is successful with a Return Value of 0. Example:
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 2
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ProcessId : 8748
ReturnValue : 0
My Suggestion would be to check for the versions on both the machines. The CmdLet you using may not be working on the previous version.
I again have a suggestion to make, you can use the below command to get your work done, if you have powershell Version 3 or above.
$Outputreport = "Test message to send data using port 443"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
$wc = new-object System.Net.WebClient
Invoke-RestMethod -Method Post https://hostnamedotcom/cgi-bin/dir-path/$hostname-filename -Body $Outputreport
Related
I am working on a set of build scripts which are called from a ubuntu hosted CI environment. The powershell build script calls jest via react-scripts via npm. Unfortunately jest doesn't use stderr correctly and writes non-errors to the stream.
I have redirected the error stream using 3>&1 2>&1 and this works fine from just powershell core ($LASTEXITCODE is 0 after running, no content from stderr is written in red).
However when I introduce docker via docker run, the build script appears to not behave and outputs the line that should be redirected from the error stream in red (and crashes). i.e. something like: docker : PASS src/App.test.js. Error: Process completed with exit code 1..
Can anyone suggest what I am doing wrong? because I'm a bit stumped. I include the sample PowerShell call below:-
function Invoke-ShellExecutable
{
param (
[ScriptBlock]
$Command
)
$Output = Invoke-Command $Command -NoNewScope | Out-String
if($LASTEXITCODE -ne 0) {
$CmdString = $Command.ToString().Trim()
throw "Process [$($CmdString)] returned a failure status code [$($LASTEXITCODE)]. The process may have outputted details about the error."
}
return $Output
}
Invoke-ShellExecutable {
($env:CI = "true") -and (npm run test:ci)
} 3>&1 2>&1
I am able to create a new node via the Jenkins web GUI and then have the node running in a container connect back to the Jenkins master via the name and -secret value
ex.
docker run jenkinsci/jnlp-slave -url http://jenkins-server:port <secret> <slave name>
Is there a way to programmatically create a Jenkins node and get the secret and slave name so I don't have to do it via the GUI?
Creating an agent programmatically
You can use the create-node CLI command to create new agents with a given configuration.
For example, given this minimal JNLP agent configuration in a file config.xml:
<slave>
<remoteFS>/opt/jenkins</remoteFS>
<numExecutors>2</numExecutors>
<launcher class="hudson.slaves.JNLPLauncher" />
</slave>
you can run the create-node command via the CLI client, or the SSH interface:
cat config.xml | java -jar jenkins-cli.jar -s https://jenkins/ create-node my-agent
Viewing agent configuration
To see what the XML configuration looks like for an existing agent, you can append config.xml to an agent URL, e.g. https://jenkins/computer/some-agent-name/config.xml, or you can use the get-node CLI command.
Fetching the per-agent secret programmatically
To fetch the secret hex value without using the Jenkins web UI, you can run a script via the groovy CLI command:
echo 'println jenkins.model.Jenkins.instance.nodesObject.getNode("my-agent")?.computer?.jnlpMac' \
| java -jar ~/Downloads/jenkins-cli.jar -s https://jenkins/ groovy =
This will return the secret value directly. Note that in order to use the groovy command via the SSH interface, you need Jenkins 2.46 or newer. In earlier versions, it only works via the CLI client.
You can also create an agent using the REST API. This is especially useful when having an apache proxy in front (see issue JENKINS47279) and no direct access to the jenkins otherwise (e.g. in a corporate network) where CLI will not work.
I recommend to create an API token for this purpose. Then you can do something like this
Linux (Bash)
export JENKINS_URL=https://jenkins.intra
export JENKINS_USER=papanito
export JENKINS_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx
export NODE_NAME=testnode
export JSON_OBJECT="{ 'name':+'${NODE_NAME}',+'nodeDescription':+'Linux+slave',+'numExecutors':+'5',+'remoteFS':+'/home/jenkins/agent',+'labelString':+'SLAVE-DOCKER+linux',+'mode':+'EXCLUSIVE',+'':+['hudson.slaves.JNLPLauncher',+'hudson.slaves.RetentionStrategy\$Always'],+'launcher':+{'stapler-class':+'hudson.slaves.JNLPLauncher',+'\$class':+'hudson.slaves.JNLPLauncher',+'workDirSettings':+{'disabled':+true,+'workDirPath':+'',+'internalDir':+'remoting',+'failIfWorkDirIsMissing':+false},+'tunnel':+'',+'vmargs':+'-Xmx1024m'},+'retentionStrategy':+{'stapler-class':+'hudson.slaves.RetentionStrategy\$Always',+'\$class':+'hudson.slaves.RetentionStrategy\$Always'},+'nodeProperties':+{'stapler-class-bag':+'true',+'hudson-slaves-EnvironmentVariablesNodeProperty':+{'env':+[{'key':+'JAVA_HOME',+'value':+'/docker-java-home'},+{'key':+'JENKINS_HOME',+'value':+'/home/jenkins'}]},+'hudson-tools-ToolLocationNodeProperty':+{'locations':+[{'key':+'hudson.plugins.git.GitTool\$DescriptorImpl#Default',+'home':+'/usr/bin/git'},+{'key':+'hudson.model.JDK\$DescriptorImpl#JAVA-8',+'home':+'/usr/bin/java'},+{'key':+'hudson.tasks.Maven\$MavenInstallation\$DescriptorImpl#MAVEN-3.5.2',+'home':+'/usr/bin/mvn'}]}}}"
curl -L -s -o /dev/null -v -k -w "%{http_code}" -u "${JENKINS_USER}:${JENKINS_API_TOKEN}" -H "Content-Type:application/x-www-form-urlencoded" -X POST -d "json=${JSON_OBJECT}" "${JENKINS_URL}/computer/doCreateItem?name=${NODE_NAME}&type=hudson.slaves.DumbSlave"
In order to get the agent secret via REST API checkout this, which would look something like this:
curl -L -s -u ${JENKINS_USER}:${JENKINS_API_TOKEN} -X GET ${JENKINS_URL}/computer/${NODE_NAME}/slave-agent.jnlp | sed "s/.*<application-desc main-class=\"hudson.remoting.jnlp.Main\"><argument>\([a-z0-9]*\).*/\1/"
Windows (PS)
And here my solution for Windows using Powershell:
$JENKINS_URL="https://jenkins.intra"
$JENKINS_USER="papanito"
$JENKINS_API_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxx"
$NODE_NAME="testnode-ps"
# https://stackoverflow.com/questions/27951561/use-invoke-webrequest-with-a-username-and-password-for-basic-authentication-on-t
$bytes = [System.Text.Encoding]::ASCII.GetBytes("${JENKINS_USER}:${JENKINS_API_TOKEN}")
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = #{ Authorization = $basicAuthValue; }
$hash=#{
name="${NODE_NAME}";
nodeDescription="Linux slave";
numExecutors="5";
remoteFS="/home/jenkins/agent";
labelString="SLAVE-DOCKER linux";
mode="EXCLUSIVE";
""=#(
"hudson.slaves.JNLPLauncher";
'hudson.slaves.RetentionStrategy$Always'
);
launcher=#{
"stapler-class"="hudson.slaves.JNLPLauncher";
"\$class"="hudson.slaves.JNLPLauncher";
"workDirSettings"=#{
"disabled"="true";
"workDirPath"="";
"internalDir"="remoting";
"failIfWorkDirIsMissing"="false"
};
"tunnel"="";
"vmargs"="-Xmx1024m"
};
"retentionStrategy"=#{
"stapler-class"= 'hudson.slaves.RetentionStrategy$Always';
'$class'= 'hudson.slaves.RetentionStrategy$Always'
};
"nodeProperties"=#{
"stapler-class-bag"= "true";
"hudson-slaves-EnvironmentVariablesNodeProperty"=#{
"env"=#(
#{
"key"="JAVA_HOME";
"value"="/docker-java-home"
};
#{
"key"="JENKINS_HOME";
"value"="/home/jenkins"
}
)
};
"hudson-tools-ToolLocationNodeProperty"=#{
"locations"=#(
#{
"key"= 'hudson.plugins.git.GitTool$DescriptorImpl#Default';
"home"= "/usr/bin/git"
};
#{
"key"= 'hudson.model.JDK\$DescriptorImpl#JAVA-8';
"home"= "/usr/bin/java"
};
#{
"key"= 'hudson.tasks.Maven$MavenInstallation$DescriptorImpl#MAVEN-3.5.2';
"home"= "/usr/bin/mvn"
}
)
}
}
}
#https://stackoverflow.com/questions/17929494/powershell-convertto-json-with-embedded-hashtable
$JSON_OBJECT = $hash | convertto-json -Depth 5
$JSON_OBJECT
Invoke-WebRequest -Headers $headers -ContentType "application/x-www-form-urlencoded" -Method POST -Body "json=${JSON_OBJECT}" -Uri "${JENKINS_URL}/computer/doCreateItem?name=${NODE_NAME}&type=hudson.slaves.DumbSlave"
Just chiming in a bit late to the party here, but I would highly recommend looking at the Jenkins Client plugin instead. Once the plugin is installed, you need only to start the client JAR from the build node and give it the IP address of the master.
As far as the master goes, you don't need to bother configuring anything. Nodes that register with the master are available automatically to start executing jobs. This is much easier than any of the slave.jar-based approaches.
I'm trying to install a Tcl program as a service on my Windows machine using the TclDevKit's TclServiceManager. I'm following the guide here step by step and yet I am experiencing a lot of issues.
If I try to use my raw .tcl file to create the service, I get the following error:
Error 1053: The service did not respond to the start or control request in a timely fashion.
I've followed a solution for this issue here to give the program more time to start up before the Service Control Manager terminates it; to no avail.
Then I decided to try and wrap the program using TclApp and see if that worked. Like the guide says, I used the base-tclsvc-win32-ix86.exe prefix file located in my TclDevKit bin directory. Installing the service that way, and then trying to run it resulted in the following error:
Windows could not start the <service name> service on Local Computer.
Error 1067: The process terminated unexpectedly.
There wasn't much information at all that I could find googling this error. The only Stackoverflow post on it is this one. So I tried installing the service manually through the command prompt using <TheProgram>.exe <Service Name> -install and tried running it - still gave me the same error.
Then I tried to see if I could get any useful information by running <TheProgram>.exe <Service Name> -debug and interestingly enough I got the following output:
Debugging <Service Name>.
InitTypes: failed to find the DictUpdateInfo AuxData type
abnormal program termination
Googling InitTypes: failed to find the DictUpdateInfo AuxData type leads me nowhere, however it seems to be something Tcl related.
Finally, if it means anything, the source code for the program I was trying to install as a service is some simple web server code:
proc Serve {chan addr port} {
fconfigure $chan -translation auto -buffering line
set line [gets $chan]
set path [file join . [string trimleft [lindex $line 1] /]]
if {$path == "."} {set path ./index.html}
if {[catch {
set f1 [open $path]
} err]} {
puts $chan "HTTP/1.0 404 Not Found"
} else {
puts $chan "HTTP/1.0 200 OK"
puts $chan "Content-Type: text/html"
puts $chan ""
puts $chan [read $f1]
close $f1
}
close $chan
}
if {![info exists reload]} {
set sk [socket -server Serve 3000]
puts "Server listening on port 3000"
vwait forever
} else {
unset reload
}
To check and see if the source code was the problem, I tried another, simpler example that simply created a file in a particular directory:
set filePath "C:/some/path/here";
set fileName "Test.txt";
set file [open [file join $filePath $fileName] w];
puts $file "Hello, World";
close $file;
Both programs work if you simply source them from tclsh86.exe, but give the above errors if you try and run them as services unwrapped and wrapped respectively.
Any ideas?
I am looking to execute a command in remote machine using invoke but the .cmd file will call for additional .vbs script. So i guess i may have to mention CScript if so how do i mention both cmd/c and cscript in the below command
Invoke-Command -computername blrscrv01 -ScriptBlock { param($path, $command ) cmd /c $path $command } -args '"C:\windows\system32\cscript.exe"','"/?"'
Your example worked for me when I removed the extra level of quoting.
Invoke-Command -computername blrscrv01 -ScriptBlock { param($path, $command ) cmd /c $path $command } -args 'C:\windows\system32\cscript.exe','/?'
Troubleshooting
Enter a remote session and poke around.
Enter-PSSession -computername blrscrv01
Verify that the target script exists and is accessible.
dir \\lcsap027\deploy\c2.cmd
dir \\lcsap027\deploy
type \\lcsap027\deploy\c2.cmd
Attempt to run the script interactively.
\\lcsap027\deploy\c2.cmd
or
cmd /c \\lcsap027\deploy\c2.cmd
Alternative
Another thing you might try is not invoking a cmd script remotely, but issuing the commands remotely. New-PSSession will return a handle you can use to deal interactively with the remote machine. You can repeatedly issue commands with Invoke-Command and get the results (as primitive data types and generic objects, though, not the actual objects themselves).
Altered Script
Here's an altered version of the script you put in your comment. I've removed the nested Invoke-Command (I don't know why it was necessary, you're already running commands on the remote machine). Since the line breaks got lost in the comment, I don't know if there were any statement separator problems (I'll just assume there weren't, though in its "formatted" form as a one-liner, it would have died horribly because PoSH wouldn't have known where one statement ended and the next began).
param(
[string]$ComputerName,
[string]$User,
[string]$pass
)
Get-PSSEssion | Remove-PSSession
$session = New-PSSession -ComputerName $ComputerName
Invoke-Command -Session $session -ScriptBlock {
param(
[string]$ComputerName,
[string]$Username,
[string]$Password
)
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("x:", "\\machinename\sharename", $false, $Username, $Password)
cmd.exe /c "x:\c2.cmd"
$net.RemoveNetworkDrive("x:")
} -args $ComputerName, $User, $pass
This at least got the remote script to run and produced the expected output. (I emitted the computer name, user name, and file location.)
Bear in mind that this method doesn't employ any transport-/application-layer encryption, so the password is sent cleartext over the network.
I am attempting to execute a Powershell script on a remote computer from a Powershell window on my local computer using Powershell 2.0. My goal is to store an exit code from the script on the remote computer to a variable on my local computer, whether it be in a local script or just a local Powershell window. Currently all I get back is an error message stating the following . . .
Cannot invoke pipeline because run space is not in the Opened state. Current state of run space is Closed. + CategoryInfo: OperationStopped: Microsoft.Power...tHelperRunspace:ExecutionCmdletHelperRunspace) [], InvalidRunspaceStateException + FullyQualifiedErrorID : RemotePipeLineExecutionFailed
My situation is this . . . I am trying to return an exit code to a variable on my local machine from a script on a remote machine. There are actually two scripts involved here and both are on the remote machine and in the same folder. The first script is called "VerifyBatchExistence.ps1". This file takes as input a batch file called "Batch.ps1", an integer that represents an exit code to be output if "Batch.ps1" does not exist, another integer representing the number of parameters needed by "Batch.ps1", and the variable string(s) needed as input for "Batch.ps1". Within "Batch.ps1" I have the following piece of code which I expect to be triggered when one of my passed-in parameters is invalid. . .
exit 931
Within "VerifyBatchExistence.ps1" I have the following piece of code . . .
Powershell - File .\Batch.ps1 BATCHPARAM1 BATCHPARAM2
$Code1 = $LASTEXITCODE
$Host.SetShouldExit($Code1)
exit
On my local machine, I did the following . . .
$Remote=New-PSSession -ComputerName 7.7.7.7 -Credential $cred
Invoke-Command -Session $Remote -ScriptBlock {$Code1=.\VerifyBatchExistence.ps1 7777 2 .\Batch.ps1 NAME1 NAME2}
$Code2=Invoke-Command -Session $Remote -ScriptBlock {$Code1}
$Code2
After this, I receive the error stated above. Any idea what I am doing wrong or how I can return an exit code to a variable on my local machine from a remote machine which has a script consuming and running a second script? Any answer to this would be appreciated. Thanks.
I do it like this:
invoke-command -session $Remote -scriptblock { mycommand }
$remotelastexitcode = invoke-command -session $Remote -ScriptBlock { $lastexitcode }
if ( $remotelastexitcode -ne 0 )
{
"$remotelastexitcode"
exit 1
}