AllenAdministrator
(KiX Supporter)
2010-07-31 08:06 AM
Com Interface to Powershell

I may have struck upon a seriously powerful nugget tonight. \:\)

I'll be the first one to admit that I despise the syntax of Powershell, but there are those that think Kixtart is dying and PS is the future. To each his own opinion I guess. Anyway, tonight I was fumbling around looking for god knows what and found the following article:

Invoking PowerShell from VBScript (COM)
http://blogs.msdn.com/b/powershell/archive/2008/07/25/invoking-powershell-from-vbscript-com.aspx

See the instructions for download here: http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=213343#Post213343
This leads you to Sapien.com... where you can download the ActiveX Powershell for free after giving them your email address. http://www.sapien.com/auth Then click "Downloads" and then click "Free Components", then click "ActiveXPosh", then Download.

The Object supports these methods and properties.
  • ClearOutput()
  • Execute()
  • Eval()
  • GetValue()
  • Int()
  • IsPowerShellInstalled()
  • Output()
  • OutputString()
  • OutputMode
  • OutputWidth

After I downloaded the exe, I installed it. I don't know if it was because I have a 64bit OS or not, but I had to copy the dll to the system32 directory, and the use regasm in the .net folder to register it.

Thankfully I hadn't gotten rid of that book I bought on Powershell (although the dust was piling up on it). So I started trying things...

First I made a UDF to initialize PS with it's constants.
Function PSInit()
Global $OUTPUT_CONSOLE, $OUTPUT_WINDOW, $OUTPUT_BUFFER
$OUTPUT_CONSOLE = 0
$OUTPUT_WINDOW = 1
$OUTPUT_BUFFER = 2
$PSInit = CreateObject("SAPIEN.ActiveXPoSH")
EndFunction


(As I was testing I realized you must turn on "NoVarsinStrings" and "NoMacrosinStrings")

And here is just some of the things I came up with...

Hello World
break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")


dim $ps


$PS=PSInit()
if $PS.init(not 0)
if $PS.IsPowerShellInstalled
$PS.outputmode = $output_buffer
? $PS.getvalue('"hello world".substring(0,5)')
$PS.execute('$test = "hello world"')
? $PS.getvalue("$test.substring(6,5)")
endif
else
? "Init Failed"
endif



Contents of a Dir command
break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")


dim $ps


$PS=PSInit()
if $PS.init(not 0)
if $PS.IsPowerShellInstalled
$PS.outputmode = $output_buffer
$PS.Execute('Get-ChildItem -path "d:\temp"')
;$PS.Execute('dir "d:\temp"') ; same as command above
? $PS.outputstring
endif
else
? "Init Failed"
endif


Something called a Hashtable
break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")


dim $ps


$PS=PSInit()
if $PS.init(not 0)
if $PS.IsPowerShellInstalled
$PS.outputmode = $output_buffer
$PS.execute('$user=@{FirstName="John";LastName="Smith";PhoneNumber="555-1212"}')
? $PS.getvalue("$user.lastname")
? $PS.getvalue("$user.PhoneNumber")
endif
else
? "Init Failed"
endif


Finally, using I think .Net to create a form...
break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")


dim $ps


$PS=PSInit()
if $PS.init(not 0)
if $PS.IsPowerShellInstalled
$PS.outputmode = $output_buffer
$PS.execute('[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")')
$PS.execute('$form=new-object Windows.forms.form')
$PS.execute('$form.text="My First Form"')
$PS.execute('$button=new-object Windows.Forms.Button')
$PS.execute('$button.text="Push Me"')
$PS.execute('$button.dock="fill"')
$PS.execute('$button.add_click({form.close()})')
$PS.execute('$form.controls.add($button)')
$PS.execute('$form.add_shown({$form.Activate()})')
$PS.execute('$form.showdialog()')
endif
else
? "Init Failed"
endif


Arend_
(MM club member)
2010-07-31 11:15 AM
Re: Com Interface to Powershell

Nice find!!

Eventhough your find can be reversed by using the KiXtart.dll in PowerShell ;\)

Btw, RegAsm is for .Net assemblies, doesn't matter of it's 32-bit or 64-bit OS \:\)


Arend_
(MM club member)
2010-07-31 11:18 AM
Re: Com Interface to Powershell

Hastables, brings back fond memories, in mIRC Scripting Language I made lots of use of that if I had to store a LOT in memory, for instance the search results of .exe files on your C Drive. Basically you can think of a Hash Table as a MDB file loaded into memory, never touching the Hard Drive (unless it exceeds your memory limit and gets pushed into a swap file.

Hash Tables can seriously speed up things, given you have a LOT of things to store.


Arend_
(MM club member)
2010-07-31 11:20 AM
Re: Com Interface to Powershell

Btw to introduce PowerShell a bit, I've rewritten my Remote Task Manager into PowerShell a while ago:

 Code:
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.Application]::EnableVisualStyles()

Function Main {
  $Form1 = New-Object System.Windows.Forms.Form
  $Form1.Size = New-Object System.Drawing.Size 441,450 #387
  $Form1.Text = "Remote Task Manager"

  $Button1 = New-Object System.Windows.Forms.Button
  $Button1.Anchor = "Bottom, Right"
  $Button1.Location = New-Object System.Drawing.Point 258, 345
  $Button1.Size = New-Object System.Drawing.Size 75, 23
  $Button1.TabIndex = 1
  $Button1.Text = "Refresh"
  $Button1.Add_Click({Refresh_Form})
  $Form1.Controls.Add($Button1)

  $Button2 = New-Object System.Windows.Forms.Button
  $Button2.Anchor = "Bottom, Right"
  $Button2.Location = New-Object System.Drawing.Point 339, 345
  $Button2.Size = New-Object System.Drawing.Size 75, 23
  $Button2.TabIndex = 2
  $Button2.Text = "Kill"
  $Button2.Add_Click({Kill_Process})
  $Form1.Controls.Add($Button2)

  $ComboBox1 = New-Object System.Windows.Forms.ComboBox
  $ComboBox1.Anchor = "Bottom, Left, Right"
  $ComboBox1.FormattingEnabled = $True
  $ComboBox1.Location = New-Object System.Drawing.Point 12, 346
  $ComboBox1.Size = New-Object System.Drawing.Size 240, 21
  $ComboBox1.TabIndex = 3
  $ComboBox1.FlatStyle = "System"
  $Form1.Controls.Add($ComboBox1)
  
  $ListView1 = New-Object System.Windows.Forms.ListView
  $listView1.Anchor = "Bottom, Top, Left, Right"
  $ListView1.FullRowSelect = $True
  $ListView1.Location = New-Object System.Drawing.Point 12, 12
  $ListView1.Size = New-Object System.Drawing.Size 402, 317 #274
  $ListView1.TabIndex = 0
  $ListView1.View = "Details"
  [void] $ListView1.Columns.Add("Process", 125)
  [void] $ListView1.Columns.Add("User Name", 117)
  [void] $ListView1.Columns.Add("PID", 36)
  [void] $ListView1.Columns.Add("Memory", 103, "Right")
  $Form1.Controls.Add($ListView1)

  $StatusStrip1 = New-Object System.Windows.Forms.StatusStrip
  $StatusStrip1.Location = New-Object System.Drawing.Point 12, 294
  $StatusStrip1.Size = New-Object System.Drawing.Size 426, 22
  $StatusStrip1.SizingGrip = $False
  $StatusStrip1.TabIndex = 4
  $StatusStrip1.Text = "StatusStrip1"
  $Form1.Controls.Add($StatusStrip1)

  $ToolStripStatusLabel1 = New-Object System.Windows.Forms.ToolStripStatusLabel
  $ToolStripStatusLabel1.Size = New-Object System.Drawing.Size 0, 17
  [void] $StatusStrip1.Items.Add($ToolStripStatusLabel1)

  $Form1.Add_Load({Load_Form})
  [void] $Form1.ShowDialog()
}

Function Load_Form {
  $strComputer = [System.Environment]::GetEnvironmentVariable("ComputerName")
  #[System.Windows.Forms.MessageBox]::Show("$strComputerName")
  $ComboBox1.Text = $strComputer
  Refresh_Form
}

Function Kill_Process {
  $intPID = $($ListView1.SelectedItems[0].SubItems[2].text)
  $objProcess = Get-WmiObject -class Win32_Process -namespace "root\CIMV2" -computername $ComboBox1.Text -Filter "ProcessID=$intPID"
  Try {
    $objProcess.Terminate()
  }
  Catch [System.Management.Automation.RuntimeException]{
    $ToolStripStatusLabel1.Text = "Process: $($PID) could not be terminated"
  }
  $ToolStripStatusLabel1.Text = "Process: $($PID) Terminated!"
  Refresh_Form
}

Function Refresh_Form {
  $ToolStripStatusLabel1.Text = "Listing Processes of $($ComboBox1.Text) ..."
  $ListView1.BeginUpdate()
  $ListView1.Items.Clear()
  Try {
    $colItems = Get-WMIObject -class "Win32_Process" -namespace "root\CIMV2" -computername $ComboBox1.Text
    ForEach ($objItem in $colItems) {
      $lvwItem = $ListView1.Items.Add($objItem.Name)
      If ($objItem.Name -notlike "system*") {
        $lvwItem.SubItems.Add($objItem.GetOwner().User)
      }
      Else {
        $lvwItem.SubItems.Add("SYSTEM")
      }
      $lvwItem.SubItems.Add($objItem.ProcessId)
      $lvwItem.SubItems.Add($objItem.WorkingSetSize /1024 /2)
    }
    $ListView1.Sorting = "Ascending"
    $ListView1.Sort()
    If (-Not $ComboBox1.Items.Contains($ComboBox1.Text)) {
      $ComboBox1.Items.Add($ComboBox1.Text)
    }
    $ToolStripStatusLabel1.Text = "Processes: $($ListView1.Items.Count)"
  }
  Catch [System.Exception] {
    $ToolStripStatusLabel1.Text = "Connection to $($ComboBox1.Text) could not be made"
  }
  $ListView1.EndUpdate()
}

Main


AllenAdministrator
(KiX Supporter)
2010-07-31 03:34 PM
Re: Com Interface to Powershell

 Quote:
Eventhough your find can be reversed by using the KiXtart.dll in PowerShell ;\)


...but using that dll would mean I've left my warm and comfy kixtart environment. ;\)

The nice thing about this ps.dll is now we can basically use/steal code and import it right into kix. Hmmmm speaking of that, I wonder why there is no load/run method? Regardless, I was thinking about writing a wrapper/importer that takes an existing ps script and put the kix code around it.


Bryce
(KiX Supporter)
2010-08-01 10:35 AM
Re: Com Interface to Powershell

one thing i dont like about powershell.... the darn hoops you got to jump though to execute a script from a cmd line :P

Arend_
(MM club member)
2010-08-01 11:55 AM
Re: Com Interface to Powershell

what hoops?
 Code:
Powershell .\script.ps1


Bryce
(KiX Supporter)
2010-08-01 04:40 PM
Re: Com Interface to Powershell

 Originally Posted By: apronk
what hoops?
 Code:
Powershell .\script.ps1


see that extra .\ totally unacceptable!

Ok, I guess i need to play with powershell more... but i ran into a bunch of "security" locks when trying to execute scripts like that.


Arend_
(MM club member)
2010-08-02 08:33 AM
Re: Com Interface to Powershell

Yeah, the security of PS is [censored], I have to agree, you have to set security per workstation \:\(

AllenAdministrator
(KiX Supporter)
2010-08-06 01:50 AM
Re: Com Interface to Powershell

Hey Bryce... check this out... Run PS scripts right in Kix.

Function PSShell($FQFN, optional $PSObject, optional $output)
if $PSobject=""
$PSObject=CreateObject("SAPIEN.ActiveXPoSH")
endif
if $PSObject.init(not 0)
if exist($fqfn)
if $output
$PSObject.outputmode = $output
else
$PSObject.outputmode = 2
endif
$PSObject.execute('Set-ExecutionPolicy Unrestricted')
$PSObject.execute('& "' + $FQFN + '"')
endif
endif
endfunction


A couple of things about this... first I ran into the permissions thing. I guess not allowing any PS scripts by default is a good thing, but talk about frustrating when you don't really understand why. Here is the article I found that help with this: http://technet.microsoft.com/en-us/library/ee176949.aspx

Next I ran into the problem of still not being able to run the script. The examples all said either fullpath\script or .\script or by setting an environment variable. Nothing was working. Happened to notice that it was truncating the directory and found the following link on what to do when there is a space in the path name... http://arcware.net/running-a-powershell-script-with-a-space-in-the-path/

I finally got it to work. I'm assuming the & is a escape character, but have yet to find anything concrete explaining its purpose. Anyone?


AllenAdministrator
(KiX Supporter)
2010-08-06 02:59 AM
Re: Com Interface to Powershell

The & has to do with the type of Parsing Mode PS is using... something else new I've learned

http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6058.entry

 Quote:

 Code:
PS> 'C:\Program Files\Windows NT\Accessories\wordpad.exe'
C:\Program Files\Windows NT\Accessories\wordpad.exe

That didn't work because are far as PowerShell is concerned we gave it a string, so it just echoes it back to the screen. It did this because it parsed this line in expression mode. We need to tell PowerShell to parse the line in command mode. To do that we use the call operator '&' like so:

 Code:
PS> & 'C:\Program Files\Windows NT\Accessories\wordpad.exe'

What's going on with this example is that PowerShell looks at the first non-whitespace character of a line to determine which mode to start parsing in. If it sees [_aA-zZ] or & or . or \ then PowerShell parses in Command mode. One exception to these rules happens when the line starts with a name that corresponds to a PowerShell language keyword like "if", "do", "while", etc. In this case, PowerShell uses expression parsing mode and expects you to provide the rest of the syntax associated with that keyword.


AllenAdministrator
(KiX Supporter)
2010-08-23 07:54 PM
Re: Com Interface to Powershell

My first real use of the Powershell Object. WMI does not have a way to get the Window Title, however, .Net does... and Powershell's get-process can tie all this together...

Function PSGetWindowNamefromPID($PID, optional $PSObject)
  if $PSobject=""
    $PSObject=CreateObject("SAPIEN.ActiveXPoSH")
  endif
  if $PSObject.init(not 0)     
    $PSObject.Execute('$process=Get-Process | Where-Object {$_.ID -eq "' + $PID + '"}')
    $PSGetWindowNamefromPID=$PSObject.GetValue('$process.MainWindowTitle') 
  endif
endfunction

Function PSGetPIDfromWindowName($WindowName, optional $PSObject)
  if $PSobject=""
    $PSObject=CreateObject("SAPIEN.ActiveXPoSH")
  endif
  if $PSObject.init(not 0)     
    $PSObject.Execute('$process=Get-Process | Where-Object {$_.MainWindowTitle -eq "' + $WindowName + '"}')
    $PSGetPIDfromWindowName=$PSObject.GetValue('$process.ID') 
  endif
endfunction


So the code would be simply...

break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")
 
? PSGetWindowNamefromPid(4784)
? PSGetPIDfromWindowName("Administrator: Windows Powershell")


Mart
(KiX Supporter)
2010-08-24 04:21 PM
Re: Com Interface to Powershell

Wow \:o

This is really useful stuff.
Just finished a small kixtart/kixforms.NET app that puts some text into an application window. There are nine possible titles of the window that are now hardcoded into the script. Getting the title of the window would make things a lot easier. I can get the PID easily so getting the title should be doable.

I'll do some testing when I'm back at the office next week.


Arend_
(MM club member)
2010-08-25 01:16 PM
Re: Com Interface to Powershell

Well, I hate to be the one to point this out, but AutoIT (a KiX-like scripting language) also has a dll with COM interface which does the same. One of my first posts uses this.
Found it



AllenAdministrator
(KiX Supporter)
2010-09-15 06:49 AM
Re: Com Interface to Powershell

I'm really starting to see the power of .Net. Why oh why can't we get this added to Kix?

Anyway... Fire off a process and return the new processes PID.

break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")
 
PSStartProcess("%systemroot%\system32\Calc.exe")

Function PSStartProcess($exe, optional $arguments, optional $PSObject) if $PSobject="" $PSObject=CreateObject("SAPIEN.ActiveXPoSH") endif if $PSObject.init(not 0) if exist($exe) if $arguments $PSObject.execute('$Process=[System.Diagnostics.Process]::Start("' + $exe + '","' + $arguments + '")') else $PSObject.execute('$Process=[System.Diagnostics.Process]::Start("' + $exe + '")') endif $PSStartProcess=$PSObject.getvalue('$Process.ID') else exit 2 endif endif endfunction


Bryce
(KiX Supporter)
2010-09-15 07:22 PM
Re: Com Interface to Powershell

Hey Allen,

I am testing PSStartProcess()

 Code:
$pid = psstartprocess($dsync, $dsyncflag + $dpath[$i] + $storage)


$exe gets turned into this captured during a debug session.

 Code:
? $exe
c:\dexis\DEXSYNC.EXE, /v /h /c /i /n /m \\lan-dexis01\d-Drive\DEXIS\DATA e:\dexis\data



this line throws an error.
 Code:
$PSObject.execute('$Process=[System.Diagnostics.Process]::Start("' + $exe + '")')



 Code:
ERROR: Exception calling "Start" with "1" argument(s): "The system cannot find the fil
ERROR: e specified"
ERROR: At line:1 char:45
ERROR: + $Process=[System.Diagnostics.Process]::Start( <<<< "c:\dexis\DEXSYNC.EXE, /v
ERROR: /h /c /i /n /m \\lan-dexis01\d-Drive\DEXIS\DATA e:\dexis\data")


My tests done with just launching Notepad.exe worked great! But seems that adding an argument, causes problems.


AllenAdministrator
(KiX Supporter)
2010-09-15 07:27 PM
Re: Com Interface to Powershell

I see why... just a sec...

AllenAdministrator
(KiX Supporter)
2010-09-15 07:34 PM
Re: Com Interface to Powershell

I updated the function above... see if that works any better.

Bryce
(KiX Supporter)
2010-09-15 07:41 PM
Re: Com Interface to Powershell

 Originally Posted By: Allen
I updated the function above... see if that works any better.


And that's the stuff!!!

Thanks Allen!


AllenAdministrator
(KiX Supporter)
2010-11-20 01:59 AM
Re: Com Interface to Powershell

Next up... using dlls with Powershell. In the past we've used a number of methods including the DynamicWrapper.dll(Dynawrap). The problem I had with dynawrapper is it was so complicated and cryptic to read, especially after I hadn't looked at the code lately. I had read it was possible to import dlls in PS. So I decided to see if I could convert some of the dynawrap udfs to ps.

The first one I decided to translate was the SetKeyState UDF. And after much trial and error, I got it to work. (I can't say that about the second one, which will be the topic of another post)

You can find the $sig or signature to use the dll at http://www.pinvoke.net The C# sigs work with Powershell. Powershell uses the @ to define a multi-line string (called a here string) and all the powershell examples defined the sig this way. Unfortunately, the ActiveXPosh dll doesn't like here strings, so I had to break each line down and add the @CRLF.

The lines with the -memberdefintion basically take the $sig and assigns it to a var. The namespace and name values seem to be completely up to the coder, with (as far as I can tell) little to no value. I think they can contain just about any value, they just can't be the same value, and they have to be there.

function PSSetKeyState($Key, $toggle, optional $PSObject)
if $PSobject=""
$PSObject=CreateObject("SAPIEN.ActiveXPoSH")
endif
if $toggle="on"
$toggle="1"
endif
if $toggle="off"
$toggle="0"
endif
Select
Case $key="ScrollLock"
$key="0x91"
Case $key="CapsLock"
$key="0x14"
Case $key="NumLock"
$key="0x90"
endselect
if $PSObject.init(not 0)
$PSObject.Execute("$sig='" + '[DllImport("user32.dll")]' + @CRLF +
'public static extern short GetKeyState(int keyCode);' + "'")


$PSObject.Execute('$GetKeyState=Add-Type -memberDefinition $sig -namespace Win32Functions -name "Win32GetKeyState" -passThru')


$PSObject.Execute("$sig='" + '[DllImport("user32.dll")]' + @CRLF +
'public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);' + "'")


$PSObject.Execute('$keybdevent=Add-Type -memberDefinition $sig -namespace Win32Functions -name "Win32keybd_event" -passThru')


$PSSetKeyState=$PSObject.GetValue('$GetKeyState::GetKeyState(' + $key + ')')
if $PSSetKeyState<>$toggle
$PSObject.Execute('$keybdevent::keybd_event(' + $key + ',0,0,0)') ; Press the key
$PSObject.Execute('$keybdevent::keybd_event(' + $key + ',0,2,0)') ; Release the key
endif
endif
endfunction






Benny69
(MM club member)
2011-03-30 04:21 AM
Re: Com Interface to Powershell

Hey Allen,
Just reading thru your thred, cool stuff, i will have to play with this, i luv the .net stuff.


AllenAdministrator
(KiX Supporter)
2011-10-07 06:07 PM
Re: Com Interface to Powershell

My latest use of the .net / ActiveXPoSH dll... MD5 and SHA1 Checksum/Hash

Borrowed code from: http://www.tinyint.com/index.php/2011/09/14/get-an-md5-or-sha1-checksum-with-powershell/

break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")
 
? GetCheckSum(@scriptdir + "\ActiveXPoSH.exe","MD5") ? GetCheckSum(@scriptdir + "\ActiveXPoSH.exe","SHA1")

Function GetCheckSum($file, $algorithm, optional $PSObject) if $PSobject="" $PSObject=CreateObject("SAPIEN.ActiveXPoSH") endif if $PSObject.init(not 0) if exist($file) $PSObject.execute('$fs = new-object System.IO.FileStream "' + $file + '", "Open"') $PSObject.execute('$algo = [type]"System.Security.Cryptography.' + $Algorithm + '"') $PSObject.execute('$crypto = $algo::Create()') $PSobject.execute('$hash = [BitConverter]::ToString($crypto.ComputeHash($fs)).Replace("-", "")') $PSObject.execute('$fs.Close()') $GetChecksum=$PSObject.getvalue('$hash') else exit 2 endif endif endfunction


AllenAdministrator
(KiX Supporter)
2012-02-10 07:00 PM
Re: Com Interface to Powershell

How to determine if an EXE is 16bit, 32bit (x86), or 64bit (x64)...

break on
$RC=setoption("NoVarsInStrings","on")
$RC=setoption("NoMacrosInStrings","on")
$RC=setoption("WrapATEOL","on")
 
? PSGetBinaryType('%systemroot%\notepad.exe')
? PSGetBinaryType(@scriptdir + '\kix32.exe')
 
function PSGetBinaryType($FQFN, optional $PSObject) dim $result,$values[7] $values="Windows 32bit","MSDOS","Windows 16bit","PIF","POSIX","OS/2 16bit","Windows 64bit" if $PSobject="" $PSObject=CreateObject("SAPIEN.ActiveXPoSH") endif if exist($FQFN) if $PSObject.init(not 0) $PSGetBinaryType=-1 $PSObject.Execute("$sig='" + '[DllImport("kernel32.dll")]' + @CRLF + 'public static extern bool GetBinaryType(string lpApplicationName,ref int lpBinaryType);' + "'") $PSObject.Execute('$GetBinaryType=Add-Type -memberDefinition $sig -namespace Win32Functions -name "BinaryType" -passThru') $PSObject.Execute('$ReturnedType = -1') $Result=$PSObject.GetValue('$GetBinaryType::GetBinaryType("' + $FQFN + '",[ref] $ReturnedType)') if $result="True" $PSGetBinaryType=$values[$PSObject.Getvalue('$ReturnedType')] endif endif endif endfunction


AllenAdministrator
(KiX Supporter)
2018-06-05 11:06 PM
Re: Com Interface to Powershell

It seems Sapien has made it harder to find this download. As of 2018/06/05 it can be found with the following instructions.

1. Go to http://www.sapien.com
2. Sign in or Create an account (free)
3. Go here: https://www.sapien.com/downloads#
4. Click the "Free Components" folder in the left panel
5. In the right panel, you will see ActiveXPoshv2, ActiveXPoshV3x86 and ActiveXPoshV3x64