How can I pass parameters to a script block in a new process - powershell-5.0

I want to start a new powershell session from pwsh core to run some code that is designed to run in powershell 5.1 (it checks the version table).
I can get the script block to execute fine, but I want to pass variable values from my pwsh session to the new session.
An example that isn't working is:
7.0.3: >_ $block = {param($name)Write-Host "Hello, $name. How are you?"}
7.0.3: >_ start powershell -argumentlist "-noexit $block 'friend'"
new window opens:
5.1: >_ Hello, . How are you? friend
5.1: >_
However, when I wrap this in a full blown .ps1 script it seems to work fine.

Most likely the $block variable is not defined in the new scope. This works.
start powershell -ArgumentList '-noexit & {param($name)Write-Host "Hello, $name. How are you?"} friend'
I used the & invoke method, you could also use .
start powershell -ArgumentList '-noexit . {param($name)Write-Host "Hello, $name. How are you?"} friend'
output in the new console
Hello friend . How are you?

Related

VB.NET Executing PowerShell Script

I am currently trying to run a PowerShell script from VB.NET. If I run the script directly from a PowerShell window I open in C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe then the script runs absoloutely fine.
However, when I run it from VB.NET using the following command
Dim LoggedInUsers As New ProcessStartInfo("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe", "-noexit C:\LoggedInUsers\CurrentLoggedOnServers.ps1")
Process.Start(LoggedinUsers)
The PowerShell console will say that the term query is not recognized as the name of a cmdlet.
I am trying to run a script the contains this.
$username = 'User1'
$Path = 'C:\Folder1\ServerLoginStatus\'
$servers = Get-Content C:\Folder1\ServerList.txt
foreach ($server in $servers) {
$servernamepath = $path + $server + '.txt'
query user /server:$server | Out-File $servernamepath
}
Do I have to import a specific module or function to use this cmdlet?

VB.net and powershell variables

I have a Visual Studio form running with VB.net and I'm collecting info needed to setup an AD user. In the end, this info will need to simply be passed to Powershell with no return info needed. Before that though, I need it to check if a printer code has already been assigned to someone before allowing it to be submitted to another user. I have a simple powershell script written up for it.
(We use the Pager field to store the printer code.)
Import-Module ActiveDirectory
$Page = $args[0]
Get-ADUser -Filter { Pager -like $Page } | FT Name
I setup the code I found HERE, and attempted to modify it to my script but it keeps crashing on
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
It gives me: An unhandled exception of type 'System.Management.Automation.ParseException' occurred in System.Management.Automation.dll
If I run his little 6+5 basic example script, it works, but when I try to retrieve info and return a name, it doesn't like it. How can I get it to return the name of the person if it find it? And since it won't run, I'm not even sure if passing the printer code as $args[0] is going to work yet.
Your results is expecting a collection of PowerShell objects. When you pipe the Get-ADUser command to Format-Table, it effectively strips the object down to a stream of strings. Try without the | FT Name.
Import-Module ActiveDirectory #if you're using powershell 3 or later, this may be redundant
# $Page = $args[0] # don't need to do this
$results = Get-ADUser -Filter { Pager -like $args[0] }
Write-Verbose $results
#Write-Verbose $results.Name #try this if the above one works
Update:
Write-Verbose may be causing an issue.
Try this:
Get-ADUser -Filter { Pager -like $args[0] }
Just that one line as the total PS code. (Assuming you have PowerShell 3.0 or later, you don't need Import-Module) That line will return objects of type TypeName: Microsoft.ActiveDirectory.Management.ADUser (from `Get-ADUser username | Get-Member).
You may also be able to use the .Net object type directly, without PowerShell. I'm not knowledgeable about .NET beyond what I picked up working with PowerShell.
Accessing AD using .NET, info from MSDN.

how to set export command for apache user

I'm developing a site where I need to use a program but I have to export one VAR, so ok by command line in my user it's easy,
export MY_VAR=/PATH
The problem is when try to execute the same program through the website I got an error telling me this:
Set environment variable $MY_VAR to the location
I've try to execute a script, but I think the problem is set the variable but with my user, I mean, I've try to do this in php:
echo exec('sh /PATH/exportscript.sh');
Also this:
$cmd = "export";
$path="MY_VAR=/PATH/data_tables/";
$export= $cmd . " " . $path;
shell_exec($export);
No result with this command....any other option? How I can put MY_VAR for Apache???

VB.NET PowerShell Cmdlet Start-Transcript

I am writing a VB.NET PowerShell Cmdlet which needs to start, and later stop, the Transcript file (Start-Transcript).
So how do I manage to run the command Start-Transcript from within the cmdlet? I have tried this:
Dim myRunSpace As Runspace = RunspaceFactory.CreateRunspace()
myRunSpace.Open()
Dim MyPipeline As Pipeline = myRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript("Start-Transcript -Path $pwd\session.txt")
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
myRunSpace.Close()
Produces the error "Start-transcript : this host does not support transription". Yet when I enter the command manually
no error is produced and transcription starts.
The Start-Transcript method is host specific and implemented by the host. The reason for this, I'm guessing, is that it is not clear what input and output is available on different hosts and therefore not easy to create a generic implementation which works in all cases.
The PowerShell Console host supports the Start-Transcript function (which you see, since it works when you call it), but other hosts need to implement it before it is usable in that host. If you, for example, try to write Start-Transcript in the PowerShell ISE host you'll get an error like the following:
Start-Transcript : This host does not support transcription.
At line:1 char:1
+ Start-Transcript
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotImplemented: (:) [Start-Transcript], PSNotSupportedExce
ption
+ FullyQualifiedErrorId : NotSupported,Microsoft.PowerShell.Commands.StartTranscript
Command
In order to get it to work using a custom host such as the one you're creating in VB you would have to find a way to implement support for transcription.
That is a limitation of the cmdlet. MSFT made it so Start-Transcript only works when invoked from powershell.exe console, it doesn't even work from their ISE. The workaround has been to use add-content / out-file / tee-object to create your own log file.
It's a lot more work, but can be done. maybe these cmdlets can help.
http://www.powertheshell.com/transcript/
I have followed one of your earlier links and patched this VB.NET code from the PowerShell script there:
Dim thisType As Object = MyBase.Host.GetType().GetProperty("ExternalHost",Reflection.BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(MyBase.Host, New Object() {})
Dim abc As Object = thisType.GetType().GetProperty("IsTranscribing", Reflection.BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(thisType, New Object() {})
WriteObject(abc.ToString)
This returns correctly True or False. So can I do any more than this here, ie like Stop-Transcript? Apologies for the comment above, but this link is slow and the text became garbled.

Equivalent to bash "expect" in powershell

I'm using powershell to run another powershell script, at some point the other script asks for some input, I would like to be able to read the output from the other script and based on that supply input to it. Similar to what you can do with expect on bash.
Any ideas?
Thanks
Just posting my solution so that it can help someone. I faced the same problem while running some other script that will ask for answers. First create a file "inputFileLocation.txt" with answers to each question in each line in sequence. Then run the script in below syntax. And it will do the work.
`cmd.exe /c "script.bat < inputFileLocation.txt"`
You just use Expect program in your powershell. It works. Powershell is a shell too, you can run code wrote by powershell, which call bash code, which call powershell again.
Bellow is a test, it passed.
It "can work with tcl expect" {
$bs = #'
echo "Do you wish to install this program?"
select yn in "Yes" "No"; do
case $yn in
Yes ) echo "install"; break;;
No ) exit;;
esac
done
'#
$bsf = New-TemporaryFile
$bs | Set-Content -Path $bsf
$tcls = #'
#!/bin/sh
# exp.tcl \
exec tclsh "$0" ${1+"$#"}
package require Expect
set timeout 100000
spawn {spawn-command}
expect {
"Enter password: $" {
exp_send "$password\r"
exp_continue
}
"#\? $" {
exp_send "1"
}
eof {}
timeout {}
}
'#
$tclf = New-TemporaryFile
$tcls -replace "{spawn-command}",("bash",$bsf -join " ") | Set-Content -Path $tclf
"bash", $tclf -join " " | Invoke-Expression
Remove-Item $bsf
Remove-Item $tclf
}
Let me explain the test.
create a bash file which expect an input.
create a tcl file which call bash created in step one.
invoke tcl program from powershell, it works, will not waiting for input.
Sample to solve part of the problem
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Start-Process -FilePath C:\myexecbatchfile.bat
# Wait the application start for 2 sec
Start-Sleep -m 2000
# Send keys
[System.Windows.Forms.SendKeys]::SendWait("input1")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -m 3000
[System.Windows.Forms.SendKeys]::SendWait("input2")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
I am not aware of any native capability to duplicate exact. This question has an answer that claims to be able to pass content to/from a process, so it might work with what you want.
How to run interactive commands in another application window from powershell
Good Luck!
Lee Holmes put out an "Expect for Powershell" in 2014 on the Powershell Gallery called Await. Turns out emulating expect is a lot more complicated than you'd imagine, involving the Win32 calls.
Package
https://www.powershellgallery.com/packages/Await/0.8
Demo
https://www.youtube.com/watch?v=tKyAVm7bXcQ