Page 1 of 2 12>
Topic Options
#199178 - 2010-07-31 08:06 AM Com Interface to Powershell
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
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

Top
#199180 - 2010-07-31 11:15 AM Re: Com Interface to Powershell [Re: Allen]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1895
Loc: Hilversum, The Netherlands
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 \:\)

Top
#199181 - 2010-07-31 11:18 AM Re: Com Interface to Powershell [Re: Arend_]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1895
Loc: Hilversum, The Netherlands
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.

Top
#199182 - 2010-07-31 11:20 AM Re: Com Interface to Powershell [Re: Arend_]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1895
Loc: Hilversum, The Netherlands
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

Top
#199183 - 2010-07-31 03:34 PM Re: Com Interface to Powershell [Re: Arend_]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
 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.

Top
#199190 - 2010-08-01 10:35 AM Re: Com Interface to Powershell [Re: Allen]
Bryce Offline
KiX Supporter
*****

Registered: 2000-02-29
Posts: 3167
Loc: Houston TX
one thing i dont like about powershell.... the darn hoops you got to jump though to execute a script from a cmd line :P
Top
#199191 - 2010-08-01 11:55 AM Re: Com Interface to Powershell [Re: Bryce]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1895
Loc: Hilversum, The Netherlands
what hoops?
 Code:
Powershell .\script.ps1

Top
#199192 - 2010-08-01 04:40 PM Re: Com Interface to Powershell [Re: Arend_]
Bryce Offline
KiX Supporter
*****

Registered: 2000-02-29
Posts: 3167
Loc: Houston TX
 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.


Edited by Bryce (2010-08-01 04:40 PM)

Top
#199208 - 2010-08-02 08:33 AM Re: Com Interface to Powershell [Re: Bryce]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1895
Loc: Hilversum, The Netherlands
Yeah, the security of PS is [censored], I have to agree, you have to set security per workstation \:\(
Top
#199362 - 2010-08-06 01:50 AM Re: Com Interface to Powershell [Re: Arend_]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
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?

Top
#199364 - 2010-08-06 02:59 AM Re: Com Interface to Powershell [Re: Allen]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
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.

Top
#199638 - 2010-08-23 07:54 PM Re: Com Interface to Powershell [Re: Allen]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
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")

Top
#199646 - 2010-08-24 04:21 PM Re: Com Interface to Powershell [Re: Allen]
Mart Moderator Offline
KiX Supporter
*****

Registered: 2002-03-27
Posts: 4673
Loc: The Netherlands
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.
_________________________
Mart

- Chuck Norris once sold ebay to ebay on ebay.

Top
#199649 - 2010-08-25 01:16 PM Re: Com Interface to Powershell [Re: Mart]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1895
Loc: Hilversum, The Netherlands
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



Edited by apronk (2010-08-26 09:39 AM)
Edit Reason: Updated link

Top
#199884 - 2010-09-15 06:49 AM Re: Com Interface to Powershell [Re: Arend_]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
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


Edited by Allen (2010-09-15 07:33 PM)

Top
#199892 - 2010-09-15 07:22 PM Re: Com Interface to Powershell [Re: Allen]
Bryce Offline
KiX Supporter
*****

Registered: 2000-02-29
Posts: 3167
Loc: Houston TX
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.

Top
#199893 - 2010-09-15 07:27 PM Re: Com Interface to Powershell [Re: Bryce]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
I see why... just a sec...
Top
#199894 - 2010-09-15 07:34 PM Re: Com Interface to Powershell [Re: Allen]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
I updated the function above... see if that works any better.
Top
#199896 - 2010-09-15 07:41 PM Re: Com Interface to Powershell [Re: Allen]
Bryce Offline
KiX Supporter
*****

Registered: 2000-02-29
Posts: 3167
Loc: Houston TX
 Originally Posted By: Allen
I updated the function above... see if that works any better.


And that's the stuff!!!

Thanks Allen!

Top
#200660 - 2010-11-20 01:59 AM Re: Com Interface to Powershell [Re: Bryce]
Allen Administrator Offline
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4549
Loc: USA
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





Top
Page 1 of 2 12>


Moderator:  Shawn, ShaneEP, Ruud van Velsen, Arend_, Jochen, Radimus, Glenn Barnas, Allen, Mart 
Hop to:
Shout Box

Who's Online
0 registered and 370 anonymous users online.
Newest Members
Timothy, Jojo67, MaikSimon, kvn317, kixtarts2025
17874 Registered Users

Generated in 0.155 seconds in which 0.106 seconds were spent on a total of 15 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org