VB.NET PowerShell Cmdlet Start-Transcript - vb.net

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.

Related

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

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?

PowerShell doesn't recognize string correctly

I'm passing a command to powershell
Dim command As String
command = "ffmpeg -vsync 0 –hwaccel cuvid -c:v h264_cuvid –resize 1280x720 -i D:\Imagens\nova\bol.mkv -c:a copy -c:v h264_nvenc -b:v 5M D:\Imagens\nova\bol_encod.mkv"
with
Dim powerShell As String = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
Process.Start("powershell", "-noexit " + command)
but powershell returns
Unable to find a suitable output format for 'ÔÇôhwaccel' ÔÇôhwaccel:
Invalid argument
where I believe 'ÔÇôhwaccel' to be –hwaccel; That's completely strange, once when I past the code directly on PowerShell it works fine.
Is that a problem with my string?
thank you!
I'm assuming powershell 5 and not core, I copied the test and pasted it into the terminal and found this u instead of a '-'. I would start by retyping and avoiding what looks like it may be a long hyphen or something else which is breaking the terminal.

Shell Command to launch application with parameters

I am trying to launch spotfire application from VBA like following
Dim retval As Double
retval = Shell("Path\Spotfire.Dxp.exe", vbNormalFocus)
It works. It launches spotfire with the default servername,username and password
But I want to launch the application by giving the servername, username and password as parameters in the script. How do I do it?
I tried this
retval = Shell("Path\Spotfire.Dxp.exe -s http://spotfire.abcd.com -u ABCD\A7 -p ABC", vbNormalFocus)
But it launched the application with default parameters and gives error at the end "Unable to load file. Could not find the specified file : -s"
Please suggest the possible solution.
after checking our support db, I found a few references to / notation instead of -. so the following command should work:
c:\path\Spotfire.Dxp.exe /server:http://localhost:8080/ /username:user /password:pass

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.

Why isn't handles.exe discovering my DLL while ProcessExplorer can?

The problem:
On a windows server 2012 r2 box, I'm trying to use Chef to programmatically replace a .dll command component (aka a vb 6 library that I've registered on the box using regsvr32.exe) but when I try to copy over the file, the app pool of the website has a lock on it. I'm not sure if it matters, but the w3wp process is set to run as 32 bit via IIS.
My Solution (which isn't working):
In order to fix it, I was thinking about using a command line tool to find the reference to the dll and then recycling the app pool that's using it. Unfortunately, while I can get SysInternals' process explorer to find the dll, Handles.exe (the supposed command line version of process explorer) does not return anything. I was hoping that someone might be able to tell me how I was using handles incorrectly, or if there was a better tool for this.
Process Explorer - it has found my dll ComHelper.dll
Handles via command line - it has not found my dll ComHelper.dll
-- Edit --
This is the output of handles when I point it at w3wp while running as Admin
I would suspect you are running into access issues. Are you running Handle from an elevated command prompt ? Are you able to get any output covering handles in w3wp.exe (by using the pid of the process in handle.exe command line) ?
Looking at the handle enum output of w3wp.exe it seems,
listdll.exe -d ComHelper.dll
may be what you are looking for. Handle seems to be focused on files opened not dlls loaded. listdll is a tool that can be downloaded from sysinternals.
Alright so 32 bitness did matter. I ended up having to resort to powershell as opposed to trying to use handles. The code for finding a PID that has a lock on your file is scattered around the internet, but here's the link:
http://blogs.technet.com/b/heyscriptingguy/archive/2013/12/01/weekend-scripter-determine-process-that-locks-a-file.aspx (it's marv the robot's answer at the bottom)
For the record, this is what was suggested
$lockedFile="C:\Windows\System32\acproxy.dll"
$isLocked = $false
Get-Process | foreach{
$processVar = $_;$_.Modules | foreach{
if($_.FileName -eq $lockedFile){
$isLocked = $true
$processVar.Name + " PID:" + $processVar.id
}
}
}
This is what I had translated it into with my powershell noobishness
$lockedFile = "E:\Components\___ComHelper.dll"
$list = Get-Process
foreach ($process in $list)
{
foreach ($module in $process.Modules)
{
if ($module.FileName -ne $lockedFile) { continue }
$process.Name + " PID:" + $process.Id
}
}